'use strict' const { PERMISSION_META } = require('pearcord-guild-roles/permissions') const memberRolesMixin = { _memberRoleGossipKeys: null, _memberRoleHealWatermark: null, _effectivePermHealWatermark: null, _initMemberRolesMixinState () { if (!this._memberRoleGossipKeys) { this._memberRoleGossipKeys = new Set() } }, _shouldGossipMemberRoles (link) { this._initMemberRolesMixinState() if (!link?.guildId || !link?.userId) return true const ids = (link.roleIds || []).join(',') const hash = `${link.guildId}:${link.userId}:${ids}:${link.updatedAt || 0}` if (this._memberRoleGossipKeys.has(hash)) return false this._memberRoleGossipKeys.add(hash) if (this._memberRoleGossipKeys.size > 8192) { const first = this._memberRoleGossipKeys.values().next().value if (first) this._memberRoleGossipKeys.delete(first) } return true }, async _healMemberRoleLinksOnPartition (guildId) { const gid = guildId || this.guild?.guild?.id || null const span = this.log.time('role.heal', { spanKind: 'role.heal', guildId: gid, slice: 'member-links' }) try { if (!gid || !this.guildRoles?.listMemberLinks) { span.end({ relisted: 0, skipped: true }) return { relisted: 0, skipped: true } } const links = await this.guildRoles.listMemberLinks(gid).catch(() => []) let relisted = 0 for (const link of links) { if (link.guildId && link.guildId !== gid) continue if (this._shouldGossipMemberRoles(link) && this.guild?.gossipMemberCustomRoles) { this.guild.gossipMemberCustomRoles(link) relisted++ } } const watermark = Date.now() this._memberRoleHealWatermark = watermark span.end({ relisted, watermark, linkCount: links.length }) return { relisted, watermark, linkCount: links.length } } catch (err) { this.log.error('role.heal error', { guildId: gid, slice: 'member-links', error: err?.message || String(err) }) span.fail(err) return { relisted: 0, error: err?.message || String(err) } } }, async _healEffectivePermissionCacheOnPartition (guildId) { const gid = guildId || this.guild?.guild?.id || null const span = this.log.time('permission.eval', { spanKind: 'permission.eval', guildId: gid, context: 'heal.cache' }) try { if (!gid) { span.end({ relisted: 0, skipped: true, effectivePermissionCount: 0 }) return { relisted: 0, skipped: true } } const flagCount = (PERMISSION_META || []).length const watermark = Date.now() this._effectivePermHealWatermark = watermark span.end({ relisted: 0, watermark, effectivePermissionCount: flagCount, guildCount: (this.guilds || []).length, activeChannelId: this.activeChannelId || null }) return { relisted: 0, watermark, effectivePermissionCount: flagCount } } catch (err) { this.log.error('permission.eval error', { guildId: gid, context: 'heal.cache', error: err?.message || String(err) }) span.fail(err) return { relisted: 0, error: err?.message || String(err) } } } } module.exports = { memberRolesMixin }