Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 7 additions & 3 deletions Models/Connection/ConnectionUtil.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,13 @@ export default class ConnectionUtil {
break;
}
default: {
throw new WebServerException(
`Provider type '${parts[1]}' not support in connection manager`
);
if (parts[1] == "ws") {
continue;
} else {
throw new WebServerException(
`Provider type '${parts[1]}' not support in connection manager`
);
}
}
}
retVal.push(connection);
Expand Down
8 changes: 2 additions & 6 deletions Models/Connection/EdgeConnectionInfo.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,8 @@ import Request from "../request.js";
import IEdgeSettingData from "./IEdgeSettingData.js";
import EdgeMessage from "../../edge/edgeMessage.js";
import WebServerException from "../Exceptions/WebServerException.js";
/**
* @typedef {Object} LoadDataRequest
* @property {string} dmnid --domainID
* @property {string} command --the basis core command
* @property {NodeJS.Dict<string>} params -- other parameters
*/
import LoadDataRequest from "../LoadDataRequest.js";

export default class EdgeConnectionInfo extends ConnectionInfo {
/** @type {IEdgeSettingData} */
settings;
Expand Down
8 changes: 8 additions & 0 deletions Models/LoadDataRequest.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
export default class LoadDataRequest {
/** @type {string} */
dmnid;
/** @type {string} */
command;
/** @type {NodeJS.Dict<string>} */
params;
}
8 changes: 8 additions & 0 deletions Models/WSMessageType.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
const WSMessageType = Object.freeze({
CONNECT :1 ,
MESSAGE :2,
DISCONNECT :3,
AD_HOC :4,
NOT_EXIST : 5
})
export default WSMessageType;
4 changes: 4 additions & 0 deletions Models/WebsocketServiceOptions.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export default class WebsocketServiceOptions {
/** @type {string} */
url
}
1 change: 0 additions & 1 deletion Services/HttpHostService.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import HostService from "./hostService.js";
import WebServerException from "../models/Exceptions/WebServerException.js";
import Request from "../models/request.js";
import Response from "../models/response.js";

export class HttpHostService extends HostService {
/**
* @param {string} name
Expand Down
76 changes: 76 additions & 0 deletions Services/WebsocketService.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import HostService from "./hostService.js";
import WebServerException from "../models/Exceptions/WebServerException.js";
import { HostServiceOptions } from "../models/model.js";
import WSMessageType from "../Models/WSMessageType.js";
import WebSocket from "ws";
import SessionManager from "./sessionManager.js";

export default class WebsocketService extends HostService {
/** @type {SessionManager} */
sessionManager;
/** @type {boolean} */
isInitialized;
/**
* @param {string} name
* @param {HostServiceOptions} options
*/
constructor(name, options) {
super(name, options);
this.isInitialized = false;
this.sessionManager = new SessionManager();
if (!this._options.Settings["Connections.ws.wsmain"]) {
throw new WebServerException(
`Router connection not set in '${name}' websocket base host service!`
);
}
this.socket = new WebSocket(
this._options.Settings["Connections.ws.wsmain"].endpoint
);
}
init(sessionId, serverSocket) {
const clientSocket = this.sessionManager.findSession(String(sessionId));
clientSocket.on("message", (data) => {
let jsData = JSON.parse(data);
if (typeof jsData != "string") {
jsData.sessionId = sessionId;
serverSocket.send(JSON.stringify(jsData));
}
});
}
/** @param {WebSocket} socket */
createSession(socket) {
let sessionId = this.sessionManager.addSession(socket);
this.socket.send(
JSON.stringify({
messageType: WSMessageType.CONNECT,
})
);
return sessionId;
}
sendMessage(sessionId, message) {
this.socket.send(
JSON.stringify({
sessionId,
message,
messageType: WSMessageType.MESSAGE,
})
);
}
adHoc(sessionId, message) {
this.socket.send(
JSON.stringify({
sessionId,
message,
messageType: WSMessageType.AD_HOC,
})
);
}
disconnect(sessionId) {
this.socket.send(
JSON.stringify({
sessionId,
messageType: WSMessageType.DISCONNECT,
})
);
}
}
26 changes: 26 additions & 0 deletions Services/sessionManager.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { randomUUID } from "crypto";


export default class SessionManager {
/** @type {Map<string,WebSocket>} */
sessionMap;

constructor() {
this.sessionMap = new Map();
}

addSession(session) {
let sessionId = randomUUID();
this.sessionMap.set(sessionId, session);
return sessionId;
}
deleteSession(sessionId) {
return this.sessionMap.delete(sessionId);
}
findSession(sessionId) {
return this.sessionMap.get(sessionId);
}
findOtherSessions(sessionId){
return Array.from(this.sessionMap).filter(([key]) => key !== sessionId);
}
}
63 changes: 63 additions & 0 deletions Services/testChatService.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import HostService from "./hostService.js";
import WebServerException from "../models/Exceptions/WebServerException.js";
import { HostServiceOptions } from "../models/model.js";
import WSMessageType from "../Models/WSMessageType.js";
import WebSocket from "ws";
import SessionManager from "./sessionManager.js";

export default class TestChatService extends HostService {
/** @type {SessionManager} */
sessionManager;
/** @type {boolean} */
isInitialized;

/**
* @param {string} name
* @param {HostServiceOptions} options
*/
constructor(name, options) {
super(name, options);
this.isInitialized = false;
this.sessionManager = new SessionManager();
}
init(sessionId, serverSocket) {
}
/** @param {WebSocket} socket */
createSession(socket) {
let sessionId = this.sessionManager.addSession(socket);
const otherSessions = this.sessionManager.findOtherSessions(sessionId);
otherSessions.map((session) => {
session[1].send(
JSON.stringify({
messageType: WSMessageType.CONNECT,
sessionId: sessionId,
message: `user with sessionId of ${sessionId} connected`,
})
);
});
return sessionId;
}
sendMessage(sessionId, message) {
const otherSessions = this.sessionManager.findOtherSessions(sessionId);
otherSessions.map((session) => {
session[1].send(
JSON.stringify({
sessionId,
message,
messageType: WSMessageType.MESSAGE,
})
);
});
}
disconnect(sessionId) {
const otherSessions = this.sessionManager.findOtherSessions(sessionId);
otherSessions.map((session) => {
session[1].send(
JSON.stringify({
sessionId,
messageType: WSMessageType.DISCONNECT,
})
);
});
}
}
55 changes: 55 additions & 0 deletions endPoint/WebsocketEndpoint.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import http from "http";
import https from "https";
import { WebSocketServer } from "ws";
import HostEndPoint from "./hostEndPoint.js";
import WebsocketService from "../Services/WebsocketService.js";
import WebServerException from "../models/Exceptions/WebServerException.js";
import TestChatService from "../Services/testChatService.js";

export default class WebsocketEndPoint extends HostEndPoint {
/** @type {import("tls").SecureContextOptions} */
#options;
/** @type {WebsocketService} */
_service;
/**
* @param {string} ip
* @param {number} port
* @param {HostService} service
* @param {import("tls").SecureContextOptions} options
* @param {string} targetServer
*/
constructor(ip, port, service, options) {
super(ip, port);
this.#options = options;
if (!(service instanceof WebsocketService || TestChatService)) {
throw new WebServerException(
"The service for Web Socket endpoint must be Websocket Service only."
);
}
this._service = service;
}

_createServer() {

const wss = new WebSocketServer({ ip: this._ip, port :this._port });

wss.on("connection", (clientSocket) => {

const sessionId = this._service.createSession(clientSocket);
this._service.init(sessionId,clientSocket);
clientSocket.on("message", (message) => {
this._service.sendMessage(sessionId,message.toString())
});
clientSocket.on("close", () => {
this._service.disconnect(sessionId)
});
clientSocket.on("error", (err) => {
console.error("Client socket error:", err);
});
});
return this.server;
}
listenAsync() {
this._createServer();
}
}
35 changes: 32 additions & 3 deletions hostManager.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ import {
import H2HttpHostEndPoint from "./endPoint/h2HttpHostEndPoint.js";
import { HttpHostService } from "./services/HttpHostService.js";
import EndPointController from "./EndpointController.js";
import WebsocketEndPoint from "./endPoint/WebsocketEndpoint.js";
import WebsocketService from "./Services/WebsocketService.js";
import TestChatService from "./Services/testChatService.js";

export default class HostManager {
/**@type {HostEndPoint[]} */
Expand All @@ -39,7 +42,7 @@ export default class HostManager {

listenAsync() {
const tasks = this.hosts.map((x) =>
x.listenAsync().catch((err) => console.error(err))
x.listenAsync()?.catch((err) => console.error(err))
);
return Promise.all(tasks);
}
Expand Down Expand Up @@ -70,6 +73,14 @@ export default class HostManager {
this.#createHttpEndPoint(name, endPointsOptions, service);
break;
}
case "websocket": {
this.#createwebsocketEndPoint(name, endPointsOptions, service)
break;
}
case "testchat": {
this.#createTestChatEndPoint(name, endPointsOptions, service)
break;
}
default: {
console.error(
`${endPointsOptions.Type} not support in this version of web server`
Expand Down Expand Up @@ -145,7 +156,6 @@ export default class HostManager {
const sniCallback = (serverName, callback) => {
const set = hostLookup[serverName.toLowerCase()];
if (set) {
console.log("set", set);
if (set.cert) {
callback(
null,
Expand Down Expand Up @@ -209,7 +219,18 @@ export default class HostManager {
}
});
}

#createwebsocketEndPoint(name, options, service) {
options.Addresses.forEach((address) => {
const [ip, port] = address.EndPoint.split(":", 2);
this.hosts.push(new WebsocketEndPoint(ip, port, service, options))
});
}
#createTestChatEndPoint(name, options, service) {
options.Addresses.forEach((address) => {
const [ip, port] = address.EndPoint.split(":", 2);
this.hosts.push(new WebsocketEndPoint(ip, port, service, options))
});
}
/**
* @param {NodeJS.Dict<HostServiceOptions>} services
* @returns {HostService[]}
Expand All @@ -230,6 +251,14 @@ export default class HostManager {
retVal.push(this.#createFileDispatcher(name, serviceOptions));
break;
}
case "websocket": {
retVal.push(new WebsocketService(name, serviceOptions))
break;
}
case "testchat": {
retVal.push(new TestChatService(name, serviceOptions))
break;
}
default: {
console.error(
`${serviceOptions.Type} not support in this version of web server`
Expand Down
Loading