WebSocketServer.clientsByCamera

This commit is contained in:
2026-07-04 18:09:16 +05:00
parent e0437edf18
commit eb001771b5
4 changed files with 29 additions and 20 deletions

View File

@@ -12,7 +12,8 @@
<body> <body>
<video id="v" controls autoplay muted></video> <video id="v" controls autoplay muted></video>
<script> <script>
const wsUrl = `${location.protocol === 'https:' ? 'wss' : 'ws'}://${location.host}/ws`; const cameraId = new URLSearchParams(location.search).get('camera') ?? 'v1';
const wsUrl = `${location.protocol === 'https:' ? 'wss' : 'ws'}://${location.host}/ws/${cameraId}`;
const player = mpegts.createPlayer( const player = mpegts.createPlayer(
{ type: 'mpegts', isLive: true, url: wsUrl }, { type: 'mpegts', isLive: true, url: wsUrl },
{ liveBufferLatencyChasing: true, liveBufferLatencyMaxLatency: 1.5 } { liveBufferLatencyChasing: true, liveBufferLatencyMaxLatency: 1.5 }

View File

@@ -1,5 +1,6 @@
import { log } from '../helpers/log.js' import { log } from '../helpers/log.js'
import { lastTopicSegment } from '../helpers/topic-match.js' import { lastTopicSegment } from '../helpers/topic-match.js'
import { onEdgeChunk } from '../stream/edge-chunk-relay.js'
import type { TopicHandler } from '../types.js' import type { TopicHandler } from '../types.js'
const LOG_INTERVAL_MS = 10_000 const LOG_INTERVAL_MS = 10_000
@@ -9,15 +10,12 @@ const lastLogByCamera = new Map<string, number>()
export const handleEdge5VideoV2: TopicHandler = async (topic, payload) => { export const handleEdge5VideoV2: TopicHandler = async (topic, payload) => {
const cameraId = lastTopicSegment(topic) const cameraId = lastTopicSegment(topic)
if (!cameraId) {
console.warn('edge5.video.v2.invalid_topic', { topic })
return
}
const now = Date.now() const now = Date.now()
const lastLog = lastLogByCamera.get(cameraId) ?? 0 const lastLog = lastLogByCamera.get(cameraId) ?? 0
if (now - lastLog >= LOG_INTERVAL_MS) { if (now - lastLog >= LOG_INTERVAL_MS) {
log(`edge5.video.v2 [${cameraId}] ↑ ${payload.length}B`) log(`edge5.video.v2 [${cameraId}] ↑ ${payload.length}B`)
lastLogByCamera.set(cameraId, now) lastLogByCamera.set(cameraId, now)
} }
onEdgeChunk(cameraId, payload);
} }

View File

@@ -11,5 +11,5 @@ export const handleEdge5Video: TopicHandler = async (_topic, payload) => {
log(`edge5.video ↑ ${payload.length}B`) log(`edge5.video ↑ ${payload.length}B`)
lastLog = now lastLog = now
} }
onEdgeChunk(payload) onEdgeChunk('v1', payload);
} }

View File

@@ -2,30 +2,40 @@ import type { IncomingMessage } from 'http'
import { WebSocket, WebSocketServer } from 'ws' import { WebSocket, WebSocketServer } from 'ws'
import { log } from '../helpers/log.js' import { log } from '../helpers/log.js'
import { lastTopicSegment } from '../helpers/topic-match.js'
const wsPort = Number(process.env.WS_PORT) const wsPort = Number(process.env.WS_PORT)
const wss = new WebSocketServer({ port: wsPort, perMessageDeflate: false }) const wss = new WebSocketServer({ port: wsPort, perMessageDeflate: false })
const clients = new Set<WebSocket>()
const clientsByCamera = new Map<string, Set<WebSocket>>()
function getClients(cameraId: string): Set<WebSocket> {
let clients = clientsByCamera.get(cameraId)
if (!clients) {
clients = new Set()
clientsByCamera.set(cameraId, clients)
}
return clients
}
wss.on('connection', (ws: WebSocket, req: IncomingMessage) => { wss.on('connection', (ws: WebSocket, req: IncomingMessage) => {
clients.add(ws) log(`ws.connection ${req.url}`);
log('ws.client_connected', { const cameraId = req.url ? lastTopicSegment(req.url) : 'v1';
clients: clients.size,
ip: req.socket.remoteAddress, const clients = getClients(cameraId);
}) clients.add(ws);
ws.on('close', () => { ws.on('close', () => {
clients.delete(ws) clients.delete(ws)
log('ws.client_closed', { clients: clients.size }) if (clients.size === 0) clientsByCamera.delete(cameraId)
}) });
}) })
wss.on('listening', () => { export function onEdgeChunk(cameraId: string, chunk: Buffer): void {
log('ws.server_started', { port: wsPort }) const clients = clientsByCamera.get(cameraId)
}) if (!clients) return
export function onEdgeChunk(chunk: Buffer): void {
for (const client of clients) { for (const client of clients) {
if (client.readyState === WebSocket.OPEN) { if (client.readyState === WebSocket.OPEN) {
client.send(chunk) client.send(chunk)