diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/common/AbstractTbQueueTemplate.java b/common/queue/src/main/java/org/thingsboard/server/queue/common/AbstractTbQueueTemplate.java index 1b193b7416..5204de42e7 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/common/AbstractTbQueueTemplate.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/common/AbstractTbQueueTemplate.java @@ -22,7 +22,7 @@ import java.util.UUID; public class AbstractTbQueueTemplate { protected static final String REQUEST_ID_HEADER = "requestId"; protected static final String RESPONSE_TOPIC_HEADER = "responseTopic"; - protected static final String REQUEST_TIME = "requestTime"; + protected static final String EXPIRE_TS_HEADER = "expireTs"; protected byte[] uuidToBytes(UUID uuid) { ByteBuffer buf = ByteBuffer.allocate(16); diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/common/DefaultTbQueueRequestTemplate.java b/common/queue/src/main/java/org/thingsboard/server/queue/common/DefaultTbQueueRequestTemplate.java index 9fbe9b1104..1ba1422162 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/common/DefaultTbQueueRequestTemplate.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/common/DefaultTbQueueRequestTemplate.java @@ -56,6 +56,7 @@ public class DefaultTbQueueRequestTemplate expectedResponse = pendingRequests.remove(requestId); if (expectedResponse == null) { log.debug("[{}] Invalid or stale request, response: {}", requestId, String.valueOf(response).replace("\n", " ")); @@ -216,7 +218,7 @@ public class DefaultTbQueueRequestTemplate future = SettableFuture.create(); ResponseMetaData responseMetaData = new ResponseMetaData<>(currentClockNs + requestTimeoutNs, future, currentClockNs, requestTimeoutNs); diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/common/DefaultTbQueueResponseTemplate.java b/common/queue/src/main/java/org/thingsboard/server/queue/common/DefaultTbQueueResponseTemplate.java index 4859b2953b..ed3c3b8cc5 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/common/DefaultTbQueueResponseTemplate.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/common/DefaultTbQueueResponseTemplate.java @@ -97,8 +97,8 @@ public class DefaultTbQueueResponseTemplate { long currentTime = System.currentTimeMillis(); - long requestTime = bytesToLong(request.getHeaders().get(REQUEST_TIME)); - if (requestTime + requestTimeout >= currentTime) { + long expireTs = bytesToLong(request.getHeaders().get(EXPIRE_TS_HEADER)); + if (expireTs >= currentTime) { byte[] requestIdHeader = request.getHeaders().get(REQUEST_ID_HEADER); if (requestIdHeader == null) { log.error("[{}] Missing requestId in header", request); diff --git a/msa/js-executor/api/httpServer.js b/msa/js-executor/api/httpServer.js deleted file mode 100644 index 62bf5807b1..0000000000 --- a/msa/js-executor/api/httpServer.js +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright © 2016-2022 The Thingsboard Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -const config = require('config'), - logger = require('../config/logger')._logger('httpServer'), - express = require('express'); - -const httpPort = Number(config.get('http_port')); - -const app = express(); - -app.get('/livenessProbe', async (req, res) => { - const date = new Date(); - const message = { now: date.toISOString() }; - res.send(message); -}) - -app.listen(httpPort, () => logger.info(`Started http endpoint on port ${httpPort}. Please, use /livenessProbe !`)) \ No newline at end of file diff --git a/msa/js-executor/api/httpServer.ts b/msa/js-executor/api/httpServer.ts new file mode 100644 index 0000000000..f3671a1b89 --- /dev/null +++ b/msa/js-executor/api/httpServer.ts @@ -0,0 +1,46 @@ +/// +/// Copyright © 2016-2022 The Thingsboard Authors +/// +/// Licensed under the Apache License, Version 2.0 (the "License"); +/// you may not use this file except in compliance with the License. +/// You may obtain a copy of the License at +/// +/// http://www.apache.org/licenses/LICENSE-2.0 +/// +/// Unless required by applicable law or agreed to in writing, software +/// distributed under the License is distributed on an "AS IS" BASIS, +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +/// See the License for the specific language governing permissions and +/// limitations under the License. +/// + +import express from 'express'; +import { _logger} from '../config/logger'; + +export class HttpServer { + + private logger = _logger('httpServer'); + private app = express(); + private server; + + constructor(httpPort: number) { + this.app.get('/livenessProbe', async (req, res) => { + const message = { + now: new Date().toISOString() + }; + res.send(message); + }) + + this.server = this.app.listen(httpPort, () => { + this.logger.info('Started http endpoint on port %s. Please, use /livenessProbe !', httpPort); + }).on('error', (error) => { + this.logger.error(error); + }); + } + + stop() { + this.server.close(() => { + this.logger.info('Http server stop'); + }); + } +} diff --git a/msa/js-executor/api/jsExecutor.js b/msa/js-executor/api/jsExecutor.js deleted file mode 100644 index 02190406d2..0000000000 --- a/msa/js-executor/api/jsExecutor.js +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright © 2016-2022 The Thingsboard Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -'use strict'; - -const vm = require('vm'); - -function JsExecutor(useSandbox) { - this.useSandbox = useSandbox; -} - -JsExecutor.prototype.compileScript = function(code) { - if (this.useSandbox) { - return createScript(code); - } else { - return createFunction(code); - } -} - -JsExecutor.prototype.executeScript = function(script, args, timeout) { - if (this.useSandbox) { - return invokeScript(script, args, timeout); - } else { - return invokeFunction(script, args); - } -} - -function createScript(code) { - return new Promise((resolve, reject) => { - try { - code = "("+code+")(...args)"; - var script = new vm.Script(code); - resolve(script); - } catch (err) { - reject(err); - } - }); -} - -function invokeScript(script, args, timeout) { - return new Promise((resolve, reject) => { - try { - var sandbox = Object.create(null); - sandbox.args = args; - var result = script.runInNewContext(sandbox, {timeout: timeout}); - resolve(result); - } catch (err) { - reject(err); - } - }); -} - - -function createFunction(code) { - return new Promise((resolve, reject) => { - try { - code = "return ("+code+")(...args)"; - const parsingContext = vm.createContext({}); - const func = vm.compileFunction(code, ['args'], {parsingContext: parsingContext}); - resolve(func); - } catch (err) { - reject(err); - } - }); -} - -function invokeFunction(func, args) { - return new Promise((resolve, reject) => { - try { - var result = func(args); - resolve(result); - } catch (err) { - reject(err); - } - }); -} - -module.exports = JsExecutor; diff --git a/msa/js-executor/api/jsExecutor.models.ts b/msa/js-executor/api/jsExecutor.models.ts new file mode 100644 index 0000000000..db2ced52c4 --- /dev/null +++ b/msa/js-executor/api/jsExecutor.models.ts @@ -0,0 +1,69 @@ +/// +/// Copyright © 2016-2022 The Thingsboard Authors +/// +/// Licensed under the Apache License, Version 2.0 (the "License"); +/// you may not use this file except in compliance with the License. +/// You may obtain a copy of the License at +/// +/// http://www.apache.org/licenses/LICENSE-2.0 +/// +/// Unless required by applicable law or agreed to in writing, software +/// distributed under the License is distributed on an "AS IS" BASIS, +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +/// See the License for the specific language governing permissions and +/// limitations under the License. +/// + + +export interface TbMessage { + scriptIdMSB: string; + scriptIdLSB: string; +} + +export interface RemoteJsRequest { + compileRequest?: JsCompileRequest; + invokeRequest?: JsInvokeRequest; + releaseRequest?: JsReleaseRequest; +} + +export interface JsReleaseRequest extends TbMessage { + functionName: string; +} + +export interface JsInvokeRequest extends TbMessage { + functionName: string; + scriptBody: string; + timeout: number; + args: string[]; +} + +export interface JsCompileRequest extends TbMessage { + functionName: string; + scriptBody: string; +} + + +export interface JsReleaseResponse extends TbMessage { + success: boolean; +} + +export interface JsCompileResponse extends TbMessage { + success: boolean; + errorCode?: number; + errorDetails?: string; +} + +export interface JsInvokeResponse { + success: boolean; + result: string; + errorCode?: number; + errorDetails?: string; +} + +export interface RemoteJsResponse { + requestIdMSB: string; + requestIdLSB: string; + compileResponse?: JsCompileResponse; + invokeResponse?: JsInvokeResponse; + releaseResponse?: JsReleaseResponse; +} diff --git a/msa/js-executor/api/jsExecutor.ts b/msa/js-executor/api/jsExecutor.ts new file mode 100644 index 0000000000..f22f14281b --- /dev/null +++ b/msa/js-executor/api/jsExecutor.ts @@ -0,0 +1,93 @@ +/// +/// Copyright © 2016-2022 The Thingsboard Authors +/// +/// Licensed under the Apache License, Version 2.0 (the "License"); +/// you may not use this file except in compliance with the License. +/// You may obtain a copy of the License at +/// +/// http://www.apache.org/licenses/LICENSE-2.0 +/// +/// Unless required by applicable law or agreed to in writing, software +/// distributed under the License is distributed on an "AS IS" BASIS, +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +/// See the License for the specific language governing permissions and +/// limitations under the License. +/// + +import vm, { Script } from 'vm'; + +export type TbScript = Script | Function; + +export class JsExecutor { + useSandbox: boolean; + + constructor(useSandbox: boolean) { + this.useSandbox = useSandbox; + } + + compileScript(code: string): Promise { + if (this.useSandbox) { + return this.createScript(code); + } else { + return this.createFunction(code); + } + } + + executeScript(script: TbScript, args: string[], timeout?: number): Promise { + if (this.useSandbox) { + return this.invokeScript(script as Script, args, timeout); + } else { + return this.invokeFunction(script as Function, args); + } + } + + private createScript(code: string): Promise