cloudcms-server 0.9.261 → 0.9.262

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.
@@ -163,10 +163,10 @@ var handleInvalidate = function(req, res)
163
163
  // new timestamp
164
164
  process.env.CLOUDCMS_APPSERVER_TIMESTAMP = new Date().getTime();
165
165
 
166
- // update all socket clients
167
- process.IO.sockets.emit("timestamp", {
168
- "timestamp": process.env.CLOUDCMS_APPSERVER_TIMESTAMP
169
- });
166
+ // // update all socket clients
167
+ // process.IO.sockets.emit("timestamp", {
168
+ // "timestamp": process.env.CLOUDCMS_APPSERVER_TIMESTAMP
169
+ // });
170
170
 
171
171
  console.log("Server timestamp regenerated");
172
172
 
@@ -1,5 +1,18 @@
1
1
  const cluster = require("cluster");
2
2
 
3
+ // Handle uncaught exceptions...
4
+ process.on('uncaughtException', function(err, source) {
5
+ // if (err === "read ECONNRESET")
6
+ // {
7
+ // // skip
8
+ // }
9
+ // else
10
+ // {
11
+ console.log(`Launchpad - process received event 'uncaughtException': ${err}, source: ${source}`);
12
+ console.log(err.stack);
13
+ // }
14
+ });
15
+
3
16
  module.exports = function(type, config, options)
4
17
  {
5
18
  if (!type) {
@@ -6,6 +6,9 @@ const numCPUs = require("os").cpus().length;
6
6
  const { setupMaster, setupWorker } = require("@socket.io/sticky");
7
7
  const { createAdapter, setupPrimary } = require("@socket.io/cluster-adapter");
8
8
 
9
+ // numCPUs = 1;
10
+ // console.log("FORCE ONE CPU");
11
+
9
12
  module.exports = function(config) {
10
13
 
11
14
  var r = {};
@@ -14,7 +17,7 @@ module.exports = function(config) {
14
17
  {
15
18
  // setup sticky sessions
16
19
  setupMaster(httpServer, {
17
- loadBalancingMethod: "least-connection",
20
+ loadBalancingMethod: "least-connection"
18
21
  });
19
22
 
20
23
  // setup connections between the workers
@@ -46,14 +49,23 @@ module.exports = function(config) {
46
49
  var worker = cluster.fork(workerEnv);
47
50
 
48
51
  worker.on('message', function (msg, c) {
52
+ //console.log("Worker message: " + msg + ", c: " + c);
49
53
  if (msg === "worker-startup") {
50
54
  startupCount++;
51
55
  }
52
56
  });
53
57
 
58
+ worker.on('error', function(err) {
59
+ console.log("Worker.on(error) - " + JSON.stringify(err));
60
+ });
61
+
54
62
  workers.push(worker);
55
63
  }
56
64
 
65
+ cluster.on("error", function(err) {
66
+ console.log("Cluster.on(error) - " + JSON.stringify(err));
67
+ });
68
+
57
69
  cluster.on("exit", (worker) => {
58
70
  console.log(`Worker ${worker.process.pid} died`);
59
71
  cluster.fork();
@@ -79,19 +91,25 @@ module.exports = function(config) {
79
91
  // worker
80
92
 
81
93
  const io = new Server(httpServer);
82
-
94
+ httpServer.io = io;
95
+
83
96
  // use the cluster adapter
84
97
  io.adapter(createAdapter());
85
98
 
86
99
  // setup connection with the primary process
87
100
  setupWorker(io);
88
-
101
+
102
+ // on connect
89
103
  io.on("connection", (socket) => {
90
104
  // TODO
105
+
106
+ // always catch err
107
+ socket.on("error", function(err) {
108
+ console.log("Caught socket error");
109
+ console.log(err.stack);
110
+ });
91
111
  });
92
112
 
93
- httpServer.io = io;
94
-
95
113
  return callback();
96
114
  };
97
115
 
@@ -1,6 +1,6 @@
1
1
  const { Server } = require("socket.io");
2
2
  const { setupWorker } = require("@socket.io/sticky");
3
- const { createAdapter } = require("@socket.io/cluster-adapter");
3
+ const { createAdapter } = require("@socket.io/redis-adapter");
4
4
  const redisHelper = require("../../util/redis");
5
5
 
6
6
  const clusterLauncherFactory = require("./cluster");
@@ -23,30 +23,61 @@ module.exports = function(config) {
23
23
 
24
24
  r.afterStartServer = function(app, httpServer, callback)
25
25
  {
26
- const io = new Server(httpServer);
27
-
28
- (async function() {
26
+ (async function(app, httpServer, callback) {
29
27
  var redisOptions = redisHelper.redisOptions({}, "CLOUDCMS_CLUSTER");
30
28
  await redisHelper.createAndConnect(redisOptions, function(err, _client) {
31
-
29
+
32
30
  const pubClient = _client;
33
31
  const subClient = pubClient.duplicate();
34
-
35
- io.adapter(createAdapter(pubClient, subClient));
36
- //io.listen(httpServerPort);
37
-
38
- io.on("connection", (socket) => {
39
- // TODO
32
+
33
+ pubClient.on("error", function(err) {
34
+ // something went wrong
35
+ console.log("Pub Client caught error: ", err);
40
36
  });
41
-
37
+
38
+ subClient.on("error", function(err) {
39
+ // something went wrong
40
+ console.log("Sub Client caught error: ", err);
41
+ });
42
+
43
+ const io = new Server(httpServer);
44
+ httpServer.io = io;
45
+
46
+ io.engine.on("connection_error", function(err) {
47
+ // console.log("CONNECTION ERROR");
48
+ // console.log("REQUEST: " + err.req); // the request object
49
+ // console.log("CODE: " + err.code); // the error code, for example 1
50
+ // console.log("MESSAGE: " + err.message); // the error message, for example "Session ID unknown"
51
+ // console.log("CONTEXT: " + err.context); // some additional error context
52
+ });
53
+
54
+ // use the redis adapter
55
+ io.adapter(createAdapter(pubClient, subClient, {
56
+ //publishOnSpecificResponseChannel: true
57
+ }));
58
+
42
59
  // setup connection with the primary process
43
60
  setupWorker(io);
44
-
45
- httpServer.io = io;
46
-
61
+
62
+ // on connect
63
+ io.on("connection", (socket) => {
64
+ //console.log("Redis Launcher on('connection') - socket id:" + socket.id);
65
+ // socket.on('message', function(m) {
66
+ // console.log("Socket Connection message: " + m);
67
+ // });
68
+ //
69
+ // // always catch err
70
+ // socket.on("error", function(err) {
71
+ // console.log("Caught socket error");
72
+ // console.log(err.stack);
73
+ // });
74
+
75
+ // TODO
76
+ });
77
+
47
78
  return callback();
48
79
  });
49
- })();
80
+ })(app, httpServer, callback);
50
81
  };
51
82
 
52
83
  return r;
@@ -20,6 +20,12 @@ module.exports = function(config) {
20
20
 
21
21
  io.on("connection", (socket) => {
22
22
  // TODO
23
+
24
+ // always catch err
25
+ socket.on("error", function(err) {
26
+ console.log("Caught socket error");
27
+ console.log(err.stack);
28
+ });
23
29
  });
24
30
 
25
31
  httpServer.io = io;
@@ -1,6 +1,5 @@
1
1
  //var auth = require("../../../util/auth");
2
2
 
3
- //var SamlStrategy = require("../../../temp/passport-saml").Strategy;
4
3
  var SamlStrategy = require('passport-saml').Strategy;
5
4
  var AbstractProvider = require("./abstract");
6
5
 
@@ -60,10 +60,15 @@ exports = module.exports = function()
60
60
  if (!process.configuration.awareness.config) {
61
61
  process.configuration.awareness.config = {};
62
62
  }
63
-
63
+
64
+ // init any plugins?
65
+ if (!process.configuration.awareness.plugins) {
66
+ process.configuration.awareness.plugins = [];
67
+ }
68
+
64
69
  var type = process.configuration.awareness.type;
65
70
  var config = process.configuration.awareness.config;
66
-
71
+
67
72
  var providerFactory = require("./providers/" + type);
68
73
  provider = new providerFactory(config);
69
74
 
@@ -74,12 +79,6 @@ exports = module.exports = function()
74
79
  return callback(err);
75
80
  }
76
81
 
77
- // init any plugins?
78
- if (!process.configuration.awareness.plugins) {
79
- process.configuration.awareness.plugins = [];
80
- }
81
-
82
-
83
82
  var fns = [];
84
83
  for (var i = 0; i < pluginPaths.length; i++)
85
84
  {
@@ -115,15 +114,18 @@ exports = module.exports = function()
115
114
  /**
116
115
  * This gets called whenever a new socket is connected to the Cloud CMS server.
117
116
  *
117
+ * @param io
118
+ * @param callback
119
+ *
118
120
  * @type {Function}
119
121
  */
120
- var initSocketIO = r.initSocketIO = function(callback) {
121
-
122
+ var initSocketIO = r.initSocketIO = function(io, callback) {
123
+
122
124
  // initialize socket IO event handlers so that awareness binds to any new, incoming sockets
123
- socketInit(process.IO);
125
+ socketInit(io);
124
126
 
125
127
  // ensure the reaper is initialized
126
- reaperInit(process.IO, REAP_FREQUENCY_MS, REAP_MAX_AGE_MS, function(err) {
128
+ reaperInit(io, REAP_FREQUENCY_MS, REAP_MAX_AGE_MS, function(err) {
127
129
  callback(err);
128
130
  });
129
131
  };
@@ -172,7 +174,7 @@ exports = module.exports = function()
172
174
  // when a socket.io connection is established, we set up some default listeners for events that the client
173
175
  // may emit to us
174
176
  io.on("connection", function(socket) {
175
-
177
+
176
178
  // "register" -> indicates that a user is in a channel
177
179
  socket.on("register", function(channelId, user, dirty, callback) {
178
180
 
@@ -193,24 +195,32 @@ exports = module.exports = function()
193
195
  return callback(err);
194
196
  }
195
197
 
196
- // if we were already registered, just callback
197
- // however, if "dirty" is set, then we always hand back membership
198
- if (!dirty && alreadyRegistered)
199
- {
200
- return callback();
201
- }
202
-
203
- if (!alreadyRegistered)
204
- {
205
- // logger.info("New registration - channelId: " + channelId + ",userId=" + user.id + " (" + user.name + ")");
206
-
198
+ // // if we were already registered, just callback
199
+ // // however, if "dirty" is set, then we always hand back membership
200
+ // if (!dirty && alreadyRegistered)
201
+ // {
202
+ // logger.info("Already registered, not dirty - channelId: " + channelId + ",userId=" + user.id + " (" + user.name + ")");
203
+ //
204
+ // return callback();
205
+ // }
206
+ //
207
+ // if (!alreadyRegistered)
208
+ // {
209
+ // logger.info("New registration - channelId: " + channelId + ",userId=" + user.id + " (" + user.name + ")");
210
+
211
+ //logger.info("Register - channelId: " + channelId + ", userId=" + user.id + " (" + user.name + ")");
207
212
  socket.join(channelId);
208
- }
213
+ //}
209
214
 
210
215
  discover(channelId, function(err, userArray) {
211
216
 
212
- if (!err) {
213
- logger.info("Discover - channelId: " + channelId + ", userId=" + user.id + " (" + user.name + ") handing back: " + userArray.length);
217
+ if (err)
218
+ {
219
+ logger.info("Discover - channelId: " + channelId + ", err: " + JSON.stringify(err));
220
+ }
221
+ else
222
+ {
223
+ //logger.info("Discover - channelId: " + channelId + ", userId=" + user.id + " (" + user.name + ") handing back: " + userArray.length);
214
224
  io.sockets.in(channelId).emit("membershipChanged", channelId, userArray);
215
225
  }
216
226
 
@@ -412,6 +422,8 @@ exports = module.exports = function()
412
422
  */
413
423
  var register = r.register = function(channelId, user, callback)
414
424
  {
425
+ //console.log("Awareness - heard register, channel: " + channelId + ", user: " + user.id);
426
+
415
427
  provider.register(channelId, user, callback);
416
428
  };
417
429
 
@@ -14,28 +14,33 @@ class AbstractAsyncProvider extends AbstractProvider
14
14
  {
15
15
  super(config);
16
16
  }
17
-
17
+
18
+ _lock(lockKey, workFunction)
19
+ {
20
+ process.locks.lock(lockKey, workFunction);
21
+ }
22
+
18
23
  readOrCreateChannel(channelId, callback) {
19
24
 
20
25
  var self = this;
21
26
 
22
27
  self.readChannel(channelId, function(err, channel) {
23
-
28
+
24
29
  if (err) {
25
30
  return callback(err);
26
31
  }
27
-
32
+
28
33
  if (channel) {
29
34
  return callback(null, channel);
30
35
  }
31
36
 
32
37
  var channel = {};
33
38
  self.writeChannel(channelId, channel, function(err) {
34
-
39
+
35
40
  if (err) {
36
41
  return callback(err);
37
42
  }
38
-
43
+
39
44
  callback(null, channel);
40
45
  });
41
46
  });
@@ -46,26 +51,47 @@ class AbstractAsyncProvider extends AbstractProvider
46
51
  register(channelId, user, callback)
47
52
  {
48
53
  var self = this;
49
-
54
+
55
+ self._lock("channels", function(err, releaseLockFn) {
56
+ self.doRegister(channelId, user, function(err) {
57
+ callback(err);
58
+ return releaseLockFn();
59
+ });
60
+ });
61
+ }
62
+
63
+ /**
64
+ * Workhorse method. The "channels" lock is taken out ahead of this being called.
65
+ *
66
+ * @param channelId
67
+ * @param user
68
+ * @param callback
69
+ * @private
70
+ */
71
+ doRegister(channelId, user, callback)
72
+ {
73
+ var self = this;
74
+
50
75
  self.readOrCreateChannel(channelId, function (err, channel) {
51
-
76
+
52
77
  if (err) {
53
78
  return callback(err);
54
79
  }
55
-
80
+
56
81
  if (!channel.users) {
57
82
  channel.users = {};
58
83
  }
59
-
84
+
60
85
  channel.users[user.id] = {
61
86
  "user": user,
62
87
  "time": new Date().getTime()
63
88
  };
64
-
89
+
65
90
  self.writeChannel(channelId, channel, function (err) {
66
91
  callback(err);
67
92
  });
68
93
  });
94
+
69
95
  }
70
96
 
71
97
  discover(channelId, callback)
@@ -101,46 +127,86 @@ class AbstractAsyncProvider extends AbstractProvider
101
127
  });
102
128
  }
103
129
 
104
- expire(beforeMs, callback)
130
+ checkRegistered(channelId, userId, callback)
105
131
  {
106
132
  var self = this;
107
133
 
108
- self.listChannelIds(function(err, channelIds) {
134
+ self.readChannel(channelId, function(err, channel) {
109
135
 
110
136
  if (err) {
111
137
  return callback(err);
112
138
  }
113
139
 
140
+ if (!channel) {
141
+ return callback(null, false);
142
+ }
143
+
144
+ if (!channel.users) {
145
+ return callback(null, false);
146
+ }
147
+
148
+ if (channel.users[userId]) {
149
+ return callback(null, true);
150
+ }
151
+
152
+ callback(null, false);
153
+
154
+ });
155
+ }
156
+
157
+ expire(beforeMs, callback)
158
+ {
159
+ var self = this;
160
+
161
+ self._lock("channels", function(err, releaseLockFn) {
162
+ self._expire(beforeMs, function(err) {
163
+ callback(err);
164
+ return releaseLockFn();
165
+ });
166
+ });
167
+ }
168
+
169
+ /**
170
+ * @override
171
+ */
172
+ _expire(beforeMs, callback)
173
+ {
174
+ var self = this;
175
+
176
+ self.listChannelIds(function(err, channelIds) {
177
+
178
+ if (err) {
179
+ return callback(err);
180
+ }
181
+
114
182
  if (!channelIds || channelIds.length === 0) {
115
183
  return callback(null, [], {});
116
184
  }
117
-
185
+
118
186
  // a list of channel IDs whose memberships were updated
119
187
  var updatedMembershipChannelIds = [];
120
188
  var expiredUserIdsByChannelId = {};
121
-
189
+
122
190
  var fns = [];
123
-
191
+
124
192
  for (var i = 0; i < channelIds.length; i++)
125
193
  {
126
194
  var channelId = channelIds[i];
127
-
195
+
128
196
  var fn = function (channelId, updatedMembershipChannelIds, expiredUserIdsByChannelId, beforeMs) {
129
197
  return function (done) {
130
-
198
+
131
199
  self.readChannel(channelId, function(err, channel) {
132
-
200
+
133
201
  if (err) {
134
202
  return done(err);
135
203
  }
136
-
204
+
137
205
  if (!channel) {
138
206
  return done();
139
207
  }
140
-
141
- var updatedMembership = false;
142
-
143
- if (channel.users)
208
+
209
+ if (channel.users && Object.keys(channel.users).length > 0)
144
210
  {
145
211
  // populate all of the user IDs that need to be removed
146
212
  var userIdsToRemove = [];
@@ -149,75 +215,46 @@ class AbstractAsyncProvider extends AbstractProvider
149
215
  var entry = channel.users[userId];
150
216
  if (entry.time < beforeMs)
151
217
  {
152
- updatedMembership = true;
218
+ updatedMembershipChannelIds.push(channelId);
153
219
  userIdsToRemove.push(userId);
154
-
220
+
155
221
  var expiredUserIds = expiredUserIdsByChannelId[channelId]
156
222
  if (!expiredUserIds) {
157
223
  expiredUserIds = expiredUserIdsByChannelId[channelId] = [];
158
224
  }
159
-
225
+
160
226
  expiredUserIds.push(userId);
161
227
  }
162
228
  }
163
-
229
+
164
230
  // remove the user IDs
165
231
  for (var i = 0; i < userIdsToRemove.length; i++)
166
232
  {
167
233
  delete channel.users[userIdsToRemove[i]];
168
234
  }
235
+
236
+ self.writeChannel(channelId, channel, function() {
237
+ done();
238
+ });
169
239
  }
170
-
171
- if (updatedMembership)
172
- {
173
- updatedMembershipChannelIds.push(channelId);
174
- }
175
-
176
- done();
240
+
177
241
  });
178
242
  };
179
243
  }(channelId, updatedMembershipChannelIds, expiredUserIdsByChannelId, beforeMs);
180
244
  fns.push(fn);
181
245
  }
182
-
246
+
183
247
  async.parallel(fns, function(err) {
184
-
248
+
185
249
  if (err) {
186
250
  return callback(err);
187
251
  }
188
-
252
+
189
253
  callback(null, updatedMembershipChannelIds, expiredUserIdsByChannelId);
190
254
  });
191
255
  });
192
- }
193
-
194
- checkRegistered(channelId, userId, callback)
195
- {
196
- var self = this;
197
-
198
- self.readChannel(channelId, function(err, channel) {
199
-
200
- if (err) {
201
- return callback(err);
202
- }
203
-
204
- if (!channel) {
205
- return callback(null, false);
206
- }
207
-
208
- if (!channel.users) {
209
- return callback(null, false);
210
- }
211
-
212
- if (channel.users[userId]) {
213
- return callback(null, true);
214
- }
215
-
216
- callback(null, false);
217
-
218
- });
219
- }
220
-
256
+ };
257
+
221
258
  acquireLock(channelId, user, callback)
222
259
  {
223
260
  var self = this;
@@ -303,14 +340,16 @@ class AbstractAsyncProvider extends AbstractProvider
303
340
  callback(null, lock);
304
341
  });
305
342
  }
306
-
307
-
343
+
344
+
345
+
346
+
308
347
  //////////////////////////////////////////////////////////////////////////////////////////////////////////
309
348
  //
310
349
  // ABSTRACT METHODS
311
350
  //
312
351
  //////////////////////////////////////////////////////////////////////////////////////////////////////////
313
-
352
+
314
353
  // ABSTRACT
315
354
  readChannel(channelId, callback)
316
355
  {
@@ -328,7 +367,7 @@ class AbstractAsyncProvider extends AbstractProvider
328
367
  {
329
368
  throw new Error("listChannelIds() method is not implemented");
330
369
  }
331
-
370
+
332
371
  // ABSTRACT
333
372
  readLock(lockId, callback)
334
373
  {
@@ -2,7 +2,7 @@
2
2
  * Abstract class for an Awareness Provider.
3
3
  *
4
4
  * This class provides an interface or base functions that any implementation class must implement in order to
5
- * work with the Awareness Service. Any methods that
5
+ * work with the Awareness Service.
6
6
  *
7
7
  */
8
8
  class AbstractProvider
@@ -24,20 +24,6 @@ class MemoryProvider extends AbstractAsyncProvider
24
24
  callback();
25
25
  }
26
26
 
27
- readOrCreateChannel(channelId, callback)
28
- {
29
- var self = this;
30
-
31
- var channel = self.channelMap[channelId];
32
- if (channel) {
33
- return callback(null, channel);
34
- }
35
-
36
- channel = self.channelMap[channelId] = {};
37
-
38
- callback(null, channel);
39
- }
40
-
41
27
  readChannel(channelId, callback)
42
28
  {
43
29
  var self = this;