@arcblock/ws 1.13.36 → 1.13.40

Sign up to get free protection for your applications and to get access to all the features.
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
  }