ziron-state 7.2.0 → 8.0.0

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/dist/index.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import { StateServer } from "./lib/StateServer";
2
2
  import { LogLevel } from "./lib/Logger";
3
3
  import StateServerOptions from "./lib/StateServerOptions";
4
- export { StateServer, StateServerOptions, LogLevel };
4
+ import { Block } from "ziron-server";
5
+ export { StateServer, StateServerOptions, LogLevel, Block };
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.LogLevel=exports.StateServer=void 0;const StateServer_1=require("./lib/StateServer");Object.defineProperty(exports,"StateServer",{enumerable:!0,get:function(){return StateServer_1.StateServer}});const Logger_1=require("./lib/Logger");Object.defineProperty(exports,"LogLevel",{enumerable:!0,get:function(){return Logger_1.LogLevel}});
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.Block=exports.LogLevel=exports.StateServer=void 0;const StateServer_1=require("./lib/StateServer");Object.defineProperty(exports,"StateServer",{enumerable:!0,get:function(){return StateServer_1.StateServer}});const Logger_1=require("./lib/Logger");Object.defineProperty(exports,"LogLevel",{enumerable:!0,get:function(){return Logger_1.LogLevel}});const ziron_server_1=require("ziron-server");Object.defineProperty(exports,"Block",{enumerable:!0,get:function(){return ziron_server_1.Block}});
@@ -8,6 +8,7 @@ export default class Logger {
8
8
  constructor(level: LogLevel);
9
9
  logBusy(...msg: string[]): void;
10
10
  logActive(...msg: string[]): void;
11
+ logFailed(...msg: string[]): void;
11
12
  private static RUNNING_TABLE_HEADER;
12
13
  logRunningState(joinedWorkers: Socket[], joinedBrokers: Socket[], joinToken: string): void;
13
14
  }
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.LogLevel=void 0;const logUpdate=require("log-update"),table_1=require("table");var LogLevel;!function(e){e[e.Nothing=0]="Nothing",e[e.Everything=1]="Everything"}(LogLevel=exports.LogLevel||(exports.LogLevel={}));class Logger{constructor(e){this.level=e}logBusy(...e){this.level>=LogLevel.Everything&&console.log("%s"," [BUSY]",e.join("\n"))}logActive(...e){this.level>=LogLevel.Everything&&console.log("%s"," [ACTIVE]",e.join("\n"))}logRunningState(e,o,t){if(this.level<=LogLevel.Nothing)return;const r=[];e.length>1&&o.length<=0&&r.push("[WARNING] The cluster has no brokers! Channel messages will not be distributed to other workers.️️️"),r.push(`Join a new broker or worker by using the join token: ${t}`),logUpdate(table_1.table([Logger.RUNNING_TABLE_HEADER,...[...e,...o].map(({node:e})=>[e.id,0===e.type?"Worker"+(e.leader?" 👑":""):"Broker",e.ip,e.port])],{header:{alignment:"center",content:"Cluster"}})+r.join("\n"))}}exports.default=Logger,Logger.RUNNING_TABLE_HEADER=["Id","Type","IP","Port"];
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.LogLevel=void 0;const logUpdate=require("log-update"),table_1=require("table");var LogLevel;!function(e){e[e.Nothing=0]="Nothing",e[e.Everything=1]="Everything"}(LogLevel=exports.LogLevel||(exports.LogLevel={}));class Logger{constructor(e){this.level=e}logBusy(...e){this.level>=LogLevel.Everything&&console.log("%s"," [BUSY]",e.join("\n"))}logActive(...e){this.level>=LogLevel.Everything&&console.log("%s"," [ACTIVE]",e.join("\n"))}logFailed(...e){this.level>=LogLevel.Everything&&console.log("%s"," [FAILED]",e.join("\n"))}logRunningState(e,o,t){if(this.level<=LogLevel.Nothing)return;const l=[];e.length>1&&o.length<=0&&l.push("[WARNING] The cluster has no brokers! Channel messages will not be distributed to other workers.️️️"),l.push(`Join a new broker or worker by using the join token: ${t}`),logUpdate(table_1.table([Logger.RUNNING_TABLE_HEADER,...[...e,...o].map(({node:e})=>[e.id,0===e.type?"Worker"+(e.leader?" 👑":""):"Broker",e.ip,e.port])],{header:{alignment:"center",content:"Cluster"}})+l.join("\n"))}}exports.default=Logger,Logger.RUNNING_TABLE_HEADER=["Id","Type","IP","Port"];
@@ -16,16 +16,20 @@ declare module 'ziron-server' {
16
16
  path: string;
17
17
  uri: string;
18
18
  leader: boolean;
19
+ joinPayload?: Record<string, any>;
19
20
  };
20
21
  }
21
22
  }
22
- declare type WorkerJoinMiddleware = (socket: Socket, payload: Record<any, any>) => Promise<void> | void;
23
+ declare type WorkerJoinMiddleware = (socket: Socket, payload: Record<any, any>) => void;
23
24
  export declare class StateServer {
24
25
  get id(): string;
25
26
  private readonly _options;
26
27
  private _workerLeader;
27
28
  private _joinedWorkers;
28
29
  private _joinedBrokers;
30
+ get joinedWorkers(): Socket[];
31
+ get joinedBrokers(): Socket[];
32
+ get workerLeader(): Socket | null;
29
33
  private readonly _logger;
30
34
  /**
31
35
  * @description
@@ -41,6 +45,8 @@ export declare class StateServer {
41
45
  readonly procedures: StandaloneProcedures<'#leave' | '#join'>;
42
46
  readonly receivers: StandaloneReceivers;
43
47
  constructor(options?: StateServerOptions);
48
+ private _initScaleDelayActive;
49
+ private _startInitScaleDelayTicker;
44
50
  listen(): Promise<void>;
45
51
  private _logRunningState;
46
52
  private _getJoinToken;
@@ -1 +1 @@
1
- "use strict";var __awaiter=this&&this.__awaiter||function(e,t,r,s){return new(r||(r=Promise))((function(i,o){function n(e){try{d(s.next(e))}catch(e){o(e)}}function a(e){try{d(s.throw(e))}catch(e){o(e)}}function d(e){var t;e.done?i(e.value):(t=e.value,t instanceof r?t:new r((function(e){e(t)}))).then(n,a)}d((s=s.apply(e,t||[])).next())}))};Object.defineProperty(exports,"__esModule",{value:!0}),exports.StateServer=void 0;const ziron_server_1=require("ziron-server"),Logger_1=require("./Logger"),Crypto_1=require("./Crypto"),uniqId=require("uniqid"),ip=require("ip"),isIp=require("is-ip"),Object_1=require("./Object"),Errors_1=require("./Errors"),CLUSTER_VERSION=1;class StateServer{constructor(e={}){this._options={logLevel:1,secret:Crypto_1.generateSecret().substring(0,32),port:7777,path:"/",scaleDelay:100},this._workerLeader=null,this._joinedWorkers={},this._joinedBrokers={},this._clusterSession=null,this.procedures={},this.receivers={},this._handleWorkerJoin=(e,t,r,s)=>__awaiter(this,void 0,void 0,(function*(){if(this._joinedWorkers[e.node.id]===e)return r({session:this._clusterSession,brokers:this.getJoinedBrokersState()});"object"!=typeof t&&(t={});const{shared:i,payload:o}=t;if(this.workerJoinMiddleware)try{yield this.workerJoinMiddleware(e,"object"!=typeof o?{}:o)}catch(e){return s(new Error(e.message||"Join was blocked by the join middleware"))}if(this._isNodeIdInUse(e.node.id))return s(new Errors_1.IdAlreadyUsedInClusterError(e.node.id));0===Object.keys(this._joinedWorkers).length&&this._createClusterSession(i),this._joinedWorkers[e.node.id]=e,e.join("JoinedWorkers"),this._selectWorkerLeader(),r({session:this._clusterSession,brokers:this.getJoinedBrokersState()}),this._logRunningState()})),this._handleWorkerLeave=e=>{const t=e.node.id;this._joinedWorkers[t]===e&&(delete this._joinedWorkers[t],e.leave("JoinedWorkers"),this._workerLeader===e&&(this._workerLeader=null,e.node.leader=!1,this._selectWorkerLeader()),0===Object.keys(this._joinedWorkers).length&&this._resetClusterSession(),this._logRunningState())},this._handleBrokerJoin=(e,t,r,s)=>{const i=e.node.id;return this._joinedBrokers[i]===e?r():this._isNodeIdInUse(i)?s(new Errors_1.IdAlreadyUsedInClusterError(i)):(this._joinedBrokers[i]=e,this._scaleOut(),r(),void this._logRunningState())},this._handleBrokerLeave=e=>{const t=e.node.id;this._joinedBrokers[t]===e&&(delete this._joinedBrokers[e.node.id],this._scaleBack(),this._logRunningState())},this._workerLeaderSelectionPromise=Promise.resolve(),this._options=Object_1.buildOptions(this._options,e),this._logger=new Logger_1.default(this._options.logLevel),this.joinToken=this._getJoinToken(),this.server=new ziron_server_1.Server({port:this._options.port,pingInterval:1e3,path:this._options.path}),this._initServer()}get id(){return this.server.id}listen(){return __awaiter(this,void 0,void 0,(function*(){this.server.isListening()||(this._logger.logBusy("Launching state server..."),yield this.server.listen(),this._logger.logActive(`State server launched successfully on port: ${this._options.port}.`),this._logRunningState())}))}_logRunningState(){this._logger.logRunningState(Object.values(this._joinedWorkers),Object.values(this._joinedBrokers),this.joinToken)}_getJoinToken(){const e=ip.address(),t=""===this._options.path||"/"===this._options.path?"":this._options.path.startsWith("/")?this._options.path:"/"+this._options.path;return`${this._options.secret?this._options.secret+"@":""}ws://${isIp.v6(e)?`[${e}]`:e}:${this._options.port}${t}`}_initServer(){this.server.upgradeMiddleware=e=>{const t=e.attachment;if("object"!=typeof t)throw new ziron_server_1.Block(400,"Invalid attachment structure");if(t.secret!==this._options.secret)throw new ziron_server_1.Block(403,"Permission denied");if(1!==t.clusterVersion)throw new ziron_server_1.Block(412,"Incompatible cluster versions")},this.server.socketMiddleware=e=>{const t=e.handshakeAttachment.node;if("object"!=typeof t||0!==t.type&&1!==t.type||"string"!=typeof t.id||"number"!=typeof t.port||"string"!=typeof t.path)throw new ziron_server_1.Block(4005,"Invalid attachment structure");{const r="string"==typeof t.ip&&isIp(t.ip)?t.ip:e.remoteAddress;if(!r)throw new ziron_server_1.Block(4012,"Could not detect node IP address");if(""!==t.path&&!t.path.startsWith("/"))throw new ziron_server_1.Block(4005,"Invalid node path");e.node={id:t.id,type:t.type,ip:r,port:t.port,path:t.path,uri:`ws://${isIp.v6(r)?`[${r}]`:r}:${t.port}${t.path}`,leader:!1}}},this.server.connectionHandler=e=>{const t=e.node.type;return e.on("disconnect",0===t?()=>this._handleWorkerLeave(e):()=>this._handleBrokerLeave(e)),ziron_server_1.applyStandaloneProcedures(e,this.procedures),ziron_server_1.applyStandaloneReceivers(e,this.receivers),e.procedures["#leave"]=0===t?(t,r)=>{this._handleWorkerLeave(e),r()}:(t,r)=>{this._handleBrokerLeave(e),r()},e.procedures["#join"]=0===t?(...t)=>this._handleWorkerJoin(e,...t):(...t)=>this._handleBrokerJoin(e,...t),this.id}}_createClusterSession(e){this._clusterSession={id:uniqId(),shared:e}}_resetClusterSession(){this._clusterSession=null}static _getJoinedState(e){return{time:Date.now(),uris:Object.values(e).map(e=>e.node.uri)}}getJoinedBrokersState(){return StateServer._getJoinedState(this._joinedBrokers)}getJoinedWorkersState(){return StateServer._getJoinedState(this._joinedWorkers)}_getRandomWorker(){return Crypto_1.getRandomArrayItem(Object.values(this._joinedWorkers))}_selectWorkerLeader(){this._workerLeaderSelectionPromise=this._workerLeaderSelectionPromise.then(()=>this._selectWorkerLeaderProcess())}_selectWorkerLeaderProcess(){return __awaiter(this,void 0,void 0,(function*(){let e;if(null==this._workerLeader&&void 0!==(e=this._getRandomWorker())){try{yield e.invoke("addLeadership")}catch(e){return yield this._selectWorkerLeaderProcess()}e.node.leader=!0,this._workerLeader=e,this._logRunningState()}}))}_scaleOut(){this._setScaleTimeout(()=>this._updateWorkersBrokerState())}_scaleBack(){this._setScaleTimeout(()=>this._updateWorkersBrokerState())}_setScaleTimeout(e){null!=this._scaleTimeout&&clearTimeout(this._scaleTimeout),this._scaleTimeout=setTimeout(e,this._options.scaleDelay)}_updateWorkersBrokerState(){this.server.transmitToGroup("JoinedWorkers","updateBrokers",this.getJoinedBrokersState())}_isNodeIdInUse(e){return this._joinedWorkers.hasOwnProperty(e)||this._joinedBrokers.hasOwnProperty(e)||e===this.server.id}terminate(){this._workerLeader=null,this._joinedWorkers={},this._joinedBrokers={},this.server.terminate()}}exports.StateServer=StateServer;
1
+ "use strict";var __awaiter=this&&this.__awaiter||function(e,t,r,i){return new(r||(r=Promise))((function(s,o){function n(e){try{h(i.next(e))}catch(e){o(e)}}function a(e){try{h(i.throw(e))}catch(e){o(e)}}function h(e){var t;e.done?s(e.value):(t=e.value,t instanceof r?t:new r((function(e){e(t)}))).then(n,a)}h((i=i.apply(e,t||[])).next())}))};Object.defineProperty(exports,"__esModule",{value:!0}),exports.StateServer=void 0;const ziron_server_1=require("ziron-server"),Logger_1=require("./Logger"),Crypto_1=require("./Crypto"),uniqId=require("uniqid"),ip=require("ip"),isIp=require("is-ip"),Object_1=require("./Object"),Errors_1=require("./Errors"),CLUSTER_VERSION=1;class StateServer{constructor(e={}){this._options={logLevel:1,secret:Crypto_1.generateSecret().substring(0,32),port:7777,path:"/",scaleDelay:100,initScaleDelay:4e3},this._workerLeader=null,this._joinedWorkers={},this._joinedBrokers={},this._clusterSession=null,this.procedures={},this.receivers={},this._initScaleDelayActive=!0,this._handleWorkerJoin=(e,t,r,i)=>{if(this._joinedWorkers[e.node.id]===e)return r({session:this._clusterSession,brokers:this.getJoinedBrokersState()});"object"!=typeof t&&(t={});let{shared:s,payload:o}=t;if("object"!=typeof o&&(o={}),this.workerJoinMiddleware)try{this.workerJoinMiddleware(e,o)}catch(e){return i(e instanceof ziron_server_1.Block?e:new Error("Join was blocked by the join middleware"))}if(this._isNodeIdInUse(e.node.id))return i(new Errors_1.IdAlreadyUsedInClusterError(e.node.id));0===Object.keys(this._joinedWorkers).length&&this._createClusterSession(s),e.node.joinPayload=o,this._joinedWorkers[e.node.id]=e,e.join("JoinedWorkers"),this._selectWorkerLeader(),r({session:this._clusterSession,brokers:this._initScaleDelayActive?null:this.getJoinedBrokersState()}),this._logRunningState()},this._handleWorkerLeave=e=>{const t=e.node.id;this._joinedWorkers[t]===e&&(delete this._joinedWorkers[t],e.leave("JoinedWorkers"),this._workerLeader===e&&(this._workerLeader=null,e.node.leader=!1,this._selectWorkerLeader()),0===Object.keys(this._joinedWorkers).length&&this._resetClusterSession(),this._logRunningState())},this._handleBrokerJoin=(e,t,r,i)=>{const s=e.node.id;return this._joinedBrokers[s]===e?r():this._isNodeIdInUse(s)?i(new Errors_1.IdAlreadyUsedInClusterError(s)):(this._joinedBrokers[s]=e,this._scaleOut(),r(),void this._logRunningState())},this._handleBrokerLeave=e=>{const t=e.node.id;this._joinedBrokers[t]===e&&(delete this._joinedBrokers[e.node.id],this._scaleBack(),this._logRunningState())},this._workerLeaderSelectionPromise=Promise.resolve(),this._options=Object_1.buildOptions(this._options,e),this._logger=new Logger_1.default(this._options.logLevel),this.joinToken=this._getJoinToken(),this.server=new ziron_server_1.Server({port:this._options.port,pingInterval:1e3,path:this._options.path}),this._initServer()}get id(){return this.server.id}get joinedWorkers(){return Object.values(this._joinedWorkers)}get joinedBrokers(){return Object.values(this._joinedBrokers)}get workerLeader(){return this._workerLeader}_startInitScaleDelayTicker(){setTimeout(()=>{this._initScaleDelayActive=!1,this._updateWorkersBrokerState()},this._options.initScaleDelay)}listen(){return __awaiter(this,void 0,void 0,(function*(){if(!this.server.isListening())try{this._logger.logBusy("Launching state server..."),yield this.server.listen(),this._startInitScaleDelayTicker(),this._logger.logActive(`State server launched successfully on port: ${this._options.port}.`),this._logRunningState()}catch(e){throw e instanceof ziron_server_1.FailedToListenError&&this._logger.logFailed(`Failed to listen on port: ${this._options.port}. Maybe the port is already in use.`),e}}))}_logRunningState(){this._logger.logRunningState(Object.values(this._joinedWorkers),Object.values(this._joinedBrokers),this.joinToken)}_getJoinToken(){const e=ip.address(),t=""===this._options.path||"/"===this._options.path?"":this._options.path.startsWith("/")?this._options.path:"/"+this._options.path;return`${this._options.secret?this._options.secret+"@":""}ws://${isIp.v6(e)?`[${e}]`:e}:${this._options.port}${t}`}_initServer(){this.server.upgradeMiddleware=e=>{const t=e.attachment;if("object"!=typeof t)throw new ziron_server_1.Block(400,"Invalid attachment structure");if(t.secret!==this._options.secret)throw new ziron_server_1.Block(403,"Permission denied");if(1!==t.clusterVersion)throw new ziron_server_1.Block(412,"Incompatible cluster versions")},this.server.socketMiddleware=e=>{const t=e.handshakeAttachment.node;if("object"!=typeof t||0!==t.type&&1!==t.type||"string"!=typeof t.id||"number"!=typeof t.port||"string"!=typeof t.path)throw new ziron_server_1.Block(4005,"Invalid attachment structure");{const r="string"==typeof t.ip&&isIp(t.ip)?t.ip:e.remoteAddress;if(!r)throw new ziron_server_1.Block(4012,"Could not detect node IP address");if(""!==t.path&&!t.path.startsWith("/"))throw new ziron_server_1.Block(4005,"Invalid node path");e.node={id:t.id,type:t.type,ip:r,port:t.port,path:t.path,uri:`ws://${isIp.v6(r)?`[${r}]`:r}:${t.port}${t.path}`,leader:!1}}},this.server.connectionHandler=e=>{const t=e.node.type;return e.on("disconnect",0===t?()=>this._handleWorkerLeave(e):()=>this._handleBrokerLeave(e)),ziron_server_1.applyStandaloneProcedures(e,this.procedures),ziron_server_1.applyStandaloneReceivers(e,this.receivers),e.procedures["#leave"]=0===t?(t,r)=>{this._handleWorkerLeave(e),r()}:(t,r)=>{this._handleBrokerLeave(e),r()},e.procedures["#join"]=0===t?(...t)=>this._handleWorkerJoin(e,...t):(...t)=>this._handleBrokerJoin(e,...t),this.id}}_createClusterSession(e){this._clusterSession={id:uniqId(),shared:e}}_resetClusterSession(){this._clusterSession=null}static _getJoinedState(e){return{time:Date.now(),uris:Object.values(e).map(e=>e.node.uri)}}getJoinedBrokersState(){return StateServer._getJoinedState(this._joinedBrokers)}getJoinedWorkersState(){return StateServer._getJoinedState(this._joinedWorkers)}_getRandomWorker(){return Crypto_1.getRandomArrayItem(Object.values(this._joinedWorkers))}_selectWorkerLeader(){this._workerLeaderSelectionPromise=this._workerLeaderSelectionPromise.then(()=>this._selectWorkerLeaderProcess())}_selectWorkerLeaderProcess(){return __awaiter(this,void 0,void 0,(function*(){let e;if(null==this._workerLeader&&void 0!==(e=this._getRandomWorker())){try{yield e.invoke("addLeadership")}catch(e){return yield this._selectWorkerLeaderProcess()}e.node.leader=!0,this._workerLeader=e,this._logRunningState()}}))}_scaleOut(){this._setScaleTimeout(()=>this._updateWorkersBrokerState())}_scaleBack(){this._setScaleTimeout(()=>this._updateWorkersBrokerState())}_setScaleTimeout(e){null!=this._scaleTimeout&&clearTimeout(this._scaleTimeout),this._scaleTimeout=setTimeout(e,this._options.scaleDelay)}_updateWorkersBrokerState(){this.server.transmitToGroup("JoinedWorkers","updateBrokers",this.getJoinedBrokersState())}_isNodeIdInUse(e){return this._joinedWorkers.hasOwnProperty(e)||this._joinedBrokers.hasOwnProperty(e)||e===this.server.id}terminate(){this._workerLeader=null,this._joinedWorkers={},this._joinedBrokers={},this.server.terminate()}}exports.StateServer=StateServer;
@@ -5,4 +5,5 @@ export default interface StateServerOptions {
5
5
  port?: number;
6
6
  path?: string;
7
7
  scaleDelay?: number;
8
+ initScaleDelay?: number;
8
9
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ziron-state",
3
- "version": "7.2.0",
3
+ "version": "8.0.0",
4
4
  "description": "Ziron state",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -18,10 +18,10 @@
18
18
  "email": "lucacode1@gmail.com"
19
19
  },
20
20
  "dependencies": {
21
- "ziron-server": "7.2.0",
21
+ "ziron-server": "8.0.0",
22
22
  "log-update": "^4.0.0",
23
23
  "table": "^6.7.5",
24
- "ip": "^1.1.5",
24
+ "ip": "^1.1.8",
25
25
  "is-ip": "^3.1.0",
26
26
  "uniqid": "^5.4.0",
27
27
  "docker-secret": "^1.2.4"
@@ -37,7 +37,7 @@
37
37
  "mocha": "7.0.1",
38
38
  "@types/mocha": "^7.0.2",
39
39
  "@types/ip": "^1.1.0",
40
- "@types/uniqid": "^5.3.0"
40
+ "@types/uniqid": "^5.3.2"
41
41
  },
42
42
  "scripts": {
43
43
  "build": "gulp build",