ran prettier
This commit is contained in:
@@ -127,12 +127,14 @@ export default class PeerConnection implements IPeerConnectionOperations {
|
|||||||
this._iceConnectionState.value = peerConnection.iceConnectionState;
|
this._iceConnectionState.value = peerConnection.iceConnectionState;
|
||||||
};
|
};
|
||||||
|
|
||||||
this._disposables.add(new Disposable(() => {
|
this._disposables.add(
|
||||||
|
new Disposable(() => {
|
||||||
peerConnection.oniceconnectionstatechange = null;
|
peerConnection.oniceconnectionstatechange = null;
|
||||||
peerConnection.onicegatheringstatechange = null;
|
peerConnection.onicegatheringstatechange = null;
|
||||||
peerConnection.onconnectionstatechange = null;
|
peerConnection.onconnectionstatechange = null;
|
||||||
peerConnection.onsignalingstatechange = null;
|
peerConnection.onsignalingstatechange = null;
|
||||||
}));
|
})
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private setPeerConnectionEventListeners(peerConnection: RTCPeerConnection): void {
|
private setPeerConnectionEventListeners(peerConnection: RTCPeerConnection): void {
|
||||||
@@ -157,10 +159,12 @@ export default class PeerConnection implements IPeerConnectionOperations {
|
|||||||
peerConnection.onicecandidate = iceCandidateHandler;
|
peerConnection.onicecandidate = iceCandidateHandler;
|
||||||
peerConnection.ontrack = trackHandler;
|
peerConnection.ontrack = trackHandler;
|
||||||
|
|
||||||
this._disposables.add(new Disposable(() => {
|
this._disposables.add(
|
||||||
|
new Disposable(() => {
|
||||||
peerConnection.onicecandidate = null;
|
peerConnection.onicecandidate = null;
|
||||||
peerConnection.ontrack = null;
|
peerConnection.ontrack = null;
|
||||||
}));
|
})
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private initialize(): void {
|
private initialize(): void {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import type { ICandidateMessage, IAnswerMessage, IOfferMessage, IMessage } from "./messaging/IMessage";
|
import type {ICandidateMessage, IAnswerMessage, IOfferMessage, IMessage} from './messaging/IMessage';
|
||||||
import { MessageKind } from "./messaging/MessageKind";
|
import {MessageKind} from './messaging/MessageKind';
|
||||||
import type { ISignalingClient } from "./interfaces/ISignalingClient";
|
import type {ISignalingClient} from './interfaces/ISignalingClient';
|
||||||
|
|
||||||
export default class SignalingServer implements ISignalingClient {
|
export default class SignalingServer implements ISignalingClient {
|
||||||
private readonly _webSocket: WebSocket;
|
private readonly _webSocket: WebSocket;
|
||||||
@@ -10,7 +10,7 @@ export default class SignalingServer implements ISignalingClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public on<T>(kind: MessageKind, callback: (message: IMessage<T>) => Promise<void>): void {
|
public on<T>(kind: MessageKind, callback: (message: IMessage<T>) => Promise<void>): void {
|
||||||
this._webSocket.addEventListener('message', (event) => {
|
this._webSocket.addEventListener('message', event => {
|
||||||
const message = JSON.parse(event.data) as IMessage<T>;
|
const message = JSON.parse(event.data) as IMessage<T>;
|
||||||
|
|
||||||
if (message.type === kind) {
|
if (message.type === kind) {
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import type {ILogger} from '@techniker-me/logger';
|
import type {ILogger} from '@techniker-me/logger';
|
||||||
import {LoggerFactory} from '@techniker-me/logger';
|
import {LoggerFactory} from '@techniker-me/logger';
|
||||||
import {ReadOnlySubject, Subject, type IEvent} from '@techniker-me/tools';
|
import {ReadOnlySubject, Subject, type IEvent} from '@techniker-me/tools';
|
||||||
import type { IPeerConnectionOperations } from './interfaces/IPeerConnectionOperations';
|
import type {IPeerConnectionOperations} from './interfaces/IPeerConnectionOperations';
|
||||||
import type { ISignalingClient } from './interfaces/ISignalingClient';
|
import type {ISignalingClient} from './interfaces/ISignalingClient';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* User class - manages local and remote media streams
|
* User class - manages local and remote media streams
|
||||||
@@ -39,7 +39,7 @@ export default class User {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public async startLocalMedia(): Promise<void> {
|
public async startLocalMedia(): Promise<void> {
|
||||||
const mediaStream = await navigator.mediaDevices.getUserMedia({ audio: true, video: true });
|
const mediaStream = await navigator.mediaDevices.getUserMedia({audio: true, video: true});
|
||||||
|
|
||||||
this._peerConnection.addMediaStream(mediaStream);
|
this._peerConnection.addMediaStream(mediaStream);
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
import { Caller } from './Caller';
|
import {Caller} from './Caller';
|
||||||
import { Callee } from './Callee';
|
import {Callee} from './Callee';
|
||||||
import type { ISignalingClient } from '../interfaces/ISignalingClient';
|
import type {ISignalingClient} from '../interfaces/ISignalingClient';
|
||||||
import type { IPeerConnectionOperations } from '../interfaces/IPeerConnectionOperations';
|
import type {IPeerConnectionOperations} from '../interfaces/IPeerConnectionOperations';
|
||||||
import { MessageKind } from '../messaging/MessageKind';
|
import {MessageKind} from '../messaging/MessageKind';
|
||||||
import type { IMessage } from '../messaging/IMessage';
|
import type {IMessage} from '../messaging/IMessage';
|
||||||
import type { ILogger } from '@techniker-me/logger';
|
import type {ILogger} from '@techniker-me/logger';
|
||||||
import { LoggerFactory } from '@techniker-me/logger';
|
import {LoggerFactory} from '@techniker-me/logger';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* CallCoordinator - coordinates between Caller and Callee roles
|
* CallCoordinator - coordinates between Caller and Callee roles
|
||||||
@@ -20,10 +20,7 @@ export class CallCoordinator {
|
|||||||
private readonly _peerConnection: IPeerConnectionOperations;
|
private readonly _peerConnection: IPeerConnectionOperations;
|
||||||
private _lastReceivedOffer: RTCSessionDescriptionInit | null = null;
|
private _lastReceivedOffer: RTCSessionDescriptionInit | null = null;
|
||||||
|
|
||||||
constructor(
|
constructor(signalingClient: ISignalingClient, peerConnection: IPeerConnectionOperations) {
|
||||||
signalingClient: ISignalingClient,
|
|
||||||
peerConnection: IPeerConnectionOperations
|
|
||||||
) {
|
|
||||||
this._signalingClient = signalingClient;
|
this._signalingClient = signalingClient;
|
||||||
this._peerConnection = peerConnection;
|
this._peerConnection = peerConnection;
|
||||||
this._caller = new Caller(signalingClient, peerConnection);
|
this._caller = new Caller(signalingClient, peerConnection);
|
||||||
@@ -81,9 +78,7 @@ export class CallCoordinator {
|
|||||||
// Handle incoming offers (when acting as callee)
|
// Handle incoming offers (when acting as callee)
|
||||||
// Only set remote description - don't automatically create/send answer
|
// Only set remote description - don't automatically create/send answer
|
||||||
// The answer will be sent when the user clicks the "Send Answer" button
|
// The answer will be sent when the user clicks the "Send Answer" button
|
||||||
this._signalingClient.on<RTCSessionDescriptionInit>(
|
this._signalingClient.on<RTCSessionDescriptionInit>(MessageKind.Offer, async (message: IMessage<RTCSessionDescriptionInit>) => {
|
||||||
MessageKind.Offer,
|
|
||||||
async (message: IMessage<RTCSessionDescriptionInit>) => {
|
|
||||||
// Only handle offer if we're not the caller (don't have local offer)
|
// Only handle offer if we're not the caller (don't have local offer)
|
||||||
const currentState = this._peerConnection.getSignalingState();
|
const currentState = this._peerConnection.getSignalingState();
|
||||||
if (currentState === 'have-local-offer' || currentState === 'have-local-pranswer') {
|
if (currentState === 'have-local-offer' || currentState === 'have-local-pranswer') {
|
||||||
@@ -97,13 +92,10 @@ export class CallCoordinator {
|
|||||||
// Only set the remote description - don't create/send answer yet
|
// Only set the remote description - don't create/send answer yet
|
||||||
// This allows the callee to manually click "Send Answer" button
|
// This allows the callee to manually click "Send Answer" button
|
||||||
await this._peerConnection.setRemoteDescription(message.payload);
|
await this._peerConnection.setRemoteDescription(message.payload);
|
||||||
}
|
});
|
||||||
);
|
|
||||||
|
|
||||||
// Handle incoming answers (when acting as caller)
|
// Handle incoming answers (when acting as caller)
|
||||||
this._signalingClient.on<RTCSessionDescriptionInit>(
|
this._signalingClient.on<RTCSessionDescriptionInit>(MessageKind.Answer, async (message: IMessage<RTCSessionDescriptionInit>) => {
|
||||||
MessageKind.Answer,
|
|
||||||
async (message: IMessage<RTCSessionDescriptionInit>) => {
|
|
||||||
// Only handle answer if we're the caller (have local offer)
|
// Only handle answer if we're the caller (have local offer)
|
||||||
const currentState = this._peerConnection.getSignalingState();
|
const currentState = this._peerConnection.getSignalingState();
|
||||||
if (currentState !== 'have-local-offer' && currentState !== 'have-local-pranswer') {
|
if (currentState !== 'have-local-offer' && currentState !== 'have-local-pranswer') {
|
||||||
@@ -113,8 +105,6 @@ export class CallCoordinator {
|
|||||||
|
|
||||||
this._logger.info('Received answer, acting as caller');
|
this._logger.info('Received answer, acting as caller');
|
||||||
await this._caller.handleAnswer(message.payload);
|
await this._caller.handleAnswer(message.payload);
|
||||||
}
|
});
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import type { ISignalingClient } from '../interfaces/ISignalingClient';
|
import type {ISignalingClient} from '../interfaces/ISignalingClient';
|
||||||
import type { IPeerConnectionOperations } from '../interfaces/IPeerConnectionOperations';
|
import type {IPeerConnectionOperations} from '../interfaces/IPeerConnectionOperations';
|
||||||
import type { ILogger } from '@techniker-me/logger';
|
import type {ILogger} from '@techniker-me/logger';
|
||||||
import { LoggerFactory } from '@techniker-me/logger';
|
import {LoggerFactory} from '@techniker-me/logger';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Callee class - responsible for receiving and responding to WebRTC calls
|
* Callee class - responsible for receiving and responding to WebRTC calls
|
||||||
@@ -13,10 +13,7 @@ export class Callee {
|
|||||||
private readonly _signalingClient: ISignalingClient;
|
private readonly _signalingClient: ISignalingClient;
|
||||||
private readonly _peerConnection: IPeerConnectionOperations;
|
private readonly _peerConnection: IPeerConnectionOperations;
|
||||||
|
|
||||||
constructor(
|
constructor(signalingClient: ISignalingClient, peerConnection: IPeerConnectionOperations) {
|
||||||
signalingClient: ISignalingClient,
|
|
||||||
peerConnection: IPeerConnectionOperations
|
|
||||||
) {
|
|
||||||
this._signalingClient = signalingClient;
|
this._signalingClient = signalingClient;
|
||||||
this._peerConnection = peerConnection;
|
this._peerConnection = peerConnection;
|
||||||
}
|
}
|
||||||
@@ -54,4 +51,3 @@ export class Callee {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import type { ISignalingClient } from '../interfaces/ISignalingClient';
|
import type {ISignalingClient} from '../interfaces/ISignalingClient';
|
||||||
import type { IPeerConnectionOperations } from '../interfaces/IPeerConnectionOperations';
|
import type {IPeerConnectionOperations} from '../interfaces/IPeerConnectionOperations';
|
||||||
import type { ILogger } from '@techniker-me/logger';
|
import type {ILogger} from '@techniker-me/logger';
|
||||||
import { LoggerFactory } from '@techniker-me/logger';
|
import {LoggerFactory} from '@techniker-me/logger';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Caller class - responsible for initiating WebRTC calls
|
* Caller class - responsible for initiating WebRTC calls
|
||||||
@@ -13,10 +13,7 @@ export class Caller {
|
|||||||
private readonly _signalingClient: ISignalingClient;
|
private readonly _signalingClient: ISignalingClient;
|
||||||
private readonly _peerConnection: IPeerConnectionOperations;
|
private readonly _peerConnection: IPeerConnectionOperations;
|
||||||
|
|
||||||
constructor(
|
constructor(signalingClient: ISignalingClient, peerConnection: IPeerConnectionOperations) {
|
||||||
signalingClient: ISignalingClient,
|
|
||||||
peerConnection: IPeerConnectionOperations
|
|
||||||
) {
|
|
||||||
this._signalingClient = signalingClient;
|
this._signalingClient = signalingClient;
|
||||||
this._peerConnection = peerConnection;
|
this._peerConnection = peerConnection;
|
||||||
}
|
}
|
||||||
@@ -64,4 +61,3 @@ export class Caller {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import type { IEvent, IDisposable } from '@techniker-me/tools';
|
import type {IEvent, IDisposable} from '@techniker-me/tools';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Interface for peer connection operations
|
* Interface for peer connection operations
|
||||||
@@ -44,4 +44,3 @@ export interface IPeerConnectionOperations {
|
|||||||
*/
|
*/
|
||||||
on<T>(event: string, callback: (event: IEvent<T>) => void | Promise<void>): IDisposable;
|
on<T>(event: string, callback: (event: IEvent<T>) => void | Promise<void>): IDisposable;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import type { IMessage } from '../messaging/IMessage';
|
import type {IMessage} from '../messaging/IMessage';
|
||||||
import { MessageKind } from '../messaging/MessageKind';
|
import {MessageKind} from '../messaging/MessageKind';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Interface for signaling client operations
|
* Interface for signaling client operations
|
||||||
@@ -26,4 +26,3 @@ export interface ISignalingClient {
|
|||||||
*/
|
*/
|
||||||
sendCandidate(candidate: RTCIceCandidateInit): Promise<void>;
|
sendCandidate(candidate: RTCIceCandidateInit): Promise<void>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
import PeerConnection from './PeerConnection';
|
import PeerConnection from './PeerConnection';
|
||||||
import User from './User';
|
import User from './User';
|
||||||
import SignalingServer from './SignalingServer';
|
import SignalingServer from './SignalingServer';
|
||||||
import { CallCoordinator } from './call/CallCoordinator';
|
import {CallCoordinator} from './call/CallCoordinator';
|
||||||
import { MessageKind } from './messaging/MessageKind';
|
import {MessageKind} from './messaging/MessageKind';
|
||||||
import type { IMessage } from './messaging/IMessage';
|
import type {IMessage} from './messaging/IMessage';
|
||||||
import type { ISignalingClient } from './interfaces/ISignalingClient';
|
import type {ISignalingClient} from './interfaces/ISignalingClient';
|
||||||
|
|
||||||
type Elements = {
|
type Elements = {
|
||||||
localVideo: HTMLVideoElement;
|
localVideo: HTMLVideoElement;
|
||||||
@@ -16,7 +16,7 @@ type Elements = {
|
|||||||
iceConnectionStateValue: HTMLSpanElement;
|
iceConnectionStateValue: HTMLSpanElement;
|
||||||
iceGatheringStateValue: HTMLSpanElement;
|
iceGatheringStateValue: HTMLSpanElement;
|
||||||
connectionStateValue: HTMLSpanElement;
|
connectionStateValue: HTMLSpanElement;
|
||||||
}
|
};
|
||||||
|
|
||||||
const elements: Elements = {
|
const elements: Elements = {
|
||||||
localVideo: document.getElementById('local-video') as HTMLVideoElement,
|
localVideo: document.getElementById('local-video') as HTMLVideoElement,
|
||||||
@@ -28,7 +28,7 @@ const elements: Elements = {
|
|||||||
iceConnectionStateValue: document.getElementById('ice-connection-state-value') as HTMLSpanElement,
|
iceConnectionStateValue: document.getElementById('ice-connection-state-value') as HTMLSpanElement,
|
||||||
iceGatheringStateValue: document.getElementById('ice-gathering-state-value') as HTMLSpanElement,
|
iceGatheringStateValue: document.getElementById('ice-gathering-state-value') as HTMLSpanElement,
|
||||||
connectionStateValue: document.getElementById('connection-state-value') as HTMLSpanElement
|
connectionStateValue: document.getElementById('connection-state-value') as HTMLSpanElement
|
||||||
}
|
};
|
||||||
|
|
||||||
// Initialize WebSocket and signaling server
|
// Initialize WebSocket and signaling server
|
||||||
const websocket = new WebSocket(`ws://${window.location.hostname}:3000/ws`);
|
const websocket = new WebSocket(`ws://${window.location.hostname}:3000/ws`);
|
||||||
@@ -57,7 +57,7 @@ signalingServer.on<RTCIceCandidateInit>(MessageKind.Candidate, async (message: I
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Setup UI state subscriptions
|
// Setup UI state subscriptions
|
||||||
peerConnection.signalingState.subscribe((state) => {
|
peerConnection.signalingState.subscribe(state => {
|
||||||
elements.signalingStateValue.textContent = state;
|
elements.signalingStateValue.textContent = state;
|
||||||
|
|
||||||
// Enable send answer button when remote offer is received
|
// Enable send answer button when remote offer is received
|
||||||
@@ -68,15 +68,15 @@ peerConnection.signalingState.subscribe((state) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
peerConnection.iceConnectionState.subscribe((state) => {
|
peerConnection.iceConnectionState.subscribe(state => {
|
||||||
elements.iceConnectionStateValue.textContent = state;
|
elements.iceConnectionStateValue.textContent = state;
|
||||||
});
|
});
|
||||||
|
|
||||||
peerConnection.iceGatheringState.subscribe((state) => {
|
peerConnection.iceGatheringState.subscribe(state => {
|
||||||
elements.iceGatheringStateValue.textContent = state;
|
elements.iceGatheringStateValue.textContent = state;
|
||||||
});
|
});
|
||||||
|
|
||||||
peerConnection.connectionState.subscribe((state) => {
|
peerConnection.connectionState.subscribe(state => {
|
||||||
elements.connectionStateValue.textContent = state;
|
elements.connectionStateValue.textContent = state;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -5,20 +5,19 @@ export interface IMessage<T> {
|
|||||||
payload: T;
|
payload: T;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export type IOfferMessage = {
|
export type IOfferMessage = {
|
||||||
type: 'offer';
|
type: 'offer';
|
||||||
payload: RTCSessionDescriptionInit;
|
payload: RTCSessionDescriptionInit;
|
||||||
}
|
};
|
||||||
|
|
||||||
export type IAnswerMessage = {
|
export type IAnswerMessage = {
|
||||||
type: 'answer';
|
type: 'answer';
|
||||||
payload: RTCSessionDescriptionInit;
|
payload: RTCSessionDescriptionInit;
|
||||||
}
|
};
|
||||||
|
|
||||||
export type ICandidateMessage = {
|
export type ICandidateMessage = {
|
||||||
type: 'candidate';
|
type: 'candidate';
|
||||||
payload: RTCIceCandidateInit;
|
payload: RTCIceCandidateInit;
|
||||||
}
|
};
|
||||||
|
|
||||||
export type Message = IOfferMessage | IAnswerMessage | ICandidateMessage;
|
export type Message = IOfferMessage | IAnswerMessage | ICandidateMessage;
|
||||||
@@ -1,15 +1,20 @@
|
|||||||
import type { Server, ServerWebSocket } from "bun";
|
import type { Server, ServerWebSocket } from "bun";
|
||||||
import {LoggerFactory, type ILogger} from '@techniker-me/logger';
|
import { LoggerFactory, type ILogger } from "@techniker-me/logger";
|
||||||
import { MessageKindMapping } from "./messaging/MessageKind";
|
import { MessageKindMapping } from "./messaging/MessageKind";
|
||||||
|
|
||||||
export default class SignalingServer {
|
export default class SignalingServer {
|
||||||
private readonly _logger: ILogger = LoggerFactory.getLogger('SignalingServer');
|
private readonly _logger: ILogger =
|
||||||
|
LoggerFactory.getLogger("SignalingServer");
|
||||||
private readonly _port: number;
|
private readonly _port: number;
|
||||||
private readonly _hostname: string;
|
private readonly _hostname: string;
|
||||||
private readonly _development: boolean;
|
private readonly _development: boolean;
|
||||||
private readonly _clients: Set<ServerWebSocket<undefined>> = new Set();
|
private readonly _clients: Set<ServerWebSocket<undefined>> = new Set();
|
||||||
|
|
||||||
constructor(port: number, hostname: string = '0.0.0.0', development: boolean = false) {
|
constructor(
|
||||||
|
port: number,
|
||||||
|
hostname: string = "0.0.0.0",
|
||||||
|
development: boolean = false,
|
||||||
|
) {
|
||||||
this._port = port;
|
this._port = port;
|
||||||
this._hostname = hostname;
|
this._hostname = hostname;
|
||||||
this._development = development;
|
this._development = development;
|
||||||
@@ -35,55 +40,67 @@ export default class SignalingServer {
|
|||||||
drain: this.handleWebSocketDrain.bind(this),
|
drain: this.handleWebSocketDrain.bind(this),
|
||||||
error: this.handleWebSocketError.bind(this),
|
error: this.handleWebSocketError.bind(this),
|
||||||
perMessageDeflate: true,
|
perMessageDeflate: true,
|
||||||
maxPayloadLength: 10 * 1024
|
maxPayloadLength: 10 * 1024,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
get fetch() {
|
get fetch() {
|
||||||
return (req: Request, server: Server<undefined>) => {
|
return (req: Request, server: Server<undefined>) => {
|
||||||
this._logger.info(`Fetch request received [${req.url}] from [${server.requestIP(req)?.address}:${server.requestIP(req)?.port}]`);
|
this._logger.info(
|
||||||
|
`Fetch request received [${req.url}] from [${server.requestIP(req)?.address}:${server.requestIP(req)?.port}]`,
|
||||||
|
);
|
||||||
const url = new URL(req.url);
|
const url = new URL(req.url);
|
||||||
|
|
||||||
if (url.pathname.endsWith('/ws')) {
|
if (url.pathname.endsWith("/ws")) {
|
||||||
this._logger.info('Upgrading to WebSocket');
|
this._logger.info("Upgrading to WebSocket");
|
||||||
server.upgrade(req)
|
server.upgrade(req);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
return new Response('Hello World');
|
return new Response("Hello World");
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private handleWebSocketOpen(ws: ServerWebSocket<undefined>): void {
|
private handleWebSocketOpen(ws: ServerWebSocket<undefined>): void {
|
||||||
this._logger.info('WebSocket opened');
|
this._logger.info("WebSocket opened");
|
||||||
this._clients.add(ws);
|
this._clients.add(ws);
|
||||||
}
|
}
|
||||||
|
|
||||||
private handleWebSocketMessage(ws: ServerWebSocket<undefined>, message: string | Buffer): void {
|
private handleWebSocketMessage(
|
||||||
const messageString = typeof message === 'string' ? message : message.toString();
|
ws: ServerWebSocket<undefined>,
|
||||||
|
message: string | Buffer,
|
||||||
|
): void {
|
||||||
|
const messageString =
|
||||||
|
typeof message === "string" ? message : message.toString();
|
||||||
const jsonMessage = JSON.parse(messageString);
|
const jsonMessage = JSON.parse(messageString);
|
||||||
this._logger.info(`WebSocket message received [${MessageKindMapping.convertMessageKindToMessageType(jsonMessage.type)}]`);
|
this._logger.info(
|
||||||
|
`WebSocket message received [${MessageKindMapping.convertMessageKindToMessageType(jsonMessage.type)}]`,
|
||||||
|
);
|
||||||
|
|
||||||
// Forward message to all other clients (following sequence diagram)
|
// Forward message to all other clients (following sequence diagram)
|
||||||
// This allows the signaling server to relay offers/answers between caller and callee
|
// This allows the signaling server to relay offers/answers between caller and callee
|
||||||
this._clients.forEach(client => {
|
this._clients.forEach((client) => {
|
||||||
if (client !== ws && client.readyState === 1) { // 1 = OPEN
|
if (client !== ws && client.readyState === 1) {
|
||||||
|
// 1 = OPEN
|
||||||
client.send(messageString);
|
client.send(messageString);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private handleWebSocketClose(ws: ServerWebSocket<undefined>): void {
|
private handleWebSocketClose(ws: ServerWebSocket<undefined>): void {
|
||||||
this._logger.info('WebSocket closed');
|
this._logger.info("WebSocket closed");
|
||||||
this._clients.delete(ws);
|
this._clients.delete(ws);
|
||||||
}
|
}
|
||||||
|
|
||||||
private handleWebSocketError(ws: ServerWebSocket<undefined>, error: Error): void {
|
private handleWebSocketError(
|
||||||
this._logger.error('WebSocket error', error);
|
ws: ServerWebSocket<undefined>,
|
||||||
|
error: Error,
|
||||||
|
): void {
|
||||||
|
this._logger.error("WebSocket error", error);
|
||||||
}
|
}
|
||||||
|
|
||||||
private handleWebSocketDrain(ws: ServerWebSocket<undefined>): void {
|
private handleWebSocketDrain(ws: ServerWebSocket<undefined>): void {
|
||||||
this._logger.info('WebSocket drained');
|
this._logger.info("WebSocket drained");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,7 +1,9 @@
|
|||||||
import SignalingServer from "./SignalingServer";
|
import SignalingServer from "./SignalingServer";
|
||||||
|
|
||||||
const signalingServer = new SignalingServer(3000, '0.0.0.0', true);
|
const signalingServer = new SignalingServer(3000, "0.0.0.0", true);
|
||||||
|
|
||||||
Bun.serve(signalingServer);
|
Bun.serve(signalingServer);
|
||||||
|
|
||||||
console.log(`Signaling server started on [${signalingServer.hostname}:${signalingServer.port}]`);
|
console.log(
|
||||||
|
`Signaling server started on [${signalingServer.hostname}:${signalingServer.port}]`,
|
||||||
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user