feat(fax): add fax routing, job tracking, inbox management, and T.38/UDPTL media support

This commit is contained in:
2026-04-20 20:43:42 +00:00
parent 3c010a3b1b
commit d2c18a4ebb
27 changed files with 4247 additions and 280 deletions
+13 -1
View File
@@ -9,6 +9,8 @@ import fs from 'node:fs';
import path from 'node:path';
import { loadConfig, type IAppConfig } from './config.ts';
import { FaxBoxManager } from './faxbox.ts';
import { FaxJobManager } from './faxjobs.ts';
import { broadcastWs, initWebUi } from './frontend.ts';
import { initWebRtcSignaling, getAllBrowserDeviceIds, sendToBrowserDevice } from './webrtcbridge.ts';
import { VoiceboxManager } from './voicebox.ts';
@@ -35,8 +37,12 @@ const instanceId = `${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
const statusStore = new StatusStore(appConfig);
const webRtcLinks = new WebRtcLinkManager();
const faxBoxManager = new FaxBoxManager(log);
const faxJobManager = new FaxJobManager(log);
const voiceboxManager = new VoiceboxManager(log);
faxBoxManager.init(appConfig.faxboxes ?? []);
faxJobManager.init();
voiceboxManager.init(appConfig.voiceboxes ?? []);
initWebRtcSignaling({ log });
@@ -61,6 +67,7 @@ function buildProxyConfig(config: IAppConfig): Record<string, unknown> {
providers: config.providers,
devices: config.devices,
routing: config.routing,
faxboxes: config.faxboxes ?? [],
voiceboxes: config.voiceboxes ?? [],
ivr: config.ivr,
};
@@ -93,6 +100,7 @@ async function reloadConfig(): Promise<void> {
appConfig = nextConfig;
statusStore.updateConfig(nextConfig);
faxBoxManager.init(nextConfig.faxboxes ?? []);
voiceboxManager.init(nextConfig.voiceboxes ?? []);
if (nextConfig.proxy.lanPort !== previousConfig.proxy.lanPort) {
@@ -123,6 +131,8 @@ async function startProxyEngine(): Promise<void> {
registerProxyEventHandlers({
log,
statusStore,
faxBoxManager,
faxJobManager,
voiceboxManager,
webRtcLinks,
getBrowserDeviceIds: getAllBrowserDeviceIds,
@@ -167,6 +177,8 @@ initWebUi({
return true;
},
onConfigSaved: reloadConfig,
faxBoxManager,
faxJobManager,
voiceboxManager,
onWebRtcOffer: async (sessionId, sdp, ws) => {
log(`[webrtc] offer from browser session=${sessionId.slice(0, 8)} sdp_type=${typeof sdp} sdp_len=${sdp?.length || 0}`);
@@ -187,7 +199,7 @@ initWebUi({
log('[webrtc] ERROR: no answer SDP from Rust');
},
onWebRtcIce: async (sessionId, candidate) => {
await webrtcIce(sessionId, candidate);
await webrtcIce(sessionId, candidate as Parameters<typeof webrtcIce>[1]);
},
onWebRtcClose: async (sessionId) => {
webRtcLinks.removeSession(sessionId);