Phase 664: voice note diagnostics, gate in view, and gossip idempotency.
Adds exportVoiceNoteDiagnostics, voiceNoteGate in view, voiceNote.commit span, max duration guard on stage, and _ingestVoiceNoteGossip for duplicate VOICE_NOTE_CREATE payloads. Co-authored-by: Cursor <[email protected]>
This commit is contained in:
@@ -9896,6 +9896,9 @@ class PearcordPlatform extends EventEmitter {
|
||||
}
|
||||
})
|
||||
})
|
||||
guildInstance.on('voice-note', (payload) => {
|
||||
void this._ingestVoiceNoteGossip(payload).catch(() => {})
|
||||
})
|
||||
guildInstance.on('channel', (ch) => {
|
||||
this._fanoutBotEvent(BOT_EVENTS.CHANNEL_CREATE, { channel: ch })
|
||||
this.emit('channel', ch)
|
||||
@@ -12908,6 +12911,13 @@ class PearcordPlatform extends EventEmitter {
|
||||
async stageVoiceNoteDraft ({ data, durationMs, mimeType, waveformPeaks }) {
|
||||
const guildId = this.mode === 'dm' ? DM_GUILD_ID : this.guild?.guild?.id || null
|
||||
const channelId = this.activeChannelId
|
||||
const maxMs = Math.max(
|
||||
1000,
|
||||
Number(process.env.PEARCORD_VOICE_NOTE_MAX_MS) || 15 * 60 * 1000
|
||||
)
|
||||
if (Number(durationMs) > maxMs) {
|
||||
throw new Error(`Voice message exceeds maximum length (${Math.round(maxMs / 60000)} minutes)`)
|
||||
}
|
||||
const span = this.log.time('voiceNote.stage', {
|
||||
spanKind: 'voiceNote.stage',
|
||||
channelId,
|
||||
@@ -12978,14 +12988,36 @@ class PearcordPlatform extends EventEmitter {
|
||||
return row
|
||||
}
|
||||
|
||||
exportVoiceNoteDiagnostics (guildId = null) {
|
||||
const gid = guildId || this.guild?.guild?.id || (this.mode === 'dm' ? DM_GUILD_ID : null)
|
||||
const diag = this.voiceNotes?.getDiagnostics?.() || {}
|
||||
return {
|
||||
guildId: gid,
|
||||
channelId: this.activeChannelId || null,
|
||||
mode: this.mode,
|
||||
...diag,
|
||||
draft: this.voiceNotes?.getActiveDraftId?.() || null
|
||||
}
|
||||
}
|
||||
|
||||
async commitVoiceNoteDraft ({ messageId } = {}) {
|
||||
if (!this.voiceNotes) throw new Error('voice notes not ready')
|
||||
const out = await this.voiceNotes.commitDraft({ messageId })
|
||||
if (this.mode === 'guild' && this.guild?.gossipVoiceNoteCreate) {
|
||||
void this.guild.gossipVoiceNoteCreate(out.gossip).catch(() => {})
|
||||
const commitSpan = this.log.time('voiceNote.commit', {
|
||||
spanKind: 'voiceNote.commit',
|
||||
draftId: this.voiceNotes.getActiveDraftId?.() || null
|
||||
})
|
||||
try {
|
||||
const out = await this.voiceNotes.commitDraft({ messageId })
|
||||
if (this.mode === 'guild' && this.guild?.gossipVoiceNoteCreate) {
|
||||
void this.guild.gossipVoiceNoteCreate(out.gossip).catch(() => {})
|
||||
}
|
||||
commitSpan.end({ voiceNoteId: out.record?.id, size: out.record?.size })
|
||||
this.emit('voice-note-draft')
|
||||
return out
|
||||
} catch (err) {
|
||||
commitSpan.fail(err)
|
||||
throw err
|
||||
}
|
||||
this.emit('voice-note-draft')
|
||||
return out
|
||||
}
|
||||
|
||||
async sendVoiceNote ({ replyToId } = {}) {
|
||||
@@ -13031,6 +13063,19 @@ class PearcordPlatform extends EventEmitter {
|
||||
}
|
||||
}
|
||||
|
||||
async _ingestVoiceNoteGossip (payload) {
|
||||
if (!this.voiceNotes?.upsertFromGossip) return null
|
||||
const out = await this.voiceNotes.upsertFromGossip(payload)
|
||||
if (out?.applied) {
|
||||
this.log.info('voiceNote.ingest', {
|
||||
spanKind: 'voiceNote.ingest',
|
||||
voiceNoteId: payload?.id,
|
||||
duplicate: false
|
||||
})
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
async setMemberRole (userId, role) {
|
||||
const user = this.identity.user
|
||||
if (!user || !this.guild?.guild) throw new Error('no guild')
|
||||
@@ -23681,6 +23726,7 @@ class PearcordPlatform extends EventEmitter {
|
||||
channelConsistencyAudit.skippedAfterChannelRecovery = true
|
||||
}
|
||||
let voiceNoteDraft = null
|
||||
let voiceNoteGate = { ok: true, reason: null, message: '' }
|
||||
if (this.voiceNotes) {
|
||||
const vn = await this.voiceNotes.getDraft().catch(() => null)
|
||||
if (vn) {
|
||||
@@ -23694,6 +23740,11 @@ class PearcordPlatform extends EventEmitter {
|
||||
transcriptPlaceholder: vn.transcriptPlaceholder || null
|
||||
}
|
||||
}
|
||||
const activeCh =
|
||||
this.mode === 'guild' && this.guild
|
||||
? activeChannel
|
||||
: this.dm?.channel
|
||||
voiceNoteGate = this._voiceNoteGate(activeCh || null)
|
||||
}
|
||||
let stagedAttachments = []
|
||||
if (this.attachments && this.activeChannelId) {
|
||||
@@ -23839,6 +23890,7 @@ class PearcordPlatform extends EventEmitter {
|
||||
stagedAttachmentUi:
|
||||
userPrefs?.stagedAttachmentUi?.[this.activeChannelId] || null,
|
||||
voiceNoteDraft,
|
||||
voiceNoteGate,
|
||||
voiceStatesByChannel,
|
||||
stageRolesByChannel,
|
||||
myStageRole,
|
||||
|
||||
Reference in New Issue
Block a user