'use strict' const botsMixin = { _botInstallGossipKeys: null, _botRegistryHealWatermark: null, _botTokenHealWatermark: null, _initBotsMixinState () { if (!this._botInstallGossipKeys) { this._botInstallGossipKeys = new Set() } }, _shouldGossipBotInstall (bot) { this._initBotsMixinState() if (!bot?.guildId || !bot?.id) return true const hash = `${bot.guildId}:${bot.id}:${bot.name || ''}:${bot.permissions ?? ''}:${bot.intents ?? ''}:${bot.publicKey || ''}:${bot.createdAt || 0}` if (this._botInstallGossipKeys.has(hash)) return false this._botInstallGossipKeys.add(hash) if (this._botInstallGossipKeys.size > 8192) { const first = this._botInstallGossipKeys.values().next().value if (first) this._botInstallGossipKeys.delete(first) } return true }, async _healBotRegistryOnPartition (guildId) { const gid = guildId || this.guild?.guild?.id || null const span = this.log.time('bot.heal', { spanKind: 'bot.heal', guildId: gid, slice: 'registry' }) try { if (!gid || !this.listBots) { span.end({ relisted: 0, skipped: true }) return { relisted: 0, skipped: true } } const rows = await this.listBots().catch(() => []) let relisted = 0 for (const row of rows) { if (row.guildId && row.guildId !== gid) continue if (this._shouldGossipBotInstall(row) && this.guild?.gossipBotInstall) { this.guild.gossipBotInstall(row) relisted++ } } const watermark = Date.now() this._botRegistryHealWatermark = watermark span.end({ relisted, watermark, botCount: rows.length }) return { relisted, watermark, botCount: rows.length } } catch (err) { this.log.error('bot.heal error', { guildId: gid, slice: 'registry', error: err?.message || String(err) }) span.fail(err) return { relisted: 0, error: err?.message || String(err) } } }, async _healBotTokenCursorOnPartition (guildId) { const gid = guildId || this.guild?.guild?.id || null const span = this.log.time('bot.install', { spanKind: 'bot.install', guildId: gid, context: 'heal.token' }) try { if (!gid) { span.end({ relisted: 0, skipped: true, guildBotCount: 0 }) return { relisted: 0, skipped: true } } const list = await this.listBots().catch(() => []) const watermark = Date.now() this._botTokenHealWatermark = watermark span.end({ relisted: 0, watermark, guildBotCount: list.length, activeCount: list.filter((b) => b.active !== false).length, guildCount: (this.guilds || []).length, activeChannelId: this.activeChannelId || null }) return { relisted: 0, watermark, guildBotCount: list.length } } catch (err) { this.log.error('bot.install error', { guildId: gid, context: 'heal.token', error: err?.message || String(err) }) span.fail(err) return { relisted: 0, error: err?.message || String(err) } } } } module.exports = { botsMixin }