@arcblock/ws 1.13.36 → 1.13.40

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.
Files changed (2) hide show
  1. package/lib/server/index.js +55 -13
  2. package/package.json +3 -2
@@ -1,9 +1,14 @@
1
1
  const EventEmitter = require('events');
2
+ const cluster = require('cluster');
3
+
2
4
  const uuid = require('uuid');
3
5
  const WebSocket = require('ws');
6
+ const eventHub = cluster.isMaster ? require('@arcblock/event-hub/single') : require('@arcblock/event-hub');
4
7
 
5
8
  const createLogger = require('../logger');
6
9
 
10
+ const sleep = (timeout) => new Promise((resolve) => setTimeout(resolve, timeout));
11
+
7
12
  const reply = (socket, topic, event, response, status = 'ok') => {
8
13
  if (socket.readyState === WebSocket.OPEN) {
9
14
  const res = JSON.stringify([socket.joinRef, socket.ref, topic, event, { status, response }]);
@@ -30,6 +35,7 @@ const defaultHooks = {
30
35
  * @param {Object} opts.authenticate - authentication function to be called on connection
31
36
  * @param {Object} opts.hooks - hooks to be called on events
32
37
  * @param {Object} opts.logger - logger used to log messages
38
+ * @param {Object} opts.broadcastEventName - used in cluster mode, default is '@arcblock/ws:broadcast'
33
39
  * @class WsServer
34
40
  * @extends {EventEmitter}
35
41
  */
@@ -47,6 +53,9 @@ class WsServer extends EventEmitter {
47
53
  this.wss.on('error', this.onWssError.bind(this));
48
54
 
49
55
  this.topics = {}; // <topic>: Set<socket>
56
+
57
+ this.broadcastEventName = opts.broadcastEventName || '@arcblock/ws:broadcast';
58
+ eventHub.on(this.broadcastEventName, (data) => this._doBroadCast(data));
50
59
  }
51
60
 
52
61
  attach(server) {
@@ -92,6 +101,11 @@ class WsServer extends EventEmitter {
92
101
  let event;
93
102
  let data;
94
103
  let options = {};
104
+ let cb = () => {};
105
+
106
+ if (typeof args[args.length - 1] === 'function') {
107
+ cb = args.pop();
108
+ }
95
109
 
96
110
  if (args.length < 2) {
97
111
  throw new Error('Broadcasting requires at least 2 arguments');
@@ -105,29 +119,57 @@ class WsServer extends EventEmitter {
105
119
  [topic, event, data, options] = args;
106
120
  }
107
121
 
108
- const opts = { enableLog: true, ...options };
122
+ const enableLog = options.enableLog !== undefined ? !!options.enableLog : true;
123
+ const replyId = uuid.v4();
109
124
 
125
+ // Count of clients what will receive the message
126
+ // The count is NOT reliable
110
127
  let count = 0;
128
+ eventHub.on(replyId, ({ count: c } = {}) => {
129
+ if (c) {
130
+ count += c;
131
+ }
132
+ });
111
133
 
112
- if (this.topics[topic] && this.topics[topic].size) {
113
- this.topics[topic].forEach((socket) => {
114
- count++;
115
- if (opts.enableLog) {
116
- this.logger.info('broadcast message to', { topic, event, id: socket.id });
117
- }
118
- reply(socket, topic, event, data);
119
- });
120
- } else if (opts.enableLog) {
121
- this.logger.info('no connections when broadcast message', { topic, event });
122
- }
134
+ eventHub.broadcast(this.broadcastEventName, { topic, event, data, options, enableLog, replyId });
135
+
136
+ // wait 600ms for message sending by each process
137
+ await sleep(600);
138
+ eventHub.off(replyId);
123
139
 
140
+ const opts = { count, topic, event, data, options };
141
+ cb(opts);
124
142
  try {
125
- await this.hooks.postBroadcast({ count, topic, event, data, options });
143
+ await this.hooks.postBroadcast(opts);
126
144
  } catch (error) {
127
145
  this.logger.error('postBroadcast error', { error });
128
146
  }
129
147
  }
130
148
 
149
+ async _doBroadCast({ topic, event, data, enableLog, replyId } = {}) {
150
+ try {
151
+ let count = 0;
152
+
153
+ if (this.topics[topic] && this.topics[topic].size) {
154
+ this.topics[topic].forEach((socket) => {
155
+ count++;
156
+ if (enableLog) {
157
+ this.logger.info('broadcast message to', { topic, event, id: socket.id });
158
+ }
159
+ reply(socket, topic, event, data);
160
+ });
161
+ } else if (enableLog) {
162
+ this.logger.info('no connections when broadcast message', { topic, event });
163
+ }
164
+
165
+ if (count > 0 && replyId) {
166
+ eventHub.broadcast(replyId, { count });
167
+ }
168
+ } catch (error) {
169
+ this.logger.error('_doBroadcast error', { error });
170
+ }
171
+ }
172
+
131
173
  /**
132
174
  * Send message to 1 subscriber of a topic, can be used as
133
175
  * - send(socket, event, data)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@arcblock/ws",
3
- "version": "1.13.36",
3
+ "version": "1.13.40",
4
4
  "description": "OCAP Chain websocket server and client",
5
5
  "keywords": [
6
6
  "websocket"
@@ -34,6 +34,7 @@
34
34
  "url": "https://github.com/ArcBlock/asset-chain/issues"
35
35
  },
36
36
  "dependencies": {
37
+ "@arcblock/event-hub": "1.13.40",
37
38
  "debug": "^4.3.2",
38
39
  "eventemitter3": "^4.0.4",
39
40
  "phoenix": "1.5.12",
@@ -43,5 +44,5 @@
43
44
  "devDependencies": {
44
45
  "get-port": "^5.1.1"
45
46
  },
46
- "gitHead": "856b0a35bdc74c11d18f19f49bfa9cd2a85dd8db"
47
+ "gitHead": "b540a835813d114c47236f929c7cf0df84949be9"
47
48
  }