sockethub 4.0.1 → 5.0.0-alpha.1

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 (139) hide show
  1. package/README.md +3 -3
  2. package/bin/sockethub +23 -19
  3. package/dist/bootstrap/init.js +14 -4
  4. package/dist/bootstrap/init.js.map +1 -1
  5. package/dist/bootstrap/platforms.js +81 -69
  6. package/dist/common.js +10 -12
  7. package/dist/common.js.map +1 -1
  8. package/dist/config.js +4 -22
  9. package/dist/config.js.map +1 -1
  10. package/dist/crypto.js +7 -8
  11. package/dist/crypto.js.map +1 -1
  12. package/dist/janitor.js +14 -9
  13. package/dist/janitor.js.map +1 -1
  14. package/dist/middleware/create-activity-object.js +19 -0
  15. package/dist/middleware/create-activity-object.js.map +1 -0
  16. package/dist/middleware/expand-activity-stream.js +33 -0
  17. package/dist/middleware/expand-activity-stream.js.map +1 -0
  18. package/dist/middleware/expand-activity-stream.test.data.js +360 -0
  19. package/dist/middleware/expand-activity-stream.test.data.js.map +1 -0
  20. package/dist/middleware/store-credentials.js +19 -0
  21. package/dist/middleware/store-credentials.js.map +1 -0
  22. package/dist/middleware/validate.js +77 -0
  23. package/dist/middleware/validate.js.map +1 -0
  24. package/dist/middleware/validate.test.data.js +321 -0
  25. package/dist/middleware/validate.test.data.js.map +1 -0
  26. package/dist/middleware.js +47 -49
  27. package/dist/middleware.js.map +1 -1
  28. package/dist/platform-instance.js +84 -66
  29. package/dist/platform-instance.js.map +1 -1
  30. package/dist/platform.js +50 -25
  31. package/dist/platform.js.map +1 -1
  32. package/dist/process-manager.js +7 -4
  33. package/dist/process-manager.js.map +1 -1
  34. package/dist/routes.js +8 -6
  35. package/dist/routes.js.map +1 -1
  36. package/dist/serve.js +3 -3
  37. package/dist/serve.js.map +1 -1
  38. package/dist/sockethub-client.js +2604 -0
  39. package/dist/sockethub-client.js.map +1 -0
  40. package/dist/sockethub-client.min.js +2 -0
  41. package/dist/sockethub-client.min.js.LICENSE.txt +24 -0
  42. package/dist/sockethub.js +75 -58
  43. package/dist/sockethub.js.map +1 -1
  44. package/dist/store.js +17 -0
  45. package/dist/store.js.map +1 -0
  46. package/package.json +48 -44
  47. package/src/bootstrap/init.ts +16 -2
  48. package/src/bootstrap/platforms.js +14 -18
  49. package/src/common.test.ts +44 -33
  50. package/src/common.ts +9 -17
  51. package/src/config.test.ts +16 -38
  52. package/src/config.ts +1 -23
  53. package/src/crypto.test.ts +15 -17
  54. package/src/crypto.ts +4 -5
  55. package/src/janitor.ts +19 -12
  56. package/src/middleware/create-activity-object.test.ts +10 -0
  57. package/src/middleware/create-activity-object.ts +13 -0
  58. package/src/middleware/expand-activity-stream.test.data.ts +365 -0
  59. package/src/middleware/expand-activity-stream.test.ts +78 -0
  60. package/src/middleware/expand-activity-stream.ts +27 -0
  61. package/src/middleware/store-credentials.test.ts +72 -0
  62. package/src/middleware/store-credentials.ts +16 -0
  63. package/src/{validate.d.ts → middleware/validate.d.ts} +0 -0
  64. package/src/middleware/validate.test.data.ts +320 -0
  65. package/src/middleware/validate.test.ts +47 -0
  66. package/src/middleware/validate.ts +49 -0
  67. package/src/middleware.test.ts +148 -0
  68. package/src/middleware.ts +46 -51
  69. package/src/platform-instance.test.ts +224 -196
  70. package/src/platform-instance.ts +74 -58
  71. package/src/platform.ts +44 -24
  72. package/src/process-manager.ts +7 -4
  73. package/src/routes.test.ts +32 -19
  74. package/src/routes.ts +7 -5
  75. package/src/serve.ts +1 -1
  76. package/src/sockethub-client.test.ts +235 -0
  77. package/src/sockethub-client.ts +164 -0
  78. package/src/sockethub.ts +96 -93
  79. package/src/store.test.ts +26 -0
  80. package/src/store.ts +17 -0
  81. package/tsconfig.json +8 -8
  82. package/views/examples/dummy.ejs +7 -7
  83. package/views/examples/feeds.ejs +10 -10
  84. package/views/examples/irc.ejs +65 -59
  85. package/views/examples/shared.js +31 -29
  86. package/views/examples/xmpp.ejs +49 -58
  87. package/webpack.minified.config.js +14 -0
  88. package/webpack.normal.config.js +14 -0
  89. package/coverage/clover.xml +0 -190
  90. package/coverage/coverage-final.json +0 -6
  91. package/coverage/lcov-report/base.css +0 -224
  92. package/coverage/lcov-report/block-navigation.js +0 -79
  93. package/coverage/lcov-report/common.ts.html +0 -143
  94. package/coverage/lcov-report/config.ts.html +0 -359
  95. package/coverage/lcov-report/crypto.ts.html +0 -203
  96. package/coverage/lcov-report/favicon.png +0 -0
  97. package/coverage/lcov-report/index.html +0 -171
  98. package/coverage/lcov-report/platform-instance.ts.html +0 -740
  99. package/coverage/lcov-report/prettify.css +0 -1
  100. package/coverage/lcov-report/prettify.js +0 -2
  101. package/coverage/lcov-report/routes.ts.html +0 -353
  102. package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
  103. package/coverage/lcov-report/sorter.js +0 -170
  104. package/coverage/lcov-report/src/common.ts.html +0 -143
  105. package/coverage/lcov-report/src/config.ts.html +0 -359
  106. package/coverage/lcov-report/src/crypto.ts.html +0 -182
  107. package/coverage/lcov-report/src/index.html +0 -156
  108. package/coverage/lcov-report/src/platform-instance.ts.html +0 -740
  109. package/coverage/lcov-report/src/routes/base.ts.html +0 -359
  110. package/coverage/lcov-report/src/routes/examples.ts.html +0 -311
  111. package/coverage/lcov-report/src/routes/index.html +0 -111
  112. package/coverage/lcov-report/src/services/http.ts.html +0 -239
  113. package/coverage/lcov-report/src/services/index.html +0 -111
  114. package/coverage/lcov-report/src/services/redis.ts.html +0 -140
  115. package/coverage/lcov-report/src/shared-resources.ts.html +0 -104
  116. package/coverage/lcov.info +0 -336
  117. package/coverage/tmp/coverage-21649-1621596477257-0.json +0 -1
  118. package/dist/bootstrap/platforms.js.map +0 -1
  119. package/dist/js/client.js +0 -177
  120. package/dist/js/client.js.map +0 -1
  121. package/dist/resource-manager.js +0 -66
  122. package/dist/resource-manager.js.map +0 -1
  123. package/dist/routes/base.js +0 -92
  124. package/dist/routes/base.js.map +0 -1
  125. package/dist/routes/examples.js +0 -93
  126. package/dist/routes/examples.js.map +0 -1
  127. package/dist/services/http.js +0 -67
  128. package/dist/services/http.js.map +0 -1
  129. package/dist/services/redis.js +0 -23
  130. package/dist/services/redis.js.map +0 -1
  131. package/dist/shared-resources.js +0 -11
  132. package/dist/shared-resources.js.map +0 -1
  133. package/dist/validate.js +0 -157
  134. package/dist/validate.js.map +0 -1
  135. package/jest.config.js +0 -18
  136. package/src/js/client.js +0 -190
  137. package/src/validate.ts +0 -147
  138. package/test/middleware-suite.js +0 -101
  139. package/test/validate-suite.js +0 -338
@@ -3,13 +3,13 @@ import { join } from 'path';
3
3
  import { debug, Debugger } from 'debug';
4
4
  import Queue from 'bull';
5
5
 
6
- import redisConfig from "./config";
7
- import crypto from "./crypto";
8
- import { ActivityObject, Job } from "./sockethub";
6
+ import config from "./config";
7
+ import { ActivityStream, JobDataDecrypted, JobEncrypted } from "./sockethub";
9
8
  import { getSocket } from "./serve";
9
+ import { decryptJobData } from "./common";
10
10
 
11
11
  // collection of platform instances, stored by `id`
12
- export const platformInstances = new Map();
12
+ export const platformInstances = new Map<string, PlatformInstance>();
13
13
 
14
14
  export interface PlatformInstanceParams {
15
15
  identifier: string;
@@ -18,26 +18,32 @@ export interface PlatformInstanceParams {
18
18
  actor?: string;
19
19
  }
20
20
 
21
- interface MessageFromPlatform extends Array<string|ActivityObject>{
22
- 0: string, 1: ActivityObject, 2: string}
21
+ interface MessageFromPlatform extends Array<string|ActivityStream>{
22
+ 0: string, 1: ActivityStream, 2: string}
23
23
  export interface MessageFromParent extends Array<string|any>{0: string, 1: any}
24
24
 
25
+ interface PlatformConfig {
26
+ persist?: boolean;
27
+ requireCredentials?: Array<string>;
28
+ }
25
29
 
26
30
  export default class PlatformInstance {
27
31
  flaggedForTermination: boolean = false;
28
32
  id: string;
29
33
  queue: Queue;
34
+ completedJobHandlers: Map<string, Function> = new Map();
35
+ config: PlatformConfig = {};
30
36
  readonly name: string;
31
37
  readonly process: ChildProcess;
32
38
  readonly debug: Debugger;
33
39
  readonly parentId: string;
34
40
  readonly sessions: Set<string> = new Set();
35
- public readonly global?: boolean = false;
36
- private readonly actor?: string;
37
- private readonly sessionCallbacks: object = {
41
+ readonly sessionCallbacks: object = {
38
42
  'close': (() => new Map())(),
39
- 'message': (() => new Map())(),
43
+ 'message': (() => new Map())()
40
44
  };
45
+ public readonly global?: boolean = false;
46
+ private readonly actor?: string;
41
47
 
42
48
  constructor(params: PlatformInstanceParams) {
43
49
  this.id = params.identifier;
@@ -57,37 +63,46 @@ export default class PlatformInstance {
57
63
  /**
58
64
  * Destroys all references to this platform instance, internal listeners and controlled processes
59
65
  */
60
- public destroy() {
66
+ public async destroy() {
67
+ this.debug(`cleaning up`);
61
68
  this.flaggedForTermination = true;
62
- platformInstances.delete(this.id);
63
69
  try {
64
- this.queue.clean(0);
70
+ await this.queue.removeAllListeners();
71
+ } catch (e) { }
72
+ try {
73
+ await this.queue.obliterate({ force: true });
65
74
  } catch (e) { }
66
75
  try {
67
- this.process.removeAllListeners('close');
68
- this.process.unref();
69
- this.process.kill();
76
+ delete this.queue;
77
+ await this.process.removeAllListeners('close');
78
+ await this.process.unref();
79
+ await this.process.kill();
70
80
  } catch (e) { }
81
+ platformInstances.delete(this.id);
71
82
  }
72
83
 
73
84
  /**
74
85
  * When jobs are completed or failed, we prepare the results and send them to the client socket
75
86
  */
76
87
  public initQueue(secret: string) {
77
- this.queue = new Queue(this.parentId + this.id, redisConfig);
78
- this.queue.on('global:completed', (jobId, result) => {
79
- this.queue.getJob(jobId).then((job) => {
80
- job.data.msg = crypto.decrypt(job.data.msg, secret);
81
- this.handleJobResult('completed', job, result);
88
+ this.queue = new Queue(this.parentId + this.id, { redis: config.get('redis') });
89
+
90
+ this.queue.on('global:completed', (jobId, resultString) => {
91
+ const result = resultString ? JSON.parse(resultString) : "";
92
+ this.queue.getJob(jobId).then(async (job: JobEncrypted) => {
93
+ await this.handleJobResult('completed', decryptJobData(job, secret), result);
94
+ await job.remove();
82
95
  });
83
96
  });
97
+
84
98
  this.queue.on('global:error', (jobId, result) => {
85
99
  this.debug("unknown queue error", jobId, result);
86
100
  });
101
+
87
102
  this.queue.on('global:failed', (jobId, result) => {
88
- this.queue.getJob(jobId).then((job) => {
89
- job.data.msg = crypto.decrypt(job.data.msg, secret);
90
- this.handleJobResult('failed', job, result);
103
+ this.queue.getJob(jobId).then(async (job: JobEncrypted) => {
104
+ await this.handleJobResult('failed', decryptJobData(job, secret), result);
105
+ await job.remove();
91
106
  });
92
107
  });
93
108
  }
@@ -111,54 +126,58 @@ export default class PlatformInstance {
111
126
  * Sends a message to client (user), can be registered with an event emitted from the platform
112
127
  * process.
113
128
  * @param sessionId ID of the socket connection to send the message to
114
- * @param type type of message to emit. 'message', 'completed', 'failed'
115
129
  * @param msg ActivityStream object to send to client
116
130
  */
117
- public sendToClient(sessionId: string, type: string, msg: ActivityObject) {
131
+ public sendToClient(sessionId: string, msg: ActivityStream) {
118
132
  getSocket(sessionId).then((socket) => {
119
133
  try {
120
134
  // this property should never be exposed externally
121
135
  delete msg.sessionSecret;
122
136
  } catch (e) {}
123
137
  msg.context = this.name;
124
- socket.emit(type, msg);
138
+ if ((msg.type === 'error') && (typeof msg.actor === 'undefined') && (this.actor)) {
139
+ // ensure an actor is present if not otherwise defined
140
+ msg.actor = { id: this.actor };
141
+ }
142
+ socket.emit('message', msg);
125
143
  }, (err) => this.debug(`sendToClient ${err}`));
126
144
  }
127
145
 
128
146
  // send message to every connected socket associated with this platform instance.
129
- private async broadcastToSharedPeers(sessionId: string, msg: ActivityObject) {
147
+ private async broadcastToSharedPeers(sessionId: string, msg: ActivityStream) {
130
148
  for (let sid of this.sessions.values()) {
131
149
  if (sid !== sessionId) {
132
150
  this.debug(`broadcasting message to ${sid}`);
133
- this.sendToClient(sid, 'message', msg);
151
+ await this.sendToClient(sid, msg);
134
152
  }
135
153
  }
136
154
  }
137
155
 
138
156
  // handle job results coming in on the queue from platform instances
139
- private handleJobResult(type: string, job: Job, result) {
140
- this.debug(`job ${job.data.title}: ${type}`);
141
-
142
- if ((type === 'completed') && (result)) {
143
- job.data.msg.object = {
144
- '@type': 'result',
145
- content: result
146
- };
147
- } else if (type === 'failed') {
148
- job.data.msg.object = {
149
- '@type': 'error',
150
- content: result ? result : "job failed for unknown reason"
151
- };
157
+ private async handleJobResult(type: string, jobData: JobDataDecrypted, result) {
158
+ this.debug(`${type} job ${jobData.title}`);
159
+ delete jobData.msg.sessionSecret;
160
+ let msg = jobData.msg;
161
+ if (type === 'failed') {
162
+ msg.error = result ? result : "job failed for unknown reason";
163
+ if ((this.config.persist) && (this.config.requireCredentials.includes(jobData.msg.type))) {
164
+ this.debug(`critical job type ${jobData.msg.type} failed, terminating platform instance`);
165
+ await this.destroy();
166
+ }
152
167
  }
153
168
 
154
- // send message to client as completed for failed job
155
- this.sendToClient(job.data.sessionId, type, job.data.msg);
169
+ // send result to client
170
+ const callback = this.completedJobHandlers.get(jobData.title);
171
+ if (callback) {
172
+ callback(msg);
173
+ this.completedJobHandlers.delete(jobData.title);
174
+ } else {
175
+ await this.sendToClient(jobData.sessionId, msg);
176
+ }
156
177
 
157
178
  // let all related peers know of result as an independent message
158
179
  // (not as part of a job completion, or failure)
159
- this.broadcastToSharedPeers(job.data.sessionId, job.data.msg);
160
-
161
- job.remove();
180
+ await this.broadcastToSharedPeers(jobData.sessionId, msg);
162
181
  }
163
182
 
164
183
  /**
@@ -166,19 +185,16 @@ export default class PlatformInstance {
166
185
  * @param sessionId
167
186
  * @param errorMessage
168
187
  */
169
- private reportError(sessionId: string, errorMessage: any) {
170
- const errorObject: ActivityObject = {
188
+ private async reportError(sessionId: string, errorMessage: any) {
189
+ const errorObject: ActivityStream = {
171
190
  context: this.name,
172
- '@type': 'error',
173
- target: this.actor,
174
- object: {
175
- '@type': 'error',
176
- content: errorMessage
177
- }
191
+ type: 'error',
192
+ actor: { id: this.actor },
193
+ error: errorMessage
178
194
  };
179
- this.sendToClient(sessionId, 'message', errorObject);
195
+ this.sendToClient(sessionId, errorObject);
180
196
  this.sessions.clear();
181
- this.destroy();
197
+ await this.destroy();
182
198
  }
183
199
 
184
200
  /**
@@ -211,7 +227,7 @@ export default class PlatformInstance {
211
227
  this.reportError(sessionId, data[1]);
212
228
  } else {
213
229
  // treat like a message to clients
214
- this.sendToClient(sessionId, 'message', data[1]);
230
+ this.sendToClient(sessionId, data[1]);
215
231
  }
216
232
  }
217
233
  };
package/src/platform.ts CHANGED
@@ -1,11 +1,11 @@
1
1
  import debug from 'debug';
2
2
  import hash from "object-hash";
3
- import redisConfig from './config';
4
- import crypto from "./crypto";
3
+ import config from './config';
5
4
  import Queue from 'bull';
6
- import { getSessionStore, getPlatformId, Store } from "./common";
7
- import { ActivityObject, Job } from "./sockethub";
5
+ import { getPlatformId, decryptJobData } from "./common";
6
+ import { ActivityStream, JobDataDecrypted, JobEncrypted } from "./sockethub";
8
7
  import { MessageFromParent } from './platform-instance';
8
+ import { getSessionStore } from "./store";
9
9
 
10
10
  // command-line params
11
11
  const parentId = process.argv[2];
@@ -23,7 +23,7 @@ logger(`platform handler initialized for ${platformName} ${identifier}`);
23
23
 
24
24
  export interface PlatformSession {
25
25
  debug(msg: string): void;
26
- sendToClient(msg: ActivityObject, special?: string): void;
26
+ sendToClient(msg: ActivityStream, special?: string): void;
27
27
  updateActor(credentials: object): void;
28
28
  }
29
29
 
@@ -31,7 +31,8 @@ export interface PlatformSession {
31
31
  * Handle any uncaught errors from the platform by alerting the worker and shutting down.
32
32
  */
33
33
  process.on('uncaughtException', (err) => {
34
- console.log(`\nUNCAUGHT EXCEPTION IN PLATFORM\n`);
34
+ console.log('EXCEPTION IN PLATFORM');
35
+ // eslint-disable-next-line security-node/detect-crlf
35
36
  console.log(err.stack);
36
37
  process.send(['error', err.toString()]);
37
38
  process.exit(1);
@@ -70,7 +71,7 @@ const platform = new PlatformModule(platformSession);
70
71
  */
71
72
  function getCredentials(actorId: string, sessionId: string, sessionSecret: string, cb: Function) {
72
73
  if (platform.config.noCredentials) { return cb(); }
73
- const store: Store = getSessionStore(parentId, parentSecret1, sessionId, sessionSecret);
74
+ const store = getSessionStore(parentId, parentSecret1, sessionId, sessionSecret);
74
75
  store.get(actorId, (err, credentials) => {
75
76
  if (platform.config.persist) {
76
77
  // don't continue if we don't get credentials
@@ -83,7 +84,7 @@ function getCredentials(actorId: string, sessionId: string, sessionSecret: strin
83
84
  if (platform.credentialsHash) {
84
85
  if (platform.credentialsHash !== hash(credentials.object)) {
85
86
  return cb('provided credentials do not match existing platform instance for actor '
86
- + platform.actor['@id']);
87
+ + platform.actor.id);
87
88
  }
88
89
  } else {
89
90
  platform.credentialsHash = hash(credentials.object);
@@ -97,29 +98,48 @@ function getCredentials(actorId: string, sessionId: string, sessionSecret: strin
97
98
  * @param secret the secret used to decrypt credentials
98
99
  */
99
100
  function getJobHandler(secret: string) {
100
- return (job: Job, done: Function) => {
101
- job.data.msg = crypto.decrypt(job.data.msg, secret);
102
- const jobLog = debug(`${loggerPrefix}:${job.data.sessionId}`);
103
- jobLog(`job ${job.data.title}: ${job.data.msg['@type']}`);
104
- const sessionSecret = job.data.msg.sessionSecret;
105
- delete job.data.msg.sessionSecret;
106
-
107
- return getCredentials(job.data.msg.actor['@id'], job.data.sessionId, sessionSecret,
101
+ return (job: JobEncrypted, done: Function) => {
102
+ const jobData: JobDataDecrypted = decryptJobData(job, secret);
103
+ const jobLog = debug(`${loggerPrefix}:${jobData.sessionId}`);
104
+ jobLog(`received ${jobData.title} ${jobData.msg.type}`);
105
+ const sessionSecret = jobData.msg.sessionSecret;
106
+ delete jobData.msg.sessionSecret;
107
+
108
+ return getCredentials(jobData.msg.actor.id, jobData.sessionId, sessionSecret,
108
109
  (err, credentials) => {
109
110
  if (err) { return done(new Error(err)); }
111
+ let jobCallbackCalled = false;
110
112
  const doneCallback = (err, result) => {
113
+ if (jobCallbackCalled) { return; }
114
+ jobCallbackCalled = true;
111
115
  if (err) {
112
- done(new Error(err));
116
+ jobLog(`errored ${jobData.title} ${jobData.msg.type}`);
117
+ let errMsg;
118
+ // some error objects (eg. TimeoutError) don't interoplate correctly to human-readable
119
+ // so we have to do this little dance
120
+ try {
121
+ errMsg = err.toString();
122
+ } catch (e) {
123
+ errMsg = err;
124
+ }
125
+ done(new Error(errMsg));
113
126
  } else {
127
+ jobLog(`completed ${jobData.title} ${jobData.msg.type}`);
114
128
  done(null, result);
115
129
  }
116
130
  };
117
131
  if ((Array.isArray(platform.config.requireCredentials)) &&
118
- (platform.config.requireCredentials.includes(job.data.msg['@type']))) {
132
+ (platform.config.requireCredentials.includes(jobData.msg.type))) {
119
133
  // add the credentials object if this method requires it
120
- platform[job.data.msg['@type']](job.data.msg, credentials, doneCallback);
134
+ platform[jobData.msg.type](jobData.msg, credentials, doneCallback);
135
+ } else if (platform.config.persist) {
136
+ if (platform.initialized) {
137
+ platform[jobData.msg.type](jobData.msg, doneCallback);
138
+ } else {
139
+ done(new Error(`${jobData.msg.type} called on uninitialized platform`));
140
+ }
121
141
  } else {
122
- platform[job.data.msg['@type']](job.data.msg, doneCallback);
142
+ platform[jobData.msg.type](jobData.msg, doneCallback);
123
143
  }
124
144
  });
125
145
  };
@@ -131,7 +151,7 @@ function getJobHandler(secret: string) {
131
151
  * @param command string containing the type of command to be sent. 'message' or 'close'
132
152
  */
133
153
  function getSendFunction(command: string) {
134
- return function (msg: ActivityObject, special?: string) {
154
+ return function (msg: ActivityStream, special?: string) {
135
155
  process.send([command, msg, special]);
136
156
  };
137
157
  }
@@ -142,8 +162,8 @@ function getSendFunction(command: string) {
142
162
  * @param credentials
143
163
  */
144
164
  function updateActor(credentials) {
145
- identifier = getPlatformId(platformName, credentials.actor['@id']);
146
- logger(`platform actor updated to ${credentials.actor['@id']} identifier ${identifier}`);
165
+ identifier = getPlatformId(platformName, credentials.actor.id);
166
+ logger(`platform actor updated to ${credentials.actor.id} identifier ${identifier}`);
147
167
  logger = debug(`sockethub:platform:${identifier}`);
148
168
  platform.credentialsHash = hash(credentials.object);
149
169
  platform.debug = debug(`sockethub:platform:${platformName}:${identifier}`);
@@ -162,7 +182,7 @@ function startQueueListener(refresh: boolean = false) {
162
182
  logger('start queue called multiple times, skipping');
163
183
  return;
164
184
  }
165
- const queue = new Queue(parentId + identifier, redisConfig);
185
+ const queue = new Queue(parentId + identifier, { redis: config.get('redis') });
166
186
  queueStarted = true;
167
187
  logger('listening on the queue for incoming jobs');
168
188
  queue.process(getJobHandler(secret));
@@ -1,7 +1,7 @@
1
1
  import init from './bootstrap/init';
2
- import PlatformInstance, { platformInstances, PlatformInstanceParams } from "./platform-instance";
2
+ import PlatformInstance, {
3
+ platformInstances, PlatformInstanceParams, MessageFromParent } from "./platform-instance";
3
4
  import { getPlatformId } from "./common";
4
- import { MessageFromParent } from "./platform-instance";
5
5
 
6
6
  class ProcessManager {
7
7
  private readonly parentId: string;
@@ -16,14 +16,17 @@ class ProcessManager {
16
16
 
17
17
  get(platform: string, actorId: string, sessionId?: string): PlatformInstance {
18
18
  const platformDetails = init.platforms.get(platform);
19
+ let pi;
19
20
 
20
21
  if (platformDetails.config.persist) {
21
22
  // ensure process is started - one for each actor
22
- return this.ensureProcess(platform, sessionId, actorId);
23
+ pi = this.ensureProcess(platform, sessionId, actorId);
23
24
  } else {
24
25
  // ensure process is started - one for all jobs
25
- return this.ensureProcess(platform);
26
+ pi = this.ensureProcess(platform);
26
27
  }
28
+ pi.config = platformDetails.config;
29
+ return pi;
27
30
  }
28
31
 
29
32
  private createPlatformInstance(identifier: string, platform: string,
@@ -1,12 +1,19 @@
1
+ import { expect } from 'chai';
2
+ import * as sinon from 'sinon';
1
3
  import { existsSync } from "fs";
2
4
 
3
5
  import routes, { basePaths, examplePaths, examplePages } from "./routes";
4
6
 
5
7
  describe('routes/base', () => {
8
+
9
+ afterEach(() => {
10
+ sinon.restore();
11
+ });
12
+
6
13
  it('can find each of the base files it serves', () => {
7
14
  Object.values(basePaths).forEach((fwd: string) => {
8
15
  try {
9
- expect(existsSync(fwd)).toBeTruthy();
16
+ expect(existsSync(fwd)).to.be.true;
10
17
  } catch (e) {
11
18
  throw new Error(`Unable to resolve path ${fwd}`);
12
19
  }
@@ -16,7 +23,7 @@ describe('routes/base', () => {
16
23
  it('can find each of the example files it serves', () => {
17
24
  Object.values(examplePaths).forEach((fwd: string) => {
18
25
  try {
19
- expect(existsSync(fwd)).toBeTruthy();
26
+ expect(existsSync(fwd)).to.be.true;
20
27
  } catch (e) {
21
28
  throw new Error(`Unable to resolve path ${fwd}`);
22
29
  }
@@ -26,7 +33,7 @@ describe('routes/base', () => {
26
33
  it('can find each of the example page files it serves', () => {
27
34
  Object.values(examplePages).forEach((fwd: string) => {
28
35
  try {
29
- expect(existsSync(fwd)).toBeTruthy();
36
+ expect(existsSync(fwd)).to.be.true;
30
37
  } catch (e) {
31
38
  throw new Error(`Unable to resolve path ${fwd}`);
32
39
  }
@@ -34,20 +41,26 @@ describe('routes/base', () => {
34
41
  });
35
42
 
36
43
  it('adds base routes', () => {
37
- let app = {
38
- get: jest.fn()
44
+ const app = {
45
+ get: sinon.spy()
39
46
  };
40
- routes.setup(app);
41
- expect(app['get']).toBeCalledTimes(Object.keys(basePaths).length);
47
+ routes.setup(app, false);
48
+ sinon.assert.callCount(
49
+ app.get,
50
+ Object.keys(basePaths).length
51
+ );
42
52
  });
43
53
 
44
54
  it('adds base and example routes', () => {
45
- let app = {
46
- get: jest.fn()
55
+ const app = {
56
+ get: sinon.spy()
47
57
  };
48
58
  routes.setup(app, true);
49
- expect(app['get']).toBeCalledTimes(
50
- Object.keys(basePaths).length + Object.keys(examplePaths).length + Object.keys(examplePages).length
59
+ sinon.assert.callCount(
60
+ app.get,
61
+ Object.keys(basePaths).length
62
+ + Object.keys(examplePaths).length
63
+ + Object.keys(examplePages).length
51
64
  );
52
65
  });
53
66
 
@@ -63,13 +76,13 @@ describe('routes/base', () => {
63
76
  function verifyPathRoutes(pathMap) {
64
77
  Object.keys(pathMap).forEach((path) => {
65
78
  const res = {
66
- setHeader: jest.fn(),
67
- sendFile: jest.fn()
79
+ setHeader: sinon.spy(),
80
+ sendFile: sinon.spy()
68
81
  };
69
- expect(pathMap[path].endsWith('.ejs')).toBeFalsy();
82
+ expect(pathMap[path].endsWith('.ejs')).to.be.false;
70
83
  routeHandlers[path]({url: path}, res);
71
- expect(res.setHeader).toHaveBeenCalled();
72
- expect(res.sendFile).toHaveBeenCalledWith(pathMap[path]);
84
+ sinon.assert.called(res.setHeader);
85
+ sinon.assert.calledWith(res.sendFile, pathMap[path]);
73
86
  });
74
87
  }
75
88
  verifyPathRoutes(basePaths);
@@ -77,11 +90,11 @@ describe('routes/base', () => {
77
90
 
78
91
  Object.keys(examplePages).forEach((path) => {
79
92
  const res = {
80
- render: jest.fn()
93
+ render: sinon.spy()
81
94
  };
82
- expect(examplePages[path].endsWith('.ejs')).toBeTruthy();
95
+ expect(examplePages[path].endsWith('.ejs')).to.be.true;
83
96
  routeHandlers[path]({url: path}, res);
84
- expect(res.render).toHaveBeenCalled();
97
+ sinon.assert.called(res.render);
85
98
  });
86
99
  });
87
100
  });
package/src/routes.ts CHANGED
@@ -1,21 +1,21 @@
1
1
  import path from 'path';
2
2
  import config from "./config";
3
+ import debug from 'debug';
3
4
 
4
5
  const debug_scope = process.env.DEBUG || '',
6
+ logger = debug('sockethub:routes'),
5
7
  address = config.get('public:protocol') + '://' +
6
8
  config.get('public:host') + ':' +
7
9
  config.get('public:port') +
8
10
  config.get('public:path');
9
11
 
10
12
  export const basePaths = {
11
- '/sockethub-client.js': path.resolve(`${__dirname}/js/client.js`),
13
+ '/sockethub-client.js': path.resolve(`${__dirname}/../dist/sockethub-client.js`),
14
+ '/sockethub-client.min.js': path.resolve(`${__dirname}/../dist/sockethub-client.min.js`),
15
+ '/sockethub-client.js.map': path.resolve(`${__dirname}/../dist/sockethub-client.js.map`),
12
16
  '/socket.io.js': path.resolve(`${__dirname}/../node_modules/socket.io/client-dist/socket.io.js`),
13
17
  '/socket.io.js.map': path.resolve(
14
18
  `${__dirname}/../node_modules/socket.io/client-dist/socket.io.js.map`),
15
- // '/activity-streams.js':
16
- // path.resolve(`${__dirname}/../node_modules/activity-streams/browser/activity-streams.js`),
17
- '/activity-streams.min.js':
18
- path.resolve(`${__dirname}/../node_modules/activity-streams/browser/activity-streams.min.js`),
19
19
  };
20
20
 
21
21
  export const examplePaths = {
@@ -42,6 +42,7 @@ function prepFileRoutes(pathMap) {
42
42
  path: key
43
43
  },
44
44
  route: (req, res) => {
45
+ logger(`serving resource ${req.url}`);
45
46
  res.setHeader('Access-Control-Allow-Origin', '*');
46
47
  res.sendFile(pathMap[req.url]);
47
48
  }
@@ -60,6 +61,7 @@ Object.keys(examplePages).forEach((key) => {
60
61
  path: key
61
62
  },
62
63
  route: (req, res) => {
64
+ logger(`serving page ${req.url}`);
63
65
  res.render(examplePages[req.url], {
64
66
  debug_scope: debug_scope,
65
67
  address: address,
package/src/serve.ts CHANGED
@@ -59,7 +59,7 @@ class Serve {
59
59
 
60
60
  const serve = new Serve();
61
61
 
62
- interface SocketInstance {
62
+ export interface SocketInstance {
63
63
  id: string;
64
64
  emit: Function;
65
65
  }