'use strict' const { now } = require('pearcord-shared') const USER_PREFS_GOSSIP_WINDOW = 4096 const userSettingsMixin = { _userPrefsGossipKeys: null, _userPrefsHealWatermark: null, _userPrefsGossipKey (payload) { if (!payload?.userId) return '' const at = payload.updatedAt || payload.prefsUpdatedAt || 0 const keys = payload.patchKeys?.join(',') || Object.keys(payload.prefs || {}).slice(0, 8).join(',') return `prefs:${payload.userId}:${at}:${keys}` }, _shouldGossipUserPrefs (payload) { const hash = this._userPrefsGossipKey(payload) if (!hash) return false if (!this._userPrefsGossipKeys) this._userPrefsGossipKeys = new Set() if (this._userPrefsGossipKeys.has(hash)) return false this._userPrefsGossipKeys.add(hash) if (this._userPrefsGossipKeys.size > USER_PREFS_GOSSIP_WINDOW) { const first = this._userPrefsGossipKeys.values().next().value if (first) this._userPrefsGossipKeys.delete(first) } return true }, async _healUserPrefsOnPartition (guildId) { const span = this.log.time('settings.heal', { spanKind: 'settings.heal', guildId: guildId || this.guild?.guild?.id || null }) try { if (!this.userSettings) { span.end({ relisted: 0, skipped: true }) return { relisted: 0, skipped: true } } const prefs = await this.userSettings.getPrefs() const watermark = Date.now() this._userPrefsHealWatermark = watermark span.end({ relisted: Object.keys(prefs || {}).length, watermark, settingsUserSection: prefs?.settingsUserSection || null }) return { relisted: Object.keys(prefs || {}).length, watermark } } catch (err) { this.log.error('settings.heal error', { guildId, error: err?.message || String(err) }) span.fail(err) return { relisted: 0, error: err?.message || String(err) } } }, async _healProfileCosmeticsOnPartition (guildId) { const span = this.log.time('privacy.heal', { spanKind: 'privacy.heal', guildId: guildId || this.guild?.guild?.id || null }) try { if (!this.profileCosmetics) { span.end({ relisted: 0, skipped: true }) return { relisted: 0, skipped: true } } const row = await this.profileCosmetics.get().catch(() => null) span.end({ relisted: row ? 1 : 0, hasBanner: !!row?.bannerColor }) return { relisted: row ? 1 : 0 } } catch (err) { this.log.error('privacy.heal error', { guildId, error: err?.message || String(err) }) span.fail(err) return { relisted: 0, error: err?.message || String(err) } } } } module.exports = { userSettingsMixin, USER_PREFS_GOSSIP_WINDOW }