refactoring index.js
This commit is contained in:
parent
c4f04b2ff8
commit
3398d65d2d
56
dist/src/index.js
vendored
56
dist/src/index.js
vendored
@ -6,56 +6,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|||||||
const express_1 = __importDefault(require("express"));
|
const express_1 = __importDefault(require("express"));
|
||||||
const http_1 = __importDefault(require("http"));
|
const http_1 = __importDefault(require("http"));
|
||||||
const https_1 = __importDefault(require("https"));
|
const https_1 = __importDefault(require("https"));
|
||||||
const api_1 = require("./api");
|
|
||||||
const config_1 = __importDefault(require("./config"));
|
const config_1 = __importDefault(require("./config"));
|
||||||
const messageHandler_1 = require("./messageHandler");
|
const instance_1 = require("./instance");
|
||||||
const realm_1 = require("./models/realm");
|
|
||||||
const checkBrokenConnections_1 = require("./services/checkBrokenConnections");
|
|
||||||
const messagesExpire_1 = require("./services/messagesExpire");
|
|
||||||
const webSocketServer_1 = require("./services/webSocketServer");
|
|
||||||
const init = ({ app, server, options }) => {
|
|
||||||
const config = options;
|
|
||||||
const realm = new realm_1.Realm();
|
|
||||||
const messageHandler = new messageHandler_1.MessageHandler(realm);
|
|
||||||
const api = api_1.Api({ config, realm, messageHandler });
|
|
||||||
const messagesExpire = new messagesExpire_1.MessagesExpire({ realm, config, messageHandler });
|
|
||||||
const checkBrokenConnections = new checkBrokenConnections_1.CheckBrokenConnections({
|
|
||||||
realm,
|
|
||||||
config,
|
|
||||||
onClose: (client) => {
|
|
||||||
app.emit("disconnect", client);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
app.use(options.path, api);
|
|
||||||
const wss = new webSocketServer_1.WebSocketServer({
|
|
||||||
server,
|
|
||||||
realm,
|
|
||||||
config
|
|
||||||
});
|
|
||||||
wss.on("connection", (client) => {
|
|
||||||
const messageQueue = realm.getMessageQueueById(client.getId());
|
|
||||||
if (messageQueue) {
|
|
||||||
let message;
|
|
||||||
while (message = messageQueue.readMessage()) {
|
|
||||||
messageHandler.handle(client, message);
|
|
||||||
}
|
|
||||||
realm.clearMessageQueue(client.getId());
|
|
||||||
}
|
|
||||||
app.emit("connection", client);
|
|
||||||
});
|
|
||||||
wss.on("message", (client, message) => {
|
|
||||||
app.emit("message", client, message);
|
|
||||||
messageHandler.handle(client, message);
|
|
||||||
});
|
|
||||||
wss.on("close", (client) => {
|
|
||||||
app.emit("disconnect", client);
|
|
||||||
});
|
|
||||||
wss.on("error", (error) => {
|
|
||||||
app.emit("error", error);
|
|
||||||
});
|
|
||||||
messagesExpire.startMessagesExpiration();
|
|
||||||
checkBrokenConnections.start();
|
|
||||||
};
|
|
||||||
function ExpressPeerServer(server, options) {
|
function ExpressPeerServer(server, options) {
|
||||||
const app = express_1.default();
|
const app = express_1.default();
|
||||||
const newOptions = Object.assign(Object.assign({}, config_1.default), options);
|
const newOptions = Object.assign(Object.assign({}, config_1.default), options);
|
||||||
@ -67,7 +19,7 @@ function ExpressPeerServer(server, options) {
|
|||||||
throw new Error("Server is not passed to constructor - " +
|
throw new Error("Server is not passed to constructor - " +
|
||||||
"can't start PeerServer");
|
"can't start PeerServer");
|
||||||
}
|
}
|
||||||
init({ app, server, options: newOptions });
|
instance_1.createInstance({ app, server, options: newOptions });
|
||||||
});
|
});
|
||||||
return app;
|
return app;
|
||||||
}
|
}
|
||||||
@ -77,10 +29,10 @@ function PeerServer(options = {}, callback) {
|
|||||||
const newOptions = Object.assign(Object.assign({}, config_1.default), options);
|
const newOptions = Object.assign(Object.assign({}, config_1.default), options);
|
||||||
let path = newOptions.path;
|
let path = newOptions.path;
|
||||||
const port = newOptions.port;
|
const port = newOptions.port;
|
||||||
if (path[0] !== "/") {
|
if (!path.startsWith('/')) {
|
||||||
path = "/" + path;
|
path = "/" + path;
|
||||||
}
|
}
|
||||||
if (path[path.length - 1] !== "/") {
|
if (!path.endsWith('/')) {
|
||||||
path += "/";
|
path += "/";
|
||||||
}
|
}
|
||||||
let server;
|
let server;
|
||||||
|
51
dist/src/instance.js
vendored
Normal file
51
dist/src/instance.js
vendored
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
"use strict";
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
const realm_1 = require("./models/realm");
|
||||||
|
const checkBrokenConnections_1 = require("./services/checkBrokenConnections");
|
||||||
|
const messagesExpire_1 = require("./services/messagesExpire");
|
||||||
|
const webSocketServer_1 = require("./services/webSocketServer");
|
||||||
|
const messageHandler_1 = require("./messageHandler");
|
||||||
|
const api_1 = require("./api");
|
||||||
|
exports.createInstance = ({ app, server, options }) => {
|
||||||
|
const config = options;
|
||||||
|
const realm = new realm_1.Realm();
|
||||||
|
const messageHandler = new messageHandler_1.MessageHandler(realm);
|
||||||
|
const api = api_1.Api({ config, realm, messageHandler });
|
||||||
|
const messagesExpire = new messagesExpire_1.MessagesExpire({ realm, config, messageHandler });
|
||||||
|
const checkBrokenConnections = new checkBrokenConnections_1.CheckBrokenConnections({
|
||||||
|
realm,
|
||||||
|
config,
|
||||||
|
onClose: client => {
|
||||||
|
app.emit("disconnect", client);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
app.use(options.path, api);
|
||||||
|
const wss = new webSocketServer_1.WebSocketServer({
|
||||||
|
server,
|
||||||
|
realm,
|
||||||
|
config
|
||||||
|
});
|
||||||
|
wss.on("connection", (client) => {
|
||||||
|
const messageQueue = realm.getMessageQueueById(client.getId());
|
||||||
|
if (messageQueue) {
|
||||||
|
let message;
|
||||||
|
while (message = messageQueue.readMessage()) {
|
||||||
|
messageHandler.handle(client, message);
|
||||||
|
}
|
||||||
|
realm.clearMessageQueue(client.getId());
|
||||||
|
}
|
||||||
|
app.emit("connection", client);
|
||||||
|
});
|
||||||
|
wss.on("message", (client, message) => {
|
||||||
|
app.emit("message", client, message);
|
||||||
|
messageHandler.handle(client, message);
|
||||||
|
});
|
||||||
|
wss.on("close", (client) => {
|
||||||
|
app.emit("disconnect", client);
|
||||||
|
});
|
||||||
|
wss.on("error", (error) => {
|
||||||
|
app.emit("error", error);
|
||||||
|
});
|
||||||
|
messagesExpire.startMessagesExpiration();
|
||||||
|
checkBrokenConnections.start();
|
||||||
|
};
|
@ -40,7 +40,8 @@ exports.TransmissionHandler = ({ realm }) => {
|
|||||||
else {
|
else {
|
||||||
// Wait for this client to connect/reconnect (XHR) for important
|
// Wait for this client to connect/reconnect (XHR) for important
|
||||||
// messages.
|
// messages.
|
||||||
if (type !== enums_1.MessageType.LEAVE && type !== enums_1.MessageType.EXPIRE && dstId) {
|
const ignoredTypes = [enums_1.MessageType.LEAVE, enums_1.MessageType.EXPIRE];
|
||||||
|
if (!ignoredTypes.includes(type) && dstId) {
|
||||||
realm.addMessageToQueue(dstId, message);
|
realm.addMessageToQueue(dstId, message);
|
||||||
}
|
}
|
||||||
else if (type === enums_1.MessageType.LEAVE && !dstId) {
|
else if (type === enums_1.MessageType.LEAVE && !dstId) {
|
||||||
|
20
dist/src/messageHandler/handlersRegistry.js
vendored
Normal file
20
dist/src/messageHandler/handlersRegistry.js
vendored
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
"use strict";
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
class HandlersRegistry {
|
||||||
|
constructor() {
|
||||||
|
this.handlers = new Map();
|
||||||
|
}
|
||||||
|
registerHandler(messageType, handler) {
|
||||||
|
if (this.handlers.has(messageType))
|
||||||
|
return;
|
||||||
|
this.handlers.set(messageType, handler);
|
||||||
|
}
|
||||||
|
handle(client, message) {
|
||||||
|
const { type } = message;
|
||||||
|
const handler = this.handlers.get(type);
|
||||||
|
if (!handler)
|
||||||
|
return false;
|
||||||
|
return handler(client, message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
exports.HandlersRegistry = HandlersRegistry;
|
30
dist/src/messageHandler/index.js
vendored
30
dist/src/messageHandler/index.js
vendored
@ -2,30 +2,30 @@
|
|||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
const enums_1 = require("../enums");
|
const enums_1 = require("../enums");
|
||||||
const handlers_1 = require("./handlers");
|
const handlers_1 = require("./handlers");
|
||||||
const messageHandlers_1 = require("./messageHandlers");
|
const handlersRegistry_1 = require("./handlersRegistry");
|
||||||
class MessageHandler {
|
class MessageHandler {
|
||||||
constructor(realm) {
|
constructor(realm, handlersRegistry = new handlersRegistry_1.HandlersRegistry()) {
|
||||||
this.messageHandlers = new messageHandlers_1.MessageHandlers();
|
this.handlersRegistry = handlersRegistry;
|
||||||
const transmissionHandler = handlers_1.TransmissionHandler({ realm });
|
const transmissionHandler = handlers_1.TransmissionHandler({ realm });
|
||||||
const heartbeatHandler = handlers_1.HeartbeatHandler;
|
const heartbeatHandler = handlers_1.HeartbeatHandler;
|
||||||
const handleTransmission = (client, message) => {
|
const handleTransmission = (client, { type, src, dst, payload }) => {
|
||||||
return transmissionHandler(client, {
|
return transmissionHandler(client, {
|
||||||
type: message.type,
|
type,
|
||||||
src: message.src,
|
src,
|
||||||
dst: message.dst,
|
dst,
|
||||||
payload: message.payload
|
payload,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
const handleHeartbeat = (client, message) => heartbeatHandler(client, message);
|
const handleHeartbeat = (client, message) => heartbeatHandler(client, message);
|
||||||
this.messageHandlers.registerHandler(enums_1.MessageType.HEARTBEAT, handleHeartbeat);
|
this.handlersRegistry.registerHandler(enums_1.MessageType.HEARTBEAT, handleHeartbeat);
|
||||||
this.messageHandlers.registerHandler(enums_1.MessageType.OFFER, handleTransmission);
|
this.handlersRegistry.registerHandler(enums_1.MessageType.OFFER, handleTransmission);
|
||||||
this.messageHandlers.registerHandler(enums_1.MessageType.ANSWER, handleTransmission);
|
this.handlersRegistry.registerHandler(enums_1.MessageType.ANSWER, handleTransmission);
|
||||||
this.messageHandlers.registerHandler(enums_1.MessageType.CANDIDATE, handleTransmission);
|
this.handlersRegistry.registerHandler(enums_1.MessageType.CANDIDATE, handleTransmission);
|
||||||
this.messageHandlers.registerHandler(enums_1.MessageType.LEAVE, handleTransmission);
|
this.handlersRegistry.registerHandler(enums_1.MessageType.LEAVE, handleTransmission);
|
||||||
this.messageHandlers.registerHandler(enums_1.MessageType.EXPIRE, handleTransmission);
|
this.handlersRegistry.registerHandler(enums_1.MessageType.EXPIRE, handleTransmission);
|
||||||
}
|
}
|
||||||
handle(client, message) {
|
handle(client, message) {
|
||||||
return this.messageHandlers.handle(client, message);
|
return this.handlersRegistry.handle(client, message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
exports.MessageHandler = MessageHandler;
|
exports.MessageHandler = MessageHandler;
|
||||||
|
9
dist/src/services/webSocketServer/index.js
vendored
9
dist/src/services/webSocketServer/index.js
vendored
@ -8,6 +8,7 @@ const url_1 = __importDefault(require("url"));
|
|||||||
const ws_1 = __importDefault(require("ws"));
|
const ws_1 = __importDefault(require("ws"));
|
||||||
const enums_1 = require("../../enums");
|
const enums_1 = require("../../enums");
|
||||||
const client_1 = require("../../models/client");
|
const client_1 = require("../../models/client");
|
||||||
|
const WS_PATH = 'peerjs';
|
||||||
class WebSocketServer extends events_1.default {
|
class WebSocketServer extends events_1.default {
|
||||||
constructor({ server, realm, config }) {
|
constructor({ server, realm, config }) {
|
||||||
super();
|
super();
|
||||||
@ -15,10 +16,10 @@ class WebSocketServer extends events_1.default {
|
|||||||
this.realm = realm;
|
this.realm = realm;
|
||||||
this.config = config;
|
this.config = config;
|
||||||
const path = this.config.path;
|
const path = this.config.path;
|
||||||
this.path = path + (path[path.length - 1] !== "/" ? "/" : "") + "peerjs";
|
this.path = `${path}${path.endsWith('/') ? "" : "/"}${WS_PATH}`;
|
||||||
this.webSocketServer = new ws_1.default.Server({ path, server });
|
this.socketServer = new ws_1.default.Server({ path: this.path, server });
|
||||||
this.webSocketServer.on("connection", (socket, req) => this._onSocketConnection(socket, req));
|
this.socketServer.on("connection", (socket, req) => this._onSocketConnection(socket, req));
|
||||||
this.webSocketServer.on("error", (error) => this._onSocketError(error));
|
this.socketServer.on("error", (error) => this._onSocketError(error));
|
||||||
}
|
}
|
||||||
_onSocketConnection(socket, req) {
|
_onSocketConnection(socket, req) {
|
||||||
const { query = {} } = url_1.default.parse(req.url, true);
|
const { query = {} } = url_1.default.parse(req.url, true);
|
||||||
|
@ -10,9 +10,9 @@ import CallsApi from "./v1/calls";
|
|||||||
import PublicApi from "./v1/public";
|
import PublicApi from "./v1/public";
|
||||||
|
|
||||||
export const Api = ({ config, realm, messageHandler }: {
|
export const Api = ({ config, realm, messageHandler }: {
|
||||||
config: IConfig,
|
config: IConfig;
|
||||||
realm: IRealm,
|
realm: IRealm;
|
||||||
messageHandler: IMessageHandler
|
messageHandler: IMessageHandler;
|
||||||
}): express.Router => {
|
}): express.Router => {
|
||||||
const authMiddleware = new AuthMiddleware(config, realm);
|
const authMiddleware = new AuthMiddleware(config, realm);
|
||||||
|
|
||||||
|
82
src/index.ts
82
src/index.ts
@ -1,77 +1,13 @@
|
|||||||
import { IRealm } from "./models/realm";
|
|
||||||
|
|
||||||
import express from "express";
|
import express from "express";
|
||||||
import http from "http";
|
import http from "http";
|
||||||
import https from "https";
|
import https from "https";
|
||||||
|
|
||||||
import { Server } from "net";
|
import { Server } from "net";
|
||||||
import { Api } from "./api";
|
|
||||||
import defaultConfig, { IConfig } from "./config";
|
import defaultConfig, { IConfig } from "./config";
|
||||||
import { MessageHandler } from "./messageHandler";
|
import { createInstance } from "./instance";
|
||||||
import { IClient } from "./models/client";
|
|
||||||
import { IMessage } from "./models/message";
|
|
||||||
import { Realm } from "./models/realm";
|
|
||||||
import { CheckBrokenConnections } from "./services/checkBrokenConnections";
|
|
||||||
import { IMessagesExpire, MessagesExpire } from "./services/messagesExpire";
|
|
||||||
import { IWebSocketServer, WebSocketServer } from "./services/webSocketServer";
|
|
||||||
|
|
||||||
const init = ({ app, server, options }: {
|
type Optional<T> = {
|
||||||
app: express.Express,
|
[P in keyof T]?: (T[P] | undefined);
|
||||||
server: Server,
|
|
||||||
options: IConfig;
|
|
||||||
}) => {
|
|
||||||
const config = options;
|
|
||||||
const realm: IRealm = new Realm();
|
|
||||||
const messageHandler = new MessageHandler(realm);
|
|
||||||
const api = Api({ config, realm, messageHandler });
|
|
||||||
|
|
||||||
const messagesExpire: IMessagesExpire = new MessagesExpire({ realm, config, messageHandler });
|
|
||||||
const checkBrokenConnections = new CheckBrokenConnections({
|
|
||||||
realm,
|
|
||||||
config,
|
|
||||||
onClose: (client: IClient) => {
|
|
||||||
app.emit("disconnect", client);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
app.use(options.path, api);
|
|
||||||
|
|
||||||
const wss: IWebSocketServer = new WebSocketServer({
|
|
||||||
server,
|
|
||||||
realm,
|
|
||||||
config
|
|
||||||
});
|
|
||||||
|
|
||||||
wss.on("connection", (client: IClient) => {
|
|
||||||
const messageQueue = realm.getMessageQueueById(client.getId());
|
|
||||||
|
|
||||||
if (messageQueue) {
|
|
||||||
let message: IMessage | undefined;
|
|
||||||
|
|
||||||
while (message = messageQueue.readMessage()) {
|
|
||||||
messageHandler.handle(client, message);
|
|
||||||
}
|
|
||||||
realm.clearMessageQueue(client.getId());
|
|
||||||
}
|
|
||||||
|
|
||||||
app.emit("connection", client);
|
|
||||||
});
|
|
||||||
|
|
||||||
wss.on("message", (client: IClient, message: IMessage) => {
|
|
||||||
app.emit("message", client, message);
|
|
||||||
messageHandler.handle(client, message);
|
|
||||||
});
|
|
||||||
|
|
||||||
wss.on("close", (client: IClient) => {
|
|
||||||
app.emit("disconnect", client);
|
|
||||||
});
|
|
||||||
|
|
||||||
wss.on("error", (error: Error) => {
|
|
||||||
app.emit("error", error);
|
|
||||||
});
|
|
||||||
|
|
||||||
messagesExpire.startMessagesExpiration();
|
|
||||||
checkBrokenConnections.start();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
function ExpressPeerServer(server: Server, options?: IConfig) {
|
function ExpressPeerServer(server: Server, options?: IConfig) {
|
||||||
@ -92,16 +28,12 @@ function ExpressPeerServer(server: Server, options?: IConfig) {
|
|||||||
"can't start PeerServer");
|
"can't start PeerServer");
|
||||||
}
|
}
|
||||||
|
|
||||||
init({ app, server, options: newOptions });
|
createInstance({ app, server, options: newOptions });
|
||||||
});
|
});
|
||||||
|
|
||||||
return app;
|
return app;
|
||||||
}
|
}
|
||||||
|
|
||||||
type Optional<T> = {
|
|
||||||
[P in keyof T]?: (T[P] | undefined);
|
|
||||||
};
|
|
||||||
|
|
||||||
function PeerServer(options: Optional<IConfig> = {}, callback?: (server: Server) => void) {
|
function PeerServer(options: Optional<IConfig> = {}, callback?: (server: Server) => void) {
|
||||||
const app = express();
|
const app = express();
|
||||||
|
|
||||||
@ -113,11 +45,11 @@ function PeerServer(options: Optional<IConfig> = {}, callback?: (server: Server)
|
|||||||
let path = newOptions.path;
|
let path = newOptions.path;
|
||||||
const port = newOptions.port;
|
const port = newOptions.port;
|
||||||
|
|
||||||
if (path[0] !== "/") {
|
if (!path.startsWith('/')) {
|
||||||
path = "/" + path;
|
path = "/" + path;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (path[path.length - 1] !== "/") {
|
if (!path.endsWith('/')) {
|
||||||
path += "/";
|
path += "/";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
71
src/instance.ts
Normal file
71
src/instance.ts
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
import express from "express";
|
||||||
|
import { Server } from "net";
|
||||||
|
import { IClient } from "./models/client";
|
||||||
|
import { IMessage } from "./models/message";
|
||||||
|
import { Realm } from "./models/realm";
|
||||||
|
import { IRealm } from "./models/realm";
|
||||||
|
import { CheckBrokenConnections } from "./services/checkBrokenConnections";
|
||||||
|
import { IMessagesExpire, MessagesExpire } from "./services/messagesExpire";
|
||||||
|
import { IWebSocketServer, WebSocketServer } from "./services/webSocketServer";
|
||||||
|
import { MessageHandler } from "./messageHandler";
|
||||||
|
import { Api } from "./api";
|
||||||
|
import { IConfig } from "./config";
|
||||||
|
|
||||||
|
export const createInstance = ({ app, server, options }: {
|
||||||
|
app: express.Application,
|
||||||
|
server: Server,
|
||||||
|
options: IConfig;
|
||||||
|
}): void => {
|
||||||
|
const config = options;
|
||||||
|
const realm: IRealm = new Realm();
|
||||||
|
const messageHandler = new MessageHandler(realm);
|
||||||
|
|
||||||
|
const api = Api({ config, realm, messageHandler });
|
||||||
|
const messagesExpire: IMessagesExpire = new MessagesExpire({ realm, config, messageHandler });
|
||||||
|
const checkBrokenConnections = new CheckBrokenConnections({
|
||||||
|
realm,
|
||||||
|
config,
|
||||||
|
onClose: client => {
|
||||||
|
app.emit("disconnect", client);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
app.use(options.path, api);
|
||||||
|
|
||||||
|
const wss: IWebSocketServer = new WebSocketServer({
|
||||||
|
server,
|
||||||
|
realm,
|
||||||
|
config
|
||||||
|
});
|
||||||
|
|
||||||
|
wss.on("connection", (client: IClient) => {
|
||||||
|
const messageQueue = realm.getMessageQueueById(client.getId());
|
||||||
|
|
||||||
|
if (messageQueue) {
|
||||||
|
let message: IMessage | undefined;
|
||||||
|
|
||||||
|
while (message = messageQueue.readMessage()) {
|
||||||
|
messageHandler.handle(client, message);
|
||||||
|
}
|
||||||
|
realm.clearMessageQueue(client.getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
app.emit("connection", client);
|
||||||
|
});
|
||||||
|
|
||||||
|
wss.on("message", (client: IClient, message: IMessage) => {
|
||||||
|
app.emit("message", client, message);
|
||||||
|
messageHandler.handle(client, message);
|
||||||
|
});
|
||||||
|
|
||||||
|
wss.on("close", (client: IClient) => {
|
||||||
|
app.emit("disconnect", client);
|
||||||
|
});
|
||||||
|
|
||||||
|
wss.on("error", (error: Error) => {
|
||||||
|
app.emit("error", error);
|
||||||
|
});
|
||||||
|
|
||||||
|
messagesExpire.startMessagesExpiration();
|
||||||
|
checkBrokenConnections.start();
|
||||||
|
};
|
@ -3,12 +3,12 @@ import { IClient } from "../models/client";
|
|||||||
import { IMessage } from "../models/message";
|
import { IMessage } from "../models/message";
|
||||||
import { Handler } from "./handler";
|
import { Handler } from "./handler";
|
||||||
|
|
||||||
export interface IMessageHandlers {
|
export interface IHandlersRegistry {
|
||||||
registerHandler(messageType: MessageType, handler: Handler): void;
|
registerHandler(messageType: MessageType, handler: Handler): void;
|
||||||
handle(client: IClient | undefined, message: IMessage): boolean;
|
handle(client: IClient | undefined, message: IMessage): boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class MessageHandlers implements IMessageHandlers {
|
export class HandlersRegistry implements IHandlersRegistry {
|
||||||
private readonly handlers: Map<MessageType, Handler> = new Map();
|
private readonly handlers: Map<MessageType, Handler> = new Map();
|
||||||
|
|
||||||
public registerHandler(messageType: MessageType, handler: Handler): void {
|
public registerHandler(messageType: MessageType, handler: Handler): void {
|
@ -4,39 +4,37 @@ import { IMessage } from "../models/message";
|
|||||||
import { IRealm } from "../models/realm";
|
import { IRealm } from "../models/realm";
|
||||||
import { Handler } from "./handler";
|
import { Handler } from "./handler";
|
||||||
import { HeartbeatHandler, TransmissionHandler } from "./handlers";
|
import { HeartbeatHandler, TransmissionHandler } from "./handlers";
|
||||||
import { IMessageHandlers, MessageHandlers } from "./messageHandlers";
|
import { IHandlersRegistry, HandlersRegistry } from "./handlersRegistry";
|
||||||
|
|
||||||
export interface IMessageHandler {
|
export interface IMessageHandler {
|
||||||
handle(client: IClient | undefined, message: IMessage): boolean;
|
handle(client: IClient | undefined, message: IMessage): boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class MessageHandler implements IMessageHandler {
|
export class MessageHandler implements IMessageHandler {
|
||||||
private readonly messageHandlers: IMessageHandlers = new MessageHandlers();
|
constructor(realm: IRealm, private readonly handlersRegistry: IHandlersRegistry = new HandlersRegistry()) {
|
||||||
|
|
||||||
constructor(realm: IRealm) {
|
|
||||||
const transmissionHandler: Handler = TransmissionHandler({ realm });
|
const transmissionHandler: Handler = TransmissionHandler({ realm });
|
||||||
const heartbeatHandler: Handler = HeartbeatHandler;
|
const heartbeatHandler: Handler = HeartbeatHandler;
|
||||||
|
|
||||||
const handleTransmission: Handler = (client: IClient | undefined, message: IMessage): boolean => {
|
const handleTransmission: Handler = (client: IClient | undefined, { type, src, dst, payload }: IMessage): boolean => {
|
||||||
return transmissionHandler(client, {
|
return transmissionHandler(client, {
|
||||||
type: message.type,
|
type,
|
||||||
src: message.src,
|
src,
|
||||||
dst: message.dst,
|
dst,
|
||||||
payload: message.payload
|
payload,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleHeartbeat = (client: IClient | undefined, message: IMessage) => heartbeatHandler(client, message);
|
const handleHeartbeat = (client: IClient | undefined, message: IMessage) => heartbeatHandler(client, message);
|
||||||
|
|
||||||
this.messageHandlers.registerHandler(MessageType.HEARTBEAT, handleHeartbeat);
|
this.handlersRegistry.registerHandler(MessageType.HEARTBEAT, handleHeartbeat);
|
||||||
this.messageHandlers.registerHandler(MessageType.OFFER, handleTransmission);
|
this.handlersRegistry.registerHandler(MessageType.OFFER, handleTransmission);
|
||||||
this.messageHandlers.registerHandler(MessageType.ANSWER, handleTransmission);
|
this.handlersRegistry.registerHandler(MessageType.ANSWER, handleTransmission);
|
||||||
this.messageHandlers.registerHandler(MessageType.CANDIDATE, handleTransmission);
|
this.handlersRegistry.registerHandler(MessageType.CANDIDATE, handleTransmission);
|
||||||
this.messageHandlers.registerHandler(MessageType.LEAVE, handleTransmission);
|
this.handlersRegistry.registerHandler(MessageType.LEAVE, handleTransmission);
|
||||||
this.messageHandlers.registerHandler(MessageType.EXPIRE, handleTransmission);
|
this.handlersRegistry.registerHandler(MessageType.EXPIRE, handleTransmission);
|
||||||
}
|
}
|
||||||
|
|
||||||
public handle(client: IClient | undefined, message: IMessage): boolean {
|
public handle(client: IClient | undefined, message: IMessage): boolean {
|
||||||
return this.messageHandlers.handle(client, message);
|
return this.handlersRegistry.handle(client, message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -40,7 +40,7 @@ export class WebSocketServer extends EventEmitter implements IWebSocketServer {
|
|||||||
const path = this.config.path;
|
const path = this.config.path;
|
||||||
this.path = `${path}${path.endsWith('/') ? "" : "/"}${WS_PATH}`;
|
this.path = `${path}${path.endsWith('/') ? "" : "/"}${WS_PATH}`;
|
||||||
|
|
||||||
this.socketServer = new WebSocketLib.Server({ path, server });
|
this.socketServer = new WebSocketLib.Server({ path: this.path, server });
|
||||||
|
|
||||||
this.socketServer.on("connection", (socket: MyWebSocket, req) => this._onSocketConnection(socket, req));
|
this.socketServer.on("connection", (socket: MyWebSocket, req) => this._onSocketConnection(socket, req));
|
||||||
this.socketServer.on("error", (error: Error) => this._onSocketError(error));
|
this.socketServer.on("error", (error: Error) => this._onSocketError(error));
|
||||||
|
96
test/messageHandler/handlers/transmission/index.ts
Normal file
96
test/messageHandler/handlers/transmission/index.ts
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
import { expect } from 'chai';
|
||||||
|
import { Client } from '../../../../src/models/client';
|
||||||
|
import { TransmissionHandler } from '../../../../src/messageHandler/handlers';
|
||||||
|
import { Realm } from '../../../../src/models/realm';
|
||||||
|
import { MessageType } from '../../../../src/enums';
|
||||||
|
import { MyWebSocket } from '../../../../src/services/webSocketServer/webSocket';
|
||||||
|
|
||||||
|
const createFakeSocket = (): MyWebSocket => {
|
||||||
|
/* eslint-disable @typescript-eslint/no-empty-function */
|
||||||
|
const sock = {
|
||||||
|
send: (): void => { },
|
||||||
|
close: (): void => { },
|
||||||
|
on: (): void => { },
|
||||||
|
};
|
||||||
|
/* eslint-enable @typescript-eslint/no-empty-function */
|
||||||
|
|
||||||
|
return (sock as unknown as MyWebSocket);
|
||||||
|
};
|
||||||
|
|
||||||
|
describe('Transmission handler', () => {
|
||||||
|
it('should save message in queue when destination client not connected', () => {
|
||||||
|
const realm = new Realm();
|
||||||
|
const handleTransmission = TransmissionHandler({ realm });
|
||||||
|
|
||||||
|
const clientFrom = new Client({ id: 'id1', token: '' });
|
||||||
|
const idTo = 'id2';
|
||||||
|
realm.setClient(clientFrom, clientFrom.getId());
|
||||||
|
|
||||||
|
handleTransmission(clientFrom, { type: MessageType.OFFER, src: clientFrom.getId(), dst: idTo });
|
||||||
|
|
||||||
|
expect(realm.getMessageQueueById(idTo)?.getMessages().length).to.be.eq(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not save LEAVE and EXPIRE messages in queue when destination client not connected', () => {
|
||||||
|
const realm = new Realm();
|
||||||
|
const handleTransmission = TransmissionHandler({ realm });
|
||||||
|
|
||||||
|
const clientFrom = new Client({ id: 'id1', token: '' });
|
||||||
|
const idTo = 'id2';
|
||||||
|
realm.setClient(clientFrom, clientFrom.getId());
|
||||||
|
|
||||||
|
handleTransmission(clientFrom, { type: MessageType.LEAVE, src: clientFrom.getId(), dst: idTo });
|
||||||
|
handleTransmission(clientFrom, { type: MessageType.EXPIRE, src: clientFrom.getId(), dst: idTo });
|
||||||
|
|
||||||
|
expect(realm.getMessageQueueById(idTo)).to.be.undefined;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should send message to destination client when destination client connected', () => {
|
||||||
|
const realm = new Realm();
|
||||||
|
const handleTransmission = TransmissionHandler({ realm });
|
||||||
|
|
||||||
|
const clientFrom = new Client({ id: 'id1', token: '' });
|
||||||
|
const clientTo = new Client({ id: 'id2', token: '' });
|
||||||
|
const socketTo = createFakeSocket();
|
||||||
|
clientTo.setSocket(socketTo);
|
||||||
|
realm.setClient(clientTo, clientTo.getId());
|
||||||
|
|
||||||
|
let sent = false;
|
||||||
|
socketTo.send = (): void => {
|
||||||
|
sent = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
handleTransmission(clientFrom, { type: MessageType.OFFER, src: clientFrom.getId(), dst: clientTo.getId() });
|
||||||
|
|
||||||
|
expect(sent).to.be.true;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should send LEAVE message to source client when sending to destination client failed', () => {
|
||||||
|
const realm = new Realm();
|
||||||
|
const handleTransmission = TransmissionHandler({ realm });
|
||||||
|
|
||||||
|
const clientFrom = new Client({ id: 'id1', token: '' });
|
||||||
|
const clientTo = new Client({ id: 'id2', token: '' });
|
||||||
|
const socketFrom = createFakeSocket();
|
||||||
|
const socketTo = createFakeSocket();
|
||||||
|
clientFrom.setSocket(socketFrom);
|
||||||
|
clientTo.setSocket(socketTo);
|
||||||
|
realm.setClient(clientFrom, clientFrom.getId());
|
||||||
|
realm.setClient(clientTo, clientTo.getId());
|
||||||
|
|
||||||
|
let sent = false;
|
||||||
|
socketFrom.send = (data: string): void => {
|
||||||
|
if (JSON.parse(data)?.type === MessageType.LEAVE) {
|
||||||
|
sent = true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
socketTo.send = (): void => {
|
||||||
|
throw Error();
|
||||||
|
};
|
||||||
|
|
||||||
|
handleTransmission(clientFrom, { type: MessageType.OFFER, src: clientFrom.getId(), dst: clientTo.getId() });
|
||||||
|
|
||||||
|
expect(sent).to.be.true;
|
||||||
|
});
|
||||||
|
});
|
23
test/messageHandler/handlersRegistry.ts
Normal file
23
test/messageHandler/handlersRegistry.ts
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
import { expect } from 'chai';
|
||||||
|
import { HandlersRegistry } from '../../src/messageHandler/handlersRegistry';
|
||||||
|
import { Handler } from '../../src/messageHandler/handler';
|
||||||
|
import { MessageType } from '../../src/enums';
|
||||||
|
|
||||||
|
describe('HandlersRegistry', () => {
|
||||||
|
it('should execute handler for message type', () => {
|
||||||
|
const handlersRegistry = new HandlersRegistry();
|
||||||
|
|
||||||
|
let handled = false;
|
||||||
|
|
||||||
|
const handler: Handler = (): boolean => {
|
||||||
|
handled = true;
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
handlersRegistry.registerHandler(MessageType.OPEN, handler);
|
||||||
|
|
||||||
|
handlersRegistry.handle(undefined, { type: MessageType.OPEN, src: 'src', dst: 'dst' });
|
||||||
|
|
||||||
|
expect(handled).to.be.true;
|
||||||
|
});
|
||||||
|
});
|
Loading…
x
Reference in New Issue
Block a user