From 7bc524ee8113becd2585d29cd6de9ce7990b78fa Mon Sep 17 00:00:00 2001 From: Ali Date: Tue, 21 May 2024 12:38:23 +0330 Subject: [PATCH 1/5] first --- Models/Connection/ConnectionInfo.js | 16 +- Models/Connection/SqliteConnectionInfo.js | 85 ++++++++- Models/Connection/SqliteSettingData.js | 2 + Models/ServiceSettings.js | 11 ++ Models/options/CacheResult.js | 8 + Models/options/CacheSettings.js | 8 + Models/options/hostServiceOptions.js | 3 + endPoint/h2HttpHostEndPoint.js | 205 +++++++++++++--------- endPoint/httpHostEndPoint.js | 70 +++++++- endPoint/nonSecureHttpHostEndPoint.js | 55 +++--- endPoint/secureHttpHostEndPoint.js | 67 +++---- index.js | 1 + package-lock.json | 41 +++-- package.json | 5 +- test.db | Bin 0 -> 118784 bytes test/connection/edge/edge-script.py | 16 +- test/connection/edge/simple.js | 4 + test/connection/sqlite/cache.js | 41 +++++ test/connection/sqlite/table.sqlite | 6 + 19 files changed, 484 insertions(+), 160 deletions(-) create mode 100644 Models/options/CacheResult.js create mode 100644 Models/options/CacheSettings.js create mode 100644 test.db create mode 100644 test/connection/sqlite/cache.js create mode 100644 test/connection/sqlite/table.sqlite diff --git a/Models/Connection/ConnectionInfo.js b/Models/Connection/ConnectionInfo.js index 7bbe2d7..2940ac1 100644 --- a/Models/Connection/ConnectionInfo.js +++ b/Models/Connection/ConnectionInfo.js @@ -3,7 +3,7 @@ import DataSourceCollection from "../../renderEngine/Source/DataSourceCollection import IRoutingRequest from "../IRoutingRequest.js"; import Request from "../request.js"; import ILoadPageResult from "./ILoadPageResult.js"; - +import CacheResult from "../options/CacheResult.js"; export default class ConnectionInfo { /** @type {string} */ name; @@ -69,4 +69,18 @@ export default class ConnectionInfo { ); } } + /** + * + * @param {string} key + * @returns {Promise} + */ + async loadContentAsync(key) {} + + /** + * @param {string} key + * @param {string} content + * @param {NodeJS.Dict} properties + * @returns {Promise} + */ + async addCacheContentAsync(key, content, properties) {} } diff --git a/Models/Connection/SqliteConnectionInfo.js b/Models/Connection/SqliteConnectionInfo.js index 0019f20..0bfeaf1 100644 --- a/Models/Connection/SqliteConnectionInfo.js +++ b/Models/Connection/SqliteConnectionInfo.js @@ -4,6 +4,8 @@ import SqliteSettingData from "./SqliteSettingData.js"; import DataSourceCollection from "../../renderEngine/Source/DataSourceCollection.js"; import CancellationToken from "../../renderEngine/Cancellation/CancellationToken.js"; import Request from "../request.js"; +import CacheResult from "./../options/CacheResult.js"; + export default class SqliteConnectionInfo extends ConnectionInfo { /** @type {SqliteSettingData} */ settings; @@ -36,9 +38,9 @@ export default class SqliteConnectionInfo extends ConnectionInfo { } }); }); - const retVal = new DataSourceCollection( - [ Array.isArray(rows) ? rows : [rows]] - ); + const retVal = new DataSourceCollection([ + Array.isArray(rows) ? rows : [rows], + ]); return retVal; } finally { @@ -47,7 +49,6 @@ export default class SqliteConnectionInfo extends ConnectionInfo { } } } - /** * @param {Request} request * @param {CancellationToken} cancellationToken @@ -59,4 +60,80 @@ export default class SqliteConnectionInfo extends ConnectionInfo { async testConnectionAsync() { throw new Error("test connection is not supported in sqlite"); } + + /** + * + * @param {string} key + * @param {CancellationToken} cancellationToken + * @returns {Promise} + */ + async loadContentAsync(key, cancellationToken) { + /**@type {sqlite3.Database} */ + let database; + try { + database = new sqlite3.Database(this.settings.dbPath); + const result = await this.#executeSqliteQuery( + database, + `SELECT * FROM ${this.settings.tableName} WHERE key = ?`, + [key] + ); + return result[0]; + } finally { + if (database) { + database.close(); + } + } + } + + /** + * @param {string} key + * @param {string} content + * @param {NodeJS.Dict} properties + * @returns {Promise} + */ + async addCacheContentAsync(key, content, properties) { + let database = new sqlite3.Database(this.settings.dbPath); + try { + const savedContent = await this.loadContentAsync(key); + if (savedContent) { + await this.#executeSqliteQuery( + database, + `DELETE FROM ${this.settings.tableName} WHERE key = ?`, + [key] + ); + } + const query = `INSERT INTO ${this.settings.tableName} (key, content, properties) VALUES (?, ?, ?)`; + const result = this.#executeSqliteQuery(database, query, [ + key, + content, + JSON.stringify(properties), + ]); + return result + console.log(result) + } catch (err) { + throw new Error("error in add cache : " + err); + } finally { + if (database) { + database.close(); + } + } + } + /** + * + * @param {sqlite3.Database} db + * @param {string} query + * @param {any[]} params + * @returns {Promise} + */ + #executeSqliteQuery(db, query, params = []) { + return new Promise((resolve, reject) => { + db.all(query, params, (err, rows) => { + if (err) { + reject(err); + } else { + resolve(rows); + } + }); + }); + } } diff --git a/Models/Connection/SqliteSettingData.js b/Models/Connection/SqliteSettingData.js index b26b560..43d9c8b 100644 --- a/Models/Connection/SqliteSettingData.js +++ b/Models/Connection/SqliteSettingData.js @@ -3,4 +3,6 @@ export default class SqlSettingData { dbPath; /** @type {string} */ query; + /** @type {string} */ + tableName } diff --git a/Models/ServiceSettings.js b/Models/ServiceSettings.js index 1ed45d1..8936662 100644 --- a/Models/ServiceSettings.js +++ b/Models/ServiceSettings.js @@ -15,6 +15,8 @@ export default class ServiceSettings { callConnection; /** @type {ConnectionInfo} */ ilUpdateConnection; + /** @type {ConnectionInfo} */ + cacheConnection; /** * @param {HostServiceOptions} options */ @@ -33,6 +35,15 @@ export default class ServiceSettings { if ("ilupdate" in this._connections) { this.ilUpdateConnection = this._connections.ilupdate; } + if ("cacheconnection" in this._connections) { + this.cacheConnection = this._connections.cacheconnection; + } + if ( + options.CacheSettings?.isEnabled && + !("cacheconnection" in this._connections) + ) { + throw new Error("must add cacheConnection if you set Cache to true"); + } } /** diff --git a/Models/options/CacheResult.js b/Models/options/CacheResult.js new file mode 100644 index 0000000..be2084c --- /dev/null +++ b/Models/options/CacheResult.js @@ -0,0 +1,8 @@ +export default class CacheResult { + /**@type {string} */ + key; + /** @type {string} */ + content; + /**@type {NodeJS.Dict}*/ + properties; +} diff --git a/Models/options/CacheSettings.js b/Models/options/CacheSettings.js new file mode 100644 index 0000000..9bcc42e --- /dev/null +++ b/Models/options/CacheSettings.js @@ -0,0 +1,8 @@ +export default class CacheSettings { + /**@type {string[]} */ + responseHeaders; + /**@type {string[]} */ + requestMethods; + /** @type {boolean} */ + isEnabled; +} diff --git a/Models/options/hostServiceOptions.js b/Models/options/hostServiceOptions.js index fcc974a..86ebe51 100644 --- a/Models/options/hostServiceOptions.js +++ b/Models/options/hostServiceOptions.js @@ -1,4 +1,5 @@ import IStreamerEngineOptions from "./IStreamerEngineOptions.js"; +import CacheSettings from "./CacheSettings.js"; export default class HostServiceOptions { /**@type {"Sql"|"Edge"|"File"} */ @@ -15,4 +16,6 @@ export default class HostServiceOptions { Streamer; /**@type {NodeJS.Dict} */ Settings; + /**@type {CacheSettings}*/ + CacheSettings; } diff --git a/endPoint/h2HttpHostEndPoint.js b/endPoint/h2HttpHostEndPoint.js index 326f561..6c5c92c 100644 --- a/endPoint/h2HttpHostEndPoint.js +++ b/endPoint/h2HttpHostEndPoint.js @@ -8,7 +8,7 @@ import http from "http"; export default class H2HttpHostEndPoint extends SecureHttpHostEndPoint { /** @type {HostService} */ - #service; + _service; /** @type {import("tls").SecureContextOptions} */ #options; @@ -23,7 +23,7 @@ export default class H2HttpHostEndPoint extends SecureHttpHostEndPoint { constructor(ip, port, service, options) { super(ip, port); this.#options = options; - this.#service = service; + this._service = service; } /** @@ -67,92 +67,100 @@ export default class H2HttpHostEndPoint extends SecureHttpHostEndPoint { return http2 .createSecureServer(this.#options) .on("stream", async (stream, headers) => { - /** @type {Request} */ - let cms = null; - /**@type {BinaryContent[]} */ - const fileContents = []; - /**@type {NodeJS.Dict} */ - const jsonHeaders = {}; - /**@type {NodeJS.Dict} */ - const formFields = {}; - const method = headers[":method"]; - const url = headers[":path"]; - let bodyStr = ""; - const createCmsAndCreateResponseAsync = async () => { - cms = await this._createCmsObjectAsync( - url, - method, - headers, - formFields, - jsonHeaders, - stream.session.socket, - bodyStr, - true - ); - const result = await this.#service.processAsync(cms, fileContents); - const [code, headerList, body] = await result.getResultAsync(); - headerList[":status"] = code; - stream.respond(headerList); - stream.end(body); - }; - stream.on("data", (chunk) => { - if (headers["content-type"] === "application/json") { - bodyStr += chunk; - } - }); - stream.on("end", () => { - if (headers["content-type"] === "application/json") { - createCmsAndCreateResponseAsync(); - } - }); - stream.on("error", (ex) => { - if (ex.code != "ERR_STREAM_WRITE_AFTER_END") { - console.error("HTTP/2 server stream error", ex); - } - stream.destroy(ex); - }); - try { - if (headers["content-length"]) { - if (headers["content-type"]?.startsWith("multipart/form-data")) { - /**@type {Array}*/ - const bb = busboy({ headers: headers }); - bb.on("file", (name, file, info) => { - const ContentParts = []; - file.on("data", (x) => ContentParts.push(x)); - file.on("end", async () => { - const content = new BinaryContent(); - content.url = `${headers["host"]}${url}`; - content.mime = info.mimeType.toLowerCase(); - content.name = info.filename; - content.payload = Buffer.concat(ContentParts); - fileContents.push(content); + this._checkCacheAsync(stream, headers, async () => { + /** @type {Request} */ + let cms = null; + /**@type {BinaryContent[]} */ + const fileContents = []; + /**@type {NodeJS.Dict} */ + const jsonHeaders = {}; + /**@type {NodeJS.Dict} */ + const formFields = {}; + const method = headers[":method"]; + const url = headers[":path"]; + let bodyStr = ""; + const createCmsAndCreateResponseAsync = async () => { + cms = await this._createCmsObjectAsync( + url, + method, + headers, + formFields, + jsonHeaders, + stream.session.socket, + bodyStr, + true + ); + const result = await this._service.processAsync(cms, fileContents); + const [code, headerList, body] = await result.getResultAsync(); + await this.addCacheContentAsync( + `${headers.host}${headers[":path"]}`, + body, + headers, + headers[":method"] + ); + headerList[":status"] = code; + stream.respond(headerList); + stream.end(body); + }; + stream.on("data", (chunk) => { + if (headers["content-type"] === "application/json") { + bodyStr += chunk; + } + }); + stream.on("end", () => { + if (headers["content-type"] === "application/json") { + createCmsAndCreateResponseAsync(); + } + }); + stream.on("error", (ex) => { + if (ex.code != "ERR_STREAM_WRITE_AFTER_END") { + console.error("HTTP/2 server stream error", ex); + } + stream.destroy(ex); + }); + try { + if (headers["content-length"]) { + if (headers["content-type"]?.startsWith("multipart/form-data")) { + /**@type {Array}*/ + const bb = busboy({ headers: headers }); + bb.on("file", (name, file, info) => { + const ContentParts = []; + file.on("data", (x) => ContentParts.push(x)); + file.on("end", async () => { + const content = new BinaryContent(); + content.url = `${headers["host"]}${url}`; + content.mime = info.mimeType.toLowerCase(); + content.name = info.filename; + content.payload = Buffer.concat(ContentParts); + fileContents.push(content); + }); }); - }); - bb.on("field", (name, val, info) => { - formFields[name] = val; - if (name.startsWith("_")) { - jsonHeaders[name] = val; - } - }); - bb.on("close", createCmsAndCreateResponseAsync); - stream.pipe(bb); - } - } else { - await createCmsAndCreateResponseAsync(); - } - } catch (ex) { - if (ex.code != "ERR_HTTP2_INVALID_STREAM") { - console.error("HTTP/2 server error", ex); - try { - stream.respond({ - ":status": StatusCodes.INTERNAL_SERVER_ERROR, - }); - } catch (ex) { + bb.on("field", (name, val, info) => { + formFields[name] = val; + if (name.startsWith("_")) { + jsonHeaders[name] = val; + } + }); + bb.on("close", createCmsAndCreateResponseAsync); + stream.pipe(bb); + } + } else { + await createCmsAndCreateResponseAsync(); + } + } catch (ex) { + if (ex.code != "ERR_HTTP2_INVALID_STREAM") { console.error("HTTP/2 server error", ex); + try { + stream.respond({ + ":status": StatusCodes.INTERNAL_SERVER_ERROR, + }); + } catch (ex) { + console.error("HTTP/2 server error", ex); + } + stream.end(ex.toString()); } - stream.end(ex.toString()); } - } + }); }) .on("clientError", (ex) => { switch (ex.code) { @@ -184,4 +192,33 @@ export default class H2HttpHostEndPoint extends SecureHttpHostEndPoint { }); }); } + + async _checkCacheAsync(stream, headers, next) { + if ( + this._service._options.CacheSettings.requestMethods.includes( + headers[":method"] + ) && + this._service.settings.cacheConnection + ) { + let connection = this._service.settings.cacheConnection; + const fullUrl = `${headers.host}${headers[":path"]}`; + const cacheOptions = await connection.loadContentAsync(fullUrl); + if (cacheOptions) { + try { + stream.respond({ + ":status": 200, + "content-type": cacheOptions.contentType, + ...this._service._options.CacheSettings.responseHeaders, + }); + stream.end(cacheOptions.file); + } catch (err) { + next(); + } + } else { + next(); + } + } else { + next(); + } + } } diff --git a/endPoint/httpHostEndPoint.js b/endPoint/httpHostEndPoint.js index eb58c20..579e4c7 100644 --- a/endPoint/httpHostEndPoint.js +++ b/endPoint/httpHostEndPoint.js @@ -8,9 +8,14 @@ import busboy from "busboy"; import { IncomingMessage, ServerResponse } from "http"; import BasisCoreException from "../models/Exceptions/BasisCoreException.js"; import BinaryContent from "../fileStreamer/Models/BinaryContent.js"; +import HostService from "../services/hostService.js"; +import mime from "mime"; +import fs from "fs/promises"; let requestId = 0; class HttpHostEndPoint extends HostEndPoint { + /** @type {HostService} */ + _service; /** * * @param {string} ip @@ -160,6 +165,69 @@ class HttpHostEndPoint extends HostEndPoint { next(); } } + /** + * @param {IncomingMessage} req + * @param {ServerResponse} res + */ + async _checkCacheAsync(req, res, next) { + if ( + this._service._options.CacheSettings?.isEnabled && + this._service._options.CacheSettings.requestMethods.includes(req.method) + ) { + let connection = this._service.settings.cacheConnection; + const fullUrl = `${req.headers.host}${req.url}`; + const cacheResults = await connection.loadContentAsync(fullUrl); + if (cacheResults) { + res.writeHead(200, { + ...cacheResults.properties, + }); + res.write(cacheResults.content ?? ""); + res.end(); + } else { + next(); + } + } else { + next(); + } + } + /** + * + * @param {string} key + * @param {string} content + * @param {NodeJS.Dict} headers + * @returns {Promise} + */ + async addCacheContentAsync(key, content, headers, method) { + if ( + this._service._options.CacheSettings?.isEnabled && + this._service._options.CacheSettings.requestMethods.includes(method) + ) { + const savedHeaders = this.findProperties( + headers, + this._service._options.CacheSettings.responseHeaders + ); + await this._service.settings.cacheConnection.addCacheContentAsync( + key, + content, + savedHeaders + ); + } + return; + } + /** + * + * @param {NodeJS.Dict} headers + * @param {string[]} keys + * @returns + */ + findProperties(headers, keys) { + const properties = {}; + keys.forEach((key) => { + if (headers.hasOwnProperty(key)) { + properties[key] = headers[key]; + } + }); + return properties; + } } - export default HttpHostEndPoint; diff --git a/endPoint/nonSecureHttpHostEndPoint.js b/endPoint/nonSecureHttpHostEndPoint.js index 35e29a3..fd25ade 100644 --- a/endPoint/nonSecureHttpHostEndPoint.js +++ b/endPoint/nonSecureHttpHostEndPoint.js @@ -5,7 +5,7 @@ import { HostService } from "../services/hostServices.js"; export default class NonSecureHttpHostEndPoint extends HttpHostEndPoint { /** @type {HostService} */ - #service; + _service; /** * @@ -15,7 +15,7 @@ export default class NonSecureHttpHostEndPoint extends HttpHostEndPoint { */ constructor(ip, port, service) { super(ip, port); - this.#service = service; + this._service = service; } _createServer() { @@ -23,27 +23,36 @@ export default class NonSecureHttpHostEndPoint extends HttpHostEndPoint { try { /** @type {Request} */ let cms = null; - this._handleContentTypes(req, res, async () => { - const createCmsAndCreateResponseAsync = async () => { - cms = await this._createCmsObjectAsync( - req.url, - req.method, - req.headers, - req.formFields, - req.jsonHeaders ? req.jsonHeaders : {}, - req.socket, - req.bodyStr, - false - ); - const result = await this.#service.processAsync( - cms, - req.fileContents - ); - const [code, headers, body] = await result.getResultAsync(); - res.writeHead(code, headers); - res.end(body); - }; - await createCmsAndCreateResponseAsync(); + this._checkCacheAsync(req, res, async () => { + this._handleContentTypes(req, res, async () => { + const createCmsAndCreateResponseAsync = async () => { + cms = await this._createCmsObjectAsync( + req.url, + req.method, + req.headers, + req.formFields, + req.jsonHeaders ? req.jsonHeaders : {}, + req.socket, + req.bodyStr, + false + ); + const result = await this._service.processAsync( + cms, + req.fileContents + ); + const [code, headers, body] = await result.getResultAsync(); + await this.addCacheContentAsync( + `${req.headers.host}${req.url}`, + body, + headers, + req.method + ); + res.writeHead(code, headers); + console.log(body) + res.end(body); + }; + await createCmsAndCreateResponseAsync(); + }); }); } catch (ex) { console.error(ex); diff --git a/endPoint/secureHttpHostEndPoint.js b/endPoint/secureHttpHostEndPoint.js index a2eb90f..20ce3c2 100644 --- a/endPoint/secureHttpHostEndPoint.js +++ b/endPoint/secureHttpHostEndPoint.js @@ -4,9 +4,6 @@ import HttpHostEndPoint from "./HttpHostEndPoint.js"; import { HostService } from "../services/hostServices.js"; export default class SecureHttpHostEndPoint extends HttpHostEndPoint { - /** @type {HostService} */ - #service; - /** @type {import("tls").SecureContextOptions} */ #options; /** @@ -18,7 +15,7 @@ export default class SecureHttpHostEndPoint extends HttpHostEndPoint { constructor(ip, port, service, options) { super(ip, port); this.#options = options; - this.#service = service; + this._service = service; } _createServer() { @@ -26,33 +23,41 @@ export default class SecureHttpHostEndPoint extends HttpHostEndPoint { .createServer(this.#options, async (req, res) => { /** @type {Request} */ let cms = null; - this._handleContentTypes(req, res, () => { - const createCmsAndCreateResponseAsync = async () => { - cms = await this._createCmsObjectAsync( - req.url, - req.method, - req.headers, - req.formFields, - req.jsonHeaders ? req.jsonHeaders : {}, - req.socket, - req.bodyStr, - true - ); - const result = await this.#service.processAsync( - cms, - req.fileContents - ); - const [code, headers, body] = await result.getResultAsync(); - res.writeHead(code, headers); - res.end(body); - }; - try { - createCmsAndCreateResponseAsync(); - } catch (ex) { - console.error(ex); - res.writeHead(StatusCodes.INTERNAL_SERVER_ERROR); - res.end(ex.toString()); - } + this._checkCacheAsync(req, res, async () => { + this._handleContentTypes(req, res, () => { + const createCmsAndCreateResponseAsync = async () => { + cms = await this._createCmsObjectAsync( + req.url, + req.method, + req.headers, + req.formFields, + req.jsonHeaders ? req.jsonHeaders : {}, + req.socket, + req.bodyStr, + true + ); + const result = await this._service.processAsync( + cms, + req.fileContents + ); + const [code, headers, body] = await result.getResultAsync(); + await this.addCacheContentAsync( + `${req.headers.host}${req.url}`, + body, + headers, + req.method + ); + res.writeHead(code, headers); + res.end(body); + }; + try { + createCmsAndCreateResponseAsync(); + } catch (ex) { + console.error(ex); + res.writeHead(StatusCodes.INTERNAL_SERVER_ERROR); + res.end(ex.toString()); + } + }); }); }) .on("error", (er) => console.error(er)) diff --git a/index.js b/index.js index 2fd0c7e..bfde465 100644 --- a/index.js +++ b/index.js @@ -1,5 +1,6 @@ import HostManager from "./hostManager.js"; import { HostManagerOptions } from "./models/model.js"; +import CacheSettings from "./models/options/CacheSettings.js"; /** @type {HostManagerOptions} */ const host = { diff --git a/package-lock.json b/package-lock.json index 23512d4..a240aa7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17,6 +17,8 @@ "http-status-codes": "^2.2.0", "imagemagick": "^0.1.3", "memorystream": "^0.3.1", + "mime": "^4.0.3", + "mime-db": "^1.52.0", "mime-types": "^2.1.35", "mongodb": "^6.3.0", "mssql": "^9.3.2", @@ -4520,15 +4522,17 @@ } }, "node_modules/mime": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", - "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", - "dev": true, + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/mime/-/mime-4.0.3.tgz", + "integrity": "sha512-KgUb15Oorc0NEKPbvfa0wRU+PItIEZmiv+pyAO2i0oTIVTJhlzMclU7w4RXWQrSOVH5ax/p/CkIO7KI4OyFJTQ==", + "funding": [ + "https://github.com/sponsors/broofa" + ], "bin": { - "mime": "cli.js" + "mime": "bin/cli.js" }, "engines": { - "node": ">=4.0.0" + "node": ">=16" } }, "node_modules/mime-db": { @@ -5914,6 +5918,18 @@ "node": ">=10" } }, + "node_modules/superagent/node_modules/mime": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", + "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", + "dev": true, + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4.0.0" + } + }, "node_modules/superagent/node_modules/semver": { "version": "7.5.4", "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", @@ -9774,10 +9790,9 @@ } }, "mime": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", - "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", - "dev": true + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/mime/-/mime-4.0.3.tgz", + "integrity": "sha512-KgUb15Oorc0NEKPbvfa0wRU+PItIEZmiv+pyAO2i0oTIVTJhlzMclU7w4RXWQrSOVH5ax/p/CkIO7KI4OyFJTQ==" }, "mime-db": { "version": "1.52.0", @@ -10756,6 +10771,12 @@ "yallist": "^4.0.0" } }, + "mime": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", + "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", + "dev": true + }, "semver": { "version": "7.5.4", "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", diff --git a/package.json b/package.json index 3a66cb3..5247386 100644 --- a/package.json +++ b/package.json @@ -59,7 +59,8 @@ "unknown": "node test\\command\\UnknownCommand\\simple.js", "fileStreamer": "node test\\fileStreamer\\index.js", "inlinesourcexml": "node test/command/inlinesource/inlinesourcexmlCommand.js", - "bug": "node --trace-warnings --trace-deprecation test\\bug.js" + "bug": "node --trace-warnings --trace-deprecation test\\bug.js", + "cache": "node test\\connection\\sqlite\\cache.js" }, "type": "module", "dependencies": { @@ -71,6 +72,8 @@ "http-status-codes": "^2.2.0", "imagemagick": "^0.1.3", "memorystream": "^0.3.1", + "mime": "^4.0.3", + "mime-db": "^1.52.0", "mime-types": "^2.1.35", "mongodb": "^6.3.0", "mssql": "^9.3.2", diff --git a/test.db b/test.db new file mode 100644 index 0000000000000000000000000000000000000000..427b159ad4ba7f587517e99fa5fe684471d43e9f GIT binary patch literal 118784 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 literal 0 HcmV?d00001 diff --git a/test/connection/edge/edge-script.py b/test/connection/edge/edge-script.py index 5750c22..2c6d047 100644 --- a/test/connection/edge/edge-script.py +++ b/test/connection/edge/edge-script.py @@ -1,18 +1,24 @@ from bclib import edge options = { - "endpoint": "127.0.0.1:8080", - "router": "web" + "endpoint": "127.0.0.1:8000", + "router": "restful" } app = edge.from_options(options) import asyncio #index 5 -@app.web_action() +@app.restful_action() async def process_web_remain_request(context: edge.WebContext): - await asyncio.sleep(10) - return "

hi from edge

" + context.mime = edge.HttpMimeTypes.JPEG + context.response_type = edge.ResponseTypes.STATIC_FILE + cms = context.cms.cms + if "webserver" not in cms: + cms["webserver"] = dict() + cms["webserver"]["filepath"] = "C:\\Users\\Ali\\Desktop\\fingerfoofProduct1.jpg" + print(context.cms) + return context.cms #index 1 # @app.web_action() # async def process_web_remain_request(context: edge.WebContext): diff --git a/test/connection/edge/simple.js b/test/connection/edge/simple.js index ebcb706..8818ccf 100644 --- a/test/connection/edge/simple.js +++ b/test/connection/edge/simple.js @@ -23,6 +23,10 @@ const host = { "Connections.edge.RoutingData": { endpoint: "127.0.0.1:1025", }, + "Connections.sqlite.cacheConnection" :{ + dbPath : "./../../../test.db", + table : "cache_results" + } }, }, }, diff --git a/test/connection/sqlite/cache.js b/test/connection/sqlite/cache.js new file mode 100644 index 0000000..8b118f2 --- /dev/null +++ b/test/connection/sqlite/cache.js @@ -0,0 +1,41 @@ +import HostManager from "../../../hostManager.js"; +import { HostManagerOptions } from "../../../models/model.js"; + +/** @type {HostManagerOptions} */ +const host = { + Lazy: true, + EndPoints: { + Main06: { + Type: "http", + Addresses: [ + { + EndPoint: "127.0.0.1:1563", + }, + ], + Active: true, + Routing: "mainService", + }, + }, + Services: { + mainService: { + Type: "http", + CacheSettings: { + requestMethods: "GET", + responseHeaders: ["content-type"], + isEnabled: true, + }, + Settings: { + "Connections.edge.RoutingData": { + endpoint: "127.0.0.1:8000", + }, + "Connections.sqlite.cacheConnection": { + dbPath: "test.db", + tableName: "cache_results", + }, + }, + }, + }, +}; + +const service = HostManager.fromJson(host); +service.listen(); diff --git a/test/connection/sqlite/table.sqlite b/test/connection/sqlite/table.sqlite new file mode 100644 index 0000000..93b2c0d --- /dev/null +++ b/test/connection/sqlite/table.sqlite @@ -0,0 +1,6 @@ +CREATE TABLE cache_results ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + key TEXT, + content TEXT, + properties TEXT +); \ No newline at end of file From 7937f1786c4a2ad33786ac43b83990e1868821be Mon Sep 17 00:00:00 2001 From: Ali Date: Tue, 21 May 2024 12:38:48 +0330 Subject: [PATCH 2/5] first --- endPoint/nonSecureHttpHostEndPoint.js | 1 - 1 file changed, 1 deletion(-) diff --git a/endPoint/nonSecureHttpHostEndPoint.js b/endPoint/nonSecureHttpHostEndPoint.js index fd25ade..1bce7b1 100644 --- a/endPoint/nonSecureHttpHostEndPoint.js +++ b/endPoint/nonSecureHttpHostEndPoint.js @@ -48,7 +48,6 @@ export default class NonSecureHttpHostEndPoint extends HttpHostEndPoint { req.method ); res.writeHead(code, headers); - console.log(body) res.end(body); }; await createCmsAndCreateResponseAsync(); From 181f4c26dc2895781e7b74bb1fff6d6aa73ed255 Mon Sep 17 00:00:00 2001 From: Ali Date: Tue, 21 May 2024 12:51:06 +0330 Subject: [PATCH 3/5] final --- rabbit.js | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 rabbit.js diff --git a/rabbit.js b/rabbit.js new file mode 100644 index 0000000..d2d9b1b --- /dev/null +++ b/rabbit.js @@ -0,0 +1,51 @@ +const amqp = require('amqplib/callback_api'); +const sqlite3 = require('sqlite3').verbose(); + +// Connect to RabbitMQ +amqp.connect('amqp://localhost', function(error0, connection) { + if (error0) { + throw error0; + } + + connection.createChannel(function(error1, channel) { + if (error1) { + throw error1; + } + + const queue = 'task_queue'; + + channel.assertQueue(queue, { + durable: true + }); + + console.log(" [*] Waiting for messages in %s. To exit press CTRL+C", queue); + + channel.consume(queue, function(msg) { + const task = JSON.parse(msg.content.toString()); + const db = new sqlite3.Database('test.db', sqlite3.OPEN_READWRITE, (err) => { + if (err) { + console.error(err.message); + } + console.log('Connected to the database.'); + }); + + const sql = `DELETE FROM your_table`; + + db.run(sql, [], function(err) { + if (err) { + throw err; + } + console.log(`Deleted ${this.changes} rows from the table.`); + }); + db.close((err) => { + if (err) { + console.error(err.message); + } + console.log('Close the database connection.'); + }); + + }, { + noAck: true + }); + }); +}); From d28d8e3ab1554e777013e0e9e1c2edf14c100a55 Mon Sep 17 00:00:00 2001 From: Ali Date: Wed, 5 Jun 2024 09:54:05 +0200 Subject: [PATCH 4/5] add handler --- ExternalCommands/External.ws.ws.js | 2 +- Models/CacheCommands/BaseCacheUtil.js | 20 ++++++++ Models/CacheCommands/RabbitMQCacheUtil.js | 51 +++++++++++++++++++ Models/CacheCommands/RabbitMqSetting.js | 5 ++ Models/Connection/ConnectionInfo.js | 3 ++ Models/Connection/SqliteConnectionInfo.js | 27 +++++----- Models/options/CacheSettings.js | 5 ++ endPoint/h2HttpHostEndPoint.js | 2 +- endPoint/httpHostEndPoint.js | 19 ++++++- endPoint/nonSecureHttpHostEndPoint.js | 2 +- endPoint/secureHttpHostEndPoint.js | 2 +- rabbit.js | 51 ------------------- .../Source/BaseClasses/SourceCommand.js | 4 +- renderEngine/Command/Source/ws.js | 2 +- 14 files changed, 123 insertions(+), 72 deletions(-) create mode 100644 Models/CacheCommands/BaseCacheUtil.js create mode 100644 Models/CacheCommands/RabbitMQCacheUtil.js create mode 100644 Models/CacheCommands/RabbitMqSetting.js delete mode 100644 rabbit.js diff --git a/ExternalCommands/External.ws.ws.js b/ExternalCommands/External.ws.ws.js index 0413f6b..0843116 100644 --- a/ExternalCommands/External.ws.ws.js +++ b/ExternalCommands/External.ws.ws.js @@ -13,7 +13,7 @@ export default class WsCommand extends SourceCommand { * @param {IContext} context * @returns {Promise} */ - async #loadDataAsync(sourceName, context) { + async _loadDataAsync(sourceName, context) { const [connectionName, command] = await Promise.all([ this.connectionName.getValueAsync(context), this.toCustomFormatHtmlAsync(context), diff --git a/Models/CacheCommands/BaseCacheUtil.js b/Models/CacheCommands/BaseCacheUtil.js new file mode 100644 index 0000000..e64cc50 --- /dev/null +++ b/Models/CacheCommands/BaseCacheUtil.js @@ -0,0 +1,20 @@ +import ConnectionInfo from "../Connection/ConnectionInfo"; +export default class BaseCacheUtil { + /**@type {ConnectionInfo}*/ + connectionInfo; + channel; + + /**@param {ConnectionInfo} */ + constractor(connectionInfo,settings) { + this.connectionInfo = connectionInfo; + this.settings = settings + } + + /** + * @returns {Promise} + */ + connectAsync() {} + + /**@returns {Promise} */ + createDeleteChannel() {} +} diff --git a/Models/CacheCommands/RabbitMQCacheUtil.js b/Models/CacheCommands/RabbitMQCacheUtil.js new file mode 100644 index 0000000..fb3ba6b --- /dev/null +++ b/Models/CacheCommands/RabbitMQCacheUtil.js @@ -0,0 +1,51 @@ +import ConnectionInfo from "../Connection/ConnectionInfo.js"; +import BaseCacheUtil from "./BaseCacheUtil.js"; +import * as ampq from "amqplib/callback_api"; +import RabbitMQSetting from "./RabbitMqSetting.js"; +export default class RabbitMQCacheUtil extends BaseCacheUtil { + /**@type {ConnectionInfo}*/ + connectionInfo; + /**@type {RabbitMQSetting} */ + settings; + /** @type {ampq.Channel} */ + channel; + + /** + * @param {ConnectionInfo} + * @param {RabbitMQSetting} settings + */ + constractor(connectionInfo, settings) { + super(connectionInfo,settings); + } + /** + * @returns {Promise} + */ + connectAsync() { + return new Promise((resolve, reject) => { + ampq.connect(this.settings.address, function (error0, connection) { + if (error0) { + reject(error0); + } + connection.createChannel(function (error1, channel) { + if (error1) { + reject(error1); + } + this.channel = channel; + resolve(); + }); + }); + }); + } + /** + * @param {string} queueName + * @returns {Promise} + */ + createDeleteChannel(queueName) { + channel.assertQueue(queueName, { + durable: true, + }); + this.channel.consume(queueName, async function (msg) { + await this.connection.deleteAllCache(); + }); + } +} diff --git a/Models/CacheCommands/RabbitMqSetting.js b/Models/CacheCommands/RabbitMqSetting.js new file mode 100644 index 0000000..6d0569e --- /dev/null +++ b/Models/CacheCommands/RabbitMqSetting.js @@ -0,0 +1,5 @@ +export default class RabbitMQSetting { + /** @type {string} */ + address; + } + \ No newline at end of file diff --git a/Models/Connection/ConnectionInfo.js b/Models/Connection/ConnectionInfo.js index 2940ac1..a899701 100644 --- a/Models/Connection/ConnectionInfo.js +++ b/Models/Connection/ConnectionInfo.js @@ -83,4 +83,7 @@ export default class ConnectionInfo { * @returns {Promise} */ async addCacheContentAsync(key, content, properties) {} + + /** @returns {Promise} */ + async deleteAllCache() {} } diff --git a/Models/Connection/SqliteConnectionInfo.js b/Models/Connection/SqliteConnectionInfo.js index 0bfeaf1..fa36a91 100644 --- a/Models/Connection/SqliteConnectionInfo.js +++ b/Models/Connection/SqliteConnectionInfo.js @@ -92,24 +92,23 @@ export default class SqliteConnectionInfo extends ConnectionInfo { * @returns {Promise} */ async addCacheContentAsync(key, content, properties) { - let database = new sqlite3.Database(this.settings.dbPath); + const database = new sqlite3.Database(this.settings.dbPath); try { - const savedContent = await this.loadContentAsync(key); - if (savedContent) { - await this.#executeSqliteQuery( - database, - `DELETE FROM ${this.settings.tableName} WHERE key = ?`, - [key] - ); - } - const query = `INSERT INTO ${this.settings.tableName} (key, content, properties) VALUES (?, ?, ?)`; + const query = ` + BEGIN TRANSACTION; + WITH Selected AS ( + SELECT * FROM ${this.settings.tableName} WHERE key = ? + ) + DELETE FROM ${this.settings.tableName} WHERE key = ? AND EXISTS (SELECT 1 FROM Selected); + INSERT INTO ${this.settings.tableName} (key, content, properties) VALUES (?, ?, ?); + COMMIT TRANSACTION; + `; const result = this.#executeSqliteQuery(database, query, [ key, content, JSON.stringify(properties), ]); - return result - console.log(result) + return result; } catch (err) { throw new Error("error in add cache : " + err); } finally { @@ -136,4 +135,8 @@ export default class SqliteConnectionInfo extends ConnectionInfo { }); }); } + /** @returns {Promise} */ + async deleteAllCache() { + return this.#executeSqliteQuery(`DELETE FROM ${this.settings.tableName}`); + } } diff --git a/Models/options/CacheSettings.js b/Models/options/CacheSettings.js index 9bcc42e..44502e5 100644 --- a/Models/options/CacheSettings.js +++ b/Models/options/CacheSettings.js @@ -5,4 +5,9 @@ export default class CacheSettings { requestMethods; /** @type {boolean} */ isEnabled; + //for now is rabbit + /** @type {"Rabbit"} */ + utilType + /**@type { NodeJS.Dict } */ + utilSetting } diff --git a/endPoint/h2HttpHostEndPoint.js b/endPoint/h2HttpHostEndPoint.js index 6cb65dc..c972438 100644 --- a/endPoint/h2HttpHostEndPoint.js +++ b/endPoint/h2HttpHostEndPoint.js @@ -88,7 +88,7 @@ export default class H2HttpHostEndPoint extends SecureHttpHostEndPoint { ); const result = await this._service.processAsync(cms, fileContents); const [code, headerList, body] = await result.getResultAsync(); - await this.addCacheContentAsync( + this.addCacheContentAsync( `${headers.host}${headers[":path"]}`, body, headers, diff --git a/endPoint/httpHostEndPoint.js b/endPoint/httpHostEndPoint.js index a6ed352..a9c3cc5 100644 --- a/endPoint/httpHostEndPoint.js +++ b/endPoint/httpHostEndPoint.js @@ -9,6 +9,8 @@ import { IncomingMessage, ServerResponse } from "http"; import BasisCoreException from "../models/Exceptions/BasisCoreException.js"; import BinaryContent from "../fileStreamer/Models/BinaryContent.js"; import HostService from "../services/hostService.js"; +import RabbitMQCacheUtil from "./../Models/CacheCommands/RabbitMQCacheUtil.js"; +import BaseCacheUtil from "../Models/CacheCommands/BaseCacheUtil.js"; let requestId = 0; class HttpHostEndPoint extends HostEndPoint { @@ -31,6 +33,20 @@ class HttpHostEndPoint extends HostEndPoint { /**@returns {Promise} */ async listenAsync() { + /** @type {BaseCacheUtil} */ + let cacheUtil; + switch (this._service._options?.CacheSettings.utilType) { + case "Rabbit": { + cacheUtil = new RabbitMQCacheUtil( + this._service.settings.cacheConnection, + this._service._options.CacheSettings.utilSetting + ); + } + } + if (cacheUtil) { + await cacheUtil.connectAsync(); + await cacheUtil.createDeleteChannel() + } const server = this._createServer(); await this.initializeAsync(); server @@ -213,7 +229,6 @@ class HttpHostEndPoint extends HostEndPoint { savedHeaders ); } - return; } /** * @@ -229,7 +244,7 @@ class HttpHostEndPoint extends HostEndPoint { } }); return properties; - } + } async initializeAsync() { return this._service.initializeAsync(); } diff --git a/endPoint/nonSecureHttpHostEndPoint.js b/endPoint/nonSecureHttpHostEndPoint.js index ac9ee19..98c7a46 100644 --- a/endPoint/nonSecureHttpHostEndPoint.js +++ b/endPoint/nonSecureHttpHostEndPoint.js @@ -40,7 +40,7 @@ export default class NonSecureHttpHostEndPoint extends HttpHostEndPoint { req.fileContents ); const [code, headers, body] = await result.getResultAsync(); - await this.addCacheContentAsync( + this.addCacheContentAsync( `${req.headers.host}${req.url}`, body, headers, diff --git a/endPoint/secureHttpHostEndPoint.js b/endPoint/secureHttpHostEndPoint.js index ba251b2..5a559c3 100644 --- a/endPoint/secureHttpHostEndPoint.js +++ b/endPoint/secureHttpHostEndPoint.js @@ -40,7 +40,7 @@ export default class SecureHttpHostEndPoint extends HttpHostEndPoint { req.fileContents ); const [code, headers, body] = await result.getResultAsync(); - await this.addCacheContentAsync( + this.addCacheContentAsync( `${req.headers.host}${req.url}`, body, headers, diff --git a/rabbit.js b/rabbit.js deleted file mode 100644 index d2d9b1b..0000000 --- a/rabbit.js +++ /dev/null @@ -1,51 +0,0 @@ -const amqp = require('amqplib/callback_api'); -const sqlite3 = require('sqlite3').verbose(); - -// Connect to RabbitMQ -amqp.connect('amqp://localhost', function(error0, connection) { - if (error0) { - throw error0; - } - - connection.createChannel(function(error1, channel) { - if (error1) { - throw error1; - } - - const queue = 'task_queue'; - - channel.assertQueue(queue, { - durable: true - }); - - console.log(" [*] Waiting for messages in %s. To exit press CTRL+C", queue); - - channel.consume(queue, function(msg) { - const task = JSON.parse(msg.content.toString()); - const db = new sqlite3.Database('test.db', sqlite3.OPEN_READWRITE, (err) => { - if (err) { - console.error(err.message); - } - console.log('Connected to the database.'); - }); - - const sql = `DELETE FROM your_table`; - - db.run(sql, [], function(err) { - if (err) { - throw err; - } - console.log(`Deleted ${this.changes} rows from the table.`); - }); - db.close((err) => { - if (err) { - console.error(err.message); - } - console.log('Close the database connection.'); - }); - - }, { - noAck: true - }); - }); -}); diff --git a/renderEngine/Command/Source/BaseClasses/SourceCommand.js b/renderEngine/Command/Source/BaseClasses/SourceCommand.js index 6af778c..068726e 100644 --- a/renderEngine/Command/Source/BaseClasses/SourceCommand.js +++ b/renderEngine/Command/Source/BaseClasses/SourceCommand.js @@ -42,7 +42,7 @@ export default class SourceCommand extends CommandBase { async _executeCommandAsync(context) { if (this.members?.items.length > 0) { const name = await this.name.getValueAsync(context); - const dataSet = await this.#loadDataAsync(name, context); + const dataSet = await this._loadDataAsync(name, context); context.cancellation.throwIfCancellationRequested(); if (dataSet.items.length != this.members.items.length) { throw new BasisCoreException( @@ -63,7 +63,7 @@ export default class SourceCommand extends CommandBase { * @param {IContext} context * @returns {Promise} */ - async #loadDataAsync(sourceName, context) { + async _loadDataAsync(sourceName, context) { const [connectionName, command, paramList] = await Promise.all([ this.connectionName.getValueAsync(context), this.toCustomFormatHtmlAsync(context), diff --git a/renderEngine/Command/Source/ws.js b/renderEngine/Command/Source/ws.js index c870de5..4d8a39c 100644 --- a/renderEngine/Command/Source/ws.js +++ b/renderEngine/Command/Source/ws.js @@ -13,7 +13,7 @@ export default class WsCommand extends SourceCommand { * @param {IContext} context * @returns {Promise} */ - async #loadDataAsync(sourceName, context) { + async _loadDataAsync(sourceName, context) { const [connectionName, command] = await Promise.all([ this.connectionName.getValueAsync(context), this.toCustomFormatHtmlAsync(context), From 82398700893c54624417cfc5a19d04a9c04e1725 Mon Sep 17 00:00:00 2001 From: Ali Date: Wed, 5 Jun 2024 10:08:53 +0200 Subject: [PATCH 5/5] add handler --- endPoint/httpHostEndPoint.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/endPoint/httpHostEndPoint.js b/endPoint/httpHostEndPoint.js index a9c3cc5..32c3309 100644 --- a/endPoint/httpHostEndPoint.js +++ b/endPoint/httpHostEndPoint.js @@ -45,7 +45,7 @@ class HttpHostEndPoint extends HostEndPoint { } if (cacheUtil) { await cacheUtil.connectAsync(); - await cacheUtil.createDeleteChannel() + await cacheUtil.createDeleteChannel(); } const server = this._createServer(); await this.initializeAsync();