live: AMI-fed live state, /api/live WebSocket, dashboard and status dots
LiveState loads extension states and registered devices from Asterisk on every AMI connect and follows ExtensionStatus/ContactStatus; the hub sends a snapshot then deltas batched every 250 ms (devices for admins only), pings every 30 s and closes unauthenticated sockets with 4401. The web UI keeps one reconnecting socket in a zustand store, shows a Reconnecting banner, a Dashboard (online, on a call, telephony engine) and status dots. Fix: Asterisk 24 has no 'pjsip reload'; reload with 'module reload res_pjsip.so'. AMI errors now carry the CLI output. Milestone check, automated: call-test.ts registers two baresip phones and holds a 30 s call with RTP both ways (pnpm test:asterisk); the recorded session drives the live-state tests. scripts/e2e/m2-live.mjs runs api + Asterisk + phones + browser on a private Docker network: a new extension is live in Asterisk in ~1.3 s, the dashboard shows 2/2 online and red dots during the call. Task: M2-T6
This commit is contained in:
1 parent
1cfc13ead3
commit
c0c4036887
31 files changed
+4810
-28
No files matched your search
@@ -6,3 +6,4 @@ export * from './settings.ts';
|
||||
export * from './auth.ts';
|
||||
export * from './users.ts';
|
||||
export * from './extensions.ts';
|
||||
export * from './live.ts';
|
||||
@@ -0,0 +1,40 @@
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
// Live state shapes sent over the /api/live WebSocket (04 §5.1, §5.2).
|
||||
|
||||
export type ExtensionState =
|
||||
'idle' | 'inuse' | 'busy' | 'unavailable' | 'ringing' | 'onhold' | 'ringinuse';
|
||||
|
||||
export type ContactLive = {
|
||||
endpoint: string; // "101" or "101-web"
|
||||
uri: string;
|
||||
userAgent?: string;
|
||||
status: 'reachable' | 'unreachable' | 'unknown';
|
||||
rttMs?: number;
|
||||
};
|
||||
|
||||
export type ExtensionLive = {
|
||||
number: string;
|
||||
name: string;
|
||||
state: ExtensionState;
|
||||
/** Admins only; users see presence without devices. */
|
||||
contacts?: ContactLive[];
|
||||
/** Any registered device (desk phone, app or browser). */
|
||||
online: boolean;
|
||||
dnd: boolean;
|
||||
};
|
||||
|
||||
export type LiveSnapshot = {
|
||||
extensions: ExtensionLive[];
|
||||
ami: { connected: boolean };
|
||||
};
|
||||
|
||||
/** Server → client messages. */
|
||||
export type LiveMessage =
|
||||
| { type: 'snapshot'; data: LiveSnapshot }
|
||||
| { type: 'extension.updated'; data: ExtensionLive }
|
||||
| { type: 'extension.removed'; data: { number: string } }
|
||||
| { type: 'ami.status'; data: { connected: boolean } }
|
||||
| {
|
||||
type: 'system.configApplied';
|
||||
data: { ok: boolean; error: string | null; restartRequired: boolean };
|
||||
};
|
||||
Reference in new issue
Block a user