feat(server): fan dm_call_end out on host ring timeout

This commit is contained in:
Jannis Braun
2026-04-23 23:19:42 +02:00
parent 6cd7728f3e
commit f6252b8ce1
6 changed files with 84 additions and 19 deletions
+18 -1
View File
@@ -3,7 +3,7 @@ import * as schema from '../db/schema.js';
import { eq, and, inArray } from 'drizzle-orm';
import { generateSnowflake } from './snowflake.js';
import crypto from 'node:crypto';
import type { FederationRelayEvent, FederationRelayParticipant, FederationRelayAttachment, DmMessageWithUser, FederationRelayRequest } from '@backspace/shared';
import type { FederationRelayEvent, FederationRelayParticipant, FederationRelayAttachment, DmMessageWithUser, FederationRelayRequest, DmCallUndeliverableReason } from '@backspace/shared';
import { getOurOrigin, buildFederationHeaders, generateHmacSecret } from './federationAuth.js';
import { extractDomain } from '../routes/federation.js';
import { racePeering, ensurePeered } from './federationPeering.js';
@@ -527,6 +527,23 @@ export type CallRelayResult =
| { ok: true }
| { ok: false; reason: CallRelayFailureReason; error: string };
/** Per-peer failure record returned by Path-1 call fan-out helpers. */
export interface CallFanoutFailure {
origin: string;
peerLabel?: string;
reason: DmCallUndeliverableReason;
}
/** Map a sendCallRelay reason to the dm_call_undeliverable event-surface reason. */
export function mapCallReasonToEventReason(reason: CallRelayFailureReason): DmCallUndeliverableReason {
switch (reason) {
case 'peer_rejected': return 'peer_rejected';
case 'peer_awaiting_approval': return 'peer_awaiting_approval';
case 'peer_transient_failure': return 'peer_transient_failure';
case 'post_failed': return 'peer_transient_failure'; // 4xx looks transient to users
}
}
/**
* Send call signaling events directly to a remote peer (bypasses outbox).
* Latency-sensitive: if no active peer exists, race an ensurePeered handshake