diff --git a/Models/Connection/ConnectionUtil.js b/Models/Connection/ConnectionUtil.js index 31c2814..7007649 100644 --- a/Models/Connection/ConnectionUtil.js +++ b/Models/Connection/ConnectionUtil.js @@ -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); diff --git a/Models/Connection/EdgeConnectionInfo.js b/Models/Connection/EdgeConnectionInfo.js index a2808e0..d7e7502 100644 --- a/Models/Connection/EdgeConnectionInfo.js +++ b/Models/Connection/EdgeConnectionInfo.js @@ -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} params -- other parameters - */ +import LoadDataRequest from "../LoadDataRequest.js"; + export default class EdgeConnectionInfo extends ConnectionInfo { /** @type {IEdgeSettingData} */ settings; diff --git a/Models/LoadDataRequest.js b/Models/LoadDataRequest.js new file mode 100644 index 0000000..93241b7 --- /dev/null +++ b/Models/LoadDataRequest.js @@ -0,0 +1,8 @@ +export default class LoadDataRequest { + /** @type {string} */ + dmnid; + /** @type {string} */ + command; + /** @type {NodeJS.Dict} */ + params; +} \ No newline at end of file diff --git a/Models/WSMessageType.js b/Models/WSMessageType.js new file mode 100644 index 0000000..1a3ecf8 --- /dev/null +++ b/Models/WSMessageType.js @@ -0,0 +1,8 @@ + const WSMessageType = Object.freeze({ + CONNECT :1 , + MESSAGE :2, + DISCONNECT :3, + AD_HOC :4, + NOT_EXIST : 5 +}) +export default WSMessageType; \ No newline at end of file diff --git a/Models/WebsocketServiceOptions.js b/Models/WebsocketServiceOptions.js new file mode 100644 index 0000000..0e7c8ce --- /dev/null +++ b/Models/WebsocketServiceOptions.js @@ -0,0 +1,4 @@ +export default class WebsocketServiceOptions { + /** @type {string} */ + url +} \ No newline at end of file diff --git a/Services/HttpHostService.js b/Services/HttpHostService.js index 18bad9a..4cb1718 100644 --- a/Services/HttpHostService.js +++ b/Services/HttpHostService.js @@ -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 diff --git a/Services/WebsocketService.js b/Services/WebsocketService.js new file mode 100644 index 0000000..02803b7 --- /dev/null +++ b/Services/WebsocketService.js @@ -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, + }) + ); + } +} diff --git a/Services/sessionManager.js b/Services/sessionManager.js new file mode 100644 index 0000000..1508e4a --- /dev/null +++ b/Services/sessionManager.js @@ -0,0 +1,26 @@ +import { randomUUID } from "crypto"; + + +export default class SessionManager { + /** @type {Map} */ + 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); + } +} diff --git a/Services/testChatService.js b/Services/testChatService.js new file mode 100644 index 0000000..2dafbd2 --- /dev/null +++ b/Services/testChatService.js @@ -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, + }) + ); + }); + } +} diff --git a/endPoint/WebsocketEndpoint.js b/endPoint/WebsocketEndpoint.js new file mode 100644 index 0000000..7a2b27e --- /dev/null +++ b/endPoint/WebsocketEndpoint.js @@ -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(); + } +} diff --git a/hostManager.js b/hostManager.js index f476985..b7cbf00 100644 --- a/hostManager.js +++ b/hostManager.js @@ -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[]} */ @@ -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); } @@ -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` @@ -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, @@ -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} services * @returns {HostService[]} @@ -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` diff --git a/index.js b/index.js index e496152..1a96d6b 100644 --- a/index.js +++ b/index.js @@ -6,39 +6,21 @@ const host = { Lazy: true, EndPoints: { Main01: { - Type: "http", - id: "fingerfood", + Type: "websocket", + id: "chat", Addresses: [ { - EndPoint: "0.0.0.0:443", + EndPoint: "127.0.0.1:2020", }, - { EndPoint: "0.0.0.0:80" }, + { EndPoint: "127.0.0.1:1010" }, ], Active: true, - Routing: "mainService", - CacheSettings: { - requestMethods: "GET", - responseHeaders: ["content-type"], - isEnabled: true, - connectionType: "sqlite", - connectionSetting: { - dbPath: "test.db", - tableName: "cache_results", - isFileBase: true, - filesPath: "C:\\webservercache", - }, - }, + Routing: "chat", }, }, Services: { - mainService: { - Type: "http", - Settings: { - LibPath : "F:\\AliBazregar\\BasisCore.Server.Node\\ExternalCommands", - "Connections.edge.RoutingData": { - endpoint: "127.0.0.1:2002", - }, - }, + chat: { + Type: "testchat" }, }, }; diff --git a/package-lock.json b/package-lock.json index aabc78d..2495bb6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "basiscore.server", - "version": "1.0.2", + "version": "1.0.3", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "basiscore.server", - "version": "1.0.2", + "version": "1.0.3", "license": "ISC", "dependencies": { "alasql": "^4.1.9", @@ -27,9 +27,12 @@ "node-html-encoder": "^0.0.2", "pako": "^2.1.0", "promised-sqlite3": "^2.1.0", + "socket.io": "^4.7.5", + "socket.io-client": "^4.7.5", "sqlite3": "^5.1.6", "winston": "^3.13.0", - "winston-transport": "^4.7.0" + "winston-transport": "^4.7.0", + "ws": "^8.18.0" }, "devDependencies": { "@babel/preset-env": "^7.24.7", @@ -2660,6 +2663,11 @@ "@sinonjs/commons": "^3.0.0" } }, + "node_modules/@socket.io/component-emitter": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.2.tgz", + "integrity": "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==" + }, "node_modules/@tediousjs/connection-string": { "version": "0.5.0", "resolved": "https://registry.npmjs.org/@tediousjs/connection-string/-/connection-string-0.5.0.tgz", @@ -2715,6 +2723,19 @@ "@babel/types": "^7.20.7" } }, + "node_modules/@types/cookie": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.1.tgz", + "integrity": "sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==" + }, + "node_modules/@types/cors": { + "version": "2.8.17", + "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.17.tgz", + "integrity": "sha512-8CGDvrBj1zgo2qE+oS3pOCyYNqCPryMWY2bGfwA0dcfopWGgxs+78df0Rs3rc9THP4JkOhLsAa+15VdpAqkcUA==", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/eslint": { "version": "8.56.10", "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.10.tgz", @@ -2784,7 +2805,6 @@ "version": "20.14.5", "resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.5.tgz", "integrity": "sha512-aoRR+fJkZT2l0aGOJhuA8frnCSoNX6W7U2mpNq63+BxBIj5BQFt8rHy627kijCmm63ijdSdwvGgpUsU6MBsZZA==", - "dev": true, "dependencies": { "undici-types": "~5.26.4" } @@ -3028,6 +3048,18 @@ "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", "optional": true }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/acorn": { "version": "8.12.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.0.tgz", @@ -3731,6 +3763,14 @@ } ] }, + "node_modules/base64id": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz", + "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==", + "engines": { + "node": "^4.5.0 || >= 5.9" + } + }, "node_modules/bindings": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", @@ -4306,6 +4346,14 @@ "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", "dev": true }, + "node_modules/cookie": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", + "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==", + "engines": { + "node": ">= 0.6" + } + }, "node_modules/cookiejar": { "version": "2.1.4", "resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.4.tgz", @@ -4376,6 +4424,18 @@ "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" }, + "node_modules/cors": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", + "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "dependencies": { + "object-assign": "^4", + "vary": "^1" + }, + "engines": { + "node": ">= 0.10" + } + }, "node_modules/create-jest": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/create-jest/-/create-jest-29.7.0.tgz", @@ -4733,6 +4793,86 @@ "once": "^1.4.0" } }, + "node_modules/engine.io": { + "version": "6.5.5", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.5.5.tgz", + "integrity": "sha512-C5Pn8Wk+1vKBoHghJODM63yk8MvrO9EWZUfkAt5HAqIgPE4/8FF0PEGHXtEd40l223+cE5ABWuPzm38PHFXfMA==", + "dependencies": { + "@types/cookie": "^0.4.1", + "@types/cors": "^2.8.12", + "@types/node": ">=10.0.0", + "accepts": "~1.3.4", + "base64id": "2.0.0", + "cookie": "~0.4.1", + "cors": "~2.8.5", + "debug": "~4.3.1", + "engine.io-parser": "~5.2.1", + "ws": "~8.17.1" + }, + "engines": { + "node": ">=10.2.0" + } + }, + "node_modules/engine.io-client": { + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.5.4.tgz", + "integrity": "sha512-GeZeeRjpD2qf49cZQ0Wvh/8NJNfeXkXXcoGh+F77oEAgo9gUHwT1fCRxSNU+YEEaysOJTnsFHmM5oAcPy4ntvQ==", + "dependencies": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.3.1", + "engine.io-parser": "~5.2.1", + "ws": "~8.17.1", + "xmlhttprequest-ssl": "~2.0.0" + } + }, + "node_modules/engine.io-client/node_modules/ws": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz", + "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/engine.io-parser": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.3.tgz", + "integrity": "sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q==", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/engine.io/node_modules/ws": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz", + "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, "node_modules/enhanced-resolve": { "version": "5.17.0", "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.17.0.tgz", @@ -7775,7 +7915,6 @@ "version": "0.6.3", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", - "optional": true, "engines": { "node": ">= 0.6" } @@ -7985,6 +8124,14 @@ "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/object-inspect": { "version": "1.13.1", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", @@ -8986,6 +9133,78 @@ "npm": ">= 3.0.0" } }, + "node_modules/socket.io": { + "version": "4.7.5", + "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.7.5.tgz", + "integrity": "sha512-DmeAkF6cwM9jSfmp6Dr/5/mfMwb5Z5qRrSXLpo3Fq5SqyU8CMF15jIN4ZhfSwu35ksM1qmHZDQ/DK5XTccSTvA==", + "dependencies": { + "accepts": "~1.3.4", + "base64id": "~2.0.0", + "cors": "~2.8.5", + "debug": "~4.3.2", + "engine.io": "~6.5.2", + "socket.io-adapter": "~2.5.2", + "socket.io-parser": "~4.2.4" + }, + "engines": { + "node": ">=10.2.0" + } + }, + "node_modules/socket.io-adapter": { + "version": "2.5.5", + "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.5.5.tgz", + "integrity": "sha512-eLDQas5dzPgOWCk9GuuJC2lBqItuhKI4uxGgo9aIV7MYbk2h9Q6uULEh8WBzThoI7l+qU9Ast9fVUmkqPP9wYg==", + "dependencies": { + "debug": "~4.3.4", + "ws": "~8.17.1" + } + }, + "node_modules/socket.io-adapter/node_modules/ws": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz", + "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/socket.io-client": { + "version": "4.7.5", + "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.7.5.tgz", + "integrity": "sha512-sJ/tqHOCe7Z50JCBCXrsY3I2k03iOiUe+tj1OmKeD2lXPiGH/RUCdTZFoqVyN7l1MnpIzPrGtLcijffmeouNlQ==", + "dependencies": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.3.2", + "engine.io-client": "~6.5.2", + "socket.io-parser": "~4.2.4" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/socket.io-parser": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz", + "integrity": "sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==", + "dependencies": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.3.1" + }, + "engines": { + "node": ">=10.0.0" + } + }, "node_modules/socks": { "version": "2.8.3", "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.3.tgz", @@ -10043,8 +10262,7 @@ "node_modules/undici-types": { "version": "5.26.5", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", - "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", - "dev": true + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==" }, "node_modules/unicode-canonical-property-names-ecmascript": { "version": "2.0.0", @@ -10179,6 +10397,14 @@ "node": ">=10.12.0" } }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/walker": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", @@ -10603,6 +10829,34 @@ "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, + "node_modules/ws": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", + "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/xmlhttprequest-ssl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.0.0.tgz", + "integrity": "sha512-QKxVRxiRACQcVuQEYFsI1hhkrMlrXHPegbbd1yn9UHOmRxY+si12nQYzri3vbzt8VdTTRviqcKxcyllFas5z2A==", + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/xtend": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", diff --git a/package.json b/package.json index c030803..0e0b437 100644 --- a/package.json +++ b/package.json @@ -91,9 +91,12 @@ "node-html-encoder": "^0.0.2", "pako": "^2.1.0", "promised-sqlite3": "^2.1.0", + "socket.io": "^4.7.5", + "socket.io-client": "^4.7.5", "sqlite3": "^5.1.6", "winston": "^3.13.0", - "winston-transport": "^4.7.0" + "winston-transport": "^4.7.0", + "ws": "^8.18.0" }, "devDependencies": { "@babel/preset-env": "^7.24.7", diff --git a/request.js b/request.js new file mode 100644 index 0000000..849683f --- /dev/null +++ b/request.js @@ -0,0 +1,78 @@ +const request = { + cms: { + date: "09/23/2024", + time: "01:35 AM", + date2: "20240923", + time2: "013518", + date3: "2024.09.23", + }, + request: { + host: "www.vitashe.co", + connection: "keep-alive", + "user-agent": + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36", + "accept-encoding": "identity;q=1, *;q=0", + accept: "*/*", + referer: "http://www.vitashe.co/", + "accept-language": "en-US,en;q=0.9,fa;q=0.8", + cookie: "deviceid=1; agentnumber=927959", + range: "bytes=0-", + "request-id": "2", + methode: "get", + rawurl: "1047644731752001B", + url: "1047644731752001B", + "full-url": "www.vitashe.co/1047644731752001B", + hostip: "185.44.36.186", + hostport: "80", + clientip: "185.44.38.84", + ":path": "/1047644731752001B", + json: {}, + body: undefined, + }, + query: undefined, + form: undefined, + isSecure: false, +}; +Table = { + columns: [ + { type: [sql.VarChar], length: 50, name: 'ParamType' }, + { type: [sql.VarChar], length: 100, name: 'ParamName' }, + { type: [sql.VarChar], length: undefined, name: 'ParamValue' } + ], + rows: [ + [ 'cms', 'date', '09/23/2024' ], + [ 'cms', 'time', '01:42 AM' ], + [ 'cms', 'date2', '20240923' ], + [ 'cms', 'time2', '014219' ], + [ 'cms', 'date3', '2024.09.23' ], + [ 'request', 'host', 'www.vitashe.ir' ], + [ 'request', 'connection', 'keep-alive' ], + [ 'request', 'pragma', 'no-cache' ], + [ 'request', 'cache-control', 'no-cache' ], + [ 'request', 'upgrade-insecure-requests', '1' ], + [ + 'request', + 'user-agent', + 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36' + ], + [ + 'request', + 'accept', + 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7' + ], + [ 'request', 'accept-encoding', 'gzip, deflate' ], + [ 'request', 'accept-language', 'en-US,en;q=0.9' ], + [ 'request', 'cookie', 'deviceid=1; agentnumber=927959' ], + [ 'request', 'request-id', '7' ], + [ 'request', 'methode', 'get' ], + [ 'request', 'rawurl', '' ], + [ 'request', 'url', '' ], + [ 'request', 'full-url', 'www.vitashe.ir/' ], + [ 'request', 'hostip', '185.44.36.186' ], + [ 'request', 'hostport', '80' ], + [ 'request', 'clientip', '2.177.229.66' ], + [ 'request', ':path', '/' ], + [ 'request', 'json', '[object Object]' ], + [ 'request', 'body', undefined ] + ] +} diff --git a/response.js b/response.js new file mode 100644 index 0000000..27722e7 --- /dev/null +++ b/response.js @@ -0,0 +1,336 @@ +[ + { ParamType: "cms", ParamName: "date", ParamValue: "09/23/2024" }, + { ParamType: "cms", ParamName: "time", ParamValue: "02:05 AM" }, + { ParamType: "cms", ParamName: "date2", ParamValue: "20240923" }, + { ParamType: "cms", ParamName: "time2", ParamValue: "020511" }, + { ParamType: "cms", ParamName: "date3", ParamValue: "2024.09.23" }, + { + ParamType: "request", + ParamName: "host", + ParamValue: "www.vitashe.co", + }, + { + ParamType: "request", + ParamName: "connection", + ParamValue: "keep-alive", + }, + { + ParamType: "request", + ParamName: "cache-control", + ParamValue: "max-age=0", + }, + { + ParamType: "request", + ParamName: "upgrade-insecure-requests", + ParamValue: "1", + }, + { + ParamType: "request", + ParamName: "user-agent", + ParamValue: + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36", + }, + { + ParamType: "request", + ParamName: "accept", + ParamValue: + "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", + }, + { + ParamType: "request", + ParamName: "accept-encoding", + ParamValue: "gzip, deflate", + }, + { + ParamType: "request", + ParamName: "accept-language", + ParamValue: "en-US,en;q=0.9", + }, + { + ParamType: "request", + ParamName: "cookie", + ParamValue: "deviceid=1; agentnumber=927959", + }, + { ParamType: "request", ParamName: "request-id", ParamValue: "4" }, + { ParamType: "request", ParamName: "methode", ParamValue: "get" }, + { ParamType: "request", ParamName: "rawurl", ParamValue: "" }, + { ParamType: "request", ParamName: "url", ParamValue: "" }, + { + ParamType: "request", + ParamName: "full-url", + ParamValue: "www.vitashe.co/", + }, + { + ParamType: "request", + ParamName: "hostip", + ParamValue: "185.44.36.186", + }, + { ParamType: "request", ParamName: "hostport", ParamValue: "80" }, + { + ParamType: "request", + ParamName: "clientip", + ParamValue: "2.177.229.66", + }, + { ParamType: "request", ParamName: ":path", ParamValue: "/" }, + { + ParamType: "request", + ParamName: "json", + ParamValue: "[object Object]", + }, + { ParamType: "request", ParamName: "body", ParamValue: null }, + { + ParamType: "http", + ParamName: "Expires", + ParamValue: "max-age=120000,public", + }, + { + ParamType: "http", + ParamName: "date", + ParamValue: "Mon, 23 Sep 2024 12:56:54 GMT", + }, + { + ParamType: "http", + ParamName: "Server", + ParamValue: "BasisCore 4.0.1", + }, + { + ParamType: "cms", + ParamName: "content", + ParamValue: + '\n' + + ' \n' + + " \n" + + " \n" + + ' \n' + + ' \n' + + " \n" + + " \n" + + " \n" + + " \n" + + ' \n' + + ' \n' + + " \n" + + " \n" + + " \n" + + " \n" + + ' \n' + + " \n" + + ' \n' + + ' \n' + + ' \n' + + " \n" + + " Vitashe\n" + + ' \n' + + ' \n' + + " \n" + + " \n" + + ' \n' + + " \n" + + ' \n' + + " \n" + + " \n" + + " \n" + + " \n" + + '
\n' + + ' \n' + + " \n" + + ' \n' + + " \n" + + " \n" + + '
\n' + + "

Kitchen Atmosphere

\n" + + "
\n" + + "
\n" + + " \n" + + " \n" + + " \n" + + '
\n' + + '
\n' + + " \n" + + '
\n' + + " \n" + + ' \n' + + ' \n' + + ' \n" + + " \n" + + " \n" + + "
\n" + + " \n" + + "
\n" + + " \n" + + ' \n' + + " \n" + + " \n" + + "
\n" + + ' \n' + + ' \n' + + ' \n' + + ' \n' + + ' \n' + + ' \n' + + ' \n' + + " \n" + + ' \n' + + " \n" + + " \n" + + " ", + }, + { + ParamType: "cms", + ParamName: "page_il", + ParamValue: + '{"$type":"group","core":"group","name":"ROOT_GROUP","Commands":[{"$type":"dbsource","core":"dbsource","name":"db","ConnectionName":"media","extra-attribute":{"lid":"2","sourcemid":"1","usedforid":"2328059"},"Members":[{"name":"videodef","extra-attribute":{"type":"list","format":"3"}}]},{"$type":"dbsource","core":"dbsource","ConnectionName":"basiscore","name":"basisName","extra-attribute":{"lid":"2","mid":"20"},"Members":[{"extra-attribute":{"request":"cat","type":"tree","parentid":"201824"},"name":"productCat"}]},{"$type":"dbsource","core":"dbsource","name":"db","ConnectionName":"basiscore","extra-attribute":{"lid":"2","mid":"5","usedforid":"9550"},"Members":[{"name":"contactus","extra-attribute":{"type":"view"}}]},{"$type":"rawtext","core":"rawtext","content":"\\r\\n \\r\\n \\r\\n \\r\\n \\r\\n \\r\\n \\r\\n \\r\\n \\r\\n \\r\\n Vitashe\\r\\n \\r\\n \\r\\n \\r\\n \\r\\n \\r\\n \\r\\n "},{"$type":"call","core":"call","FileName":"header.inc","extra-attribute":{"lid":"2"}},{"$type":"rawtext","core":"rawtext","content":"\\r\\n \\r\\n \\r\\n \\r\\n \\r\\n
\\r\\n "},{"$type":"print","core":"print","data-member-name":"db.videodef","faces":[{"content":"\\r\\n \\r\\n "}]},{"$type":"rawtext","core":"rawtext","content":"\\r\\n
\\r\\n

Kitchen Atmosphere

\\r\\n
\\r\\n
\\r\\n \\r\\n \\r\\n \\r\\n
\\r\\n
\\r\\n \\r\\n
\\r\\n \\r\\n "},{"$type":"print","core":"print","data-member-name":"basisName.productCat","faces":[{"filter":"RowNumber>1","content":"\\r\\n \\r\\n "}]},{"$type":"rawtext","core":"rawtext","content":"\\r\\n
\\r\\n \\r\\n
\\r\\n \\r\\n "},{"$type":"call","core":"call","FileName":"footer1.inc","extra-attribute":{"lid":"2"}},{"$type":"rawtext","core":"rawtext","content":"\\r\\n \\r\\n \\r\\n
\\r\\n \\r\\n \\r\\n \\r\\n \\r\\n \\r\\n \\r\\n \\r\\n \\r\\n \\r\\n \\r\\n "}]}', + }, + { ParamType: "cms", ParamName: "il_call", ParamValue: "false" }, + { ParamType: "cms", ParamName: "pagesizeid", ParamValue: "83620" }, + { ParamType: "cms", ParamName: "pageurl", ParamValue: null }, + { + ParamType: "cms", + ParamName: "useragent", + ParamValue: + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36", + }, + { ParamType: "cms", ParamName: "pageid", ParamValue: "92589" }, + { ParamType: "cms", ParamName: "dmnid", ParamValue: "4764" }, + { ParamType: "cms", ParamName: "domainid", ParamValue: "4764" }, + { ParamType: "cms", ParamName: "ownerid", ParamValue: "9550" }, + { + ParamType: "cms", + ParamName: "link_page", + ParamValue: "default.bc?", + }, + { + ParamType: "cms", + ParamName: "PhysicalPath", + ParamValue: "\\\\192.168.96.2\\b\\", + }, + { + ParamType: "cms", + ParamName: "temppath", + ParamValue: "\\\\192.168.96.2\\b\\temp\\", + }, + { + ParamType: "cms", + ParamName: "cdn", + ParamValue: "http://cdn.basiscore.net/vitashe.co", + }, + { ParamType: "cms", ParamName: "agentnumber", ParamValue: "0" }, + { + ParamType: "cms", + ParamName: "page_index", + ParamValue: "نمایه پیش فرض", + }, + { ParamType: "cms", ParamName: "pageindex", ParamValue: "2087" }, + { ParamType: "http", ParamName: "Vary", ParamValue: "User-Agent" }, + { + ParamType: "http", + ParamName: "Set-Cookie", + ParamValue: "deviceid=1;", + }, + { ParamType: "cms", ParamName: "random", ParamValue: "0" }, + { + ParamType: "cms", + ParamName: "defaultpath", + ParamValue: "\\\\192.168.96.2\\b\\", + }, + { ParamType: "webserver", ParamName: "index", ParamValue: "1" }, + { ParamType: "webserver", ParamName: "gzip", ParamValue: "true" }, + { ParamType: "webserver", ParamName: "chunked", ParamValue: "false" }, + { ParamType: "webserver", ParamName: "chunksize", ParamValue: "0" }, + { ParamType: "webserver", ParamName: "etag", ParamValue: '"92589"' }, + { + ParamName: "lastmodified", + ParamValue: "Tue, 26 Sep 2023 14:27:51 GMT", + }, + { + ParamType: "http", + ParamName: "Cache-Control", + ParamValue: "public,max-age=120000", + }, + { + ParamType: "webserver", + ParamName: "mime", + ParamValue: "text/html; charset=UTF-8", + }, + { + ParamType: "webserver", + ParamName: "headercode", + ParamValue: "200 Ok", + }, + { ParamType: "webserver", ParamName: "filepath", ParamValue: "" }, + { ParamType: "webserver", ParamName: "id", ParamValue: "92589" }, + { + ParamType: "webserver", + ParamName: "domain", + ParamValue: "vitashe.co", + }, + { ParamType: "webserver", ParamName: "FileContent", ParamValue: "" }, + { ParamType: "webserver", ParamName: "cookie", ParamValue: "" }, + { ParamType: "webserver", ParamName: "debug", ParamValue: "false" }, + { ParamType: "index4", ParamName: "source", ParamValue: null }, + { ParamType: "index4", ParamName: "destination", ParamValue: null }, + { + ParamType: "index4", + ParamName: "properties", + ParamValue: '{"deform":true}', + }, + { ParamType: "index4", ParamName: "size", ParamValue: null }, + { ParamType: "index4", ParamName: "zippath", ParamValue: null }, + { ParamType: "index4", ParamName: "webppath", ParamValue: null }, + { ParamType: "cms", ParamName: "showcmserror", ParamValue: "true" }, + { + ParamType: "http", + ParamName: "X-XSS-Protection", + ParamValue: "1; mode=block", + }, + { ParamType: "webserver", ParamName: "savehtml", ParamValue: null }, + { ParamType: "webserver", ParamName: "export", ParamValue: "" }, +]; diff --git a/test/command/InlineSource/inlinesourceSqlCommand.js b/test/command/InlineSource/inlinesourceSqlCommand.js index c086fd6..164be9d 100644 --- a/test/command/InlineSource/inlinesourceSqlCommand.js +++ b/test/command/InlineSource/inlinesourceSqlCommand.js @@ -3,8 +3,11 @@ import ServiceSettings from "../../../models/ServiceSettings.js"; import CancellationToken from "../../../renderEngine/Cancellation/CancellationToken.js"; import GroupCommand from "../../../renderEngine/Command/Collection/GroupCommand.js"; import TestContext from "../../../renderEngine/Context/TestContext.js"; +import VoidContext from "../../../renderEngine/Context/VoidContext.js"; +import CommandUtil from "../../../renderEngine/CommandUtil.js"; var setting = new ServiceSettings({}); -const context = new TestContext(setting); +const context = new TestContext(setting,"1",CommandUtil.addDefaultCommands()); +context.debugContext = new VoidContext("test") context.cancellation = new CancellationToken(); const il = { @@ -119,8 +122,9 @@ const il = { name: "face1", replace: true, function: true, + filter: "valueId = '12688740'", content: - "

@valueID @mid @groupid @prpid @usedforid @typeid @multi @ord
", + "

@valueID @mid @groupId @prpid @usedforId @typeId @multi @ord
", }, ], replaces: [ diff --git a/test/ws.js b/test/ws.js new file mode 100644 index 0000000..f12e6ad --- /dev/null +++ b/test/ws.js @@ -0,0 +1,35 @@ +import { WebSocketServer } from "ws"; + +const server = new WebSocketServer({ port: 8000 }); + +server.on("connection", (socket) => { + console.log("Client connected"); + + // Send an object every second + const intervalId = setInterval(() => { + const obj = { + timestamp: new Date(), + message: "Hello from the server!", + }; + let objectt = { + sources: [ + { + options: { + tableName: "user.list", + mergeType: 1, + }, + data: [obj], + }, + ], + }; + socket.send(JSON.stringify(objectt)); + }, 1000); + + // Clean up when the connection is closed + socket.on("close", () => { + clearInterval(intervalId); + console.log("Client disconnected"); + }); +}); + +console.log("WebSocket server is running on ws://localhost:8080");