@resolveio/server-lib 20.6.2 → 20.6.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@resolveio/server-lib",
3
- "version": "20.6.2",
3
+ "version": "20.6.3",
4
4
  "description": "",
5
5
  "scripts": {
6
6
  "package": "./build_package.sh",
package/server-app.js CHANGED
@@ -1,2 +1,2 @@
1
- "use strict";var __awaiter=this&&this.__awaiter||function(e,o,n,s){return new(n=n||Promise)(function(t,r){function fulfilled(e){try{step(s.next(e))}catch(e){r(e)}}function rejected(e){try{step(s.throw(e))}catch(e){r(e)}}function step(e){var r;e.done?t(e.value):((r=e.value)instanceof n?r:new n(function(e){e(r)})).then(fulfilled,rejected)}step((s=s.apply(e,o||[])).next())})},__generator=this&&this.__generator||function(o,n){var s,i,a,l={label:0,sent:function(){if(1&a[0])throw a[1];return a[1]},trys:[],ops:[]},c={next:verb(0),throw:verb(1),return:verb(2)};return"function"==typeof Symbol&&(c[Symbol.iterator]=function(){return this}),c;function verb(t){return function(e){var r=[t,e];if(s)throw new TypeError("Generator is already executing.");for(;l=c&&r[c=0]?0:l;)try{if(s=1,i&&(a=2&r[0]?i.return:r[0]?i.throw||((a=i.return)&&a.call(i),0):i.next)&&!(a=a.call(i,r[1])).done)return a;switch(i=0,(r=a?[2&r[0],a.value]:r)[0]){case 0:case 1:a=r;break;case 4:return l.label++,{value:r[1],done:!1};case 5:l.label++,i=r[1],r=[0];continue;case 7:r=l.ops.pop(),l.trys.pop();continue;default:if(!(a=0<(a=l.trys).length&&a[a.length-1])&&(6===r[0]||2===r[0])){l=0;continue}if(3===r[0]&&(!a||r[1]>a[0]&&r[1]<a[3]))l.label=r[1];else if(6===r[0]&&l.label<a[1])l.label=a[1],a=r;else{if(!(a&&l.label<a[2])){a[2]&&l.ops.pop(),l.trys.pop();continue}l.label=a[2],l.ops.push(r)}}r=n.call(o,l)}catch(e){r=[6,e],i=0}finally{s=a=0}if(5&r[0])throw r[1];return{value:r[0]?r[1]:void 0,done:!0}}}},__read=this&&this.__read||function(e,r){var t="function"==typeof Symbol&&e[Symbol.iterator];if(!t)return e;var o,n,s=t.call(e),i=[];try{for(;(void 0===r||0<r--)&&!(o=s.next()).done;)i.push(o.value)}catch(e){n={error:e}}finally{try{o&&!o.done&&(t=s.return)&&t.call(s)}finally{if(n)throw n.error}}return i},__spreadArray=this&&this.__spreadArray||function(e,r,t){if(t||2===arguments.length)for(var o,n=0,s=r.length;n<s;n++)!o&&n in r||((o=o||Array.prototype.slice.call(r,0,n))[n]=r[n]);return e.concat(o||Array.prototype.slice.call(r))},__values=this&&this.__values||function(e){var r="function"==typeof Symbol&&Symbol.iterator,t=r&&e[r],o=0;if(t)return t.call(e);if(e&&"number"==typeof e.length)return{next:function(){return{value:(e=e&&o>=e.length?void 0:e)&&e[o++],done:!e}}};throw new TypeError(r?"Object is not iterable.":"Symbol.iterator is not defined.")},http_1=(Object.defineProperty(exports,"__esModule",{value:!0}),exports.ResolveIOMainServer=void 0,require("http")),express=require("express"),bodyParser=require("body-parser"),xmlParser=require("express-xml-bodyparser"),WebSocket=require("ws"),jwt=require("jsonwebtoken"),moment=require("moment-timezone"),common_1=require("./util/common"),cron_manager_1=require("./managers/cron.manager"),method_manager_1=require("./managers/method.manager"),subscription_manager_1=require("./managers/subscription.manager"),monitor_manager_1=require("./managers/monitor.manager"),log_collection_1=require("./collections/log.collection"),user_collection_1=require("./collections/user.collection"),home_1=require("./http/home"),auth_1=require("./http/auth"),health_1=require("./http/health"),mongodb_1=require("mongodb"),websocket_manager_1=require("./managers/websocket.manager"),resolveio_server_app_1=require("./resolveio-server-app"),ResolveIOMainServer=function(){function ResolveIOMainServer(){this._offlineUpdates=[],this.sesMail=!1,this.standardProgram=!1,this.publicProgram=!1,this._rebootFlag=!1,this.LOGGER="ERROR",this._clientRoutes=[],this._lastErrorMsg=null,this._debugMsgRecv=0,this._debugMsgQueue=0,this._isWorkersEnabled=!1,this._isWorkerInstance=!1,this._safeShutdown=!1,this._workers=[],this._taskQueue=[],this._inFlightRequests={},this._serverStartTime=new Date,this._lastErrorMsg=null,this._monitorManager=new monitor_manager_1.MonitorManager,this._monitorManagerFunction=new monitor_manager_1.MonitorManagerFunction}return ResolveIOMainServer.prototype.initServerApp=function(){var e=this,s=(this._isWorkersEnabled="true"===process.env.IS_WORKERS_ENABLED,this._isWorkerInstance="true"===process.env.IS_WORKER_INSTANCE,setInterval(function(){e._subscriptionManager&&e._subscriptionManager.getEnableDebug()&&(console.log(new Date,"Server App","Msg Recv Hits",e._debugMsgRecv),console.log(new Date,"Server App","Msg Queue Hits",e._debugMsgQueue)),e._debugMsgQueue=0,e._debugMsgRecv=0},6e4),!1);setTimeout(function(){s=!0},5e3),process.on("unhandledRejection",function(o,n){return __awaiter(e,void 0,void 0,function(){var r,t=this;return __generator(this,function(e){switch(e.label){case 0:return o&&"MongoError"===o.name&&48===o.code?[2]:o&&"MongoServerError"===o.name&&!s?[2]:(console.error(new Date,"Unhandled Rejection at Promise",[o,n]),r=moment().diff(this._serverStartTime,"seconds"),o&&("MongoNetworkTimeoutError"===o.name||o instanceof mongodb_1.MongoNetworkTimeoutError)?60<r&&!this._lastErrorMsg?(this._lastErrorMsg=new Date,setTimeout(function(){t._lastErrorMsg=null},6e4),[4,this._methodManager.sendEmail("dev@resolveio.com","SERVER - MongoNetworkTimeoutError - Quitting NodeJS - "+resolveio_server_app_1.ResolveIOServer.getServerConfig().CLIENT_NAME,JSON.stringify({name:o.name,message:o.message,stack:o.stack},null,2))]):[3,2]:[3,3]);case 1:e.sent(),process.exit(1),e.label=2;case 2:return[3,10];case 3:return o&&"MongoError"===o.name&&"not master"===o.message?60<r&&!this._lastErrorMsg?(this._lastErrorMsg=new Date,setTimeout(function(){t._lastErrorMsg=null},6e4),[4,this._methodManager.sendEmail("dev@resolveio.com","SERVER - Unhandled Rejection - Quitting NodeJS - "+resolveio_server_app_1.ResolveIOServer.getServerConfig().CLIENT_NAME,JSON.stringify([o.name,o.message,o.stack],null,2))]):[3,5]:[3,6];case 4:e.sent(),e.label=5;case 5:return process.exit(1),[3,10];case 6:return o&&"MongoError"===o.name&&"not master and slaveOk=false"===o.message?60<r&&!this._lastErrorMsg?(this._lastErrorMsg=new Date,setTimeout(function(){t._lastErrorMsg=null},6e4),[4,this._methodManager.sendEmail("dev@resolveio.com","SERVER - Unhandled Rejection - Quitting NodeJS - "+resolveio_server_app_1.ResolveIOServer.getServerConfig().CLIENT_NAME,JSON.stringify([o.name,o.message,o.stack],null,2))]):[3,8]:[3,9];case 7:e.sent(),e.label=8;case 8:return process.exit(1),[3,10];case 9:o&&"StatusError"!==o.name&&""!==o.message&&60<r&&!this._lastErrorMsg&&(this._lastErrorMsg=new Date,setTimeout(function(){t._lastErrorMsg=null},6e4),this._methodManager.sendEmail("dev@resolveio.com","SERVER - Unhandled Rejection - "+resolveio_server_app_1.ResolveIOServer.getServerConfig().CLIENT_NAME,JSON.stringify([o.name,o.message,o.stack],null,2))),e.label=10;case 10:return[2]}})})}),process.on("uncaughtException",function(t){return __awaiter(e,void 0,void 0,function(){var r=this;return __generator(this,function(e){switch(e.label){case 0:return(console.error(t,"Uncaught Exception thrown"),60<moment().diff(this._serverStartTime,"seconds")&&!this._lastErrorMsg)?(this._lastErrorMsg=new Date,setTimeout(function(){r._lastErrorMsg=null},6e4),[4,this._methodManager.sendEmail("dev@resolveio.com","SERVER - Unhandled Exception - "+resolveio_server_app_1.ResolveIOServer.getServerConfig().CLIENT_NAME,JSON.stringify([t.name,t.message,t.stack],null,2))]):[3,2];case 1:e.sent(),e.label=2;case 2:return[2]}})})}),process.on("SIGINT",function(){e._rebootFlag=!0,e._serverHTTP&&e._serverHTTP.close(),e.safeShutdown()}),process.on("SIGTERM",function(){e._rebootFlag=!0,e._serverHTTP&&e._serverHTTP.close(),e.safeShutdown()}),process.on("SIGQUIT",function(){e._rebootFlag=!0,e._serverHTTP&&e._serverHTTP.close(),e.safeShutdown()}),"DEBUG"===this.LOGGER&&console.log("Starting ResolveIO Server"),this._isWorkersEnabled?this._isWorkerInstance?(console.log("Running as a Worker instance"),this._methodManager=new method_manager_1.MethodManager(this._monitorManagerFunction,this._isWorkersEnabled,this._isWorkerInstance),this._cronManager=new cron_manager_1.CronManager,this.startWorkerInstance()):(console.log("Running as a Server instance"),this._websocketManager=new websocket_manager_1.WebSocketManager(this),this.startServerInstance(),this._methodManager=new method_manager_1.MethodManager(this._monitorManagerFunction,this._isWorkersEnabled,this._isWorkerInstance),this._subscriptionManager=new subscription_manager_1.SubscriptionManager(this._serverWSS,resolveio_server_app_1.ResolveIOServer.getServerConfig(),this._monitorManagerFunction),this.listen()):(console.log("Running with Workers Disabled"),this._websocketManager=new websocket_manager_1.WebSocketManager(this),this.startServerInstance(),this._methodManager=new method_manager_1.MethodManager(this._monitorManagerFunction,this._isWorkersEnabled,this._isWorkerInstance),this._subscriptionManager=new subscription_manager_1.SubscriptionManager(this._serverWSS,resolveio_server_app_1.ResolveIOServer.getServerConfig(),this._monitorManagerFunction),this._cronManager=new cron_manager_1.CronManager,this.listen())},ResolveIOMainServer.prototype.startServerInstance=function(){this._app=express(),this._app.use(bodyParser.json({limit:"50mb",reviver:common_1.dateReviver})),this._app.use(bodyParser.urlencoded({limit:"50mb",extended:!0,parameterLimit:1e6})),this._app.use(xmlParser()),this._portHTTP=process.env.PORT_HTTP||resolveio_server_app_1.ResolveIOServer.getServerConfig().PORT_HTTP||8080,this._portWSS=process.env.PORT_WSS||resolveio_server_app_1.ResolveIOServer.getServerConfig().PORT_WSS||8081,"DEBUG"===this.LOGGER&&console.log("Setup ports"),this.createServer(),"DEBUG"===this.LOGGER&&console.log("Create server"),this._app.use(function(e,r,t){r.setHeader("Access-Control-Allow-Origin","*"),r.setHeader("Access-Control-Allow-Methods","GET, POST"),r.setHeader("Access-Control-Allow-Headers","X-Requested-With,content-type"),r.setHeader("Access-Control-Allow-Credentials","false"),t()}),"DEBUG"===this.LOGGER&&console.log("Setup cors"),(0,auth_1.setupAuthRoutes)(this,this._app,resolveio_server_app_1.ResolveIOServer.getServerConfig()),(0,health_1.setupHealthRoutes)(this._app,resolveio_server_app_1.ResolveIOServer.getServerConfig()),"ResolveIO"!==resolveio_server_app_1.ResolveIOServer.getServerConfig().CLIENT_NAME&&!this.standardProgram||(0,home_1.setupHomeRoutes)(this,this._app,resolveio_server_app_1.ResolveIOServer.getServerConfig()),"DEBUG"===this.LOGGER&&console.log("Setup express routes")},ResolveIOMainServer.prototype.startWorkerInstance=function(){return __awaiter(this,void 0,void 0,function(){var t,n,s=this;return __generator(this,function(e){return console.log(new Date,"Worker instance started, connecting to main server via WebSocket..."),t=resolveio_server_app_1.ResolveIOServer.getServerConfig().SERVER_URL+"/websocket?workerToken="+resolveio_server_app_1.ResolveIOServer.getServerConfig().WORKER_TOKEN,(n=function(){var o=new WebSocket(t),e=null,r=(o&&o.readyState===o.OPEN&&o.ping(),setInterval(function(){e?(e=null,o&&o.readyState===o.OPEN&&o.ping()):o.close()},15e3));o.on("open",function(){console.log(new Date,"Connected to main server as worker",process.env.WORKER_INDEX,process.env.NODE_APP_INSTANCE)}),o.on("ping",function(){o.pong()}),o.on("pong",function(){e=new Date}),o.on("message",function(t){return __awaiter(s,void 0,void 0,function(){var r;return __generator(this,function(e){try{r=JSON.parse(t.toString(),common_1.dateReviver)}catch(e){return console.error("Worker parse error",e),[2]}return"task"===r.type&&this.handleIncomingTask(o,r),[2]})})}),o.on("close",function(){console.log(new Date,"Disconnected from main server. Reconnecting in 5s..."),setTimeout(n,5e3),clearInterval(r)}),o.on("error",function(e){console.error(new Date,"Worker WS error:",e),o.close()})})(),[2]})})},ResolveIOMainServer.prototype.handleIncomingTask=function(u,_){return __awaiter(this,void 0,void 0,function(){var r,t,o,n,s,i,a,l,c=this;return __generator(this,function(e){switch(e.label){case 0:if(r=_.taskId,t=_.method,o=_.params,n=_.userContext,!r||!t)return console.log("Invalid task message received",_),[2];s=!1,i=setTimeout(function(){s=!0,console.error("Worker timed out on task:",r),c.sendWorkerResponse(u,{type:"taskComplete",taskId:r,error:!0,message:"Task timed out"})},12e4),e.label=1;case 1:return e.trys.push([1,3,,4]),a=Object.assign({},this._methodManager,method_manager_1.MethodManager.prototype,{id_user:(null==n?void 0:n.id_user)||"",user:(null==n?void 0:n.user)||"",id_ws:(null==n?void 0:n.id_ws)||""}),[4,(l=this._methodManager.callMethod).call.apply(l,__spreadArray([a,t],__read(o),!1))];case 2:return l=e.sent(),s||(clearTimeout(i),this.sendWorkerResponse(u,{type:"taskComplete",taskId:r,error:!1,result:l})),[3,4];case 3:return a=e.sent(),s||(clearTimeout(i),console.error("Worker failed task:",r,a),this.sendWorkerResponse(u,{type:"taskComplete",taskId:r,error:!0,message:a.message||"Unknown error"})),[3,4];case 4:return[2]}})})},ResolveIOMainServer.prototype.sendWorkerResponse=function(e,r){try{e.send(JSON.stringify(r))}catch(e){console.error("Failed to send worker response:",e)}},ResolveIOMainServer.prototype.safeShutdown=function(){var e=this;this._safeShutdown||console.log(new Date,"Safe Shutdown Command Received"),this._monitorManagerFunction.getActiveMonitorFunctions().length||this._offlineUpdates.length?(this._safeShutdown||(this._safeShutdown=!0,setTimeout(function(){e._safeShutdown=!1},1e3),console.log(new Date,"Safe Exit In Progress",this._monitorManagerFunction.getActiveMonitorFunctions().length,this._offlineUpdates.length)),setImmediate(function(){e.safeShutdown()})):resolveio_server_app_1.ResolveIOServer.getMongoConnection()?resolveio_server_app_1.ResolveIOServer.getMongoConnection().close(!1).then(function(){console.log(new Date,"Safe Exit Complete, Process Exit"),process.exit(0)},function(){process.exit(1)}):process.exit(0)},ResolveIOMainServer.prototype.getIsWorkersEnabled=function(){return this._isWorkersEnabled},ResolveIOMainServer.prototype.getIsWorkerInstance=function(){return this._isWorkerInstance},ResolveIOMainServer.prototype.getWSList=function(){var r=[];return this._serverWSS.clients.forEach(function(e){r.push(e.id_socket)}),r},ResolveIOMainServer.prototype.getWSUserList=function(){var r=[];return this._serverWSS.clients.forEach(function(e){r.push(e.id_user)}),r},ResolveIOMainServer.prototype.getHTTPServer=function(){return this._serverHTTP},ResolveIOMainServer.prototype.getCronManager=function(){return this._cronManager},ResolveIOMainServer.prototype.getMethodManager=function(){return this._methodManager},ResolveIOMainServer.prototype.getSubscriptionManager=function(){return this._subscriptionManager},ResolveIOMainServer.prototype.getMonitorManager=function(){return this._monitorManager},ResolveIOMainServer.prototype.getRebootFlag=function(){return this._rebootFlag},ResolveIOMainServer.prototype.getWebSocketManager=function(){return this._websocketManager},ResolveIOMainServer.prototype.createServer=function(){var e=this;this._serverHTTP=(0,http_1.createServer)(this._app),this._serverHTTP.keepAliveTimeout=65e3,this._serverHTTP.headersTimeout=66e3,this._serverWSS=new WebSocket.Server({port:this._portWSS,verifyClient:this.publicProgram?null:function(s,i){return __awaiter(e,void 0,void 0,function(){var r,t,n=this;return __generator(this,function(e){if(this._rebootFlag)i(!1,409,"Unable To Process");else{if("DEBUG"===this.LOGGER&&console.log("Verify Client",s,i),s.req.url&&s.req.url.includes("workerToken="))return r=s.req.url.split("workerToken="),(r[1]||"")===resolveio_server_app_1.ResolveIOServer.getServerConfig().WORKER_TOKEN?i(!0):i(!1,401,"Unauthorized"),[2];r=s.req.headers["sec-websocket-protocol"].split(/,/),(s.origin===resolveio_server_app_1.ResolveIOServer.getServerConfig().ROOT_URL||s.origin===resolveio_server_app_1.ResolveIOServer.getServerConfig().SEC_ROOT_URL||s.origin===resolveio_server_app_1.ResolveIOServer.getServerConfig().RESOLVEIO_URL||s.origin===resolveio_server_app_1.ResolveIOServer.getServerConfig().RESOLVEIO_SECONDARY_URL)&&(t=r[0])?jwt.verify(t,resolveio_server_app_1.ResolveIOServer.getServerConfig().JWT_SECRET,function(t,o){return __awaiter(n,void 0,void 0,function(){var r;return __generator(this,function(e){switch(e.label){case 0:return t?(i(!1,401,"Unauthorized"),[3,5]):[3,1];case 1:s.req.id_user=o.id_user,e.label=2;case 2:return e.trys.push([2,4,,5]),[4,user_collection_1.Users.findById(o.id_user)];case 3:return(r=e.sent())?(s.req.user=r.fullname,s.req.user_readonly=r.readonly||!1,s.req.doc_user=r,i(!0)):i(!1),[3,5];case 4:return e.sent(),i(!1),[3,5];case 5:return[2]}})})}):i(!1,401,"Unauthorized")}return[2]})})}})},ResolveIOMainServer.prototype.listen=function(){var s=this;this._serverHTTP.listen(this._portHTTP,function(){console.log("Running server on port %s",s._portHTTP)}),this._serverWSS.on("listening",function(){console.log("Running server on port %s",s._portWSS)}),this._serverWSS.on("connection",function(o,e){var r,t,n;e.url&&e.url.includes("workerToken=")?(r=(0,common_1.objectIdHexString)(),o.id_worker=r,s._workers.push({id:r,ws:o,activeTasks:0,maxConcurrency:2}),t=null,o&&o.readyState===o.OPEN&&o.ping(),n=setInterval(function(){t?(t=null,o&&o.readyState===o.OPEN&&o.ping()):o.close()},15e3),console.log(new Date,"Worker connected:",r),o.on("message",function(e){s.handleWorkerMessage(r,e)}),o.on("ping",function(){o.pong()}),o.on("pong",function(){t=new Date}),o.on("close",function(){console.log(new Date,"Worker disconnected:",r),s._workers=s._workers.filter(function(e){return e.id!==r}),clearInterval(n)})):(o.id_socket=(0,common_1.objectIdHexString)(),o.id_user=e.id_user,o.user=e.user,o.user_readonly=e.user_readonly,o.doc_user=e.doc_user,s._websocketManager.addWebSocket(o),s._subscriptionManager.createLoggedInUser(o.id_socket).then(function(){setTimeout(function(){o.pingTime=new Date,o.send("ping",function(e){e&&(s._subscriptionManager.getEnableDebug()&&console.log(new Date,"Server App","Error WS Ping"),s.unsubscribeWS(o))})},5e3)}),"DEBUG"===s.LOGGER&&console.log("Connection from user: "+e.user),o.isAlive=!0,o.retryCnt=0,o.on("message",function(t){return __awaiter(s,void 0,void 0,function(){var r;return __generator(this,function(e){this._debugMsgRecv+=1,r=[];try{r=JSON.parse(t,common_1.dateReviver)}catch(e){return console.log("Error - JSON.parse",t),this._methodManager.sendEmail("dev@resolveio.com","SERVER - JSON Parse Error - "+resolveio_server_app_1.ResolveIOServer.getServerConfig().CLIENT_NAME,JSON.stringify([t,e])),[2]}return this.processSocketMessage(o,r),[2]})})}).on("end",function(){s.unsubscribeWS(o)}).on("close",function(){s.unsubscribeWS(o)}).on("error",function(e){s.unsubscribeWS(o)}))}),setInterval(function(){s._serverWSS.clients.forEach(function(r){r.pingTime&&2e4<=Date.now()-r.pingTime.getTime()&&(!1===r.isAlive?(r.retryCnt++,3<=r.retryCnt?s.unsubscribeWS(r):(r.pingTime=new Date,r.send("ping",function(e){e&&(s._subscriptionManager.getEnableDebug()&&console.log(new Date,"Server App","Error WS Ping"),s.unsubscribeWS(r))}))):(r.retryCnt=0,r.isAlive=!1,r.pingTime=new Date,r.send("ping",function(e){e&&(s._subscriptionManager.getEnableDebug()&&console.log(new Date,"Server App","Error WS Ping"),s.unsubscribeWS(r))})))})},2e4)},ResolveIOMainServer.prototype.processSocketMessage=function(i,a){return __awaiter(this,void 0,void 0,function(){var r,t,o,n,s;return __generator(this,function(e){switch(e.label){case 0:if("string"==typeof a&&"ping"===a)return i&&i.readyState===i.OPEN&&i.send("pong"),[2];if("string"==typeof a&&"pong"===a)return i.isAlive=!0,i.pongTime=new Date,i.latency=moment.duration(moment(i.pongTime).diff(i.pingTime)).asMilliseconds(),this._subscriptionManager.loggedInLatency(i),[2];if(!Array.isArray(a[0]))return console.log("Invalid message format (expected array of arrays)",a),[2];e.label=1;case 1:e.trys.push([1,6,7,8]),r=__values(a),t=r.next(),e.label=2;case 2:return t.done?[3,5]:(o=t.value,[4,this.handleClientMessage(i,o)]);case 3:e.sent(),e.label=4;case 4:return t=r.next(),[3,2];case 5:return[3,8];case 6:return o=e.sent(),n={error:o},[3,8];case 7:try{t&&!t.done&&(s=r.return)&&s.call(r)}finally{if(n)throw n.error}return[7];case 8:return[2]}})})},ResolveIOMainServer.prototype.handleClientMessage=function(h,f){return __awaiter(this,void 0,void 0,function(){var r,t,o,n,s,i,a,l,c,u,_,g,v,d,p;return __generator(this,function(e){switch(e.label){case 0:return(r=f[0],a=f[1],t=f[2],o=f[3],this.publicProgram||!this._clientRoutes.some(function(e){return r.includes(e)})||h.doc_user.roles.groups.some(function(e){return e.views.some(function(e){return r.includes(e)||e.includes(r)})})||h.doc_user.roles.super_admin)?"subscription"!==o?[3,1]:(n=f[4],c=f[5],"sub"===n?this._subscriptionManager.subscribe(r,a,h,t,c,f.slice(6)):this._subscriptionManager.unsubscribe(r,a,h,t,c,f.slice(6)),[3,11]):[2];case 1:if(this.publicProgram||"offline"!==o)return[3,10];n={messageId:t,hasError:!1,data:"ACK"},h&&h.readyState===h.OPEN&&this._websocketManager.send(h,n),this._offlineUpdates.push(h),s=f[4],i=0,e.label=2;case 2:if(!(i<s.length))return[3,9];if(a=s[i],l=a.data,l.shift(),l.shift(),c=l.shift(),l.shift(),u=l.shift(),p={messageId:c,hasError:!1,data:"ACK"},h&&h.readyState===h.OPEN&&this._websocketManager.send(h,p),"insertDocument"===u&&"driver-gps"===l[0])return[3,8];if("reportBuilderGetResults"!==u&&"reportBuilderGetDistinctValue"!==u&&"reportBuilderBuildTree"!==u&&"generatePDF"!==u&&"getWOOfflineData"!==u&&"countQuery"!==u&&"countWithQuery"!==u&&"countCollectionWithQuery"!==u&&"find"!==u&&"findOne"!==u&&"findWithOptions"!==u&&"getDrivers"!==u&&"processAirdropDistribution"!==u&&("https://resolveio.com"!==resolveio_server_app_1.ResolveIOServer.getServerConfig().ROOT_URL&&"http://localhost:4200"!==resolveio_server_app_1.ResolveIOServer.getServerConfig().ROOT_URL?resolveio_server_app_1.ResolveIOServer.getLocalLogManager().writeLog({type:"log",data:{_id:(0,common_1.objectIdHexString)(),type:"client-request",collection:"",id_document:"",payload:(0,common_1.getBinarySize)(JSON.stringify(l))<2e5?JSON.stringify(l,null,2):"Too Big",method:u,id_user:h.id_user||"",user:h.user||"",messageId:t,route:r}}):log_collection_1.Logs.insertOne({_id:(0,common_1.objectIdHexString)(),type:"client-request",collection:"",id_document:"",payload:(0,common_1.getBinarySize)(JSON.stringify(l))<2e5?JSON.stringify(l,null,2):"Too Big",method:u,id_user:h.id_user||"",user:h.user||"",messageId:t,route:r,client:"ResolveIO",instance:"backend.resolveio.com"})),!this._methodManager._methods[u])return[3,7];e.label=3;case 3:return e.trys.push([3,5,,6]),[4,(p=this._methodManager.callMethod).call.apply(p,__spreadArray([Object.assign({},this._methodManager,method_manager_1.MethodManager.prototype,{id_user:h.id_user,user:h.user,id_ws:h.id_socket}),u],__read(l),!1))];case 4:return e.sent(),[3,6];case 5:return _=e.sent(),console.log(new Date,"Offline Error",JSON.stringify(_,null,2)),[3,6];case 6:return"updateDocumentOffline"!==u&&"updateDocumentPropsOffline"!==u||resolveio_server_app_1.ResolveIOServer.getMongoManager().invalidateQueryCache(l[0]),[3,8];case 7:console.log("Offline - Could not find method: "+u),e.label=8;case 8:return i++,[3,2];case 9:return this._offlineUpdates.splice(this._offlineUpdates.map(function(e){return e.id_socket}).indexOf(h.id_socket),1),[3,11];case 10:if(_=__spreadArray([],__read(f),!1),_.shift(),_.shift(),g=_.shift(),"method"===_.shift()){if(v=_.shift(),h.user_readonly)return[2];"reportBuilderGetResults"!==v&&"reportBuilderGetDistinctValue"!==v&&"reportBuilderBuildTree"!==v&&"generatePDF"!==v&&"getWOOfflineData"!==v&&"countQuery"!==v&&"countWithQuery"!==v&&"countCollectionWithQuery"!==v&&"find"!==v&&"findOne"!==v&&"findWithOptions"!==v&&"getDrivers"!==v&&"processAirdropDistribution"!==v&&("https://resolveio.com"!==resolveio_server_app_1.ResolveIOServer.getServerConfig().ROOT_URL&&"http://localhost:4200"!==resolveio_server_app_1.ResolveIOServer.getServerConfig().ROOT_URL?resolveio_server_app_1.ResolveIOServer.getLocalLogManager().writeLog({type:"log",data:{_id:(0,common_1.objectIdHexString)(),type:"client-request",collection:"",id_document:"",payload:(0,common_1.getBinarySize)(JSON.stringify(_))<2e5?JSON.stringify(_,null,2):"Too Big",method:v,id_user:h.id_user||"",user:h.user||"",messageId:t,route:r}}):log_collection_1.Logs.insertOne({_id:(0,common_1.objectIdHexString)(),type:"client-request",collection:"",id_document:"",payload:(0,common_1.getBinarySize)(JSON.stringify(_))<2e5?JSON.stringify(_,null,2):"Too Big",method:v,id_user:h.id_user||"",user:h.user||"",messageId:t,route:r,client:"ResolveIO",instance:"backend.resolveio.com"})),d={messageId:g,hasError:!1,data:"ACK"},h&&h.readyState===h.OPEN&&this._websocketManager.send(h,d),d=this.findAvailableWorker(),this._isWorkersEnabled&&d&&"insertSubscriptionLog"!==v&&"countQuery"!==v&&"incCounter"!==v&&"supportCreateBillingUser"!==v&&"find"!==v&&"insertDocument"!==v&&"countWithQuery"!==v&&"findOne"!==v&&"updateDocumentProps"!==v&&"findWithOptions"!==v&&"getSignedUrl"!==v&&"updateDocument"!==v&&"insertErrorLog"!==v&&"getSignedUrls"!==v&&"removeDocument"!==v&&"getSignedUrlWithId"!==v&&"incorrectUser"!==v&&"reloadWS"!==v&&"reconnectWS"!==v&&"disconnectWS"!==v?(d="task-"+(0,common_1.objectIdHexString)(),this._inFlightRequests[d]={ws:h,messageId:g,method:v},this.queueTask(d,v,_,{id_user:h.id_user,user:h.user,id_ws:h.id_socket})):this.callMethodLocally(h,g,v,_)}e.label=11;case 11:return[2]}})})},ResolveIOMainServer.prototype.callMethodLocally=function(n,s,i,a){return __awaiter(this,void 0,void 0,function(){var r,t,o;return __generator(this,function(e){switch(e.label){case 0:r={messageId:s,hasError:!1,data:null},e.label=1;case 1:return e.trys.push([1,3,,4]),[4,(o=this._methodManager.callMethod).call.apply(o,__spreadArray([Object.assign({},this._methodManager,method_manager_1.MethodManager.prototype,{id_user:n.id_user,user:n.user,id_ws:n.id_socket}),i],__read(a),!1))];case 2:return o=e.sent(),r.data=o,[3,4];case 3:return t=e.sent(),r.hasError=!0,r.data=t.message||"Unknown error",[3,4];case 4:return n&&n.readyState===n.OPEN&&this._websocketManager.send(n,r),[2]}})})},ResolveIOMainServer.prototype.queueTask=function(e,r,t,o){this._taskQueue.push({taskId:e,method:r,params:t,userContext:o}),this.dispatchQueue()},ResolveIOMainServer.prototype.dispatchQueue=function(){if(this._taskQueue.length)for(var e=0;e<9999;e++){var r=this._taskQueue[0];if(!r)break;var t=this.findAvailableWorker();if(!t)break;this._taskQueue.shift(),this.assignTaskToWorker(t,r)}},ResolveIOMainServer.prototype.findAvailableWorker=function(){var e=this._workers.filter(function(e){return e.activeTasks<e.maxConcurrency});return e.length?(e.sort(function(e,r){return e.activeTasks-r.activeTasks}),e[0]):null},ResolveIOMainServer.prototype.assignTaskToWorker=function(r,t){r.activeTasks++;var e={type:"task",taskId:t.taskId,method:t.method,params:t.params,userContext:t.userContext};try{r.ws.send(JSON.stringify(e)),console.log("Assigned task",t.taskId,"to worker",r.id)}catch(e){console.error("Failed to send task to worker:",e),r.activeTasks=Math.max(0,r.activeTasks-1),this._taskQueue.unshift(t)}},ResolveIOMainServer.prototype.handleWorkerMessage=function(r,t){var e,o,n,s;try{s=JSON.parse(t,common_1.dateReviver)}catch(e){return void console.error("Failed to parse worker message:",t)}"taskComplete"===s.type&&((t=this._workers.find(function(e){return e.id===r}))?(t.activeTasks=Math.max(0,t.activeTasks-1),t=s.taskId,e=s.error,o=s.message,s=s.result,(n=this._inFlightRequests[t])?(delete this._inFlightRequests[t],s={messageId:n.messageId,hasError:!1,data:s},e&&(s.hasError=!0,s.data=o),n.ws&&n.ws.readyState===n.ws.OPEN&&this._websocketManager.send(n.ws,s)):console.error("No in-flight request found for task:",t),this.dispatchQueue()):console.error("Unknown worker for taskComplete:",r))},ResolveIOMainServer.prototype.unsubscribeWS=function(e){this._subscriptionManager&&this._subscriptionManager.getEnableDebug()&&console.log(new Date,"Server App","Unsub WS",e.user,e.id_socket),this._subscriptionManager.unsubscribeAll(e),e.removeAllListeners()},ResolveIOMainServer.prototype.getApp=function(){return this._app},ResolveIOMainServer.prototype.getServerConfig=function(){return resolveio_server_app_1.ResolveIOServer.getServerConfig()},ResolveIOMainServer}();exports.ResolveIOMainServer=ResolveIOMainServer;
1
+ "use strict";var __awaiter=this&&this.__awaiter||function(e,o,n,s){return new(n=n||Promise)(function(t,r){function fulfilled(e){try{step(s.next(e))}catch(e){r(e)}}function rejected(e){try{step(s.throw(e))}catch(e){r(e)}}function step(e){var r;e.done?t(e.value):((r=e.value)instanceof n?r:new n(function(e){e(r)})).then(fulfilled,rejected)}step((s=s.apply(e,o||[])).next())})},__generator=this&&this.__generator||function(o,n){var s,i,a,l={label:0,sent:function(){if(1&a[0])throw a[1];return a[1]},trys:[],ops:[]},c={next:verb(0),throw:verb(1),return:verb(2)};return"function"==typeof Symbol&&(c[Symbol.iterator]=function(){return this}),c;function verb(t){return function(e){var r=[t,e];if(s)throw new TypeError("Generator is already executing.");for(;l=c&&r[c=0]?0:l;)try{if(s=1,i&&(a=2&r[0]?i.return:r[0]?i.throw||((a=i.return)&&a.call(i),0):i.next)&&!(a=a.call(i,r[1])).done)return a;switch(i=0,(r=a?[2&r[0],a.value]:r)[0]){case 0:case 1:a=r;break;case 4:return l.label++,{value:r[1],done:!1};case 5:l.label++,i=r[1],r=[0];continue;case 7:r=l.ops.pop(),l.trys.pop();continue;default:if(!(a=0<(a=l.trys).length&&a[a.length-1])&&(6===r[0]||2===r[0])){l=0;continue}if(3===r[0]&&(!a||r[1]>a[0]&&r[1]<a[3]))l.label=r[1];else if(6===r[0]&&l.label<a[1])l.label=a[1],a=r;else{if(!(a&&l.label<a[2])){a[2]&&l.ops.pop(),l.trys.pop();continue}l.label=a[2],l.ops.push(r)}}r=n.call(o,l)}catch(e){r=[6,e],i=0}finally{s=a=0}if(5&r[0])throw r[1];return{value:r[0]?r[1]:void 0,done:!0}}}},__read=this&&this.__read||function(e,r){var t="function"==typeof Symbol&&e[Symbol.iterator];if(!t)return e;var o,n,s=t.call(e),i=[];try{for(;(void 0===r||0<r--)&&!(o=s.next()).done;)i.push(o.value)}catch(e){n={error:e}}finally{try{o&&!o.done&&(t=s.return)&&t.call(s)}finally{if(n)throw n.error}}return i},__spreadArray=this&&this.__spreadArray||function(e,r,t){if(t||2===arguments.length)for(var o,n=0,s=r.length;n<s;n++)!o&&n in r||((o=o||Array.prototype.slice.call(r,0,n))[n]=r[n]);return e.concat(o||Array.prototype.slice.call(r))},__values=this&&this.__values||function(e){var r="function"==typeof Symbol&&Symbol.iterator,t=r&&e[r],o=0;if(t)return t.call(e);if(e&&"number"==typeof e.length)return{next:function(){return{value:(e=e&&o>=e.length?void 0:e)&&e[o++],done:!e}}};throw new TypeError(r?"Object is not iterable.":"Symbol.iterator is not defined.")},http_1=(Object.defineProperty(exports,"__esModule",{value:!0}),exports.ResolveIOMainServer=void 0,require("http")),express=require("express"),bodyParser=require("body-parser"),xmlParser=require("express-xml-bodyparser"),WebSocket=require("ws"),jwt=require("jsonwebtoken"),moment=require("moment-timezone"),common_1=require("./util/common"),cron_manager_1=require("./managers/cron.manager"),method_manager_1=require("./managers/method.manager"),subscription_manager_1=require("./managers/subscription.manager"),monitor_manager_1=require("./managers/monitor.manager"),log_collection_1=require("./collections/log.collection"),user_collection_1=require("./collections/user.collection"),home_1=require("./http/home"),auth_1=require("./http/auth"),health_1=require("./http/health"),mongodb_1=require("mongodb"),websocket_manager_1=require("./managers/websocket.manager"),resolveio_server_app_1=require("./resolveio-server-app"),ResolveIOMainServer=function(){function ResolveIOMainServer(){this._offlineUpdates=[],this.sesMail=!1,this.standardProgram=!1,this.publicProgram=!1,this._rebootFlag=!1,this.LOGGER="ERROR",this._clientRoutes=[],this._lastErrorMsg=null,this._debugMsgRecv=0,this._debugMsgQueue=0,this._isWorkersEnabled=!1,this._isWorkerInstance=!1,this._safeShutdown=!1,this._workers=[],this._taskQueue=[],this._inFlightRequests={},this._serverStartTime=new Date,this._lastErrorMsg=null,this._monitorManager=new monitor_manager_1.MonitorManager,this._monitorManagerFunction=new monitor_manager_1.MonitorManagerFunction}return ResolveIOMainServer.prototype.initServerApp=function(){var e=this,s=(this._isWorkersEnabled="true"===process.env.IS_WORKERS_ENABLED,this._isWorkerInstance="true"===process.env.IS_WORKER_INSTANCE,setInterval(function(){e._subscriptionManager&&e._subscriptionManager.getEnableDebug()&&(console.log(new Date,"Server App","Msg Recv Hits",e._debugMsgRecv),console.log(new Date,"Server App","Msg Queue Hits",e._debugMsgQueue)),e._debugMsgQueue=0,e._debugMsgRecv=0},6e4),!1);setTimeout(function(){s=!0},5e3),process.on("unhandledRejection",function(o,n){return __awaiter(e,void 0,void 0,function(){var r,t=this;return __generator(this,function(e){switch(e.label){case 0:return o&&"MongoError"===o.name&&48===o.code?[2]:o&&"MongoServerError"===o.name&&!s?[2]:(console.error(new Date,"Unhandled Rejection at Promise",[o,n]),r=moment().diff(this._serverStartTime,"seconds"),o&&("MongoNetworkTimeoutError"===o.name||o instanceof mongodb_1.MongoNetworkTimeoutError)?60<r&&!this._lastErrorMsg?(this._lastErrorMsg=new Date,setTimeout(function(){t._lastErrorMsg=null},6e4),[4,this._methodManager.sendEmail("dev@resolveio.com","SERVER - MongoNetworkTimeoutError - Quitting NodeJS - "+resolveio_server_app_1.ResolveIOServer.getServerConfig().CLIENT_NAME,JSON.stringify({name:o.name,message:o.message,stack:o.stack},null,2))]):[3,2]:[3,3]);case 1:e.sent(),process.exit(1),e.label=2;case 2:return[3,10];case 3:return o&&"MongoError"===o.name&&"not master"===o.message?60<r&&!this._lastErrorMsg?(this._lastErrorMsg=new Date,setTimeout(function(){t._lastErrorMsg=null},6e4),[4,this._methodManager.sendEmail("dev@resolveio.com","SERVER - Unhandled Rejection - Quitting NodeJS - "+resolveio_server_app_1.ResolveIOServer.getServerConfig().CLIENT_NAME,JSON.stringify([o.name,o.message,o.stack],null,2))]):[3,5]:[3,6];case 4:e.sent(),e.label=5;case 5:return process.exit(1),[3,10];case 6:return o&&"MongoError"===o.name&&"not master and slaveOk=false"===o.message?60<r&&!this._lastErrorMsg?(this._lastErrorMsg=new Date,setTimeout(function(){t._lastErrorMsg=null},6e4),[4,this._methodManager.sendEmail("dev@resolveio.com","SERVER - Unhandled Rejection - Quitting NodeJS - "+resolveio_server_app_1.ResolveIOServer.getServerConfig().CLIENT_NAME,JSON.stringify([o.name,o.message,o.stack],null,2))]):[3,8]:[3,9];case 7:e.sent(),e.label=8;case 8:return process.exit(1),[3,10];case 9:o&&"StatusError"!==o.name&&""!==o.message&&60<r&&!this._lastErrorMsg&&(this._lastErrorMsg=new Date,setTimeout(function(){t._lastErrorMsg=null},6e4),this._methodManager.sendEmail("dev@resolveio.com","SERVER - Unhandled Rejection - "+resolveio_server_app_1.ResolveIOServer.getServerConfig().CLIENT_NAME,JSON.stringify([o.name,o.message,o.stack],null,2))),e.label=10;case 10:return[2]}})})}),process.on("uncaughtException",function(t){return __awaiter(e,void 0,void 0,function(){var r=this;return __generator(this,function(e){switch(e.label){case 0:return(console.error(t,"Uncaught Exception thrown"),60<moment().diff(this._serverStartTime,"seconds")&&!this._lastErrorMsg)?(this._lastErrorMsg=new Date,setTimeout(function(){r._lastErrorMsg=null},6e4),[4,this._methodManager.sendEmail("dev@resolveio.com","SERVER - Unhandled Exception - "+resolveio_server_app_1.ResolveIOServer.getServerConfig().CLIENT_NAME,JSON.stringify([t.name,t.message,t.stack],null,2))]):[3,2];case 1:e.sent(),e.label=2;case 2:return[2]}})})}),process.on("SIGINT",function(){e._rebootFlag=!0,e._serverHTTP&&e._serverHTTP.close(),e.safeShutdown()}),process.on("SIGTERM",function(){e._rebootFlag=!0,e._serverHTTP&&e._serverHTTP.close(),e.safeShutdown()}),process.on("SIGQUIT",function(){e._rebootFlag=!0,e._serverHTTP&&e._serverHTTP.close(),e.safeShutdown()}),"DEBUG"===this.LOGGER&&console.log("Starting ResolveIO Server"),this._isWorkersEnabled?this._isWorkerInstance?(console.log("Running as a Worker instance"),this._methodManager=new method_manager_1.MethodManager(this._monitorManagerFunction,this._isWorkersEnabled,this._isWorkerInstance),this._cronManager=new cron_manager_1.CronManager,this.startWorkerInstance()):(console.log("Running as a Server instance"),this._websocketManager=new websocket_manager_1.WebSocketManager(this),this.startServerInstance(),this._methodManager=new method_manager_1.MethodManager(this._monitorManagerFunction,this._isWorkersEnabled,this._isWorkerInstance),this._subscriptionManager=new subscription_manager_1.SubscriptionManager(this._serverWSS,resolveio_server_app_1.ResolveIOServer.getServerConfig(),this._monitorManagerFunction),this.listen()):(console.log("Running with Workers Disabled"),this._websocketManager=new websocket_manager_1.WebSocketManager(this),this.startServerInstance(),this._methodManager=new method_manager_1.MethodManager(this._monitorManagerFunction,this._isWorkersEnabled,this._isWorkerInstance),this._subscriptionManager=new subscription_manager_1.SubscriptionManager(this._serverWSS,resolveio_server_app_1.ResolveIOServer.getServerConfig(),this._monitorManagerFunction),this._cronManager=new cron_manager_1.CronManager,this.listen())},ResolveIOMainServer.prototype.startServerInstance=function(){this._app=express(),this._app.use(bodyParser.json({limit:"50mb",reviver:common_1.dateReviver})),this._app.use(bodyParser.urlencoded({limit:"50mb",extended:!0,parameterLimit:1e6})),this._app.use(xmlParser()),this._portHTTP=process.env.PORT_HTTP||resolveio_server_app_1.ResolveIOServer.getServerConfig().PORT_HTTP||8080,this._portWSS=process.env.PORT_WSS||resolveio_server_app_1.ResolveIOServer.getServerConfig().PORT_WSS||8081,"DEBUG"===this.LOGGER&&console.log("Setup ports"),this.createServer(),"DEBUG"===this.LOGGER&&console.log("Create server"),this._app.use(function(e,r,t){r.setHeader("Access-Control-Allow-Origin","*"),r.setHeader("Access-Control-Allow-Methods","GET, POST"),r.setHeader("Access-Control-Allow-Headers","X-Requested-With,content-type"),r.setHeader("Access-Control-Allow-Credentials","false"),t()}),"DEBUG"===this.LOGGER&&console.log("Setup cors"),(0,auth_1.setupAuthRoutes)(this,this._app,resolveio_server_app_1.ResolveIOServer.getServerConfig()),(0,health_1.setupHealthRoutes)(this._app,resolveio_server_app_1.ResolveIOServer.getServerConfig()),"ResolveIO"!==resolveio_server_app_1.ResolveIOServer.getServerConfig().CLIENT_NAME&&!this.standardProgram||(0,home_1.setupHomeRoutes)(this,this._app,resolveio_server_app_1.ResolveIOServer.getServerConfig()),"DEBUG"===this.LOGGER&&console.log("Setup express routes")},ResolveIOMainServer.prototype.startWorkerInstance=function(){return __awaiter(this,void 0,void 0,function(){var r,t,s=this;return __generator(this,function(e){return console.log(new Date,"Worker instance started, connecting to main server via WebSocket..."),r=resolveio_server_app_1.ResolveIOServer.getServerConfig().SERVER_URL+"/websocket?workerToken="+resolveio_server_app_1.ResolveIOServer.getServerConfig().WORKER_TOKEN,(t=function(){var o=new WebSocket(r),n=null,e=(o&&o.readyState===o.OPEN&&o.ping(),setInterval(function(){n?(n=null,o&&o.readyState===o.OPEN&&o.ping()):o.close()},15e3));o.on("open",function(){console.log(new Date,"Connected to main server as worker",process.env.WORKER_INDEX,process.env.NODE_APP_INSTANCE)}),o.on("message",function(t){return __awaiter(s,void 0,void 0,function(){var r;return __generator(this,function(e){try{r=JSON.parse(t.toString(),common_1.dateReviver)}catch(e){return console.error("Worker parse error",e),[2]}return"ping"===r.type?this.sendWorkerResponse(o,{type:"pong"}):"pong"===r.type?n=new Date:"task"===r.type&&this.handleIncomingTask(o,r),[2]})})}),o.on("close",function(){console.log(new Date,"Disconnected from main server. Reconnecting in 5s..."),setTimeout(t,5e3),clearInterval(e)}),o.on("error",function(e){console.error(new Date,"Worker WS error:",e),o.close()})})(),[2]})})},ResolveIOMainServer.prototype.handleIncomingTask=function(u,_){return __awaiter(this,void 0,void 0,function(){var r,t,o,n,s,i,a,l,c=this;return __generator(this,function(e){switch(e.label){case 0:if(r=_.taskId,t=_.method,o=_.params,n=_.userContext,!r||!t)return console.log("Invalid task message received",_),[2];s=!1,i=setTimeout(function(){s=!0,console.error("Worker timed out on task:",r),c.sendWorkerResponse(u,{type:"taskComplete",taskId:r,error:!0,message:"Task timed out"})},12e4),e.label=1;case 1:return e.trys.push([1,3,,4]),a=Object.assign({},this._methodManager,method_manager_1.MethodManager.prototype,{id_user:(null==n?void 0:n.id_user)||"",user:(null==n?void 0:n.user)||"",id_ws:(null==n?void 0:n.id_ws)||""}),[4,(l=this._methodManager.callMethod).call.apply(l,__spreadArray([a,t],__read(o),!1))];case 2:return l=e.sent(),s||(clearTimeout(i),this.sendWorkerResponse(u,{type:"taskComplete",taskId:r,error:!1,result:l})),[3,4];case 3:return a=e.sent(),s||(clearTimeout(i),console.error("Worker failed task:",r,a),this.sendWorkerResponse(u,{type:"taskComplete",taskId:r,error:!0,message:a.message||"Unknown error"})),[3,4];case 4:return[2]}})})},ResolveIOMainServer.prototype.sendWorkerResponse=function(e,r){try{e.send(JSON.stringify(r))}catch(e){console.error("Failed to send worker response:",e)}},ResolveIOMainServer.prototype.safeShutdown=function(){var e=this;this._safeShutdown||console.log(new Date,"Safe Shutdown Command Received"),this._monitorManagerFunction.getActiveMonitorFunctions().length||this._offlineUpdates.length?(this._safeShutdown||(this._safeShutdown=!0,setTimeout(function(){e._safeShutdown=!1},1e3),console.log(new Date,"Safe Exit In Progress",this._monitorManagerFunction.getActiveMonitorFunctions().length,this._offlineUpdates.length)),setImmediate(function(){e.safeShutdown()})):resolveio_server_app_1.ResolveIOServer.getMongoConnection()?resolveio_server_app_1.ResolveIOServer.getMongoConnection().close(!1).then(function(){console.log(new Date,"Safe Exit Complete, Process Exit"),process.exit(0)},function(){process.exit(1)}):process.exit(0)},ResolveIOMainServer.prototype.getIsWorkersEnabled=function(){return this._isWorkersEnabled},ResolveIOMainServer.prototype.getIsWorkerInstance=function(){return this._isWorkerInstance},ResolveIOMainServer.prototype.getWSList=function(){var r=[];return this._serverWSS.clients.forEach(function(e){r.push(e.id_socket)}),r},ResolveIOMainServer.prototype.getWSUserList=function(){var r=[];return this._serverWSS.clients.forEach(function(e){r.push(e.id_user)}),r},ResolveIOMainServer.prototype.getHTTPServer=function(){return this._serverHTTP},ResolveIOMainServer.prototype.getCronManager=function(){return this._cronManager},ResolveIOMainServer.prototype.getMethodManager=function(){return this._methodManager},ResolveIOMainServer.prototype.getSubscriptionManager=function(){return this._subscriptionManager},ResolveIOMainServer.prototype.getMonitorManager=function(){return this._monitorManager},ResolveIOMainServer.prototype.getRebootFlag=function(){return this._rebootFlag},ResolveIOMainServer.prototype.getWebSocketManager=function(){return this._websocketManager},ResolveIOMainServer.prototype.createServer=function(){var e=this;this._serverHTTP=(0,http_1.createServer)(this._app),this._serverHTTP.keepAliveTimeout=65e3,this._serverHTTP.headersTimeout=66e3,this._serverWSS=new WebSocket.Server({port:this._portWSS,verifyClient:this.publicProgram?null:function(s,i){return __awaiter(e,void 0,void 0,function(){var r,t,n=this;return __generator(this,function(e){if(this._rebootFlag)i(!1,409,"Unable To Process");else{if("DEBUG"===this.LOGGER&&console.log("Verify Client",s,i),s.req.url&&s.req.url.includes("workerToken="))return r=s.req.url.split("workerToken="),(r[1]||"")===resolveio_server_app_1.ResolveIOServer.getServerConfig().WORKER_TOKEN?i(!0):i(!1,401,"Unauthorized"),[2];r=s.req.headers["sec-websocket-protocol"].split(/,/),(s.origin===resolveio_server_app_1.ResolveIOServer.getServerConfig().ROOT_URL||s.origin===resolveio_server_app_1.ResolveIOServer.getServerConfig().SEC_ROOT_URL||s.origin===resolveio_server_app_1.ResolveIOServer.getServerConfig().RESOLVEIO_URL||s.origin===resolveio_server_app_1.ResolveIOServer.getServerConfig().RESOLVEIO_SECONDARY_URL)&&(t=r[0])?jwt.verify(t,resolveio_server_app_1.ResolveIOServer.getServerConfig().JWT_SECRET,function(t,o){return __awaiter(n,void 0,void 0,function(){var r;return __generator(this,function(e){switch(e.label){case 0:return t?(i(!1,401,"Unauthorized"),[3,5]):[3,1];case 1:s.req.id_user=o.id_user,e.label=2;case 2:return e.trys.push([2,4,,5]),[4,user_collection_1.Users.findById(o.id_user)];case 3:return(r=e.sent())?(s.req.user=r.fullname,s.req.user_readonly=r.readonly||!1,s.req.doc_user=r,i(!0)):i(!1),[3,5];case 4:return e.sent(),i(!1),[3,5];case 5:return[2]}})})}):i(!1,401,"Unauthorized")}return[2]})})}})},ResolveIOMainServer.prototype.listen=function(){var s=this;this._serverHTTP.listen(this._portHTTP,function(){console.log("Running server on port %s",s._portHTTP)}),this._serverWSS.on("listening",function(){console.log("Running server on port %s",s._portWSS)}),this._serverWSS.on("connection",function(o,e){var r,t,n;e.url&&e.url.includes("workerToken=")?(r=(0,common_1.objectIdHexString)(),o.id_worker=r,s._workers.push({id:r,ws:o,activeTasks:0,maxConcurrency:2}),t=null,o&&o.readyState===o.OPEN&&s.sendWorkerResponse(o,{type:"ping"}),n=setInterval(function(){t?(t=null,o&&o.readyState===o.OPEN&&s.sendWorkerResponse(o,{type:"ping"})):o.close()},15e3),console.log(new Date,"Worker connected:",r),o.on("message",function(e){"ping"===e?s.sendWorkerResponse(o,{type:"pong"}):"pong"===e?t=new Date:s.handleWorkerMessage(r,e)}),o.on("close",function(){console.log(new Date,"Worker disconnected:",r),s._workers=s._workers.filter(function(e){return e.id!==r}),clearInterval(n)})):(o.id_socket=(0,common_1.objectIdHexString)(),o.id_user=e.id_user,o.user=e.user,o.user_readonly=e.user_readonly,o.doc_user=e.doc_user,s._websocketManager.addWebSocket(o),s._subscriptionManager.createLoggedInUser(o.id_socket).then(function(){setTimeout(function(){o.pingTime=new Date,o.send("ping",function(e){e&&(s._subscriptionManager.getEnableDebug()&&console.log(new Date,"Server App","Error WS Ping"),s.unsubscribeWS(o))})},5e3)}),"DEBUG"===s.LOGGER&&console.log("Connection from user: "+e.user),o.isAlive=!0,o.retryCnt=0,o.on("message",function(t){return __awaiter(s,void 0,void 0,function(){var r;return __generator(this,function(e){this._debugMsgRecv+=1,r=[];try{r=JSON.parse(t,common_1.dateReviver)}catch(e){return console.log("Error - JSON.parse",t),this._methodManager.sendEmail("dev@resolveio.com","SERVER - JSON Parse Error - "+resolveio_server_app_1.ResolveIOServer.getServerConfig().CLIENT_NAME,JSON.stringify([t,e])),[2]}return this.processSocketMessage(o,r),[2]})})}).on("end",function(){s.unsubscribeWS(o)}).on("close",function(){s.unsubscribeWS(o)}).on("error",function(e){s.unsubscribeWS(o)}))}),setInterval(function(){s._serverWSS.clients.forEach(function(r){r.pingTime&&2e4<=Date.now()-r.pingTime.getTime()&&(!1===r.isAlive?(r.retryCnt++,3<=r.retryCnt?s.unsubscribeWS(r):(r.pingTime=new Date,r.send("ping",function(e){e&&(s._subscriptionManager.getEnableDebug()&&console.log(new Date,"Server App","Error WS Ping"),s.unsubscribeWS(r))}))):(r.retryCnt=0,r.isAlive=!1,r.pingTime=new Date,r.send("ping",function(e){e&&(s._subscriptionManager.getEnableDebug()&&console.log(new Date,"Server App","Error WS Ping"),s.unsubscribeWS(r))})))})},2e4)},ResolveIOMainServer.prototype.processSocketMessage=function(i,a){return __awaiter(this,void 0,void 0,function(){var r,t,o,n,s;return __generator(this,function(e){switch(e.label){case 0:if("string"==typeof a&&"ping"===a)return i&&i.readyState===i.OPEN&&i.send("pong"),[2];if("string"==typeof a&&"pong"===a)return i.isAlive=!0,i.pongTime=new Date,i.latency=moment.duration(moment(i.pongTime).diff(i.pingTime)).asMilliseconds(),this._subscriptionManager.loggedInLatency(i),[2];if(!Array.isArray(a[0]))return console.log("Invalid message format (expected array of arrays)",a),[2];e.label=1;case 1:e.trys.push([1,6,7,8]),r=__values(a),t=r.next(),e.label=2;case 2:return t.done?[3,5]:(o=t.value,[4,this.handleClientMessage(i,o)]);case 3:e.sent(),e.label=4;case 4:return t=r.next(),[3,2];case 5:return[3,8];case 6:return o=e.sent(),n={error:o},[3,8];case 7:try{t&&!t.done&&(s=r.return)&&s.call(r)}finally{if(n)throw n.error}return[7];case 8:return[2]}})})},ResolveIOMainServer.prototype.handleClientMessage=function(h,f){return __awaiter(this,void 0,void 0,function(){var r,t,o,n,s,i,a,l,c,u,_,g,v,d,p;return __generator(this,function(e){switch(e.label){case 0:return(r=f[0],a=f[1],t=f[2],o=f[3],this.publicProgram||!this._clientRoutes.some(function(e){return r.includes(e)})||h.doc_user.roles.groups.some(function(e){return e.views.some(function(e){return r.includes(e)||e.includes(r)})})||h.doc_user.roles.super_admin)?"subscription"!==o?[3,1]:(n=f[4],c=f[5],"sub"===n?this._subscriptionManager.subscribe(r,a,h,t,c,f.slice(6)):this._subscriptionManager.unsubscribe(r,a,h,t,c,f.slice(6)),[3,11]):[2];case 1:if(this.publicProgram||"offline"!==o)return[3,10];n={messageId:t,hasError:!1,data:"ACK"},h&&h.readyState===h.OPEN&&this._websocketManager.send(h,n),this._offlineUpdates.push(h),s=f[4],i=0,e.label=2;case 2:if(!(i<s.length))return[3,9];if(a=s[i],l=a.data,l.shift(),l.shift(),c=l.shift(),l.shift(),u=l.shift(),p={messageId:c,hasError:!1,data:"ACK"},h&&h.readyState===h.OPEN&&this._websocketManager.send(h,p),"insertDocument"===u&&"driver-gps"===l[0])return[3,8];if("reportBuilderGetResults"!==u&&"reportBuilderGetDistinctValue"!==u&&"reportBuilderBuildTree"!==u&&"generatePDF"!==u&&"getWOOfflineData"!==u&&"countQuery"!==u&&"countWithQuery"!==u&&"countCollectionWithQuery"!==u&&"find"!==u&&"findOne"!==u&&"findWithOptions"!==u&&"getDrivers"!==u&&"processAirdropDistribution"!==u&&("https://resolveio.com"!==resolveio_server_app_1.ResolveIOServer.getServerConfig().ROOT_URL&&"http://localhost:4200"!==resolveio_server_app_1.ResolveIOServer.getServerConfig().ROOT_URL?resolveio_server_app_1.ResolveIOServer.getLocalLogManager().writeLog({type:"log",data:{_id:(0,common_1.objectIdHexString)(),type:"client-request",collection:"",id_document:"",payload:(0,common_1.getBinarySize)(JSON.stringify(l))<2e5?JSON.stringify(l,null,2):"Too Big",method:u,id_user:h.id_user||"",user:h.user||"",messageId:t,route:r}}):log_collection_1.Logs.insertOne({_id:(0,common_1.objectIdHexString)(),type:"client-request",collection:"",id_document:"",payload:(0,common_1.getBinarySize)(JSON.stringify(l))<2e5?JSON.stringify(l,null,2):"Too Big",method:u,id_user:h.id_user||"",user:h.user||"",messageId:t,route:r,client:"ResolveIO",instance:"backend.resolveio.com"})),!this._methodManager._methods[u])return[3,7];e.label=3;case 3:return e.trys.push([3,5,,6]),[4,(p=this._methodManager.callMethod).call.apply(p,__spreadArray([Object.assign({},this._methodManager,method_manager_1.MethodManager.prototype,{id_user:h.id_user,user:h.user,id_ws:h.id_socket}),u],__read(l),!1))];case 4:return e.sent(),[3,6];case 5:return _=e.sent(),console.log(new Date,"Offline Error",JSON.stringify(_,null,2)),[3,6];case 6:return"updateDocumentOffline"!==u&&"updateDocumentPropsOffline"!==u||resolveio_server_app_1.ResolveIOServer.getMongoManager().invalidateQueryCache(l[0]),[3,8];case 7:console.log("Offline - Could not find method: "+u),e.label=8;case 8:return i++,[3,2];case 9:return this._offlineUpdates.splice(this._offlineUpdates.map(function(e){return e.id_socket}).indexOf(h.id_socket),1),[3,11];case 10:if(_=__spreadArray([],__read(f),!1),_.shift(),_.shift(),g=_.shift(),"method"===_.shift()){if(v=_.shift(),h.user_readonly)return[2];"reportBuilderGetResults"!==v&&"reportBuilderGetDistinctValue"!==v&&"reportBuilderBuildTree"!==v&&"generatePDF"!==v&&"getWOOfflineData"!==v&&"countQuery"!==v&&"countWithQuery"!==v&&"countCollectionWithQuery"!==v&&"find"!==v&&"findOne"!==v&&"findWithOptions"!==v&&"getDrivers"!==v&&"processAirdropDistribution"!==v&&("https://resolveio.com"!==resolveio_server_app_1.ResolveIOServer.getServerConfig().ROOT_URL&&"http://localhost:4200"!==resolveio_server_app_1.ResolveIOServer.getServerConfig().ROOT_URL?resolveio_server_app_1.ResolveIOServer.getLocalLogManager().writeLog({type:"log",data:{_id:(0,common_1.objectIdHexString)(),type:"client-request",collection:"",id_document:"",payload:(0,common_1.getBinarySize)(JSON.stringify(_))<2e5?JSON.stringify(_,null,2):"Too Big",method:v,id_user:h.id_user||"",user:h.user||"",messageId:t,route:r}}):log_collection_1.Logs.insertOne({_id:(0,common_1.objectIdHexString)(),type:"client-request",collection:"",id_document:"",payload:(0,common_1.getBinarySize)(JSON.stringify(_))<2e5?JSON.stringify(_,null,2):"Too Big",method:v,id_user:h.id_user||"",user:h.user||"",messageId:t,route:r,client:"ResolveIO",instance:"backend.resolveio.com"})),d={messageId:g,hasError:!1,data:"ACK"},h&&h.readyState===h.OPEN&&this._websocketManager.send(h,d),d=this.findAvailableWorker(),this._isWorkersEnabled&&d&&"insertSubscriptionLog"!==v&&"countQuery"!==v&&"incCounter"!==v&&"supportCreateBillingUser"!==v&&"find"!==v&&"insertDocument"!==v&&"countWithQuery"!==v&&"findOne"!==v&&"updateDocumentProps"!==v&&"findWithOptions"!==v&&"getSignedUrl"!==v&&"updateDocument"!==v&&"insertErrorLog"!==v&&"getSignedUrls"!==v&&"removeDocument"!==v&&"getSignedUrlWithId"!==v&&"incorrectUser"!==v&&"reloadWS"!==v&&"reconnectWS"!==v&&"disconnectWS"!==v?(d="task-"+(0,common_1.objectIdHexString)(),this._inFlightRequests[d]={ws:h,messageId:g,method:v},this.queueTask(d,v,_,{id_user:h.id_user,user:h.user,id_ws:h.id_socket})):this.callMethodLocally(h,g,v,_)}e.label=11;case 11:return[2]}})})},ResolveIOMainServer.prototype.callMethodLocally=function(n,s,i,a){return __awaiter(this,void 0,void 0,function(){var r,t,o;return __generator(this,function(e){switch(e.label){case 0:r={messageId:s,hasError:!1,data:null},e.label=1;case 1:return e.trys.push([1,3,,4]),[4,(o=this._methodManager.callMethod).call.apply(o,__spreadArray([Object.assign({},this._methodManager,method_manager_1.MethodManager.prototype,{id_user:n.id_user,user:n.user,id_ws:n.id_socket}),i],__read(a),!1))];case 2:return o=e.sent(),r.data=o,[3,4];case 3:return t=e.sent(),r.hasError=!0,r.data=t.message||"Unknown error",[3,4];case 4:return n&&n.readyState===n.OPEN&&this._websocketManager.send(n,r),[2]}})})},ResolveIOMainServer.prototype.queueTask=function(e,r,t,o){this._taskQueue.push({taskId:e,method:r,params:t,userContext:o}),this.dispatchQueue()},ResolveIOMainServer.prototype.dispatchQueue=function(){if(this._taskQueue.length)for(var e=0;e<9999;e++){var r=this._taskQueue[0];if(!r)break;var t=this.findAvailableWorker();if(!t)break;this._taskQueue.shift(),this.assignTaskToWorker(t,r)}},ResolveIOMainServer.prototype.findAvailableWorker=function(){var e=this._workers.filter(function(e){return e.activeTasks<e.maxConcurrency});return e.length?(e.sort(function(e,r){return e.activeTasks-r.activeTasks}),e[0]):null},ResolveIOMainServer.prototype.assignTaskToWorker=function(r,t){r.activeTasks++;var e={type:"task",taskId:t.taskId,method:t.method,params:t.params,userContext:t.userContext};try{r.ws.send(JSON.stringify(e)),console.log("Assigned task",t.taskId,"to worker",r.id)}catch(e){console.error("Failed to send task to worker:",e),r.activeTasks=Math.max(0,r.activeTasks-1),this._taskQueue.unshift(t)}},ResolveIOMainServer.prototype.handleWorkerMessage=function(r,t){var e,o,n,s;try{s=JSON.parse(t,common_1.dateReviver)}catch(e){return void console.error("Failed to parse worker message:",t)}"taskComplete"===s.type&&((t=this._workers.find(function(e){return e.id===r}))?(t.activeTasks=Math.max(0,t.activeTasks-1),t=s.taskId,e=s.error,o=s.message,s=s.result,(n=this._inFlightRequests[t])?(delete this._inFlightRequests[t],s={messageId:n.messageId,hasError:!1,data:s},e&&(s.hasError=!0,s.data=o),n.ws&&n.ws.readyState===n.ws.OPEN&&this._websocketManager.send(n.ws,s)):console.error("No in-flight request found for task:",t),this.dispatchQueue()):console.error("Unknown worker for taskComplete:",r))},ResolveIOMainServer.prototype.unsubscribeWS=function(e){this._subscriptionManager&&this._subscriptionManager.getEnableDebug()&&console.log(new Date,"Server App","Unsub WS",e.user,e.id_socket),this._subscriptionManager.unsubscribeAll(e),e.removeAllListeners()},ResolveIOMainServer.prototype.getApp=function(){return this._app},ResolveIOMainServer.prototype.getServerConfig=function(){return resolveio_server_app_1.ResolveIOServer.getServerConfig()},ResolveIOMainServer}();exports.ResolveIOMainServer=ResolveIOMainServer;
2
2
  //# sourceMappingURL=server-app.js.map
package/server-app.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/server-app.ts"],"names":["http_1","require","express","bodyParser","xmlParser","WebSocket","jwt","moment","common_1","cron_manager_1","method_manager_1","subscription_manager_1","monitor_manager_1","log_collection_1","user_collection_1","home_1","auth_1","health_1","mongodb_1","websocket_manager_1","resolveio_server_app_1","ResolveIOMainServer","this","_offlineUpdates","sesMail","standardProgram","publicProgram","_rebootFlag","LOGGER","_clientRoutes","_lastErrorMsg","_debugMsgRecv","_debugMsgQueue","_isWorkersEnabled","_isWorkerInstance","_safeShutdown","_workers","_taskQueue","_inFlightRequests","_serverStartTime","Date","_monitorManager","MonitorManager","_monitorManagerFunction","MonitorManagerFunction","prototype","initServerApp","_this","initServerFlag","process","env","IS_WORKERS_ENABLED","IS_WORKER_INSTANCE","setInterval","_subscriptionManager","getEnableDebug","console","log","setTimeout","on","error","rej","__awaiter","diffTimeSec","diff","MongoNetworkTimeoutError","_methodManager","sendEmail","ResolveIOServer","getServerConfig","JSON","stringify","name","message","stack","_a","sent","exit","_serverHTTP","close","safeShutdown","MethodManager","_cronManager","CronManager","startWorkerInstance","_websocketManager","WebSocketManager","startServerInstance","SubscriptionManager","_serverWSS","listen","_app","use","json","limit","reviver","dateReviver","urlencoded","extended","parameterLimit","_portHTTP","PORT_HTTP","_portWSS","PORT_WSS","createServer","req","res","next","setHeader","setupAuthRoutes","setupHealthRoutes","setupHomeRoutes","wsUrl","connect","ws","lastComm","interval","readyState","OPEN","ping","WORKER_INDEX","NODE_APP_INSTANCE","pong","rawData","msg","parse","toString","e","type","handleIncomingTask","clearInterval","err","data","taskId","method","params","userContext","timedOut","timeoutHandle","sendWorkerResponse","managerThis","Object","assign","id_user","user","id_ws","callMethod","call","apply","__spreadArray","__read","result","_b","clearTimeout","err_1","payload","send","getActiveMonitorFunctions","length","setImmediate","getMongoConnection","then","getIsWorkersEnabled","getIsWorkerInstance","getWSList","clients","forEach","push","getWSUserList","getHTTPServer","getCronManager","getMethodManager","getSubscriptionManager","getMonitorManager","getRebootFlag","getWebSocketManager","keepAliveTimeout","headersTimeout","Server","port","verifyClient","info","cb","url","includes","urlParts","split","infoData","headers","origin","token","verify","decoded","Users","findById","fullname","readonly","workerId_1","lastComm_1","interval_1","objectIdHexString","id","activeTasks","maxConcurrency","handleWorkerMessage","filter","w","addWebSocket","createLoggedInUser","unsubscribeWS","socketData","processSocketMessage","now","getTime","duration","asMilliseconds","loggedInLatency","Array","isArray","socketData_1","__values","socketData_1_1","value","handleClientMessage","messageRoute","messageDate","messageId","some","a","roles","groups","views","b","super_admin","subType","pub","subscribe","slice","unsubscribe","serverRes","hasError","offlineUpdates","i","update","shift","updateMessageId","serverResMethod","getLocalLogManager","writeLog","_id","collection","id_document","getBinarySize","route","Logs","insertOne","client","instance","_methods","err_3","getMongoManager","invalidateQueryCache","splice","map","indexOf","dataCopy","msgId","methodName","ack","worker","findAvailableWorker","queueTask","callMethodLocally","err_4","dispatchQueue","item","assignTaskToWorker","candidates","x","sort","task","Math","max","unshift","workerId","messageStr","inflight","find","unsubscribeAll","removeAllListeners","getApp","exports"],"mappings":"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","file":"server-app.js","sourcesContent":["import { createServer, Server } from 'http';\nimport * as express from 'express';\nimport * as bodyParser from 'body-parser';\nimport * as xmlParser from 'express-xml-bodyparser';\nimport * as WebSocket from 'ws';\nimport * as jwt from 'jsonwebtoken';\nimport * as moment from 'moment-timezone';\n\nimport { dateReviver, getBinarySize, objectIdHexString } from './util/common';\nimport { CronManager } from './managers/cron.manager';\nimport { MethodManager } from './managers/method.manager';\nimport { SubscriptionManager } from './managers/subscription.manager';\nimport { MonitorManager, MonitorManagerFunction } from './managers/monitor.manager';\nimport { ServerResponseModel } from './models/server-response.model';\nimport { Logs } from './collections/log.collection';\nimport { Users } from './collections/user.collection';\n\nimport { setupHomeRoutes } from './http/home';\nimport { setupAuthRoutes } from './http/auth';\nimport { setupHealthRoutes } from './http/health';\nimport { MongoNetworkTimeoutError } from 'mongodb';\n\nimport { WebSocketManager } from './managers/websocket.manager';\nimport { ResolveIOServer } from './resolveio-server-app';\n\ninterface WorkerConnection {\n\tid: string;\n\tws: WebSocket;\n\tactiveTasks: number;\n\tmaxConcurrency: number;\n}\n\ninterface TaskQueueItem {\n\ttaskId: string;\n\tmethod: string;\n\tparams: any[];\n\tuserContext?: { id_user?: string; user?: string; id_ws?: string };\n}\n\ninterface InFlightRequest {\n\tws: WebSocket; // the client's WebSocket\n\tmessageId: number; // the ID so the client knows which call this corresponds to\n\tmethod: string;\n}\n\nexport class ResolveIOMainServer {\n\tprivate _app: express.Application;\n\tprivate _serverHTTP: Server;\n\tprivate _portHTTP: string | number;\n\tprivate _serverWSS: WebSocket.Server;\n\tprivate _portWSS: number;\n\tprivate _offlineUpdates = [];\n\tpublic sesMail = false;\n\tprivate standardProgram = false;\n\tprivate publicProgram = false;\n\tprivate _rebootFlag = false;\n\n\tprivate LOGGER = 'ERROR'; //ERROR / DEBUG\n\n\tprivate _websocketManager: WebSocketManager;\n\tprivate _monitorManager: MonitorManager;\n\tprivate _monitorManagerFunction: MonitorManagerFunction;\n\tprivate _subscriptionManager: SubscriptionManager;\n\tprivate _methodManager: MethodManager;\n\tprivate _cronManager: CronManager;\n\tprivate _clientRoutes: string[] = [];\n\n\tprivate _serverStartTime: Date;\n\tprivate _lastErrorMsg: Date = null;\n\n\tprivate _debugMsgRecv = 0;\n\tprivate _debugMsgQueue = 0;\n\n\tprivate _isWorkersEnabled = false;\n\tprivate _isWorkerInstance = false;\n\n\tprivate _safeShutdown = false;\n\n\tprivate _workers: WorkerConnection[] = [];\n\tprivate _taskQueue: TaskQueueItem[] = [];\n\tprivate _inFlightRequests: { [taskId: string]: InFlightRequest } = {};\n\n\tconstructor() {\n\t\tthis._serverStartTime = new Date();\n\t\tthis._lastErrorMsg = null;\n\t\tthis._monitorManager = new MonitorManager();\n\t\tthis._monitorManagerFunction = new MonitorManagerFunction();\n\t}\n\n\tinitServerApp() {\n\t\t// Check for workers and decide what to start\n\t\tthis._isWorkersEnabled = process.env.IS_WORKERS_ENABLED === 'true';\n\t\tthis._isWorkerInstance = process.env.IS_WORKER_INSTANCE === 'true';\n\n\t\tsetInterval(() => {\n\t\t\tif (this._subscriptionManager && this._subscriptionManager.getEnableDebug()) {\n\t\t\t\tconsole.log(new Date(), 'Server App', 'Msg Recv Hits', this._debugMsgRecv);\n\t\t\t\tconsole.log(new Date(), 'Server App', 'Msg Queue Hits', this._debugMsgQueue);\n\t\t\t}\n\n\t\t\tthis._debugMsgQueue = 0;\n\t\t\tthis._debugMsgRecv = 0;\n\t\t}, 60000);\n\n\t\tlet initServerFlag = false;\n\n\t\tsetTimeout(() => {\n\t\t\tinitServerFlag = true;\n\t\t}, 5000);\n\n\t\tprocess.on('unhandledRejection', async (error, rej) => {\n\t\t\t// Condition to filter out the MongoError with code 48 (NamespaceExists)\n\t\t\tif (error && error['name'] === 'MongoError' && error['code'] === 48) {\n\t\t\t\treturn; // Simply return without doing anything further\n\t\t\t}\n\n\t\t\tif (error && error['name'] === 'MongoServerError' && !initServerFlag) {\n\t\t\t\treturn; // Simply return without doing anything further\n\t\t\t}\n\n\t\t\tconsole.error(new Date(), 'Unhandled Rejection at Promise', [error, rej]);\n\t\t\t\n\t\t\tlet diffTimeSec = moment().diff(this._serverStartTime, 'seconds');\n\n\t\t\t// If this is a MongoNetworkTimeoutError, handle it specifically\n\t\t\tif (error && (error['name'] === 'MongoNetworkTimeoutError' || error instanceof MongoNetworkTimeoutError)) {\n\t\t\t\tif (diffTimeSec > 60 && !this._lastErrorMsg) {\n\t\t\t\t\tthis._lastErrorMsg = new Date();\n\t\t\t\t\tsetTimeout(() => {\n\t\t\t\t\t\tthis._lastErrorMsg = null;\n\t\t\t\t\t}, 60000);\n\n\t\t\t\t\t// Sending email notification (using your existing method)\n\t\t\t\t\tawait this._methodManager.sendEmail('dev@resolveio.com', 'SERVER - MongoNetworkTimeoutError - Quitting NodeJS - ' + ResolveIOServer.getServerConfig()['CLIENT_NAME'], JSON.stringify({\n\t\t\t\t\t\tname: error['name'],\n\t\t\t\t\t\tmessage: error['message'],\n\t\t\t\t\t\tstack: error['stack']\n\t\t\t\t\t}, null, 2));\n\n\t\t\t\t\t// Exiting the process\n\t\t\t\t\tprocess.exit(1);\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if (error && error['name'] === 'MongoError' && error['message'] === 'not master') {\n\t\t\t\tif (diffTimeSec > 60 && !this._lastErrorMsg) {\n\t\t\t\t\tthis._lastErrorMsg = new Date();\n\n\t\t\t\t\tsetTimeout(() => {\n\t\t\t\t\t\tthis._lastErrorMsg = null;\n\t\t\t\t\t}, 60000);\n\n\t\t\t\t\tawait this._methodManager.sendEmail('dev@resolveio.com', 'SERVER - Unhandled Rejection - Quitting NodeJS - ' + ResolveIOServer.getServerConfig()['CLIENT_NAME'], JSON.stringify([error['name'], error['message'], error['stack']], null, 2));\n\t\t\t\t}\n\n\t\t\t\tprocess.exit(1);\n\t\t\t}\n\t\t\telse if (error && error['name'] === 'MongoError' && error['message'] === 'not master and slaveOk=false') {\n\t\t\t\tif (diffTimeSec > 60 && !this._lastErrorMsg) {\n\t\t\t\t\tthis._lastErrorMsg = new Date();\n\n\t\t\t\t\tsetTimeout(() => {\n\t\t\t\t\t\tthis._lastErrorMsg = null;\n\t\t\t\t\t}, 60000);\n\n\t\t\t\t\tawait this._methodManager.sendEmail('dev@resolveio.com', 'SERVER - Unhandled Rejection - Quitting NodeJS - ' + ResolveIOServer.getServerConfig()['CLIENT_NAME'], JSON.stringify([error['name'], error['message'], error['stack']], null, 2));\n\t\t\t\t}\n\n\t\t\t\tprocess.exit(1);\n\t\t\t}\n\t\t\telse if (error) {\n\t\t\t\tif (error['name'] !== 'StatusError' && error['message'] !== '') {\n\t\t\t\t\tif (diffTimeSec > 60 && !this._lastErrorMsg) {\n\t\t\t\t\t\tthis._lastErrorMsg = new Date();\n\n\t\t\t\t\t\tsetTimeout(() => {\n\t\t\t\t\t\t\tthis._lastErrorMsg = null;\n\t\t\t\t\t\t}, 60000);\n\n\t\t\t\t\t\tthis._methodManager.sendEmail('dev@resolveio.com', 'SERVER - Unhandled Rejection - ' + ResolveIOServer.getServerConfig()['CLIENT_NAME'], JSON.stringify([error['name'], error['message'], error['stack']], null, 2));\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\n\t\tprocess.on('uncaughtException', async error => {\n\t\t\tconsole.error(error, 'Uncaught Exception thrown');\n\n\n\n\t\t\tlet diffTimeSec = moment().diff(this._serverStartTime, 'seconds');\n\n\t\t\tif (diffTimeSec > 60 && !this._lastErrorMsg) {\n\t\t\t\tthis._lastErrorMsg = new Date();\n\n\t\t\t\tsetTimeout(() => {\n\t\t\t\t\tthis._lastErrorMsg = null;\n\t\t\t\t}, 60000);\n\t\t\t\t\n\t\t\t\tawait this._methodManager.sendEmail('dev@resolveio.com', 'SERVER - Unhandled Exception - ' + ResolveIOServer.getServerConfig()['CLIENT_NAME'], JSON.stringify([error['name'], error['message'], error['stack']], null, 2));\n\t\t\t}\n\t\t});\n\n\t\t//PM2 wants to reboot/restart\n\t\tprocess.on('SIGINT', () => {\n\t\t\tthis._rebootFlag = true;\n\t\t\tif (this._serverHTTP) {\n\t\t\t\tthis._serverHTTP.close();\n\t\t\t}\n\t\t\tthis.safeShutdown();\n\t\t});\n\n\t\tprocess.on('SIGTERM', () => {\n\t\t\tthis._rebootFlag = true;\n\t\t\tif (this._serverHTTP) {\n\t\t\t\tthis._serverHTTP.close();\n\t\t\t}\n\t\t\tthis.safeShutdown();\n\t\t});\n\n\t\tprocess.on('SIGQUIT', () => {\n\t\t\tthis._rebootFlag = true;\n\t\t\tif (this._serverHTTP) {\n\t\t\t\tthis._serverHTTP.close();\n\t\t\t}\n\t\t\tthis.safeShutdown();\n\t\t});\n\n\t\tif (this.LOGGER === 'DEBUG') {\n\t\t\tconsole.log('Starting ResolveIO Server');\n\t\t}\n\n\t\tif (this._isWorkersEnabled) {\n\t\t\tif (this._isWorkerInstance) {\n\t\t\t\tconsole.log('Running as a Worker instance');\n\t\t\t\tthis._methodManager = new MethodManager(this._monitorManagerFunction, this._isWorkersEnabled, this._isWorkerInstance);\n\t\t\t\tthis._cronManager = new CronManager();\n\t\t\t\tthis.startWorkerInstance();\n\t\t\t}\n\t\t\telse {\n\t\t\t\tconsole.log('Running as a Server instance');\n\t\t\t\tthis._websocketManager = new WebSocketManager(this);\n\t\t\t\tthis.startServerInstance();\n\t\t\t\tthis._methodManager = new MethodManager(this._monitorManagerFunction, this._isWorkersEnabled, this._isWorkerInstance);\n\t\t\t\tthis._subscriptionManager = new SubscriptionManager(this._serverWSS, ResolveIOServer.getServerConfig(), this._monitorManagerFunction);\n\t\t\t\tthis.listen();\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\tconsole.log('Running with Workers Disabled');\n\t\t\tthis._websocketManager = new WebSocketManager(this);\n\t\t\tthis.startServerInstance();\n\t\t\tthis._methodManager = new MethodManager(this._monitorManagerFunction, this._isWorkersEnabled, this._isWorkerInstance);\n\t\t\tthis._subscriptionManager = new SubscriptionManager(this._serverWSS, ResolveIOServer.getServerConfig(), this._monitorManagerFunction);\n\t\t\tthis._cronManager = new CronManager();\n\t\t\tthis.listen();\n\t\t}\n\t}\n\n\tprivate startServerInstance() {\n\t\t// Start express app\n\t\tthis._app = express();\n\n\t\tthis._app.use(bodyParser.json({limit: '50mb', reviver: dateReviver}));\n\t\tthis._app.use(bodyParser.urlencoded({limit: '50mb', extended: true, parameterLimit: 1000000 }));\n\t\tthis._app.use(xmlParser());\n\t\t\n\t\t// Set port\n\t\tthis._portHTTP = process.env.PORT_HTTP || ResolveIOServer.getServerConfig()['PORT_HTTP'] || 8080;\n\t\tthis._portWSS = process.env.PORT_WSS || ResolveIOServer.getServerConfig()['PORT_WSS'] || 8081;\n\n\t\tif (this.LOGGER === 'DEBUG') {\n\t\t\tconsole.log('Setup ports');\n\t\t}\n\n\t\t// Create http server and websock server\n\t\tthis.createServer();\n\n\t\tif (this.LOGGER === 'DEBUG') {\n\t\t\tconsole.log('Create server');\n\t\t}\n\n\t\t// Set CORS\n\t\tthis._app.use(function (req, res, next) {\n\t\t\tres.setHeader('Access-Control-Allow-Origin', '*');\n\t\t\tres.setHeader('Access-Control-Allow-Methods', 'GET, POST');\n\t\t\tres.setHeader('Access-Control-Allow-Headers', 'X-Requested-With,content-type');\n\t\t\tres.setHeader('Access-Control-Allow-Credentials', 'false');\n\t\t\tnext();\n\t\t});\n\n\t\tif (this.LOGGER === 'DEBUG') {\n\t\t\tconsole.log('Setup cors');\n\t\t}\n\n\t\t// Set up http login route\n\t\tsetupAuthRoutes(this, this._app, ResolveIOServer.getServerConfig());\n\t\tsetupHealthRoutes(this._app, ResolveIOServer.getServerConfig());\n\n\t\tif (ResolveIOServer.getServerConfig()['CLIENT_NAME'] === 'ResolveIO' || this.standardProgram) {\n\t\t\tsetupHomeRoutes(this, this._app, ResolveIOServer.getServerConfig());\n\t\t}\n\n\t\tif (this.LOGGER === 'DEBUG') {\n\t\t\tconsole.log('Setup express routes');\n\t\t}\n\t}\n\n\tprivate async startWorkerInstance() {\n\t\tconsole.log(new Date(), 'Worker instance started, connecting to main server via WebSocket...');\n\n\t\tlet wsUrl = ResolveIOServer.getServerConfig()['SERVER_URL'] + '/websocket?workerToken=' + ResolveIOServer.getServerConfig()['WORKER_TOKEN'];\n\n\t\tconst connect = () => {\n\t\t\tconst ws = new WebSocket(wsUrl);\n\n\t\t\tlet lastComm = null;\n\n\t\t\tif (ws && ws.readyState === ws.OPEN) {\n\t\t\t\tws.ping();\n\t\t\t}\n\n\t\t\tlet interval = setInterval(() => {\n\t\t\t\tif (!lastComm) {\n\t\t\t\t\tws.close();\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tlastComm = null;\n\n\t\t\t\t\tif (ws && ws.readyState === ws.OPEN) {\n\t\t\t\t\t\tws.ping();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}, 15000);\n\n\t\t\tws.on('open', () => {\n\t\t\t\tconsole.log(new Date(), 'Connected to main server as worker', process.env.WORKER_INDEX, process.env.NODE_APP_INSTANCE);\n\t\t\t});\n\n\t\t\tws.on('ping', () => {\n\t\t\t\tws.pong(); // manually respond\n\t\t\t});\n\n\t\t\tws.on('pong', () => {\n\t\t\t\tlastComm = new Date();\n\t\t\t});\n\n\t\t\tws.on('message', async (rawData) => {\n\t\t\t\tlet msg: any;\n\t\t\t\ttry {\n\t\t\t\t\tmsg = JSON.parse(rawData.toString(), dateReviver);\n\t\t\t\t}\n\t\t\t\tcatch (e) {\n\t\t\t\t\tconsole.error('Worker parse error', e);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\t// We expect: { type: 'task', taskId, method, params, userContext? }\n\t\t\t\tif (msg.type === 'task') {\n\t\t\t\t\tthis.handleIncomingTask(ws, msg);\n\t\t\t\t}\n\t\t\t});\n\n\t\t\tws.on('close', () => {\n\t\t\t\tconsole.log(new Date(), 'Disconnected from main server. Reconnecting in 5s...');\n\t\t\t\tsetTimeout(connect, 5000);\n\t\t\t\tclearInterval(interval);\n\t\t\t});\n\n\t\t\tws.on('error', (err) => {\n\t\t\t\tconsole.error(new Date(), 'Worker WS error:', err);\n\t\t\t\tws.close();\n\t\t\t});\n\t\t};\n\n\t\tconnect();\n\t}\n\n\tprivate async handleIncomingTask(ws: WebSocket, data: any) {\n\t\tlet { taskId, method, params, userContext } = data;\n\t\tif (!taskId || !method) {\n\t\t\tconsole.log('Invalid task message received', data);\n\t\t\treturn;\n\t\t}\n\n\t\tlet timedOut = false;\n\t\tlet timeoutHandle = setTimeout(() => {\n\t\t\ttimedOut = true;\n\t\t\tconsole.error('Worker timed out on task:', taskId);\n\n\t\t\tthis.sendWorkerResponse(ws, {\n\t\t\t\ttype: 'taskComplete',\n\t\t\t\ttaskId,\n\t\t\t\terror: true,\n\t\t\t\tmessage: 'Task timed out'\n\t\t\t});\n\t\t}, 120000);\n\n\t\ttry {\n\t\t\tlet managerThis = Object.assign({}, this._methodManager, MethodManager.prototype, {\n\t\t\t\tid_user: userContext?.id_user || '',\n\t\t\t\tuser: userContext?.user || '',\n\t\t\t\tid_ws: userContext?.id_ws || ''\n\t\t\t});\n\n\t\t\tlet result = await this._methodManager.callMethod.call(managerThis, method, ...params);\n\n\t\t\tif (!timedOut) {\n\t\t\t\tclearTimeout(timeoutHandle);\n\t\t\t\tthis.sendWorkerResponse(ws, {\n\t\t\t\t\ttype: 'taskComplete',\n\t\t\t\t\ttaskId,\n\t\t\t\t\terror: false,\n\t\t\t\t\tresult\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t\tcatch (err) {\n\t\t\tif (!timedOut) {\n\t\t\t\tclearTimeout(timeoutHandle);\n\t\t\t\tconsole.error('Worker failed task:', taskId, err);\n\t\t\t\tthis.sendWorkerResponse(ws, {\n\t\t\t\t\ttype: 'taskComplete',\n\t\t\t\t\ttaskId,\n\t\t\t\t\terror: true,\n\t\t\t\t\tmessage: err.message || 'Unknown error'\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate sendWorkerResponse(ws: WebSocket, payload: any) {\n\t\ttry {\n\t\t\tws.send(JSON.stringify(payload));\n\t\t}\n\t\tcatch (err) {\n\t\t\tconsole.error('Failed to send worker response:', err);\n\t\t}\n\t}\n\n\tprivate safeShutdown() {\n\t\tif (!this._safeShutdown) {\n\t\t\tconsole.log(new Date(), 'Safe Shutdown Command Received');\n\t\t}\n\n\t\tif (\n\t\t\t!this._monitorManagerFunction.getActiveMonitorFunctions().length\n\t\t\t&& !this._offlineUpdates.length\n\t\t) {\n\t\t\tif (ResolveIOServer.getMongoConnection()) {\n\t\t\t\tResolveIOServer.getMongoConnection().close(false).then(() => {\n\t\t\t\t\tconsole.log(new Date(), 'Safe Exit Complete, Process Exit');\n\t\t\t\t\tprocess.exit(0);\n\t\t\t\t}, () => { process.exit(1); });\n\t\t\t}\n\t\t\telse {\n\t\t\t\tprocess.exit(0);\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\tif (!this._safeShutdown) {\n\t\t\t\tthis._safeShutdown = true;\n\n\t\t\t\tsetTimeout(() => {\n\t\t\t\t\tthis._safeShutdown = false;\n\t\t\t\t}, 1000);\n\n\t\t\t\tconsole.log(new Date(), 'Safe Exit In Progress', \n\t\t\t\t\tthis._monitorManagerFunction.getActiveMonitorFunctions().length,\n\t\t\t\t\tthis._offlineUpdates.length\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tsetImmediate(() => {\n\t\t\t\tthis.safeShutdown();\n\t\t\t});\n\t\t}\n\t}\n\n\tgetIsWorkersEnabled() {\n\t\treturn this._isWorkersEnabled;\n\t}\n\n\tgetIsWorkerInstance() {\n\t\treturn this._isWorkerInstance;\n\t}\n\n\tpublic getWSList() {\n\t\tlet res = [];\n\t\tthis._serverWSS.clients.forEach((ws: WebSocket) => {\n\t\t\tres.push(ws['id_socket']);\n\t\t});\n\t\treturn res;\n\t}\n\n\tpublic getWSUserList() {\n\t\tlet res = [];\n\t\tthis._serverWSS.clients.forEach((ws: WebSocket) => {\n\t\t\tres.push(ws['id_user']);\n\t\t});\n\t\treturn res;\n\t}\n\n\tpublic getHTTPServer() {\n\t\treturn this._serverHTTP;\n\t}\n\n\tpublic getCronManager() {\n\t\treturn this._cronManager;\n\t}\n\n\tpublic getMethodManager() {\n\t\treturn this._methodManager;\n\t}\n\n\tpublic getSubscriptionManager() {\n\t\treturn this._subscriptionManager;\n\t}\n\n\tpublic getMonitorManager() {\n\t\treturn this._monitorManager;\n\t}\n\n\tpublic getRebootFlag() {\n\t\treturn this._rebootFlag;\n\t}\n\n\tpublic getWebSocketManager(): WebSocketManager {\n\t\treturn this._websocketManager;\n\t}\n\n\tprivate createServer(): void {\n\t\tthis._serverHTTP = createServer(this._app);\n\t\tthis._serverHTTP.keepAliveTimeout = 65000;\n\t\tthis._serverHTTP.headersTimeout = 66000;\n\n\t\tthis._serverWSS = new WebSocket.Server({\n\t\t\tport: this._portWSS,\n\t\t\tverifyClient: this.publicProgram ? null : async (info, cb) => {\n\t\t\t\tif (this._rebootFlag) {\n\t\t\t\t\tcb(false, 409, 'Unable To Process');\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tif (this.LOGGER === 'DEBUG') {\n\t\t\t\t\t\tconsole.log('Verify Client', info, cb);\n\t\t\t\t\t}\n\n\t\t\t\t\t// If it's a worker, we might skip token checks or do a simple check:\n\t\t\t\t\tif (info.req.url && info.req.url.includes('workerToken=')) {\n\t\t\t\t\t\tlet urlParts = info.req.url.split('workerToken='); \n\t\t\t\t\t\tlet workerToken = urlParts[1] || '';\n\n\t\t\t\t\t\tif (workerToken === ResolveIOServer.getServerConfig()['WORKER_TOKEN']) {\n\t\t\t\t\t\t\tcb(true);\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\tcb(false, 401, 'Unauthorized');\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\tlet infoData = (<string>info.req.headers['sec-websocket-protocol']).split(/,/);\n\n\t\t\t\t\tif (\n\t\t\t\t\t\tinfo.origin !== ResolveIOServer.getServerConfig()['ROOT_URL']\n\t\t\t\t\t\t&& info.origin !== ResolveIOServer.getServerConfig()['SEC_ROOT_URL']\n\t\t\t\t\t\t&& info.origin !== ResolveIOServer.getServerConfig()['RESOLVEIO_URL']\n\t\t\t\t\t\t&& info.origin !== ResolveIOServer.getServerConfig()['RESOLVEIO_SECONDARY_URL']\n\t\t\t\t\t) {\n\t\t\t\t\t\tcb(false, 401, 'Unauthorized');\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tlet token = infoData[0];\n\t\t\t\t\t\tif (!token) {\n\t\t\t\t\t\t\tcb(false, 401, 'Unauthorized');\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\tjwt.verify(token, ResolveIOServer.getServerConfig()['JWT_SECRET'], async (err, decoded) => {\n\t\t\t\t\t\t\t\tif (err) {\n\t\t\t\t\t\t\t\t\tcb(false, 401, 'Unauthorized');\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\t\tinfo.req['id_user'] = decoded['id_user'];\n\t\t\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\t\t\tlet user = await Users.findById(decoded['id_user']);\n\t\t\t\t\t\t\t\t\t\tif (user) {\n\t\t\t\t\t\t\t\t\t\t\tinfo.req['user'] = user.fullname;\n\t\t\t\t\t\t\t\t\t\t\tinfo.req['user_readonly'] = user.readonly || false;\n\t\t\t\t\t\t\t\t\t\t\tinfo.req['doc_user'] = user;\n\t\t\t\t\t\t\t\t\t\t\tcb(true);\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\t\t\t\tcb(false);\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\tcatch (err) {\n\t\t\t\t\t\t\t\t\t\tcb(false);\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t}\n\n\t/**\n\t * Listen for connections from clients or workers.\n\t */\n\tprivate listen(): void {\n\t\tthis._serverHTTP.listen(this._portHTTP, () => {\n\t\t\tconsole.log('Running server on port %s', this._portHTTP);\n\t\t});\n\n\t\tthis._serverWSS.on('listening', () => {\n\t\t\tconsole.log('Running server on port %s', this._portWSS);\n\t\t});\n\n\t\tthis._serverWSS.on('connection', (ws, req) => {\n\t\t\tif (req.url && req.url.includes('workerToken=')) {\n\t\t\t\t// It's a WORKER\n\t\t\t\tlet workerId = objectIdHexString();\n\t\t\t\tws['id_worker'] = workerId;\n\n\t\t\t\t// For demonstration, let each worker handle up to 2 tasks concurrently\n\t\t\t\tlet maxConcurrency = 2;\n\n\t\t\t\tthis._workers.push({\n\t\t\t\t\tid: workerId,\n\t\t\t\t\tws: ws,\n\t\t\t\t\tactiveTasks: 0,\n\t\t\t\t\tmaxConcurrency: maxConcurrency\n\t\t\t\t});\n\n\t\t\t\tlet lastComm = null;\n\n\t\t\t\tif (ws && ws.readyState === ws.OPEN) {\n\t\t\t\t\tws.ping();\n\t\t\t\t}\n\n\t\t\t\tlet interval = setInterval(() => {\n\t\t\t\t\tif (!lastComm) {\n\t\t\t\t\t\tws.close();\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tlastComm = null;\n\t\n\t\t\t\t\t\tif (ws && ws.readyState === ws.OPEN) {\n\t\t\t\t\t\t\tws.ping();\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}, 15000);\n\n\t\t\t\tconsole.log(new Date(), 'Worker connected:', workerId);\n\n\t\t\t\tws.on('message', (message: string) => {\n\t\t\t\t\tthis.handleWorkerMessage(workerId, message);\n\t\t\t\t});\n\n\t\t\t\tws.on('ping', () => {\n\t\t\t\t\tws.pong(); // manually respond\n\t\t\t\t});\n\n\t\t\t\tws.on('pong', () => {\n\t\t\t\t\tlastComm = new Date();\n\t\t\t\t});\n\n\t\t\t\tws.on('close', () => {\n\t\t\t\t\tconsole.log(new Date(), 'Worker disconnected:', workerId);\n\t\t\t\t\tthis._workers = this._workers.filter(w => w.id !== workerId);\n\t\t\t\t\tclearInterval(interval);\n\t\t\t\t});\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// Normal client\n\t\t\t\tws['id_socket'] = objectIdHexString();\n\t\t\t\tws['id_user'] = req['id_user'];\n\t\t\t\tws['user'] = req['user'];\n\t\t\t\tws['user_readonly'] = req['user_readonly'];\n\t\t\t\tws['doc_user'] = req['doc_user'];\n\n\t\t\t\tthis._websocketManager.addWebSocket(ws);\n\n\t\t\t\tthis._subscriptionManager.createLoggedInUser(ws['id_socket']).then(() => {\n\t\t\t\t\tsetTimeout(() => {\n\t\t\t\t\t\tws['pingTime'] = new Date();\n\t\t\t\t\t\tws.send('ping', (error) => {\n\t\t\t\t\t\t\tif (error) {\n\t\t\t\t\t\t\t\tif (this._subscriptionManager.getEnableDebug()) {\n\t\t\t\t\t\t\t\t\tconsole.log(new Date(), 'Server App', 'Error WS Ping');\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tthis.unsubscribeWS(ws);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t});\n\t\t\t\t\t}, 5000);\n\t\t\t\t});\n\n\t\t\t\tif (this.LOGGER === 'DEBUG') {\n\t\t\t\t\tconsole.log('Connection from user: ' + req['user']);\n\t\t\t\t}\n\t\t\t\n\t\t\t\tws['isAlive'] = true;\n\t\t\t\tws['retryCnt'] = 0;\n\n\t\t\t\tws.on('message', async (message: string) => {\n\t\t\t\t\tthis._debugMsgRecv += 1;\n\t\t\t\t\tlet socketData = [];\n\t\t\t\t\n\t\t\t\t\ttry {\n\t\t\t\t\t\tsocketData = JSON.parse(message, dateReviver);\n\t\t\t\t\t}\n\t\t\t\t\tcatch (e) {\n\t\t\t\t\t\tconsole.log('Error - JSON.parse', message);\n\t\t\t\t\t\tthis._methodManager.sendEmail(\n\t\t\t\t\t\t\t'dev@resolveio.com', \n\t\t\t\t\t\t\t'SERVER - JSON Parse Error - ' + ResolveIOServer.getServerConfig()['CLIENT_NAME'], \n\t\t\t\t\t\t\tJSON.stringify([message, e])\n\t\t\t\t\t\t);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\t// call our existing processSocketMessage\n\t\t\t\t\tthis.processSocketMessage(ws, socketData);\n\t\t\t\t})\n\t\t\t\t.on('end', () => {\n\t\t\t\t\tthis.unsubscribeWS(ws);\n\t\t\t\t})\n\t\t\t\t.on('close', () => {\n\t\t\t\t\tthis.unsubscribeWS(ws);\n\t\t\t\t})\n\t\t\t\t.on('error', error => {\n\t\t\t\t\tthis.unsubscribeWS(ws);\n\t\t\t\t});\n\t\t\t}\n\t\t});\n\n\t\t// Keep alive timer\n\t\tsetInterval(() => {\n\t\t\tthis._serverWSS.clients.forEach((ws: WebSocket) => {\n\t\t\t\tif (ws['pingTime'] && Date.now() - ws['pingTime'].getTime() >= 20000) {\n\t\t\t\t\tif (ws['isAlive'] === false) {\n\t\t\t\t\t\tws['retryCnt']++;\n\t\t\t\t\t\tif (ws['retryCnt'] >= 3) {\n\t\t\t\t\t\t\tthis.unsubscribeWS(ws);\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\tws['pingTime'] = new Date();\n\t\t\t\t\t\t\tws.send('ping', (error) => {\n\t\t\t\t\t\t\t\tif (error) {\n\t\t\t\t\t\t\t\t\tif (this._subscriptionManager.getEnableDebug()) {\n\t\t\t\t\t\t\t\t\t\tconsole.log(new Date(), 'Server App', 'Error WS Ping');\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\tthis.unsubscribeWS(ws);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tws['retryCnt'] = 0;\n\t\t\t\t\t\tws['isAlive'] = false;\n\t\t\t\t\t\tws['pingTime'] = new Date();\n\t\t\t\t\t\tws.send('ping', (error) => {\n\t\t\t\t\t\t\tif (error) {\n\t\t\t\t\t\t\t\tif (this._subscriptionManager.getEnableDebug()) {\n\t\t\t\t\t\t\t\t\tconsole.log(new Date(), 'Server App', 'Error WS Ping');\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tthis.unsubscribeWS(ws);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t});\n\t\t}, 20000);\n\t}\n\n\tprivate async processSocketMessage(ws: WebSocket, socketData: any) {\n\t\tif (typeof socketData === 'string' && socketData === 'ping') {\n\t\t\tif (ws && ws.readyState === ws.OPEN) {\n\t\t\t\tws.send('pong');\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t\telse if (typeof socketData === 'string' && socketData === 'pong') {\n\t\t\tws['isAlive'] = true;\n\t\t\tws['pongTime'] = new Date();\n\t\t\tws['latency'] = moment.duration(moment(ws['pongTime']).diff(ws['pingTime'])).asMilliseconds();\n\t\t\tthis._subscriptionManager.loggedInLatency(ws);\n\t\t\treturn;\n\t\t}\n\n\t\t// If the top level is not an array, let's skip\n\t\tif (!Array.isArray(socketData[0])) {\n\t\t\tconsole.log('Invalid message format (expected array of arrays)', socketData);\n\t\t\treturn;\n\t\t}\n\n\t\t// Handle each sub-message\n\t\tfor (let message of socketData) {\n\t\t\tawait this.handleClientMessage(ws, message);\n\t\t}\n\t}\n\n\tprivate async handleClientMessage(ws: WebSocket, msg: any[]): Promise<void> {\n\t\t// This is basically your old logic from processSocketMessage,\n\t\t// but we'll insert our worker-queue logic for \"method\" calls.\n\n\t\tlet messageRoute = msg[0];\n\t\tlet messageDate = msg[1];\n\t\tlet messageId = msg[2];\n\t\tlet type = msg[3];\n\n\t\tif (!this.publicProgram && this._clientRoutes.some(a => messageRoute.includes(a)) && !ws['doc_user'].roles.groups.some(a => a.views.some(b => messageRoute.includes(b) || b.includes(messageRoute))) && !ws['doc_user'].roles.super_admin) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (type === 'subscription') {\n\t\t\tlet subType = msg[4];\n\t\t\tlet pub = msg[5];\n\n\t\t\tif (subType === 'sub') {\n\t\t\t\tthis._subscriptionManager.subscribe(messageRoute, messageDate, ws, messageId, pub, msg.slice(6));\n\t\t\t}\n\t\t\telse {\n\t\t\t\tthis._subscriptionManager.unsubscribe(messageRoute, messageDate, ws, messageId, pub, msg.slice(6));\n\t\t\t}\n\t\t}\n\t\telse if (!this.publicProgram && type === 'offline') {\n\t\t\tlet serverRes: ServerResponseModel = {\n\t\t\t\tmessageId: messageId,\n\t\t\t\thasError: false,\n\t\t\t\tdata: 'ACK'\n\t\t\t};\n\n\t\t\tif (ws && ws.readyState === ws.OPEN) {\n\t\t\t\tthis._websocketManager.send(ws, serverRes);\n\t\t\t}\n\n\t\t\tthis._offlineUpdates.push(ws);\n\t\t\tlet offlineUpdates = msg[4];\n\n\t\t\tfor (let i = 0; i < offlineUpdates.length; i++) {\n\t\t\t\tlet update = offlineUpdates[i];\n\n\t\t\t\tlet data = update.data;\n\n\t\t\t\tlet updateRoute = data.shift();\n\t\t\t\tlet updateDate = data.shift();\n\t\t\t\tlet updateMessageId = data.shift();\n\t\t\t\tlet updateType = data.shift();\n\t\t\t\tlet method = data.shift();\n\n\t\t\t\tlet serverResMethod: ServerResponseModel = {\n\t\t\t\t\tmessageId: updateMessageId,\n\t\t\t\t\thasError: false,\n\t\t\t\t\tdata: 'ACK'\n\t\t\t\t};\n\n\t\t\t\tif (ws && ws.readyState === ws.OPEN) {\n\t\t\t\t\tthis._websocketManager.send(ws, serverResMethod);\n\t\t\t\t}\n\n\t\t\t\tif (method === 'insertDocument' && data[0] === 'driver-gps') {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (method !== 'reportBuilderGetResults' && method !== 'reportBuilderGetDistinctValue' && method !== 'reportBuilderBuildTree' && method !== 'generatePDF' && method !== 'getWOOfflineData' && method !== 'countQuery' && method !== 'countWithQuery' && method !== 'countCollectionWithQuery' && method !== 'find' && method !== 'findOne' && method !== 'findWithOptions' && method !== 'getDrivers' && method !== 'processAirdropDistribution') {\n\t\t\t\t\tif (\n\t\t\t\t\t\tResolveIOServer.getServerConfig()['ROOT_URL'] !== 'https://resolveio.com'\n\t\t\t\t\t&& ResolveIOServer.getServerConfig()['ROOT_URL'] !== 'http://localhost:4200'\n\t\t\t\t\t) {\n\t\t\t\t\t\tResolveIOServer.getLocalLogManager().writeLog({\n\t\t\t\t\t\t\ttype: 'log',\n\t\t\t\t\t\t\tdata: {\n\t\t\t\t\t\t\t\t_id: objectIdHexString(),\n\t\t\t\t\t\t\t\ttype: 'client-request',\n\t\t\t\t\t\t\t\tcollection: '',\n\t\t\t\t\t\t\t\tid_document: '',\n\t\t\t\t\t\t\t\tpayload: getBinarySize(JSON.stringify(data)) < 200000 ? JSON.stringify(data, null, 2) : 'Too Big',\n\t\t\t\t\t\t\t\tmethod: method,\n\t\t\t\t\t\t\t\tid_user: ws['id_user'] || '',\n\t\t\t\t\t\t\t\tuser: ws['user'] || '',\n\t\t\t\t\t\t\t\tmessageId: messageId,\n\t\t\t\t\t\t\t\troute: messageRoute\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tLogs.insertOne({\n\t\t\t\t\t\t\t_id: objectIdHexString(),\n\t\t\t\t\t\t\ttype: 'client-request',\n\t\t\t\t\t\t\tcollection: '',\n\t\t\t\t\t\t\tid_document: '',\n\t\t\t\t\t\t\tpayload: getBinarySize(JSON.stringify(data)) < 200000 ? JSON.stringify(data, null, 2) : 'Too Big',\n\t\t\t\t\t\t\tmethod: method,\n\t\t\t\t\t\t\tid_user: ws['id_user'] || '',\n\t\t\t\t\t\t\tuser: ws['user'] || '',\n\t\t\t\t\t\t\tmessageId: messageId,\n\t\t\t\t\t\t\troute: messageRoute,\n\t\t\t\t\t\t\tclient: 'ResolveIO',\n\t\t\t\t\t\t\tinstance: 'backend.resolveio.com'\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (this._methodManager._methods[method]) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tawait this._methodManager.callMethod.call(Object.assign({}, this._methodManager, MethodManager.prototype, {id_user: ws['id_user'], user: ws['user'], id_ws: ws['id_socket']}), method, ...data);\n\t\t\t\t\t}\n\t\t\t\t\tcatch (err) {\n\t\t\t\t\t\tconsole.log(new Date(), 'Offline Error', JSON.stringify(err, null, 2));\n\t\t\t\t\t}\n\n\t\t\t\t\tif (method === 'updateDocumentOffline' || method === 'updateDocumentPropsOffline') {\n\t\t\t\t\t\tResolveIOServer.getMongoManager().invalidateQueryCache(data[0]);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tconsole.log('Offline - Could not find method: ' + method);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tthis._offlineUpdates.splice(this._offlineUpdates.map(a => a['id_socket']).indexOf(ws['id_socket']), 1);\n\t\t}\n\t\telse {\n\t\t\t// It's presumably a 'method' or something else\n\t\t\tlet dataCopy = [...msg];\n\n\t\t\tlet route = dataCopy.shift();\n\t\t\tlet date = dataCopy.shift();\n\t\t\tlet msgId = dataCopy.shift();\n\t\t\tlet msgType = dataCopy.shift();\n\t\t\t\n\t\t\tif (msgType === 'method') {\n\t\t\t\tlet methodName = dataCopy.shift();\n\n\t\t\t\tif (ws['user_readonly']) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tif (methodName !== 'reportBuilderGetResults' && methodName !== 'reportBuilderGetDistinctValue' && methodName !== 'reportBuilderBuildTree' && methodName !== 'generatePDF' && methodName !== 'getWOOfflineData' && methodName !== 'countQuery' && methodName !== 'countWithQuery' && methodName !== 'countCollectionWithQuery' && methodName !== 'find' && methodName !== 'findOne' && methodName !== 'findWithOptions' && methodName !== 'getDrivers' && methodName !== 'processAirdropDistribution') {\n\t\t\t\t\tif (\n\t\t\t\t\t\tResolveIOServer.getServerConfig()['ROOT_URL'] !== 'https://resolveio.com'\n\t\t\t\t\t&& ResolveIOServer.getServerConfig()['ROOT_URL'] !== 'http://localhost:4200'\n\t\t\t\t\t) {\n\t\t\t\t\t\tResolveIOServer.getLocalLogManager().writeLog({\n\t\t\t\t\t\t\ttype: 'log',\n\t\t\t\t\t\t\tdata: {\n\t\t\t\t\t\t\t\t_id: objectIdHexString(),\n\t\t\t\t\t\t\t\ttype: 'client-request',\n\t\t\t\t\t\t\t\tcollection: '',\n\t\t\t\t\t\t\t\tid_document: '',\n\t\t\t\t\t\t\t\tpayload: getBinarySize(JSON.stringify(dataCopy)) < 200000 ? JSON.stringify(dataCopy, null, 2) : 'Too Big',\n\t\t\t\t\t\t\t\tmethod: methodName,\n\t\t\t\t\t\t\t\tid_user: ws['id_user'] || '',\n\t\t\t\t\t\t\t\tuser: ws['user'] || '',\n\t\t\t\t\t\t\t\tmessageId: messageId,\n\t\t\t\t\t\t\t\troute: messageRoute\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tLogs.insertOne({\n\t\t\t\t\t\t\t_id: objectIdHexString(),\n\t\t\t\t\t\t\ttype: 'client-request',\n\t\t\t\t\t\t\tcollection: '',\n\t\t\t\t\t\t\tid_document: '',\n\t\t\t\t\t\t\tpayload: getBinarySize(JSON.stringify(dataCopy)) < 200000 ? JSON.stringify(dataCopy, null, 2) : 'Too Big',\n\t\t\t\t\t\t\tmethod: methodName,\n\t\t\t\t\t\t\tid_user: ws['id_user'] || '',\n\t\t\t\t\t\t\tuser: ws['user'] || '',\n\t\t\t\t\t\t\tmessageId: messageId,\n\t\t\t\t\t\t\troute: messageRoute,\n\t\t\t\t\t\t\tclient: 'ResolveIO',\n\t\t\t\t\t\t\tinstance: 'backend.resolveio.com'\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Immediately ACK\n\t\t\t\tlet ack: ServerResponseModel = {\n\t\t\t\t\tmessageId: msgId,\n\t\t\t\t\thasError: false,\n\t\t\t\t\tdata: 'ACK'\n\t\t\t\t};\n\t\t\t\tif (ws && ws.readyState === ws.OPEN) {\n\t\t\t\t\tthis._websocketManager.send(ws, ack);\n\t\t\t\t}\n\n\t\t\t\t// Check if we can offload to a worker\n\t\t\t\tlet worker = this.findAvailableWorker();\n\t\t\t\tif (this._isWorkersEnabled && \n\t\t\t\t\tworker && \n\t\t\t\t\tmethodName !== 'insertSubscriptionLog' && \n\t\t\t\t\tmethodName !== 'countQuery' &&\n\t\t\t\t\tmethodName !== 'incCounter' && \n\t\t\t\t\tmethodName !== 'supportCreateBillingUser' &&\n\t\t\t\t\tmethodName !== 'find' &&\n\t\t\t\t\tmethodName !== 'insertDocument' &&\n\t\t\t\t\tmethodName !== 'countWithQuery' &&\n\t\t\t\t\tmethodName !== 'findOne' &&\n\t\t\t\t\tmethodName !== 'updateDocumentProps' &&\n\t\t\t\t\tmethodName !== 'findWithOptions' &&\n\t\t\t\t\tmethodName !== 'getSignedUrl' &&\n\t\t\t\t\tmethodName !== 'updateDocument' &&\n\t\t\t\t\tmethodName !== 'insertErrorLog' &&\n\t\t\t\t\tmethodName !== 'getSignedUrls' &&\n\t\t\t\t\tmethodName !== 'removeDocument' &&\n\t\t\t\t\tmethodName !== 'getSignedUrlWithId' &&\n\t\t\t\t\tmethodName !== 'incorrectUser' &&\n\t\t\t\t\tmethodName !== 'reloadWS' &&\n\t\t\t\t\tmethodName !== 'reconnectWS' &&\n\t\t\t\t\tmethodName !== 'disconnectWS'\n\t\t\t\t) {\n\t\t\t\t\t// Offload to a worker\n\t\t\t\t\tlet taskId = 'task-' + objectIdHexString();\n\n\t\t\t\t\t// Store correlation so when worker finishes, we can respond\n\t\t\t\t\tthis._inFlightRequests[taskId] = {\n\t\t\t\t\t\tws,\n\t\t\t\t\t\tmessageId: msgId,\n\t\t\t\t\t\tmethod: methodName\n\t\t\t\t\t};\n\n\t\t\t\t\tthis.queueTask(taskId, methodName, dataCopy, {\n\t\t\t\t\t\tid_user: ws['id_user'],\n\t\t\t\t\t\tuser: ws['user'],\n\t\t\t\t\t\tid_ws: ws['id_socket']\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t// No worker available: do method locally\n\t\t\t\t\tthis.callMethodLocally(ws, msgId, methodName, dataCopy);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * callMethodLocally is your old approach for invoking the method in-process.\n\t */\n\tprivate async callMethodLocally(ws: WebSocket, messageId: number, method: string, params: any[]) {\n\t\tlet serverRes: ServerResponseModel = {\n\t\t\tmessageId: messageId,\n\t\t\thasError: false,\n\t\t\tdata: null\n\t\t};\n\n\t\ttry {\n\t\t\t// You can keep your logging code (LogMethodLatencies, Logs.insertOne, etc.)\n\t\t\tlet result = await this._methodManager.callMethod.call(\n\t\t\t\tObject.assign({}, this._methodManager, MethodManager.prototype, {\n\t\t\t\t\tid_user: ws['id_user'],\n\t\t\t\t\tuser: ws['user'],\n\t\t\t\t\tid_ws: ws['id_socket']\n\t\t\t\t}),\n\t\t\t\tmethod,\n\t\t\t\t...params\n\t\t\t);\n\n\t\t\tserverRes.data = result;\n\t\t}\n\t\tcatch (err) {\n\t\t\tserverRes.hasError = true;\n\t\t\tserverRes.data = err.message || 'Unknown error';\n\t\t}\n\n\t\tif (ws && ws.readyState === ws.OPEN) {\n\t\t\tthis._websocketManager.send(ws, serverRes);\n\t\t}\n\t}\n\n\t/**\n\t * Add a new task to our in-memory queue and try to dispatch.\n\t */\n\tprivate queueTask(taskId: string, method: string, params: any[], userContext?: { id_user?: string; user?: string; id_ws?: string }) {\n\t\tthis._taskQueue.push({\n\t\t\ttaskId,\n\t\t\tmethod,\n\t\t\tparams,\n\t\t\tuserContext\n\t\t});\n\t\tthis.dispatchQueue();\n\t}\n\n\t/**\n\t * The main loop that assigns tasks from _taskQueue to any worker that has capacity.\n\t */\n\tprivate dispatchQueue() {\n\t\tif (!this._taskQueue.length) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Try to assign tasks while we have them\n\t\tfor (let i = 0; i < 9999; i++) {\n\t\t\tlet item = this._taskQueue[0];\n\t\t\tif (!item) {\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tlet w = this.findAvailableWorker();\n\t\t\tif (!w) {\n\t\t\t\tbreak; // no worker can take more tasks\n\t\t\t}\n\n\t\t\t// Remove from queue\n\t\t\tthis._taskQueue.shift();\n\t\t\tthis.assignTaskToWorker(w, item);\n\t\t}\n\t}\n\n\t/**\n\t * Returns the worker with the fewest activeTasks that is under maxConcurrency. Or null if none.\n\t */\n\tprivate findAvailableWorker(): WorkerConnection | null {\n\t\tlet candidates = this._workers.filter(x => x.activeTasks < x.maxConcurrency);\n\t\tif (!candidates.length) {\n\t\t\treturn null;\n\t\t}\n\n\t\t// Sort by how busy they are\n\t\tcandidates.sort((a, b) => a.activeTasks - b.activeTasks);\n\t\treturn candidates[0];\n\t}\n\n\tprivate assignTaskToWorker(worker: WorkerConnection, task: TaskQueueItem) {\n\t\tworker.activeTasks++;\n\n\t\tlet payload = {\n\t\t\ttype: 'task',\n\t\t\ttaskId: task.taskId,\n\t\t\tmethod: task.method,\n\t\t\tparams: task.params,\n\t\t\tuserContext: task.userContext\n\t\t};\n\n\t\ttry {\n\t\t\tworker.ws.send(JSON.stringify(payload));\n\t\t\tconsole.log('Assigned task', task.taskId, 'to worker', worker.id);\n\t\t}\n\t\tcatch (err) {\n\t\t\tconsole.error('Failed to send task to worker:', err);\n\t\t\tworker.activeTasks = Math.max(0, worker.activeTasks - 1);\n\t\t\t// Put task back at front\n\t\t\tthis._taskQueue.unshift(task);\n\t\t}\n\t}\n\n\t/**\n\t * Handle messages coming back from a worker (like 'taskComplete').\n\t */\n\tprivate handleWorkerMessage(workerId: string, messageStr: string) {\n\t\tlet data: any;\n\t\ttry {\n\t\t\tdata = JSON.parse(messageStr, dateReviver);\n\t\t}\n\t\tcatch (err) {\n\t\t\tconsole.error('Failed to parse worker message:', messageStr);\n\t\t\treturn;\n\t\t}\n\n\t\tif (data.type === 'taskComplete') {\n\t\t\tlet w = this._workers.find(x => x.id === workerId);\n\t\t\tif (!w) {\n\t\t\t\tconsole.error('Unknown worker for taskComplete:', workerId);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tw.activeTasks = Math.max(0, w.activeTasks - 1);\n\n\t\t\tlet { taskId, error, message, result } = data;\n\n\t\t\t// Look up original request\n\t\t\tlet inflight = this._inFlightRequests[taskId];\n\t\t\tif (!inflight) {\n\t\t\t\tconsole.error('No in-flight request found for task:', taskId);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tdelete this._inFlightRequests[taskId];\n\n\t\t\t\t// Send the final response to the client\n\t\t\t\tlet res: ServerResponseModel = {\n\t\t\t\t\tmessageId: inflight.messageId,\n\t\t\t\t\thasError: false,\n\t\t\t\t\tdata: result\n\t\t\t\t};\n\n\t\t\t\tif (error) {\n\t\t\t\t\tres.hasError = true;\n\t\t\t\t\tres.data = message;\n\t\t\t\t}\n\n\t\t\t\tif (inflight.ws && inflight.ws.readyState === inflight.ws.OPEN) {\n\t\t\t\t\tthis._websocketManager.send(inflight.ws, res);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Try to dispatch more from the queue\n\t\t\tthis.dispatchQueue();\n\t\t}\n\t}\n\n\t/**\n\t * Cleanly remove a client from the subscription manager, etc.\n\t */\n\tpublic unsubscribeWS(ws: WebSocket) {\n\t\tif (this._subscriptionManager && this._subscriptionManager.getEnableDebug()) {\n\t\t\tconsole.log(new Date(), 'Server App', 'Unsub WS', ws['user'], ws['id_socket']);\n\t\t}\n\t\tthis._subscriptionManager.unsubscribeAll(ws);\n\t\tws.removeAllListeners();\n\t\tws = null;\n\t}\n\n\tpublic getApp() {\n\t\treturn this._app;\n\t}\n\n\tpublic getServerConfig() {\n\t\treturn ResolveIOServer.getServerConfig();\n\t}\n}"]}
1
+ {"version":3,"sources":["../../src/server-app.ts"],"names":["http_1","require","express","bodyParser","xmlParser","WebSocket","jwt","moment","common_1","cron_manager_1","method_manager_1","subscription_manager_1","monitor_manager_1","log_collection_1","user_collection_1","home_1","auth_1","health_1","mongodb_1","websocket_manager_1","resolveio_server_app_1","ResolveIOMainServer","this","_offlineUpdates","sesMail","standardProgram","publicProgram","_rebootFlag","LOGGER","_clientRoutes","_lastErrorMsg","_debugMsgRecv","_debugMsgQueue","_isWorkersEnabled","_isWorkerInstance","_safeShutdown","_workers","_taskQueue","_inFlightRequests","_serverStartTime","Date","_monitorManager","MonitorManager","_monitorManagerFunction","MonitorManagerFunction","prototype","initServerApp","_this","initServerFlag","process","env","IS_WORKERS_ENABLED","IS_WORKER_INSTANCE","setInterval","_subscriptionManager","getEnableDebug","console","log","setTimeout","on","error","rej","__awaiter","diffTimeSec","diff","MongoNetworkTimeoutError","_methodManager","sendEmail","ResolveIOServer","getServerConfig","JSON","stringify","name","message","stack","_a","sent","exit","_serverHTTP","close","safeShutdown","MethodManager","_cronManager","CronManager","startWorkerInstance","_websocketManager","WebSocketManager","startServerInstance","SubscriptionManager","_serverWSS","listen","_app","use","json","limit","reviver","dateReviver","urlencoded","extended","parameterLimit","_portHTTP","PORT_HTTP","_portWSS","PORT_WSS","createServer","req","res","next","setHeader","setupAuthRoutes","setupHealthRoutes","setupHomeRoutes","wsUrl","connect","ws","lastComm","interval","readyState","OPEN","ping","WORKER_INDEX","NODE_APP_INSTANCE","rawData","msg","parse","toString","e","type","sendWorkerResponse","handleIncomingTask","clearInterval","err","data","taskId","method","params","userContext","timedOut","timeoutHandle","managerThis","Object","assign","id_user","user","id_ws","callMethod","call","apply","__spreadArray","__read","result","_b","clearTimeout","err_1","payload","send","getActiveMonitorFunctions","length","setImmediate","getMongoConnection","then","getIsWorkersEnabled","getIsWorkerInstance","getWSList","clients","forEach","push","getWSUserList","getHTTPServer","getCronManager","getMethodManager","getSubscriptionManager","getMonitorManager","getRebootFlag","getWebSocketManager","keepAliveTimeout","headersTimeout","Server","port","verifyClient","info","cb","url","includes","urlParts","split","infoData","headers","origin","token","verify","decoded","Users","findById","fullname","readonly","workerId_1","lastComm_1","interval_1","objectIdHexString","id","activeTasks","maxConcurrency","handleWorkerMessage","filter","w","addWebSocket","createLoggedInUser","unsubscribeWS","socketData","processSocketMessage","now","getTime","duration","asMilliseconds","loggedInLatency","Array","isArray","socketData_1","__values","socketData_1_1","value","handleClientMessage","messageRoute","messageDate","messageId","some","a","roles","groups","views","b","super_admin","subType","pub","subscribe","slice","unsubscribe","serverRes","hasError","offlineUpdates","i","update","shift","updateMessageId","serverResMethod","getLocalLogManager","writeLog","_id","collection","id_document","getBinarySize","route","Logs","insertOne","client","instance","_methods","err_3","getMongoManager","invalidateQueryCache","splice","map","indexOf","dataCopy","msgId","methodName","ack","worker","findAvailableWorker","queueTask","callMethodLocally","err_4","dispatchQueue","item","assignTaskToWorker","candidates","x","sort","task","Math","max","unshift","workerId","messageStr","inflight","find","unsubscribeAll","removeAllListeners","getApp","exports"],"mappings":"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","file":"server-app.js","sourcesContent":["import { createServer, Server } from 'http';\nimport * as express from 'express';\nimport * as bodyParser from 'body-parser';\nimport * as xmlParser from 'express-xml-bodyparser';\nimport * as WebSocket from 'ws';\nimport * as jwt from 'jsonwebtoken';\nimport * as moment from 'moment-timezone';\n\nimport { dateReviver, getBinarySize, objectIdHexString } from './util/common';\nimport { CronManager } from './managers/cron.manager';\nimport { MethodManager } from './managers/method.manager';\nimport { SubscriptionManager } from './managers/subscription.manager';\nimport { MonitorManager, MonitorManagerFunction } from './managers/monitor.manager';\nimport { ServerResponseModel } from './models/server-response.model';\nimport { Logs } from './collections/log.collection';\nimport { Users } from './collections/user.collection';\n\nimport { setupHomeRoutes } from './http/home';\nimport { setupAuthRoutes } from './http/auth';\nimport { setupHealthRoutes } from './http/health';\nimport { MongoNetworkTimeoutError } from 'mongodb';\n\nimport { WebSocketManager } from './managers/websocket.manager';\nimport { ResolveIOServer } from './resolveio-server-app';\n\ninterface WorkerConnection {\n\tid: string;\n\tws: WebSocket;\n\tactiveTasks: number;\n\tmaxConcurrency: number;\n}\n\ninterface TaskQueueItem {\n\ttaskId: string;\n\tmethod: string;\n\tparams: any[];\n\tuserContext?: { id_user?: string; user?: string; id_ws?: string };\n}\n\ninterface InFlightRequest {\n\tws: WebSocket; // the client's WebSocket\n\tmessageId: number; // the ID so the client knows which call this corresponds to\n\tmethod: string;\n}\n\nexport class ResolveIOMainServer {\n\tprivate _app: express.Application;\n\tprivate _serverHTTP: Server;\n\tprivate _portHTTP: string | number;\n\tprivate _serverWSS: WebSocket.Server;\n\tprivate _portWSS: number;\n\tprivate _offlineUpdates = [];\n\tpublic sesMail = false;\n\tprivate standardProgram = false;\n\tprivate publicProgram = false;\n\tprivate _rebootFlag = false;\n\n\tprivate LOGGER = 'ERROR'; //ERROR / DEBUG\n\n\tprivate _websocketManager: WebSocketManager;\n\tprivate _monitorManager: MonitorManager;\n\tprivate _monitorManagerFunction: MonitorManagerFunction;\n\tprivate _subscriptionManager: SubscriptionManager;\n\tprivate _methodManager: MethodManager;\n\tprivate _cronManager: CronManager;\n\tprivate _clientRoutes: string[] = [];\n\n\tprivate _serverStartTime: Date;\n\tprivate _lastErrorMsg: Date = null;\n\n\tprivate _debugMsgRecv = 0;\n\tprivate _debugMsgQueue = 0;\n\n\tprivate _isWorkersEnabled = false;\n\tprivate _isWorkerInstance = false;\n\n\tprivate _safeShutdown = false;\n\n\tprivate _workers: WorkerConnection[] = [];\n\tprivate _taskQueue: TaskQueueItem[] = [];\n\tprivate _inFlightRequests: { [taskId: string]: InFlightRequest } = {};\n\n\tconstructor() {\n\t\tthis._serverStartTime = new Date();\n\t\tthis._lastErrorMsg = null;\n\t\tthis._monitorManager = new MonitorManager();\n\t\tthis._monitorManagerFunction = new MonitorManagerFunction();\n\t}\n\n\tinitServerApp() {\n\t\t// Check for workers and decide what to start\n\t\tthis._isWorkersEnabled = process.env.IS_WORKERS_ENABLED === 'true';\n\t\tthis._isWorkerInstance = process.env.IS_WORKER_INSTANCE === 'true';\n\n\t\tsetInterval(() => {\n\t\t\tif (this._subscriptionManager && this._subscriptionManager.getEnableDebug()) {\n\t\t\t\tconsole.log(new Date(), 'Server App', 'Msg Recv Hits', this._debugMsgRecv);\n\t\t\t\tconsole.log(new Date(), 'Server App', 'Msg Queue Hits', this._debugMsgQueue);\n\t\t\t}\n\n\t\t\tthis._debugMsgQueue = 0;\n\t\t\tthis._debugMsgRecv = 0;\n\t\t}, 60000);\n\n\t\tlet initServerFlag = false;\n\n\t\tsetTimeout(() => {\n\t\t\tinitServerFlag = true;\n\t\t}, 5000);\n\n\t\tprocess.on('unhandledRejection', async (error, rej) => {\n\t\t\t// Condition to filter out the MongoError with code 48 (NamespaceExists)\n\t\t\tif (error && error['name'] === 'MongoError' && error['code'] === 48) {\n\t\t\t\treturn; // Simply return without doing anything further\n\t\t\t}\n\n\t\t\tif (error && error['name'] === 'MongoServerError' && !initServerFlag) {\n\t\t\t\treturn; // Simply return without doing anything further\n\t\t\t}\n\n\t\t\tconsole.error(new Date(), 'Unhandled Rejection at Promise', [error, rej]);\n\t\t\t\n\t\t\tlet diffTimeSec = moment().diff(this._serverStartTime, 'seconds');\n\n\t\t\t// If this is a MongoNetworkTimeoutError, handle it specifically\n\t\t\tif (error && (error['name'] === 'MongoNetworkTimeoutError' || error instanceof MongoNetworkTimeoutError)) {\n\t\t\t\tif (diffTimeSec > 60 && !this._lastErrorMsg) {\n\t\t\t\t\tthis._lastErrorMsg = new Date();\n\t\t\t\t\tsetTimeout(() => {\n\t\t\t\t\t\tthis._lastErrorMsg = null;\n\t\t\t\t\t}, 60000);\n\n\t\t\t\t\t// Sending email notification (using your existing method)\n\t\t\t\t\tawait this._methodManager.sendEmail('dev@resolveio.com', 'SERVER - MongoNetworkTimeoutError - Quitting NodeJS - ' + ResolveIOServer.getServerConfig()['CLIENT_NAME'], JSON.stringify({\n\t\t\t\t\t\tname: error['name'],\n\t\t\t\t\t\tmessage: error['message'],\n\t\t\t\t\t\tstack: error['stack']\n\t\t\t\t\t}, null, 2));\n\n\t\t\t\t\t// Exiting the process\n\t\t\t\t\tprocess.exit(1);\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if (error && error['name'] === 'MongoError' && error['message'] === 'not master') {\n\t\t\t\tif (diffTimeSec > 60 && !this._lastErrorMsg) {\n\t\t\t\t\tthis._lastErrorMsg = new Date();\n\n\t\t\t\t\tsetTimeout(() => {\n\t\t\t\t\t\tthis._lastErrorMsg = null;\n\t\t\t\t\t}, 60000);\n\n\t\t\t\t\tawait this._methodManager.sendEmail('dev@resolveio.com', 'SERVER - Unhandled Rejection - Quitting NodeJS - ' + ResolveIOServer.getServerConfig()['CLIENT_NAME'], JSON.stringify([error['name'], error['message'], error['stack']], null, 2));\n\t\t\t\t}\n\n\t\t\t\tprocess.exit(1);\n\t\t\t}\n\t\t\telse if (error && error['name'] === 'MongoError' && error['message'] === 'not master and slaveOk=false') {\n\t\t\t\tif (diffTimeSec > 60 && !this._lastErrorMsg) {\n\t\t\t\t\tthis._lastErrorMsg = new Date();\n\n\t\t\t\t\tsetTimeout(() => {\n\t\t\t\t\t\tthis._lastErrorMsg = null;\n\t\t\t\t\t}, 60000);\n\n\t\t\t\t\tawait this._methodManager.sendEmail('dev@resolveio.com', 'SERVER - Unhandled Rejection - Quitting NodeJS - ' + ResolveIOServer.getServerConfig()['CLIENT_NAME'], JSON.stringify([error['name'], error['message'], error['stack']], null, 2));\n\t\t\t\t}\n\n\t\t\t\tprocess.exit(1);\n\t\t\t}\n\t\t\telse if (error) {\n\t\t\t\tif (error['name'] !== 'StatusError' && error['message'] !== '') {\n\t\t\t\t\tif (diffTimeSec > 60 && !this._lastErrorMsg) {\n\t\t\t\t\t\tthis._lastErrorMsg = new Date();\n\n\t\t\t\t\t\tsetTimeout(() => {\n\t\t\t\t\t\t\tthis._lastErrorMsg = null;\n\t\t\t\t\t\t}, 60000);\n\n\t\t\t\t\t\tthis._methodManager.sendEmail('dev@resolveio.com', 'SERVER - Unhandled Rejection - ' + ResolveIOServer.getServerConfig()['CLIENT_NAME'], JSON.stringify([error['name'], error['message'], error['stack']], null, 2));\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\n\t\tprocess.on('uncaughtException', async error => {\n\t\t\tconsole.error(error, 'Uncaught Exception thrown');\n\n\n\n\t\t\tlet diffTimeSec = moment().diff(this._serverStartTime, 'seconds');\n\n\t\t\tif (diffTimeSec > 60 && !this._lastErrorMsg) {\n\t\t\t\tthis._lastErrorMsg = new Date();\n\n\t\t\t\tsetTimeout(() => {\n\t\t\t\t\tthis._lastErrorMsg = null;\n\t\t\t\t}, 60000);\n\t\t\t\t\n\t\t\t\tawait this._methodManager.sendEmail('dev@resolveio.com', 'SERVER - Unhandled Exception - ' + ResolveIOServer.getServerConfig()['CLIENT_NAME'], JSON.stringify([error['name'], error['message'], error['stack']], null, 2));\n\t\t\t}\n\t\t});\n\n\t\t//PM2 wants to reboot/restart\n\t\tprocess.on('SIGINT', () => {\n\t\t\tthis._rebootFlag = true;\n\t\t\tif (this._serverHTTP) {\n\t\t\t\tthis._serverHTTP.close();\n\t\t\t}\n\t\t\tthis.safeShutdown();\n\t\t});\n\n\t\tprocess.on('SIGTERM', () => {\n\t\t\tthis._rebootFlag = true;\n\t\t\tif (this._serverHTTP) {\n\t\t\t\tthis._serverHTTP.close();\n\t\t\t}\n\t\t\tthis.safeShutdown();\n\t\t});\n\n\t\tprocess.on('SIGQUIT', () => {\n\t\t\tthis._rebootFlag = true;\n\t\t\tif (this._serverHTTP) {\n\t\t\t\tthis._serverHTTP.close();\n\t\t\t}\n\t\t\tthis.safeShutdown();\n\t\t});\n\n\t\tif (this.LOGGER === 'DEBUG') {\n\t\t\tconsole.log('Starting ResolveIO Server');\n\t\t}\n\n\t\tif (this._isWorkersEnabled) {\n\t\t\tif (this._isWorkerInstance) {\n\t\t\t\tconsole.log('Running as a Worker instance');\n\t\t\t\tthis._methodManager = new MethodManager(this._monitorManagerFunction, this._isWorkersEnabled, this._isWorkerInstance);\n\t\t\t\tthis._cronManager = new CronManager();\n\t\t\t\tthis.startWorkerInstance();\n\t\t\t}\n\t\t\telse {\n\t\t\t\tconsole.log('Running as a Server instance');\n\t\t\t\tthis._websocketManager = new WebSocketManager(this);\n\t\t\t\tthis.startServerInstance();\n\t\t\t\tthis._methodManager = new MethodManager(this._monitorManagerFunction, this._isWorkersEnabled, this._isWorkerInstance);\n\t\t\t\tthis._subscriptionManager = new SubscriptionManager(this._serverWSS, ResolveIOServer.getServerConfig(), this._monitorManagerFunction);\n\t\t\t\tthis.listen();\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\tconsole.log('Running with Workers Disabled');\n\t\t\tthis._websocketManager = new WebSocketManager(this);\n\t\t\tthis.startServerInstance();\n\t\t\tthis._methodManager = new MethodManager(this._monitorManagerFunction, this._isWorkersEnabled, this._isWorkerInstance);\n\t\t\tthis._subscriptionManager = new SubscriptionManager(this._serverWSS, ResolveIOServer.getServerConfig(), this._monitorManagerFunction);\n\t\t\tthis._cronManager = new CronManager();\n\t\t\tthis.listen();\n\t\t}\n\t}\n\n\tprivate startServerInstance() {\n\t\t// Start express app\n\t\tthis._app = express();\n\n\t\tthis._app.use(bodyParser.json({limit: '50mb', reviver: dateReviver}));\n\t\tthis._app.use(bodyParser.urlencoded({limit: '50mb', extended: true, parameterLimit: 1000000 }));\n\t\tthis._app.use(xmlParser());\n\t\t\n\t\t// Set port\n\t\tthis._portHTTP = process.env.PORT_HTTP || ResolveIOServer.getServerConfig()['PORT_HTTP'] || 8080;\n\t\tthis._portWSS = process.env.PORT_WSS || ResolveIOServer.getServerConfig()['PORT_WSS'] || 8081;\n\n\t\tif (this.LOGGER === 'DEBUG') {\n\t\t\tconsole.log('Setup ports');\n\t\t}\n\n\t\t// Create http server and websock server\n\t\tthis.createServer();\n\n\t\tif (this.LOGGER === 'DEBUG') {\n\t\t\tconsole.log('Create server');\n\t\t}\n\n\t\t// Set CORS\n\t\tthis._app.use(function (req, res, next) {\n\t\t\tres.setHeader('Access-Control-Allow-Origin', '*');\n\t\t\tres.setHeader('Access-Control-Allow-Methods', 'GET, POST');\n\t\t\tres.setHeader('Access-Control-Allow-Headers', 'X-Requested-With,content-type');\n\t\t\tres.setHeader('Access-Control-Allow-Credentials', 'false');\n\t\t\tnext();\n\t\t});\n\n\t\tif (this.LOGGER === 'DEBUG') {\n\t\t\tconsole.log('Setup cors');\n\t\t}\n\n\t\t// Set up http login route\n\t\tsetupAuthRoutes(this, this._app, ResolveIOServer.getServerConfig());\n\t\tsetupHealthRoutes(this._app, ResolveIOServer.getServerConfig());\n\n\t\tif (ResolveIOServer.getServerConfig()['CLIENT_NAME'] === 'ResolveIO' || this.standardProgram) {\n\t\t\tsetupHomeRoutes(this, this._app, ResolveIOServer.getServerConfig());\n\t\t}\n\n\t\tif (this.LOGGER === 'DEBUG') {\n\t\t\tconsole.log('Setup express routes');\n\t\t}\n\t}\n\n\tprivate async startWorkerInstance() {\n\t\tconsole.log(new Date(), 'Worker instance started, connecting to main server via WebSocket...');\n\n\t\tlet wsUrl = ResolveIOServer.getServerConfig()['SERVER_URL'] + '/websocket?workerToken=' + ResolveIOServer.getServerConfig()['WORKER_TOKEN'];\n\n\t\tconst connect = () => {\n\t\t\tconst ws = new WebSocket(wsUrl);\n\n\t\t\tlet lastComm = null;\n\n\t\t\tif (ws && ws.readyState === ws.OPEN) {\n\t\t\t\tws.ping();\n\t\t\t}\n\n\t\t\tlet interval = setInterval(() => {\n\t\t\t\tif (!lastComm) {\n\t\t\t\t\tws.close();\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tlastComm = null;\n\n\t\t\t\t\tif (ws && ws.readyState === ws.OPEN) {\n\t\t\t\t\t\tws.ping();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}, 15000);\n\n\t\t\tws.on('open', () => {\n\t\t\t\tconsole.log(new Date(), 'Connected to main server as worker', process.env.WORKER_INDEX, process.env.NODE_APP_INSTANCE);\n\t\t\t});\n\n\t\t\tws.on('message', async (rawData) => {\n\t\t\t\tlet msg: any;\n\t\t\t\ttry {\n\t\t\t\t\tmsg = JSON.parse(rawData.toString(), dateReviver);\n\t\t\t\t}\n\t\t\t\tcatch (e) {\n\t\t\t\t\tconsole.error('Worker parse error', e);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\t// We expect: { type: 'task', taskId, method, params, userContext? }\n\t\t\t\tif (msg.type === 'ping') {\n\t\t\t\t\tthis.sendWorkerResponse(ws, {type: 'pong'});\n\t\t\t\t}\n\t\t\t\telse if (msg.type === 'pong') {\n\t\t\t\t\tlastComm = new Date();\n\t\t\t\t}\n\t\t\t\telse if (msg.type === 'task') {\n\t\t\t\t\tthis.handleIncomingTask(ws, msg);\n\t\t\t\t}\n\t\t\t});\n\n\t\t\tws.on('close', () => {\n\t\t\t\tconsole.log(new Date(), 'Disconnected from main server. Reconnecting in 5s...');\n\t\t\t\tsetTimeout(connect, 5000);\n\t\t\t\tclearInterval(interval);\n\t\t\t});\n\n\t\t\tws.on('error', (err) => {\n\t\t\t\tconsole.error(new Date(), 'Worker WS error:', err);\n\t\t\t\tws.close();\n\t\t\t});\n\t\t};\n\n\t\tconnect();\n\t}\n\n\tprivate async handleIncomingTask(ws: WebSocket, data: any) {\n\t\tlet { taskId, method, params, userContext } = data;\n\t\tif (!taskId || !method) {\n\t\t\tconsole.log('Invalid task message received', data);\n\t\t\treturn;\n\t\t}\n\n\t\tlet timedOut = false;\n\t\tlet timeoutHandle = setTimeout(() => {\n\t\t\ttimedOut = true;\n\t\t\tconsole.error('Worker timed out on task:', taskId);\n\n\t\t\tthis.sendWorkerResponse(ws, {\n\t\t\t\ttype: 'taskComplete',\n\t\t\t\ttaskId,\n\t\t\t\terror: true,\n\t\t\t\tmessage: 'Task timed out'\n\t\t\t});\n\t\t}, 120000);\n\n\t\ttry {\n\t\t\tlet managerThis = Object.assign({}, this._methodManager, MethodManager.prototype, {\n\t\t\t\tid_user: userContext?.id_user || '',\n\t\t\t\tuser: userContext?.user || '',\n\t\t\t\tid_ws: userContext?.id_ws || ''\n\t\t\t});\n\n\t\t\tlet result = await this._methodManager.callMethod.call(managerThis, method, ...params);\n\n\t\t\tif (!timedOut) {\n\t\t\t\tclearTimeout(timeoutHandle);\n\t\t\t\tthis.sendWorkerResponse(ws, {\n\t\t\t\t\ttype: 'taskComplete',\n\t\t\t\t\ttaskId,\n\t\t\t\t\terror: false,\n\t\t\t\t\tresult\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t\tcatch (err) {\n\t\t\tif (!timedOut) {\n\t\t\t\tclearTimeout(timeoutHandle);\n\t\t\t\tconsole.error('Worker failed task:', taskId, err);\n\t\t\t\tthis.sendWorkerResponse(ws, {\n\t\t\t\t\ttype: 'taskComplete',\n\t\t\t\t\ttaskId,\n\t\t\t\t\terror: true,\n\t\t\t\t\tmessage: err.message || 'Unknown error'\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate sendWorkerResponse(ws: WebSocket, payload: any) {\n\t\ttry {\n\t\t\tws.send(JSON.stringify(payload));\n\t\t}\n\t\tcatch (err) {\n\t\t\tconsole.error('Failed to send worker response:', err);\n\t\t}\n\t}\n\n\tprivate safeShutdown() {\n\t\tif (!this._safeShutdown) {\n\t\t\tconsole.log(new Date(), 'Safe Shutdown Command Received');\n\t\t}\n\n\t\tif (\n\t\t\t!this._monitorManagerFunction.getActiveMonitorFunctions().length\n\t\t\t&& !this._offlineUpdates.length\n\t\t) {\n\t\t\tif (ResolveIOServer.getMongoConnection()) {\n\t\t\t\tResolveIOServer.getMongoConnection().close(false).then(() => {\n\t\t\t\t\tconsole.log(new Date(), 'Safe Exit Complete, Process Exit');\n\t\t\t\t\tprocess.exit(0);\n\t\t\t\t}, () => { process.exit(1); });\n\t\t\t}\n\t\t\telse {\n\t\t\t\tprocess.exit(0);\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\tif (!this._safeShutdown) {\n\t\t\t\tthis._safeShutdown = true;\n\n\t\t\t\tsetTimeout(() => {\n\t\t\t\t\tthis._safeShutdown = false;\n\t\t\t\t}, 1000);\n\n\t\t\t\tconsole.log(new Date(), 'Safe Exit In Progress', \n\t\t\t\t\tthis._monitorManagerFunction.getActiveMonitorFunctions().length,\n\t\t\t\t\tthis._offlineUpdates.length\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tsetImmediate(() => {\n\t\t\t\tthis.safeShutdown();\n\t\t\t});\n\t\t}\n\t}\n\n\tgetIsWorkersEnabled() {\n\t\treturn this._isWorkersEnabled;\n\t}\n\n\tgetIsWorkerInstance() {\n\t\treturn this._isWorkerInstance;\n\t}\n\n\tpublic getWSList() {\n\t\tlet res = [];\n\t\tthis._serverWSS.clients.forEach((ws: WebSocket) => {\n\t\t\tres.push(ws['id_socket']);\n\t\t});\n\t\treturn res;\n\t}\n\n\tpublic getWSUserList() {\n\t\tlet res = [];\n\t\tthis._serverWSS.clients.forEach((ws: WebSocket) => {\n\t\t\tres.push(ws['id_user']);\n\t\t});\n\t\treturn res;\n\t}\n\n\tpublic getHTTPServer() {\n\t\treturn this._serverHTTP;\n\t}\n\n\tpublic getCronManager() {\n\t\treturn this._cronManager;\n\t}\n\n\tpublic getMethodManager() {\n\t\treturn this._methodManager;\n\t}\n\n\tpublic getSubscriptionManager() {\n\t\treturn this._subscriptionManager;\n\t}\n\n\tpublic getMonitorManager() {\n\t\treturn this._monitorManager;\n\t}\n\n\tpublic getRebootFlag() {\n\t\treturn this._rebootFlag;\n\t}\n\n\tpublic getWebSocketManager(): WebSocketManager {\n\t\treturn this._websocketManager;\n\t}\n\n\tprivate createServer(): void {\n\t\tthis._serverHTTP = createServer(this._app);\n\t\tthis._serverHTTP.keepAliveTimeout = 65000;\n\t\tthis._serverHTTP.headersTimeout = 66000;\n\n\t\tthis._serverWSS = new WebSocket.Server({\n\t\t\tport: this._portWSS,\n\t\t\tverifyClient: this.publicProgram ? null : async (info, cb) => {\n\t\t\t\tif (this._rebootFlag) {\n\t\t\t\t\tcb(false, 409, 'Unable To Process');\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tif (this.LOGGER === 'DEBUG') {\n\t\t\t\t\t\tconsole.log('Verify Client', info, cb);\n\t\t\t\t\t}\n\n\t\t\t\t\t// If it's a worker, we might skip token checks or do a simple check:\n\t\t\t\t\tif (info.req.url && info.req.url.includes('workerToken=')) {\n\t\t\t\t\t\tlet urlParts = info.req.url.split('workerToken='); \n\t\t\t\t\t\tlet workerToken = urlParts[1] || '';\n\n\t\t\t\t\t\tif (workerToken === ResolveIOServer.getServerConfig()['WORKER_TOKEN']) {\n\t\t\t\t\t\t\tcb(true);\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\tcb(false, 401, 'Unauthorized');\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\tlet infoData = (<string>info.req.headers['sec-websocket-protocol']).split(/,/);\n\n\t\t\t\t\tif (\n\t\t\t\t\t\tinfo.origin !== ResolveIOServer.getServerConfig()['ROOT_URL']\n\t\t\t\t\t\t&& info.origin !== ResolveIOServer.getServerConfig()['SEC_ROOT_URL']\n\t\t\t\t\t\t&& info.origin !== ResolveIOServer.getServerConfig()['RESOLVEIO_URL']\n\t\t\t\t\t\t&& info.origin !== ResolveIOServer.getServerConfig()['RESOLVEIO_SECONDARY_URL']\n\t\t\t\t\t) {\n\t\t\t\t\t\tcb(false, 401, 'Unauthorized');\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tlet token = infoData[0];\n\t\t\t\t\t\tif (!token) {\n\t\t\t\t\t\t\tcb(false, 401, 'Unauthorized');\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\tjwt.verify(token, ResolveIOServer.getServerConfig()['JWT_SECRET'], async (err, decoded) => {\n\t\t\t\t\t\t\t\tif (err) {\n\t\t\t\t\t\t\t\t\tcb(false, 401, 'Unauthorized');\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\t\tinfo.req['id_user'] = decoded['id_user'];\n\t\t\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\t\t\tlet user = await Users.findById(decoded['id_user']);\n\t\t\t\t\t\t\t\t\t\tif (user) {\n\t\t\t\t\t\t\t\t\t\t\tinfo.req['user'] = user.fullname;\n\t\t\t\t\t\t\t\t\t\t\tinfo.req['user_readonly'] = user.readonly || false;\n\t\t\t\t\t\t\t\t\t\t\tinfo.req['doc_user'] = user;\n\t\t\t\t\t\t\t\t\t\t\tcb(true);\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\t\t\t\tcb(false);\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\tcatch (err) {\n\t\t\t\t\t\t\t\t\t\tcb(false);\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t}\n\n\t/**\n\t * Listen for connections from clients or workers.\n\t */\n\tprivate listen(): void {\n\t\tthis._serverHTTP.listen(this._portHTTP, () => {\n\t\t\tconsole.log('Running server on port %s', this._portHTTP);\n\t\t});\n\n\t\tthis._serverWSS.on('listening', () => {\n\t\t\tconsole.log('Running server on port %s', this._portWSS);\n\t\t});\n\n\t\tthis._serverWSS.on('connection', (ws, req) => {\n\t\t\tif (req.url && req.url.includes('workerToken=')) {\n\t\t\t\t// It's a WORKER\n\t\t\t\tlet workerId = objectIdHexString();\n\t\t\t\tws['id_worker'] = workerId;\n\n\t\t\t\t// For demonstration, let each worker handle up to 2 tasks concurrently\n\t\t\t\tlet maxConcurrency = 2;\n\n\t\t\t\tthis._workers.push({\n\t\t\t\t\tid: workerId,\n\t\t\t\t\tws: ws,\n\t\t\t\t\tactiveTasks: 0,\n\t\t\t\t\tmaxConcurrency: maxConcurrency\n\t\t\t\t});\n\n\t\t\t\tlet lastComm = null;\n\n\t\t\t\tif (ws && ws.readyState === ws.OPEN) {\n\t\t\t\t\tthis.sendWorkerResponse(ws, {type: 'ping'});\n\t\t\t\t}\n\n\t\t\t\tlet interval = setInterval(() => {\n\t\t\t\t\tif (!lastComm) {\n\t\t\t\t\t\tws.close();\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tlastComm = null;\n\t\n\t\t\t\t\t\tif (ws && ws.readyState === ws.OPEN) {\n\t\t\t\t\t\t\tthis.sendWorkerResponse(ws, {type: 'ping'});\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}, 15000);\n\n\t\t\t\tconsole.log(new Date(), 'Worker connected:', workerId);\n\n\t\t\t\tws.on('message', (message: string) => {\n\t\t\t\t\tif (message === 'ping') {\n\t\t\t\t\t\tthis.sendWorkerResponse(ws, {type: 'pong'});\n\t\t\t\t\t}\n\t\t\t\t\telse if (message === 'pong') {\n\t\t\t\t\t\tlastComm = new Date();\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tthis.handleWorkerMessage(workerId, message);\n\t\t\t\t\t}\n\t\t\t\t});\n\n\t\t\t\tws.on('close', () => {\n\t\t\t\t\tconsole.log(new Date(), 'Worker disconnected:', workerId);\n\t\t\t\t\tthis._workers = this._workers.filter(w => w.id !== workerId);\n\t\t\t\t\tclearInterval(interval);\n\t\t\t\t});\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// Normal client\n\t\t\t\tws['id_socket'] = objectIdHexString();\n\t\t\t\tws['id_user'] = req['id_user'];\n\t\t\t\tws['user'] = req['user'];\n\t\t\t\tws['user_readonly'] = req['user_readonly'];\n\t\t\t\tws['doc_user'] = req['doc_user'];\n\n\t\t\t\tthis._websocketManager.addWebSocket(ws);\n\n\t\t\t\tthis._subscriptionManager.createLoggedInUser(ws['id_socket']).then(() => {\n\t\t\t\t\tsetTimeout(() => {\n\t\t\t\t\t\tws['pingTime'] = new Date();\n\t\t\t\t\t\tws.send('ping', (error) => {\n\t\t\t\t\t\t\tif (error) {\n\t\t\t\t\t\t\t\tif (this._subscriptionManager.getEnableDebug()) {\n\t\t\t\t\t\t\t\t\tconsole.log(new Date(), 'Server App', 'Error WS Ping');\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tthis.unsubscribeWS(ws);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t});\n\t\t\t\t\t}, 5000);\n\t\t\t\t});\n\n\t\t\t\tif (this.LOGGER === 'DEBUG') {\n\t\t\t\t\tconsole.log('Connection from user: ' + req['user']);\n\t\t\t\t}\n\t\t\t\n\t\t\t\tws['isAlive'] = true;\n\t\t\t\tws['retryCnt'] = 0;\n\n\t\t\t\tws.on('message', async (message: string) => {\n\t\t\t\t\tthis._debugMsgRecv += 1;\n\t\t\t\t\tlet socketData = [];\n\t\t\t\t\n\t\t\t\t\ttry {\n\t\t\t\t\t\tsocketData = JSON.parse(message, dateReviver);\n\t\t\t\t\t}\n\t\t\t\t\tcatch (e) {\n\t\t\t\t\t\tconsole.log('Error - JSON.parse', message);\n\t\t\t\t\t\tthis._methodManager.sendEmail(\n\t\t\t\t\t\t\t'dev@resolveio.com', \n\t\t\t\t\t\t\t'SERVER - JSON Parse Error - ' + ResolveIOServer.getServerConfig()['CLIENT_NAME'], \n\t\t\t\t\t\t\tJSON.stringify([message, e])\n\t\t\t\t\t\t);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\t// call our existing processSocketMessage\n\t\t\t\t\tthis.processSocketMessage(ws, socketData);\n\t\t\t\t})\n\t\t\t\t.on('end', () => {\n\t\t\t\t\tthis.unsubscribeWS(ws);\n\t\t\t\t})\n\t\t\t\t.on('close', () => {\n\t\t\t\t\tthis.unsubscribeWS(ws);\n\t\t\t\t})\n\t\t\t\t.on('error', error => {\n\t\t\t\t\tthis.unsubscribeWS(ws);\n\t\t\t\t});\n\t\t\t}\n\t\t});\n\n\t\t// Keep alive timer\n\t\tsetInterval(() => {\n\t\t\tthis._serverWSS.clients.forEach((ws: WebSocket) => {\n\t\t\t\tif (ws['pingTime'] && Date.now() - ws['pingTime'].getTime() >= 20000) {\n\t\t\t\t\tif (ws['isAlive'] === false) {\n\t\t\t\t\t\tws['retryCnt']++;\n\t\t\t\t\t\tif (ws['retryCnt'] >= 3) {\n\t\t\t\t\t\t\tthis.unsubscribeWS(ws);\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\tws['pingTime'] = new Date();\n\t\t\t\t\t\t\tws.send('ping', (error) => {\n\t\t\t\t\t\t\t\tif (error) {\n\t\t\t\t\t\t\t\t\tif (this._subscriptionManager.getEnableDebug()) {\n\t\t\t\t\t\t\t\t\t\tconsole.log(new Date(), 'Server App', 'Error WS Ping');\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\tthis.unsubscribeWS(ws);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tws['retryCnt'] = 0;\n\t\t\t\t\t\tws['isAlive'] = false;\n\t\t\t\t\t\tws['pingTime'] = new Date();\n\t\t\t\t\t\tws.send('ping', (error) => {\n\t\t\t\t\t\t\tif (error) {\n\t\t\t\t\t\t\t\tif (this._subscriptionManager.getEnableDebug()) {\n\t\t\t\t\t\t\t\t\tconsole.log(new Date(), 'Server App', 'Error WS Ping');\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tthis.unsubscribeWS(ws);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t});\n\t\t}, 20000);\n\t}\n\n\tprivate async processSocketMessage(ws: WebSocket, socketData: any) {\n\t\tif (typeof socketData === 'string' && socketData === 'ping') {\n\t\t\tif (ws && ws.readyState === ws.OPEN) {\n\t\t\t\tws.send('pong');\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t\telse if (typeof socketData === 'string' && socketData === 'pong') {\n\t\t\tws['isAlive'] = true;\n\t\t\tws['pongTime'] = new Date();\n\t\t\tws['latency'] = moment.duration(moment(ws['pongTime']).diff(ws['pingTime'])).asMilliseconds();\n\t\t\tthis._subscriptionManager.loggedInLatency(ws);\n\t\t\treturn;\n\t\t}\n\n\t\t// If the top level is not an array, let's skip\n\t\tif (!Array.isArray(socketData[0])) {\n\t\t\tconsole.log('Invalid message format (expected array of arrays)', socketData);\n\t\t\treturn;\n\t\t}\n\n\t\t// Handle each sub-message\n\t\tfor (let message of socketData) {\n\t\t\tawait this.handleClientMessage(ws, message);\n\t\t}\n\t}\n\n\tprivate async handleClientMessage(ws: WebSocket, msg: any[]): Promise<void> {\n\t\t// This is basically your old logic from processSocketMessage,\n\t\t// but we'll insert our worker-queue logic for \"method\" calls.\n\n\t\tlet messageRoute = msg[0];\n\t\tlet messageDate = msg[1];\n\t\tlet messageId = msg[2];\n\t\tlet type = msg[3];\n\n\t\tif (!this.publicProgram && this._clientRoutes.some(a => messageRoute.includes(a)) && !ws['doc_user'].roles.groups.some(a => a.views.some(b => messageRoute.includes(b) || b.includes(messageRoute))) && !ws['doc_user'].roles.super_admin) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (type === 'subscription') {\n\t\t\tlet subType = msg[4];\n\t\t\tlet pub = msg[5];\n\n\t\t\tif (subType === 'sub') {\n\t\t\t\tthis._subscriptionManager.subscribe(messageRoute, messageDate, ws, messageId, pub, msg.slice(6));\n\t\t\t}\n\t\t\telse {\n\t\t\t\tthis._subscriptionManager.unsubscribe(messageRoute, messageDate, ws, messageId, pub, msg.slice(6));\n\t\t\t}\n\t\t}\n\t\telse if (!this.publicProgram && type === 'offline') {\n\t\t\tlet serverRes: ServerResponseModel = {\n\t\t\t\tmessageId: messageId,\n\t\t\t\thasError: false,\n\t\t\t\tdata: 'ACK'\n\t\t\t};\n\n\t\t\tif (ws && ws.readyState === ws.OPEN) {\n\t\t\t\tthis._websocketManager.send(ws, serverRes);\n\t\t\t}\n\n\t\t\tthis._offlineUpdates.push(ws);\n\t\t\tlet offlineUpdates = msg[4];\n\n\t\t\tfor (let i = 0; i < offlineUpdates.length; i++) {\n\t\t\t\tlet update = offlineUpdates[i];\n\n\t\t\t\tlet data = update.data;\n\n\t\t\t\tlet updateRoute = data.shift();\n\t\t\t\tlet updateDate = data.shift();\n\t\t\t\tlet updateMessageId = data.shift();\n\t\t\t\tlet updateType = data.shift();\n\t\t\t\tlet method = data.shift();\n\n\t\t\t\tlet serverResMethod: ServerResponseModel = {\n\t\t\t\t\tmessageId: updateMessageId,\n\t\t\t\t\thasError: false,\n\t\t\t\t\tdata: 'ACK'\n\t\t\t\t};\n\n\t\t\t\tif (ws && ws.readyState === ws.OPEN) {\n\t\t\t\t\tthis._websocketManager.send(ws, serverResMethod);\n\t\t\t\t}\n\n\t\t\t\tif (method === 'insertDocument' && data[0] === 'driver-gps') {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tif (method !== 'reportBuilderGetResults' && method !== 'reportBuilderGetDistinctValue' && method !== 'reportBuilderBuildTree' && method !== 'generatePDF' && method !== 'getWOOfflineData' && method !== 'countQuery' && method !== 'countWithQuery' && method !== 'countCollectionWithQuery' && method !== 'find' && method !== 'findOne' && method !== 'findWithOptions' && method !== 'getDrivers' && method !== 'processAirdropDistribution') {\n\t\t\t\t\tif (\n\t\t\t\t\t\tResolveIOServer.getServerConfig()['ROOT_URL'] !== 'https://resolveio.com'\n\t\t\t\t\t&& ResolveIOServer.getServerConfig()['ROOT_URL'] !== 'http://localhost:4200'\n\t\t\t\t\t) {\n\t\t\t\t\t\tResolveIOServer.getLocalLogManager().writeLog({\n\t\t\t\t\t\t\ttype: 'log',\n\t\t\t\t\t\t\tdata: {\n\t\t\t\t\t\t\t\t_id: objectIdHexString(),\n\t\t\t\t\t\t\t\ttype: 'client-request',\n\t\t\t\t\t\t\t\tcollection: '',\n\t\t\t\t\t\t\t\tid_document: '',\n\t\t\t\t\t\t\t\tpayload: getBinarySize(JSON.stringify(data)) < 200000 ? JSON.stringify(data, null, 2) : 'Too Big',\n\t\t\t\t\t\t\t\tmethod: method,\n\t\t\t\t\t\t\t\tid_user: ws['id_user'] || '',\n\t\t\t\t\t\t\t\tuser: ws['user'] || '',\n\t\t\t\t\t\t\t\tmessageId: messageId,\n\t\t\t\t\t\t\t\troute: messageRoute\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tLogs.insertOne({\n\t\t\t\t\t\t\t_id: objectIdHexString(),\n\t\t\t\t\t\t\ttype: 'client-request',\n\t\t\t\t\t\t\tcollection: '',\n\t\t\t\t\t\t\tid_document: '',\n\t\t\t\t\t\t\tpayload: getBinarySize(JSON.stringify(data)) < 200000 ? JSON.stringify(data, null, 2) : 'Too Big',\n\t\t\t\t\t\t\tmethod: method,\n\t\t\t\t\t\t\tid_user: ws['id_user'] || '',\n\t\t\t\t\t\t\tuser: ws['user'] || '',\n\t\t\t\t\t\t\tmessageId: messageId,\n\t\t\t\t\t\t\troute: messageRoute,\n\t\t\t\t\t\t\tclient: 'ResolveIO',\n\t\t\t\t\t\t\tinstance: 'backend.resolveio.com'\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (this._methodManager._methods[method]) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tawait this._methodManager.callMethod.call(Object.assign({}, this._methodManager, MethodManager.prototype, {id_user: ws['id_user'], user: ws['user'], id_ws: ws['id_socket']}), method, ...data);\n\t\t\t\t\t}\n\t\t\t\t\tcatch (err) {\n\t\t\t\t\t\tconsole.log(new Date(), 'Offline Error', JSON.stringify(err, null, 2));\n\t\t\t\t\t}\n\n\t\t\t\t\tif (method === 'updateDocumentOffline' || method === 'updateDocumentPropsOffline') {\n\t\t\t\t\t\tResolveIOServer.getMongoManager().invalidateQueryCache(data[0]);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tconsole.log('Offline - Could not find method: ' + method);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tthis._offlineUpdates.splice(this._offlineUpdates.map(a => a['id_socket']).indexOf(ws['id_socket']), 1);\n\t\t}\n\t\telse {\n\t\t\t// It's presumably a 'method' or something else\n\t\t\tlet dataCopy = [...msg];\n\n\t\t\tlet route = dataCopy.shift();\n\t\t\tlet date = dataCopy.shift();\n\t\t\tlet msgId = dataCopy.shift();\n\t\t\tlet msgType = dataCopy.shift();\n\t\t\t\n\t\t\tif (msgType === 'method') {\n\t\t\t\tlet methodName = dataCopy.shift();\n\n\t\t\t\tif (ws['user_readonly']) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tif (methodName !== 'reportBuilderGetResults' && methodName !== 'reportBuilderGetDistinctValue' && methodName !== 'reportBuilderBuildTree' && methodName !== 'generatePDF' && methodName !== 'getWOOfflineData' && methodName !== 'countQuery' && methodName !== 'countWithQuery' && methodName !== 'countCollectionWithQuery' && methodName !== 'find' && methodName !== 'findOne' && methodName !== 'findWithOptions' && methodName !== 'getDrivers' && methodName !== 'processAirdropDistribution') {\n\t\t\t\t\tif (\n\t\t\t\t\t\tResolveIOServer.getServerConfig()['ROOT_URL'] !== 'https://resolveio.com'\n\t\t\t\t\t&& ResolveIOServer.getServerConfig()['ROOT_URL'] !== 'http://localhost:4200'\n\t\t\t\t\t) {\n\t\t\t\t\t\tResolveIOServer.getLocalLogManager().writeLog({\n\t\t\t\t\t\t\ttype: 'log',\n\t\t\t\t\t\t\tdata: {\n\t\t\t\t\t\t\t\t_id: objectIdHexString(),\n\t\t\t\t\t\t\t\ttype: 'client-request',\n\t\t\t\t\t\t\t\tcollection: '',\n\t\t\t\t\t\t\t\tid_document: '',\n\t\t\t\t\t\t\t\tpayload: getBinarySize(JSON.stringify(dataCopy)) < 200000 ? JSON.stringify(dataCopy, null, 2) : 'Too Big',\n\t\t\t\t\t\t\t\tmethod: methodName,\n\t\t\t\t\t\t\t\tid_user: ws['id_user'] || '',\n\t\t\t\t\t\t\t\tuser: ws['user'] || '',\n\t\t\t\t\t\t\t\tmessageId: messageId,\n\t\t\t\t\t\t\t\troute: messageRoute\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tLogs.insertOne({\n\t\t\t\t\t\t\t_id: objectIdHexString(),\n\t\t\t\t\t\t\ttype: 'client-request',\n\t\t\t\t\t\t\tcollection: '',\n\t\t\t\t\t\t\tid_document: '',\n\t\t\t\t\t\t\tpayload: getBinarySize(JSON.stringify(dataCopy)) < 200000 ? JSON.stringify(dataCopy, null, 2) : 'Too Big',\n\t\t\t\t\t\t\tmethod: methodName,\n\t\t\t\t\t\t\tid_user: ws['id_user'] || '',\n\t\t\t\t\t\t\tuser: ws['user'] || '',\n\t\t\t\t\t\t\tmessageId: messageId,\n\t\t\t\t\t\t\troute: messageRoute,\n\t\t\t\t\t\t\tclient: 'ResolveIO',\n\t\t\t\t\t\t\tinstance: 'backend.resolveio.com'\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Immediately ACK\n\t\t\t\tlet ack: ServerResponseModel = {\n\t\t\t\t\tmessageId: msgId,\n\t\t\t\t\thasError: false,\n\t\t\t\t\tdata: 'ACK'\n\t\t\t\t};\n\t\t\t\tif (ws && ws.readyState === ws.OPEN) {\n\t\t\t\t\tthis._websocketManager.send(ws, ack);\n\t\t\t\t}\n\n\t\t\t\t// Check if we can offload to a worker\n\t\t\t\tlet worker = this.findAvailableWorker();\n\t\t\t\tif (this._isWorkersEnabled && \n\t\t\t\t\tworker && \n\t\t\t\t\tmethodName !== 'insertSubscriptionLog' && \n\t\t\t\t\tmethodName !== 'countQuery' &&\n\t\t\t\t\tmethodName !== 'incCounter' && \n\t\t\t\t\tmethodName !== 'supportCreateBillingUser' &&\n\t\t\t\t\tmethodName !== 'find' &&\n\t\t\t\t\tmethodName !== 'insertDocument' &&\n\t\t\t\t\tmethodName !== 'countWithQuery' &&\n\t\t\t\t\tmethodName !== 'findOne' &&\n\t\t\t\t\tmethodName !== 'updateDocumentProps' &&\n\t\t\t\t\tmethodName !== 'findWithOptions' &&\n\t\t\t\t\tmethodName !== 'getSignedUrl' &&\n\t\t\t\t\tmethodName !== 'updateDocument' &&\n\t\t\t\t\tmethodName !== 'insertErrorLog' &&\n\t\t\t\t\tmethodName !== 'getSignedUrls' &&\n\t\t\t\t\tmethodName !== 'removeDocument' &&\n\t\t\t\t\tmethodName !== 'getSignedUrlWithId' &&\n\t\t\t\t\tmethodName !== 'incorrectUser' &&\n\t\t\t\t\tmethodName !== 'reloadWS' &&\n\t\t\t\t\tmethodName !== 'reconnectWS' &&\n\t\t\t\t\tmethodName !== 'disconnectWS'\n\t\t\t\t) {\n\t\t\t\t\t// Offload to a worker\n\t\t\t\t\tlet taskId = 'task-' + objectIdHexString();\n\n\t\t\t\t\t// Store correlation so when worker finishes, we can respond\n\t\t\t\t\tthis._inFlightRequests[taskId] = {\n\t\t\t\t\t\tws,\n\t\t\t\t\t\tmessageId: msgId,\n\t\t\t\t\t\tmethod: methodName\n\t\t\t\t\t};\n\n\t\t\t\t\tthis.queueTask(taskId, methodName, dataCopy, {\n\t\t\t\t\t\tid_user: ws['id_user'],\n\t\t\t\t\t\tuser: ws['user'],\n\t\t\t\t\t\tid_ws: ws['id_socket']\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t// No worker available: do method locally\n\t\t\t\t\tthis.callMethodLocally(ws, msgId, methodName, dataCopy);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * callMethodLocally is your old approach for invoking the method in-process.\n\t */\n\tprivate async callMethodLocally(ws: WebSocket, messageId: number, method: string, params: any[]) {\n\t\tlet serverRes: ServerResponseModel = {\n\t\t\tmessageId: messageId,\n\t\t\thasError: false,\n\t\t\tdata: null\n\t\t};\n\n\t\ttry {\n\t\t\t// You can keep your logging code (LogMethodLatencies, Logs.insertOne, etc.)\n\t\t\tlet result = await this._methodManager.callMethod.call(\n\t\t\t\tObject.assign({}, this._methodManager, MethodManager.prototype, {\n\t\t\t\t\tid_user: ws['id_user'],\n\t\t\t\t\tuser: ws['user'],\n\t\t\t\t\tid_ws: ws['id_socket']\n\t\t\t\t}),\n\t\t\t\tmethod,\n\t\t\t\t...params\n\t\t\t);\n\n\t\t\tserverRes.data = result;\n\t\t}\n\t\tcatch (err) {\n\t\t\tserverRes.hasError = true;\n\t\t\tserverRes.data = err.message || 'Unknown error';\n\t\t}\n\n\t\tif (ws && ws.readyState === ws.OPEN) {\n\t\t\tthis._websocketManager.send(ws, serverRes);\n\t\t}\n\t}\n\n\t/**\n\t * Add a new task to our in-memory queue and try to dispatch.\n\t */\n\tprivate queueTask(taskId: string, method: string, params: any[], userContext?: { id_user?: string; user?: string; id_ws?: string }) {\n\t\tthis._taskQueue.push({\n\t\t\ttaskId,\n\t\t\tmethod,\n\t\t\tparams,\n\t\t\tuserContext\n\t\t});\n\t\tthis.dispatchQueue();\n\t}\n\n\t/**\n\t * The main loop that assigns tasks from _taskQueue to any worker that has capacity.\n\t */\n\tprivate dispatchQueue() {\n\t\tif (!this._taskQueue.length) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Try to assign tasks while we have them\n\t\tfor (let i = 0; i < 9999; i++) {\n\t\t\tlet item = this._taskQueue[0];\n\t\t\tif (!item) {\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tlet w = this.findAvailableWorker();\n\t\t\tif (!w) {\n\t\t\t\tbreak; // no worker can take more tasks\n\t\t\t}\n\n\t\t\t// Remove from queue\n\t\t\tthis._taskQueue.shift();\n\t\t\tthis.assignTaskToWorker(w, item);\n\t\t}\n\t}\n\n\t/**\n\t * Returns the worker with the fewest activeTasks that is under maxConcurrency. Or null if none.\n\t */\n\tprivate findAvailableWorker(): WorkerConnection | null {\n\t\tlet candidates = this._workers.filter(x => x.activeTasks < x.maxConcurrency);\n\t\tif (!candidates.length) {\n\t\t\treturn null;\n\t\t}\n\n\t\t// Sort by how busy they are\n\t\tcandidates.sort((a, b) => a.activeTasks - b.activeTasks);\n\t\treturn candidates[0];\n\t}\n\n\tprivate assignTaskToWorker(worker: WorkerConnection, task: TaskQueueItem) {\n\t\tworker.activeTasks++;\n\n\t\tlet payload = {\n\t\t\ttype: 'task',\n\t\t\ttaskId: task.taskId,\n\t\t\tmethod: task.method,\n\t\t\tparams: task.params,\n\t\t\tuserContext: task.userContext\n\t\t};\n\n\t\ttry {\n\t\t\tworker.ws.send(JSON.stringify(payload));\n\t\t\tconsole.log('Assigned task', task.taskId, 'to worker', worker.id);\n\t\t}\n\t\tcatch (err) {\n\t\t\tconsole.error('Failed to send task to worker:', err);\n\t\t\tworker.activeTasks = Math.max(0, worker.activeTasks - 1);\n\t\t\t// Put task back at front\n\t\t\tthis._taskQueue.unshift(task);\n\t\t}\n\t}\n\n\t/**\n\t * Handle messages coming back from a worker (like 'taskComplete').\n\t */\n\tprivate handleWorkerMessage(workerId: string, messageStr: string) {\n\t\tlet data: any;\n\t\ttry {\n\t\t\tdata = JSON.parse(messageStr, dateReviver);\n\t\t}\n\t\tcatch (err) {\n\t\t\tconsole.error('Failed to parse worker message:', messageStr);\n\t\t\treturn;\n\t\t}\n\n\t\tif (data.type === 'taskComplete') {\n\t\t\tlet w = this._workers.find(x => x.id === workerId);\n\t\t\tif (!w) {\n\t\t\t\tconsole.error('Unknown worker for taskComplete:', workerId);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tw.activeTasks = Math.max(0, w.activeTasks - 1);\n\n\t\t\tlet { taskId, error, message, result } = data;\n\n\t\t\t// Look up original request\n\t\t\tlet inflight = this._inFlightRequests[taskId];\n\t\t\tif (!inflight) {\n\t\t\t\tconsole.error('No in-flight request found for task:', taskId);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tdelete this._inFlightRequests[taskId];\n\n\t\t\t\t// Send the final response to the client\n\t\t\t\tlet res: ServerResponseModel = {\n\t\t\t\t\tmessageId: inflight.messageId,\n\t\t\t\t\thasError: false,\n\t\t\t\t\tdata: result\n\t\t\t\t};\n\n\t\t\t\tif (error) {\n\t\t\t\t\tres.hasError = true;\n\t\t\t\t\tres.data = message;\n\t\t\t\t}\n\n\t\t\t\tif (inflight.ws && inflight.ws.readyState === inflight.ws.OPEN) {\n\t\t\t\t\tthis._websocketManager.send(inflight.ws, res);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Try to dispatch more from the queue\n\t\t\tthis.dispatchQueue();\n\t\t}\n\t}\n\n\t/**\n\t * Cleanly remove a client from the subscription manager, etc.\n\t */\n\tpublic unsubscribeWS(ws: WebSocket) {\n\t\tif (this._subscriptionManager && this._subscriptionManager.getEnableDebug()) {\n\t\t\tconsole.log(new Date(), 'Server App', 'Unsub WS', ws['user'], ws['id_socket']);\n\t\t}\n\t\tthis._subscriptionManager.unsubscribeAll(ws);\n\t\tws.removeAllListeners();\n\t\tws = null;\n\t}\n\n\tpublic getApp() {\n\t\treturn this._app;\n\t}\n\n\tpublic getServerConfig() {\n\t\treturn ResolveIOServer.getServerConfig();\n\t}\n}"]}