diff --git a/.DS_Store b/.DS_Store index 656b2ad..78964ce 100644 Binary files a/.DS_Store and b/.DS_Store differ diff --git a/example/host.html b/example/host.html index 49f60ff..82e3cf5 100644 --- a/example/host.html +++ b/example/host.html @@ -6,18 +6,27 @@ document.getElementById("hostId").value = host.hostId; alert("Host ready!"); }); - host.on("error", console.error); + host.on("error", function (error) { + if (error instanceof uhst.RelayError) { + alert("Disconnected."); + } else { + console.error(error); + } + }); host.on("diagnostic", console.log); host.on("connection", function connection(ws) { ws.on("diagnostic", console.log); ws.on("message", function incoming(message) { console.log("Host received: %s from %s", message, ws.remoteId); - host.broadcast("Host received: "+ message); + host.broadcast("Host received: " + message); }); ws.on("open", function ready() { console.log("Client %s connected", ws.remoteId); ws.send("something"); }); + ws.on("close", function disconnected() { + console.log("Client %s disconnected.", ws.remoteId); + }); }); -Host ID: \ No newline at end of file +Host ID: \ No newline at end of file diff --git a/example/join.html b/example/join.html index 657e869..79211ed 100644 --- a/example/join.html +++ b/example/join.html @@ -23,8 +23,11 @@ ws.on("message", function incoming(message) { console.log("Client received: %s", message); }); + ws.on("close", function close() { + console.log("Connection to host %s dropped.", ws.remoteId); + }); } -Host ID: +Host ID: \ No newline at end of file diff --git a/lib/ApiClient.ts b/lib/ApiClient.ts index 2f33525..4440eea 100644 --- a/lib/ApiClient.ts +++ b/lib/ApiClient.ts @@ -1,6 +1,7 @@ import { MessageHandler, MessageStream, + RelayEventHandler, UhstRelayClient, } from './contracts/UhstRelayClient'; import { HostConfiguration, ClientConfiguration } from './models'; @@ -71,9 +72,17 @@ export class ApiClient implements UhstRelayClient { subscribeToMessages( token: string, - handler: MessageHandler, + messageHandler: MessageHandler, + relayErrorHandler: Function, + relayEventHandler: RelayEventHandler, receiveUrl?: string ): Promise { - return this.relayClient.subscribeToMessages(token, handler, receiveUrl); + return this.relayClient.subscribeToMessages( + token, + messageHandler, + relayErrorHandler, + relayEventHandler, + receiveUrl + ); } } diff --git a/lib/NetworkClient.ts b/lib/NetworkClient.ts index 0953624..989145c 100644 --- a/lib/NetworkClient.ts +++ b/lib/NetworkClient.ts @@ -4,28 +4,46 @@ const REQUEST_OPTIONS = { method: 'POST', }; +const getRequestOptions = (body: any): any => { + if (body) { + return { + ...REQUEST_OPTIONS, + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify(body), + }; + } else { + return REQUEST_OPTIONS; + } +}; + export class NetworkClient { async post( url: string, queryParams?: string[], + body?: any, timeout?: number ): Promise { + if (queryParams && queryParams.length > 0) { + url = `${url}?${queryParams.join('&')}`; + } + let response: Response; try { - if (queryParams && queryParams.length > 0) { - url = `${url}?${queryParams.join('&')}`; - } - const response = timeout - ? await this.fetchWithTimeout(url, { ...REQUEST_OPTIONS, timeout }) - : await fetch(url, REQUEST_OPTIONS); - if (response.status == 200) { - return response.json(); - } else { - throw new NetworkError(response.status, `${response.statusText}`); - } + response = timeout + ? await this.fetchWithTimeout(url, { + ...getRequestOptions(body), + timeout, + }) + : await fetch(url, getRequestOptions(body)); } catch (error) { - console.log(error); throw new NetworkUnreachable(error); } + if (response.status == 200) { + return response.json(); + } else { + throw new NetworkError(response.status, `${response.statusText}`); + } } async get( @@ -33,22 +51,22 @@ export class NetworkClient { queryParams?: string[], timeout?: number ): Promise { + if (queryParams && queryParams.length > 0) { + url = `${url}?${queryParams.join('&')}`; + } + let response: Response; try { - if (queryParams && queryParams.length > 0) { - url = `${url}?${queryParams.join('&')}`; - } - const response = timeout + response = timeout ? await this.fetchWithTimeout(url, { timeout }) : await fetch(url); - if (response.status == 200) { - return response.json(); - } else { - throw new NetworkError(response.status, `${response.statusText}`); - } } catch (error) { - console.log(error); throw new NetworkUnreachable(error); } + if (response.status == 200) { + return response.json(); + } else { + throw new NetworkError(response.status, `${response.statusText}`); + } } async fetchWithTimeout(resource, options): Promise { diff --git a/lib/RelayClient.ts b/lib/RelayClient.ts index 19f297b..af37697 100644 --- a/lib/RelayClient.ts +++ b/lib/RelayClient.ts @@ -2,8 +2,9 @@ import { UhstRelayClient, MessageHandler, MessageStream, + RelayEventHandler, } from './contracts/UhstRelayClient'; -import { ClientConfiguration, HostConfiguration, Message } from './models'; +import { ClientConfiguration, HostConfiguration, Message, RelayEvent } from './models'; import { InvalidToken, InvalidHostId, @@ -15,13 +16,6 @@ import { } from './UhstErrors'; import { NetworkClient } from './NetworkClient'; -const REQUEST_OPTIONS = { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, -}; - export class RelayClient implements UhstRelayClient { networkClient: NetworkClient; constructor(private relayUrl: string, networkClient?: NetworkClient) { @@ -30,10 +24,11 @@ export class RelayClient implements UhstRelayClient { async initHost(hostId?: string): Promise { try { - return this.networkClient.post( + const hostConfig = await this.networkClient.post( this.relayUrl, hostId ? ['action=host', `hostId=${hostId}`] : ['action=host'] ); + return hostConfig; } catch (error) { if (error instanceof NetworkError) { if (error.responseCode == 400) { @@ -42,7 +37,6 @@ export class RelayClient implements UhstRelayClient { throw new RelayError(error.message); } } else { - console.log(error); throw new RelayUnreachable(error); } } @@ -50,10 +44,11 @@ export class RelayClient implements UhstRelayClient { async initClient(hostId: string): Promise { try { - return this.networkClient.post(this.relayUrl, [ + const clientConfig = await this.networkClient.post(this.relayUrl, [ 'action=join', `hostId=${hostId}`, ]); + return clientConfig; } catch (error) { if (error instanceof NetworkError) { if (error.responseCode == 400) { @@ -62,7 +57,6 @@ export class RelayClient implements UhstRelayClient { throw new RelayError(error.message); } } else { - console.log(error); throw new RelayUnreachable(error); } } @@ -72,47 +66,66 @@ export class RelayClient implements UhstRelayClient { token: string, message: any, sendUrl?: string - ): Promise { + ): Promise { const url = sendUrl ?? this.relayUrl; - let response: Response; try { - response = await fetch(`${url}?token=${token}`, { - ...REQUEST_OPTIONS, - body: JSON.stringify(message), - }); + const response = await this.networkClient.post( + url, + [`token=${token}`], + message + ); + return response; } catch (error) { - console.log(error); - throw new RelayUnreachable(error); - } - if (response.status == 200) { - return; - } else if (response.status == 400) { - throw new InvalidClientOrHostId(response.statusText); - } else if (response.status == 401) { - throw new InvalidToken(response.statusText); - } else { - throw new RelayError(`${response.status} ${response.statusText}`); + if (error instanceof NetworkError) { + if (error.responseCode == 400) { + throw new InvalidClientOrHostId(error.message); + } else if (error.responseCode == 401) { + throw new InvalidToken(error.message); + } else { + throw new RelayError(`${error.responseCode} ${error.message}`); + } + } else { + throw new RelayUnreachable(error); + } } } subscribeToMessages( token: string, - handler: MessageHandler, + messageHandler: MessageHandler, + relayErrorHandler: Function, + relayEventHandler?: RelayEventHandler, receiveUrl?: string ): Promise { const url = receiveUrl ?? this.relayUrl; return new Promise((resolve, reject) => { + let resolved = false; const stream = new EventSource(`${url}?token=${token}`); - stream.onopen = (ev: Event) => { - resolve(stream); + stream.onopen = () => { + if (!resolved) { + resolve(stream); + resolved = true; + } }; - stream.onerror = (ev: Event) => { - reject(new RelayError(ev)); + stream.onerror = () => { + if (!resolved) { + // error on connect + reject(new RelayError()); + resolved = true; + } else if (relayErrorHandler) { + relayErrorHandler(new RelayError()); + } }; stream.addEventListener('message', (evt: MessageEvent) => { const message: Message = JSON.parse(evt.data); - handler(message); + messageHandler(message); }); + if (relayEventHandler) { + stream.addEventListener('relay_event', (evt: MessageEvent) => { + const relayEvent: RelayEvent = JSON.parse(evt.data); + relayEventHandler(relayEvent); + }); + } }); } } diff --git a/lib/RelaySocket.ts b/lib/RelaySocket.ts index 3abb776..493abc4 100644 --- a/lib/RelaySocket.ts +++ b/lib/RelaySocket.ts @@ -1,95 +1,154 @@ -import { EventEmitter } from "inf-ee"; -import { MessageStream, UhstRelayClient } from "./contracts/UhstRelayClient"; -import { SocketEventSet, UhstSocket } from "./contracts/UhstSocket"; -import { ClientSocketParams, HostSocketParams, Message } from "./models"; +import { EventEmitter } from 'inf-ee'; +import { MessageStream, UhstRelayClient } from './contracts/UhstRelayClient'; +import { SocketEventSet, UhstSocket } from './contracts/UhstSocket'; +import { ClientSocketParams, HostSocketParams, Message, RelayEvent, RelayEventType } from './models'; export class RelaySocket implements UhstSocket { - private _ee = new EventEmitter(); - private token: string; - private _remoteId: string; - private relayMessageStream: MessageStream; - private sendUrl?: string; + private _ee = new EventEmitter(); + private token: string; + private _remoteId: string; + private relayMessageStream?: MessageStream; + private sendUrl?: string; - constructor(private relayClient: UhstRelayClient, params: HostSocketParams | ClientSocketParams, private debug: boolean) { - this.send = this.send.bind(this); - this.handleMessage = this.handleMessage.bind(this); - this.close = this.close.bind(this); + constructor( + private relayClient: UhstRelayClient, + params: HostSocketParams | ClientSocketParams, + private debug: boolean + ) { + this.send = this.send.bind(this); + this.handleMessage = this.handleMessage.bind(this); + this.close = this.close.bind(this); - switch (params.type) { - case "client": - // will connect to host - this.initClient(params.hostId); - this._remoteId = params.hostId; - break; - case "host": - // client connected - this.token = params.token; - this.sendUrl = params.sendUrl; - this._remoteId = params.clientId; - // give consumer a chance to subscribe to open event - setTimeout(() => { - this._ee.emit("open"); - }); - break; - default: - throw Error("Unsupported Socket Parameters Type"); - } - } - get remoteId(): string { - return this._remoteId; + switch (params.type) { + case 'client': + // will connect to host + this.initClient(params.hostId); + this._remoteId = params.hostId; + break; + case 'host': + // client connected + this.token = params.token; + this.sendUrl = params.sendUrl; + this._remoteId = params.clientId; + // give consumer a chance to subscribe to open event + setTimeout(() => { + this._ee.emit('open'); + }); + break; + default: + throw Error('Unsupported Socket Parameters Type'); } + } + get remoteId(): string { + return this._remoteId; + } - on(eventName: EventName, handler: SocketEventSet[EventName]) { - this._ee.on(eventName, handler); - } + on( + eventName: EventName, + handler: SocketEventSet[EventName] + ) { + this._ee.on(eventName, handler); + } - once(eventName: EventName, handler: SocketEventSet[EventName]) { - this._ee.once(eventName, handler); - } + once( + eventName: EventName, + handler: SocketEventSet[EventName] + ) { + this._ee.once(eventName, handler); + } - off(eventName: EventName, handler: SocketEventSet[EventName]) { - this._ee.off(eventName, handler); + off( + eventName: EventName, + handler: SocketEventSet[EventName] + ) { + this._ee.off(eventName, handler); + } + + send(message: string): Promise; + send(message: Blob): Promise; + send(message: ArrayBuffer): Promise; + send(message: ArrayBufferView): Promise; + async send(message: any): Promise { + const envelope = { + type: 'string', + payload: message, + }; + try { + await this.relayClient.sendMessage(this.token, envelope, this.sendUrl); + if (this.debug) { + this._ee.emit('diagnostic', 'Sent message ' + message); + } + } catch (error) { + if (this.debug) { + this._ee.emit( + 'diagnostic', + 'Failed sending message: ' + JSON.stringify(error) + ); + } + this._ee.emit('error', error); } - - send(message: string): Promise; - send(message: Blob): Promise; - send(message: ArrayBuffer): Promise; - send(message: ArrayBufferView): Promise; - async send(message: any): Promise { - const envelope = { - "type": "string", - "payload": message - } - await this.relayClient.sendMessage(this.token, envelope, this.sendUrl).catch((error) => { - if (this.debug) { this._ee.emit("diagnostic", "Failed sending message: " + JSON.stringify(error)); } - this._ee.emit("error", error); - }); - if (this.debug) { this._ee.emit("diagnostic", "Sent message " + message); } + } + + close() { + this.relayMessageStream?.close(); + this._ee.emit('close'); + } + + handleMessage = (message: Message) => { + const payload = message.body.payload; + if (this.debug) { + this._ee.emit('diagnostic', 'Message received: ' + payload); } + this._ee.emit('message', payload); + } - close() { - this.relayMessageStream?.close(); + handleRelayEvent = (event: RelayEvent) => { + if (event.eventType === RelayEventType.HOST_CLOSED) { + if (this.debug) { + this._ee.emit('diagnostic', 'Host disconnected from relay.'); + } + this.close(); } + } - handleMessage(message: Message) { - const payload = message.body.payload - if (this.debug) { this._ee.emit("diagnostic", "Message received: " + payload); } - this._ee.emit("message", payload); + handleRelayError = () => { + if (this.debug) { + this._ee.emit('diagnostic', 'Client connection to relay dropped.'); } + this.close(); + } - private async initClient(hostId: string) { - try { - const config = await this.relayClient.initClient(hostId); - if (this.debug) { this._ee.emit("diagnostic", "Client configuration received from server."); } - this.token = config.clientToken; - this.sendUrl = config.sendUrl; - this.relayMessageStream = await this.relayClient.subscribeToMessages(config.clientToken, this.handleMessage, config.receiveUrl); - if (this.debug) { this._ee.emit("diagnostic", "Client subscribed to messages from server."); } - this._ee.emit("open"); - } catch (error) { - if (this.debug) { this._ee.emit("diagnostic", "Client failed: " + JSON.stringify(error)); } - this._ee.emit("error", error); - } + private async initClient(hostId: string) { + try { + const config = await this.relayClient.initClient(hostId); + if (this.debug) { + this._ee.emit( + 'diagnostic', + 'Client configuration received from server.' + ); + } + this.token = config.clientToken; + this.sendUrl = config.sendUrl; + this.relayMessageStream = await this.relayClient.subscribeToMessages( + config.clientToken, + this.handleMessage, + this.handleRelayError, + this.handleRelayEvent, + config.receiveUrl + ); + if (this.debug) { + this._ee.emit( + 'diagnostic', + 'Client subscribed to messages from server.' + ); + } + this._ee.emit('open'); + } catch (error) { + this.relayMessageStream = undefined; + if (this.debug) { + this._ee.emit('diagnostic', 'Client failed: ' + JSON.stringify(error)); + } + this._ee.emit('error', error); } - -} \ No newline at end of file + } +} diff --git a/lib/UhstHost.ts b/lib/UhstHost.ts index a9e6362..5564ea0 100644 --- a/lib/UhstHost.ts +++ b/lib/UhstHost.ts @@ -1,88 +1,167 @@ -import JwtDecode from "jwt-decode"; -import { EventEmitter } from "inf-ee"; -import { MessageStream, UhstRelayClient } from "./contracts/UhstRelayClient"; -import { HostConfiguration, HostMessage } from "./models"; -import { UhstSocket } from "./contracts/UhstSocket"; -import { UhstSocketProvider } from "./contracts/UhstSocketProvider"; +import JwtDecode from 'jwt-decode'; +import { EventEmitter } from 'inf-ee'; +import { MessageStream, UhstRelayClient } from './contracts/UhstRelayClient'; +import { + HostConfiguration, + HostMessage, + RelayEvent, + RelayEventType, +} from './models'; +import { UhstSocket } from './contracts/UhstSocket'; +import { UhstSocketProvider } from './contracts/UhstSocketProvider'; +import { RelayError } from './UhstErrors'; type HostEventSet = { - ready: () => void, - connection: (socket: UhstSocket) => void, - error: (error: Error) => void, - diagnostic: (message: string) => void -} + ready: () => void; + connection: (socket: UhstSocket) => void; + error: (error: Error) => void; + diagnostic: (message: string) => void; +}; export class UhstHost { - private _ee = new EventEmitter(); - private clients = new Map(); - private config: HostConfiguration; - private relayMessageStream: MessageStream; + private _ee = new EventEmitter(); + private clients = new Map(); + private config: HostConfiguration; + private relayMessageStream?: MessageStream; - constructor(private relayClient: UhstRelayClient, private socketProvider: UhstSocketProvider, requestedHostId: string | undefined, private debug: boolean) { - this.handleMessage = this.handleMessage.bind(this); - - this.init(requestedHostId); - } + constructor( + private relayClient: UhstRelayClient, + private socketProvider: UhstSocketProvider, + requestedHostId: string | undefined, + private debug: boolean + ) { + this.handleMessage = this.handleMessage.bind(this); - get hostId(): string { - return this.config.hostId; - } + this.init(requestedHostId); + } - broadcast(message: string): void; - broadcast(message: Blob): void; - broadcast(message: ArrayBuffer): void; - broadcast(message: ArrayBufferView): void; - broadcast(message: any) { - const envelope = { - "type": "string", - "payload": message - } - this.relayClient.sendMessage(this.config.hostToken, envelope, this.config.sendUrl).catch((error) => { - if (this.debug) { this._ee.emit("diagnostic", "Failed sending message: " + JSON.stringify(error)); } - this._ee.emit("error", error); - }); - if (this.debug) { this._ee.emit("diagnostic", "Sent message " + message); } - } + get hostId(): string { + return this.config.hostId; + } - on(eventName: EventName, handler: HostEventSet[EventName]) { - this._ee.on(eventName, handler); + broadcast(message: string): Promise; + broadcast(message: Blob): Promise; + broadcast(message: ArrayBuffer): Promise; + broadcast(message: ArrayBufferView): Promise; + async broadcast(message: any): Promise { + const envelope = { + type: 'string', + payload: message, + }; + try { + await this.relayClient.sendMessage( + this.config.hostToken, + envelope, + this.config.sendUrl + ); + if (this.debug) { + this._ee.emit('diagnostic', 'Sent message ' + message); + } + } catch (error) { + if (this.debug) { + this._ee.emit( + 'diagnostic', + 'Failed sending message: ' + JSON.stringify(error) + ); + } + this._ee.emit('error', error); } + } - once(eventName: EventName, handler: HostEventSet[EventName]) { - this._ee.once(eventName, handler); - } + on( + eventName: EventName, + handler: HostEventSet[EventName] + ) { + this._ee.on(eventName, handler); + } - off(eventName: EventName, handler: HostEventSet[EventName]) { - this._ee.off(eventName, handler); + once( + eventName: EventName, + handler: HostEventSet[EventName] + ) { + this._ee.once(eventName, handler); + } + + off( + eventName: EventName, + handler: HostEventSet[EventName] + ) { + this._ee.off(eventName, handler); + } + + disconnect() { + this.relayMessageStream?.close(); + } + + private handleMessage = (message: HostMessage) => { + const clientId: string = (JwtDecode(message.responseToken) as any).clientId; + let hostSocket = this.clients.get(clientId); + if (!hostSocket) { + const socket = this.socketProvider.createUhstSocket( + this.relayClient, + { + type: 'host', + token: message.responseToken, + sendUrl: this.config.sendUrl, + clientId, + }, + this.debug + ); + if (this.debug) { + this._ee.emit( + 'diagnostic', + 'Host received client connection from clientId: ' + clientId + ); + } + this._ee.emit('connection', socket); + this.clients.set(clientId, socket); + hostSocket = socket; } + hostSocket.handleMessage(message); + } - disconnect() { - this.relayMessageStream?.close(); + private handleRelayEvent = (event: RelayEvent) => { + if (event.eventType === RelayEventType.CLIENT_CLOSED) { + const clientId = event.body; + this.clients.get(clientId)?.close(); + this.clients.delete(clientId); } + } - private handleMessage(message: HostMessage) { - const clientId: string = (JwtDecode(message.responseToken) as any).clientId; - let hostSocket = this.clients.get(clientId); - if (!hostSocket) { - const socket = this.socketProvider.createUhstSocket(this.relayClient, {type: "host", token: message.responseToken, sendUrl: this.config.sendUrl, clientId}, this.debug); - if (this.debug) { this._ee.emit("diagnostic", "Host received client connection from clientId: "+clientId); } - this._ee.emit("connection", socket); - this.clients.set(clientId, socket); - hostSocket = socket; - } - hostSocket.handleMessage(message); + private handleRelayError = () => { + this.relayMessageStream?.close(); + if (this.debug) { + this._ee.emit('diagnostic', 'Host connection to relay dropped.'); } + this._ee.emit('error', new RelayError()); + } - private async init(requestedHostId?: string) { - try { - this.config = await this.relayClient.initHost(requestedHostId); - if (this.debug) { this._ee.emit("diagnostic", "Host configuration received from server."); } - this.relayMessageStream = await this.relayClient.subscribeToMessages(this.config.hostToken, this.handleMessage, this.config.receiveUrl); - if (this.debug) { this._ee.emit("diagnostic", "Host subscribed to messages from server."); } - this._ee.emit("ready"); - } catch (error) { - if (this.debug) { this._ee.emit("diagnostic", "Host failed subscribing to messages: "+JSON.stringify(error)); } - this._ee.emit("error", error); - } + private async init(requestedHostId?: string) { + try { + this.config = await this.relayClient.initHost(requestedHostId); + if (this.debug) { + this._ee.emit('diagnostic', 'Host configuration received from server.'); + } + this.relayMessageStream = await this.relayClient.subscribeToMessages( + this.config.hostToken, + this.handleMessage, + this.handleRelayError, + this.handleRelayEvent, + this.config.receiveUrl + ); + if (this.debug) { + this._ee.emit('diagnostic', 'Host subscribed to messages from server.'); + } + this._ee.emit('ready'); + } catch (error) { + this.relayMessageStream = undefined; + if (this.debug) { + this._ee.emit( + 'diagnostic', + 'Host message subscription failed: ' + JSON.stringify(error) + ); + } + this._ee.emit('error', error); } -} \ No newline at end of file + } +} diff --git a/lib/WebRTCSocket.ts b/lib/WebRTCSocket.ts index 39fe993..b602faa 100644 --- a/lib/WebRTCSocket.ts +++ b/lib/WebRTCSocket.ts @@ -178,7 +178,7 @@ export class WebRTCSocket implements UhstSocket { if (this.debug) { this._ee.emit("diagnostic", "Client configuration received from server."); } this.token = config.clientToken; this.sendUrl = config.sendUrl; - this.relayMessageStream = await this.relayClient.subscribeToMessages(config.clientToken, this.handleMessage, config.receiveUrl); + this.relayMessageStream = await this.relayClient.subscribeToMessages(config.clientToken, this.handleMessage, undefined, undefined, config.receiveUrl); if (this.debug) { this._ee.emit("diagnostic", "Client subscribed to messages from server."); } const offer = await this.connection.createOffer(); this.relayClient.sendMessage(this.token, offer, this.sendUrl).then(() => { diff --git a/lib/contracts/UhstRelayClient.ts b/lib/contracts/UhstRelayClient.ts index 31707c9..a5990ca 100644 --- a/lib/contracts/UhstRelayClient.ts +++ b/lib/contracts/UhstRelayClient.ts @@ -1,14 +1,30 @@ -import { ClientConfiguration, HostConfiguration, Message } from "../models"; +import { + ClientConfiguration, + HostConfiguration, + Message, + RelayEvent, +} from '../models'; export interface MessageHandler { - (message: Message): void; + (message: Message): void; } + +export interface RelayEventHandler { + (event: RelayEvent): void; +} + export interface MessageStream { - close():void; + close(): void; } export interface UhstRelayClient { - initHost(hostId?: string): Promise; - initClient(hostId: string): Promise; - sendMessage(token: string, message: any, sendUrl?:string): Promise; - subscribeToMessages(token: string, handler: MessageHandler, receiveUrl?: string): Promise; -} \ No newline at end of file + initHost(hostId?: string): Promise; + initClient(hostId: string): Promise; + sendMessage(token: string, message: any, sendUrl?: string): Promise; + subscribeToMessages( + token: string, + messageHandler: MessageHandler, + relayErrorHandler?: Function, + relayEventHandler?: RelayEventHandler, + receiveUrl?: string + ): Promise; +} diff --git a/lib/models/RelayEvent.ts b/lib/models/RelayEvent.ts new file mode 100644 index 0000000..f7e8c4b --- /dev/null +++ b/lib/models/RelayEvent.ts @@ -0,0 +1,14 @@ +import { Message } from './Message'; + +export enum RelayEventType { + CLIENT_CLOSED = 'client_closed', + HOST_CLOSED = 'host_closed', +} + +export interface RelayEvent extends Message { + eventType: RelayEventType; +} + +export function isRelayEvent(obj: any): obj is RelayEvent { + return obj.eventType !== undefined; +} diff --git a/lib/models/index.ts b/lib/models/index.ts index 74d141b..06cfe5c 100644 --- a/lib/models/index.ts +++ b/lib/models/index.ts @@ -4,4 +4,5 @@ export * from './HostConfiguration'; export * from './HostMessage'; export * from './Message'; export * from './SocketParams'; -export * from './RelayMessage'; \ No newline at end of file +export * from './RelayMessage'; +export * from './RelayEvent'; \ No newline at end of file diff --git a/test/RelaySocket.spec.ts b/test/RelaySocket.spec.ts index 688190a..259822b 100644 --- a/test/RelaySocket.spec.ts +++ b/test/RelaySocket.spec.ts @@ -23,7 +23,7 @@ describe("# RelaySocket", () => { receiveUrl: "testReceiveUrl", sendUrl: "testSendUrl", }); - mockRelay.subscribeToMessages = (clientToken, handleMessage, receiveUrl) => { + mockRelay.subscribeToMessages = (clientToken, handleMessage, handleRelayError, handleRelayEvent, receiveUrl) => { expect(clientToken).to.equal("testClientToken"); expect(receiveUrl).to.equal("testReceiveUrl"); messageHandler = handleMessage; diff --git a/test/UhstHost.spec.ts b/test/UhstHost.spec.ts index 0556992..2b5b45a 100644 --- a/test/UhstHost.spec.ts +++ b/test/UhstHost.spec.ts @@ -25,7 +25,7 @@ describe("# UhstHost", () => { sendUrl: "testSendUrl", }); - mockRelay.subscribeToMessages = (token, handler, receiveUrl) => { + mockRelay.subscribeToMessages = (token, handler, handleRelayError, handleRelayEvent, receiveUrl) => { expect(token).to.equal("testHostToken"); expect(receiveUrl).to.equal("testReceiveUrl"); messageHandler = handler; @@ -78,7 +78,7 @@ describe("# UhstHost", () => { sendUrl: "testSendUrl", }); - mockRelay.subscribeToMessages = (token, handler, receiveUrl) => { + mockRelay.subscribeToMessages = (token, handler, handleRelayError, handleRelayEvent, receiveUrl) => { expect(token).to.equal("testHostToken"); expect(receiveUrl).to.equal("testReceiveUrl"); messageHandler = handler; diff --git a/test/WebRTCSocket.spec.ts b/test/WebRTCSocket.spec.ts index c9cde62..e94fc5d 100644 --- a/test/WebRTCSocket.spec.ts +++ b/test/WebRTCSocket.spec.ts @@ -141,7 +141,7 @@ // receiveUrl: "testReceiveUrl", // sendUrl: "testSendUrl", // }); -// mockRelay.subscribeToMessages = (clientToken, handleMessage, receiveUrl) => { +// mockRelay.subscribeToMessages = (clientToken, handleMessage, handleRelayError, handleRelayEvent, receiveUrl) => { // expect(clientToken).to.equal("testClientToken"); // expect(receiveUrl).to.equal("testReceiveUrl"); // messageHandler = handleMessage;