sockethub 4.1.0 → 5.0.0-alpha.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.
Files changed (71) hide show
  1. package/bin/sockethub +23 -20
  2. package/coverage/tmp/coverage-15699-1646422276150-0.json +1 -0
  3. package/dist/bootstrap/init.js +1 -1
  4. package/dist/bootstrap/init.js.map +1 -1
  5. package/dist/bootstrap/platforms.js +14 -18
  6. package/dist/janitor.js +11 -5
  7. package/dist/janitor.js.map +1 -1
  8. package/dist/middleware/create-activity-object.js.map +1 -1
  9. package/dist/middleware/expand-activity-stream.js +33 -0
  10. package/dist/middleware/expand-activity-stream.js.map +1 -0
  11. package/dist/middleware/expand-activity-stream.test.data.js +360 -0
  12. package/dist/middleware/expand-activity-stream.test.data.js.map +1 -0
  13. package/dist/middleware/store-credentials.js +1 -1
  14. package/dist/middleware/store-credentials.js.map +1 -1
  15. package/dist/middleware/validate.js +30 -104
  16. package/dist/middleware/validate.js.map +1 -1
  17. package/dist/middleware/validate.test.data.js +151 -111
  18. package/dist/middleware/validate.test.data.js.map +1 -1
  19. package/dist/middleware.js +47 -77
  20. package/dist/middleware.js.map +1 -1
  21. package/dist/platform-instance.js +47 -54
  22. package/dist/platform-instance.js.map +1 -1
  23. package/dist/platform.js +29 -10
  24. package/dist/platform.js.map +1 -1
  25. package/dist/process-manager.js +5 -2
  26. package/dist/process-manager.js.map +1 -1
  27. package/dist/routes.js +3 -5
  28. package/dist/routes.js.map +1 -1
  29. package/dist/sockethub-client.js +2604 -0
  30. package/dist/sockethub-client.js.map +1 -0
  31. package/dist/sockethub-client.min.js +2 -0
  32. package/dist/sockethub-client.min.js.LICENSE.txt +24 -0
  33. package/dist/sockethub.js +67 -36
  34. package/dist/sockethub.js.map +1 -1
  35. package/package.json +40 -36
  36. package/src/bootstrap/init.ts +6 -2
  37. package/src/bootstrap/platforms.js +14 -18
  38. package/src/crypto.ts +3 -3
  39. package/src/janitor.ts +18 -10
  40. package/src/middleware/create-activity-object.ts +1 -2
  41. package/src/middleware/expand-activity-stream.test.data.ts +365 -0
  42. package/src/middleware/expand-activity-stream.test.ts +78 -0
  43. package/src/middleware/expand-activity-stream.ts +27 -0
  44. package/src/middleware/store-credentials.test.ts +12 -12
  45. package/src/middleware/store-credentials.ts +4 -4
  46. package/src/middleware/validate.test.data.ts +154 -120
  47. package/src/middleware/validate.test.ts +7 -10
  48. package/src/middleware/validate.ts +30 -123
  49. package/src/middleware.test.ts +59 -26
  50. package/src/middleware.ts +44 -76
  51. package/src/platform-instance.test.ts +8 -10
  52. package/src/platform-instance.ts +58 -57
  53. package/src/platform.ts +30 -14
  54. package/src/process-manager.ts +7 -4
  55. package/src/routes.ts +3 -6
  56. package/src/serve.ts +1 -1
  57. package/src/sockethub-client.test.ts +235 -0
  58. package/src/sockethub-client.ts +164 -0
  59. package/src/sockethub.ts +75 -68
  60. package/views/examples/dummy.ejs +6 -6
  61. package/views/examples/feeds.ejs +8 -8
  62. package/views/examples/irc.ejs +64 -58
  63. package/views/examples/shared.js +31 -29
  64. package/views/examples/xmpp.ejs +48 -57
  65. package/webpack.minified.config.js +14 -0
  66. package/webpack.normal.config.js +14 -0
  67. package/coverage/tmp/coverage-24546-1630615250805-0.json +0 -1
  68. package/dist/client/sockethub-client.js +0 -171
  69. package/dist/client/sockethub-client.js.map +0 -1
  70. package/src/client/sockethub-client.js +0 -178
  71. package/test/middleware-suite.js +0 -101
@@ -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,
package/src/routes.ts CHANGED
@@ -10,15 +10,12 @@ const debug_scope = process.env.DEBUG || '',
10
10
  config.get('public:path');
11
11
 
12
12
  export const basePaths = {
13
- '/sockethub-client.js': path.resolve(`${__dirname}/../dist/client/sockethub-client.js`),
14
- '/sockethub-client.js.map': path.resolve(`${__dirname}/../dist/client/sockethub-client.js.map`),
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`),
15
16
  '/socket.io.js': path.resolve(`${__dirname}/../node_modules/socket.io/client-dist/socket.io.js`),
16
17
  '/socket.io.js.map': path.resolve(
17
18
  `${__dirname}/../node_modules/socket.io/client-dist/socket.io.js.map`),
18
- // '/activity-streams.js':
19
- // path.resolve(`${__dirname}/../node_modules/activity-streams/browser/activity-streams.js`),
20
- '/activity-streams.min.js':
21
- path.resolve(`${__dirname}/../node_modules/activity-streams/browser/activity-streams.min.js`),
22
19
  };
23
20
 
24
21
  export const examplePaths = {
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
  }
@@ -0,0 +1,235 @@
1
+ import proxyquire from 'proxyquire';
2
+ import { expect } from 'chai';
3
+ import * as sinon from 'sinon';
4
+ import { EventEmitter2 } from 'eventemitter2';
5
+
6
+ proxyquire.noPreserveCache();
7
+ proxyquire.noCallThru();
8
+
9
+ describe("SockethubClient bad initialization", () => {
10
+ it("no socket.io instance", () => {
11
+ const SockethubClient = proxyquire('./sockethub-client', {
12
+ 'activity-streams': (config: any) => {}
13
+ });
14
+ expect(() => {
15
+ const junk = new SockethubClient();
16
+ }).to.throw("SockethubClient requires a socket.io instance");
17
+ });
18
+ });
19
+
20
+ describe("SockethubClient", () => {
21
+ let ASManager, socket, sc, sandbox;
22
+
23
+ beforeEach(() => {
24
+ sandbox = sandbox = sinon.createSandbox();
25
+ socket = new EventEmitter2();
26
+ // @ts-ignore
27
+ socket.__instance = 'socketio'; // used to uniquely identify the object we're passing in
28
+ sandbox.spy(socket, 'on');
29
+ sandbox.spy(socket, 'emit');
30
+ ASManager = new EventEmitter2();
31
+ sandbox.spy(ASManager, 'on');
32
+ sandbox.spy(ASManager, 'emit');
33
+ ASManager.Stream = sandbox.stub();
34
+ ASManager.Object = {
35
+ create: sandbox.stub()
36
+ };
37
+ const SockethubClient = proxyquire('./sockethub-client', {
38
+ 'activity-streams': (config: any) => {
39
+ return ASManager;
40
+ }
41
+ });
42
+ sc = new SockethubClient(socket);
43
+ sandbox.spy(sc.socket, 'on');
44
+ sandbox.spy(sc.socket, '_on');
45
+ sandbox.spy(sc.socket, 'emit');
46
+ sandbox.spy(sc.socket, '_emit');
47
+ });
48
+
49
+ afterEach(() => {
50
+ sinon.restore();
51
+ });
52
+
53
+ it("contains the ActivityStreams property", () => {
54
+ expect(sc.ActivityStreams).to.be.eql(ASManager);
55
+ });
56
+
57
+ it("contains the socket property", () => {
58
+ expect(sc.socket instanceof EventEmitter2).to.be.true;
59
+ // the object we passed in should not be the publically available one
60
+ expect(sc.socket.__instance).to.not.equal('socketio');
61
+ expect(sc.debug).to.be.true;
62
+ expect(sc.online).to.be.false;
63
+ });
64
+
65
+ it("registers listeners for ActivityStream events", () => {
66
+ expect(ASManager.on.callCount).to.equal(1);
67
+ expect(ASManager.on.calledWithMatch('activity-object-create')).to.be.true;
68
+ });
69
+
70
+ it("registers a listeners for socket events", () => {
71
+ expect(socket.on.callCount).to.equal(5);
72
+ expect(socket.on.calledWithMatch('activity-object')).to.be.true;
73
+ expect(socket.on.calledWithMatch('connect')).to.be.true;
74
+ expect(socket.on.calledWithMatch('connect_error')).to.be.true;
75
+ expect(socket.on.calledWithMatch('disconnect')).to.be.true;
76
+ expect(socket.on.calledWithMatch('message')).to.be.true;
77
+ });
78
+
79
+ describe("event handling", () => {
80
+ it("activity-object", (done) => {
81
+ socket.emit('activity-object', {foo:"bar"});
82
+ setTimeout(() => {
83
+ sandbox.assert.calledWith(ASManager.Object.create, {foo:"bar"});
84
+ done();
85
+ }, 0);
86
+ });
87
+
88
+ it("activity-object-create", (done) => {
89
+ ASManager.emit('activity-object-create', {foo:"bar"});
90
+ setTimeout(() => {
91
+ expect(socket.emit.callCount).to.equal(1);
92
+ expect(socket.emit.calledWithMatch('activity-object', {foo:"bar"})).to.be.true;
93
+ done();
94
+ }, 0);
95
+ });
96
+
97
+ it("connect", (done) => {
98
+ expect(sc.online).to.be.false;
99
+ sc.socket.on("connect", () => {
100
+ expect(sc.online).to.be.true;
101
+ expect(sc.socket._emit.callCount).to.equal(1);
102
+ expect(sc.socket._emit.calledWithMatch('connect'));
103
+ done();
104
+ });
105
+ socket.emit("connect");
106
+ });
107
+
108
+ it("disconnect", (done) => {
109
+ sc.online = true;
110
+ sc.socket.on("disconnect", () => {
111
+ expect(sc.online).to.be.false;
112
+ expect(sc.socket._emit.callCount).to.equal(1);
113
+ expect(sc.socket._emit.calledWithMatch('disconnect'));
114
+ done();
115
+ });
116
+ socket.emit("disconnect");
117
+ });
118
+
119
+ it("connect_error", (done) => {
120
+ sc.socket.on("connect_error", () => {
121
+ expect(sc.socket._emit.callCount).to.equal(1);
122
+ expect(sc.socket._emit.calledWithMatch('connect_error'));
123
+ done();
124
+ });
125
+ socket.emit("connect_error");
126
+ });
127
+
128
+ it("message", (done) => {
129
+ sc.socket.on("message", () => {
130
+ expect(sc.socket._emit.callCount).to.equal(1);
131
+ expect(sc.socket._emit.calledWithMatch('message'));
132
+ done();
133
+ });
134
+ socket.emit("message");
135
+ });
136
+ });
137
+
138
+ describe("event emitting", () => {
139
+ it("message (no actor)", () => {
140
+ sc.online = true;
141
+ const callback = (res) => {};
142
+ expect(() => {
143
+ sc.socket.emit("message", {foo:"bar"}, callback);
144
+ }).to.throw("actor property not present");
145
+ });
146
+
147
+ it("message", (done) => {
148
+ sc.online = true;
149
+ const callback = (res) => {};
150
+ socket.once("message", (data, cb) => {
151
+ expect(data).to.be.eql({actor: "bar", type: "bar"});
152
+ expect(cb).to.be.eql(callback);
153
+ done();
154
+ });
155
+ sc.socket.emit("message", {actor:"bar", type: "bar"}, callback);
156
+ });
157
+
158
+ it("message (join)", (done) => {
159
+ sc.online = true;
160
+ const callback = (res) => {};
161
+ socket.once("message", (data, cb) => {
162
+ expect(data).to.be.eql({actor: "bar", type: "join"});
163
+ expect(cb).to.be.eql(callback);
164
+ done();
165
+ });
166
+ sc.socket.emit("message", {actor:"bar", type: "join"}, callback);
167
+ });
168
+
169
+ it("message (leave)", (done) => {
170
+ sc.online = true;
171
+ const callback = (res) => {};
172
+ socket.once("message", (data, cb) => {
173
+ expect(data).to.be.eql({actor: "bar", type: "leave"});
174
+ expect(cb).to.be.eql(callback);
175
+ done();
176
+ });
177
+ sc.socket.emit("message", {actor:"bar", type: "leave"}, callback);
178
+ });
179
+
180
+ it("message (connect)", (done) => {
181
+ sc.online = true;
182
+ const callback = (res) => {};
183
+ socket.once("message", (data, cb) => {
184
+ expect(data).to.be.eql({actor: "bar", type: "connect"});
185
+ expect(cb).to.be.eql(callback);
186
+ done();
187
+ });
188
+ sc.socket.emit("message", {actor:"bar", type: "connect"}, callback);
189
+ });
190
+
191
+ it("message (disconnect)", (done) => {
192
+ sc.online = true;
193
+ const callback = (res) => {};
194
+ socket.once("message", (data, cb) => {
195
+ expect(data).to.be.eql({actor: "bar", type: "disconnect"});
196
+ expect(cb).to.be.eql(callback);
197
+ done();
198
+ });
199
+ sc.socket.emit("message", {actor:"bar", type: "disconnect"}, callback);
200
+ });
201
+
202
+ it("message (offline)", (done) => {
203
+ sc.online = false;
204
+ const callback = (res) => {};
205
+ socket.once("message", (data, cb) => {
206
+ expect(data).to.be.eql({actor: "bar"});
207
+ expect(cb).to.be.eql(callback);
208
+ done();
209
+ });
210
+ sc.socket.emit("message", {actor:"bar"}, callback);
211
+ });
212
+
213
+ it("activity-object", (done) => {
214
+ sc.online = true;
215
+ const callback = (res) => {};
216
+ socket.once("activity-object", (data, cb) => {
217
+ expect(data).to.be.eql({actor: "bar"});
218
+ expect(cb).to.be.eql(callback);
219
+ done();
220
+ });
221
+ sc.socket.emit("activity-object", {actor:"bar"}, callback);
222
+ });
223
+
224
+ it("credentials", (done) => {
225
+ sc.online = true;
226
+ const callback = (res) => {};
227
+ socket.once("credentials", (data, cb) => {
228
+ expect(data).to.be.eql({actor: "bar"});
229
+ expect(cb).to.be.eql(callback);
230
+ done();
231
+ });
232
+ sc.socket.emit("credentials", {actor:"bar"}, callback);
233
+ });
234
+ });
235
+ });
@@ -0,0 +1,164 @@
1
+ import { EventEmitter2 } from 'eventemitter2';
2
+ import ASFactory from 'activity-streams';
3
+
4
+ export interface ActivityObjectManager {
5
+ create(obj: any): any;
6
+ delete(id: string): boolean;
7
+ list(): Array<string>,
8
+ get(id: string, expand: boolean): any;
9
+ }
10
+
11
+ export interface ASManager {
12
+ Stream(meta: any): any,
13
+ Object: ActivityObjectManager,
14
+ on(event, func): void;
15
+ once(event, func): void;
16
+ off(event, funcName): void;
17
+ }
18
+
19
+ class SockethubClient {
20
+ private _socket;
21
+ private events = {
22
+ 'credentials': new Map(),
23
+ 'activity-object': new Map(),
24
+ 'connect': new Map(),
25
+ 'join': new Map()
26
+ };
27
+ public socket;
28
+ public ActivityStreams: ASManager;
29
+ public online = false;
30
+ public debug = true;
31
+
32
+ constructor(socket) {
33
+ if (! socket) { throw new Error('SockethubClient requires a socket.io instance'); }
34
+ this._socket = socket;
35
+ // @ts-ignore
36
+ this.ActivityStreams = ASFactory({specialObjs: ['credentials']});
37
+
38
+ this.socket = this.createPublicEmitter();
39
+ this.registerSocketIOHandlers();
40
+
41
+ this.ActivityStreams.on('activity-object-create', (obj) => {
42
+ socket.emit('activity-object', obj, (err) => {
43
+ if (err) { console.error('failed to create activity-object ', err); }
44
+ else { this.eventActivityObject(obj); }
45
+ });
46
+ });
47
+
48
+ socket.on('activity-object', (obj) => {
49
+ this.ActivityStreams.Object.create(obj);
50
+ });
51
+ }
52
+
53
+ private createPublicEmitter(): EventEmitter2 {
54
+ let socket = new EventEmitter2({
55
+ wildcard: true,
56
+ verboseMemoryLeak: false
57
+ });
58
+ // @ts-ignore
59
+ socket._emit = socket.emit;
60
+ socket.emit = (event, content, callback): any => {
61
+ if (event === 'credentials') {
62
+ this.eventCredentials(content);
63
+ } else if (event === 'activity-object') {
64
+ this.eventActivityObject(content);
65
+ } else if (event === 'message') {
66
+ this.eventMessage(content);
67
+ }
68
+ this._socket.emit(event, content, callback);
69
+ };
70
+ return socket;
71
+ }
72
+
73
+ private eventActivityObject(content: any) {
74
+ if (content.id) {
75
+ this.events['activity-object'].set(content.id, content);
76
+ }
77
+ }
78
+
79
+ private eventCredentials(content: any) {
80
+ if ((content.object) && (content.object.type === 'credentials')) {
81
+ this.events['credentials'].set(content.actor.id || content.actor, content);
82
+ }
83
+ }
84
+
85
+ private eventMessage(content: any) {
86
+ if (! this.online) { return; }
87
+ // either store or delete the specified content onto the storedJoins map,
88
+ // for reply once we're back online.
89
+ const key = SockethubClient.getKey(content);
90
+ if (content.type === 'join' || content.type === 'connect') {
91
+ this.events[content.type].set(key, content);
92
+ } else if (content.type === 'leave') {
93
+ this.events['join'].delete(key);
94
+ } else if (content.type === 'disconnect') {
95
+ this.events['connect'].delete(key);
96
+ }
97
+ }
98
+
99
+ private static getKey(content: any) {
100
+ let actor = content.actor?.id || content.actor;
101
+ if (! actor) {
102
+ throw new Error("actor property not present for message type: " + content?.type);
103
+ }
104
+ let target = content.target ? content.target.id || content.target : '';
105
+ return actor + '-' + target;
106
+ }
107
+
108
+ private log(msg: string, obj?: any) {
109
+ if (this.debug) {
110
+ // eslint-disable-next-line security-node/detect-crlf
111
+ console.log(msg, obj);
112
+ }
113
+ }
114
+
115
+ private registerSocketIOHandlers() {
116
+ // middleware for events which don't deal in AS objects
117
+ const callHandler = (event: string) => {
118
+ return (obj, cb) => {
119
+ if (event === 'connect') {
120
+ this.online = true;
121
+ this.replay('activity-object', this.events['activity-object']);
122
+ this.replay('credentials', this.events['credentials']);
123
+ this.replay('message', this.events['connect']);
124
+ this.replay('message', this.events['join']);
125
+ } else if (event === 'disconnect') {
126
+ this.online = false;
127
+ }
128
+ this.socket._emit(event, obj, cb);
129
+ };
130
+ };
131
+
132
+ // register for events that give us information on connection status
133
+ this._socket.on('connect', callHandler('connect'));
134
+ this._socket.on('connect_error', callHandler('connect_error'));
135
+ this._socket.on('disconnect', callHandler('disconnect'));
136
+
137
+ // use as a middleware to receive incoming Sockethub messages and unpack them
138
+ // using the ActivityStreams library before passing them along to the app.
139
+ this._socket.on('message', (obj, cb) => {
140
+ this.socket._emit('message', this.ActivityStreams.Stream(obj), cb);
141
+ });
142
+ }
143
+
144
+ private replay(name: string, asMap: any) {
145
+ asMap.forEach((obj) => {
146
+ this.log(`replaying ${name}`, obj);
147
+ this._socket.emit(name, obj);
148
+ });
149
+ };
150
+ }
151
+
152
+ if (typeof module === 'object' && module.exports) {
153
+ module.exports = SockethubClient;
154
+ }
155
+
156
+ if (typeof exports === 'object') {
157
+ exports = SockethubClient; // lgtm [js/useless-assignment-to-local]
158
+ }
159
+
160
+ // @ts-ignore
161
+ if (typeof window === 'object') {
162
+ // @ts-ignore
163
+ window.SockethubClient = SockethubClient;
164
+ }
package/src/sockethub.ts CHANGED
@@ -3,14 +3,15 @@ import { Socket } from "socket.io";
3
3
 
4
4
  import crypto from './crypto';
5
5
  import init from './bootstrap/init';
6
- import createMiddleware from './middleware';
6
+ import middleware from './middleware';
7
7
  import createActivityObject from "./middleware/create-activity-object";
8
+ import expandActivityStream from "./middleware/expand-activity-stream";
8
9
  import storeCredentials from "./middleware/store-credentials";
9
10
  import validate from "./middleware/validate";
10
11
  import janitor from './janitor';
11
12
  import serve from './serve';
12
13
  import ProcessManager from "./process-manager";
13
- import { platformInstances } from "./platform-instance";
14
+ import PlatformInstance, { platformInstances } from "./platform-instance";
14
15
  import { getSessionStore } from "./store";
15
16
 
16
17
  const log = debug('sockethub:core');
@@ -18,7 +19,7 @@ const log = debug('sockethub:core');
18
19
 
19
20
  export interface JobDataDecrypted {
20
21
  title?: string;
21
- msg: ActivityObject;
22
+ msg: ActivityStream;
22
23
  sessionId: string;
23
24
  }
24
25
 
@@ -38,34 +39,34 @@ export interface JobEncrypted {
38
39
  remove?: Function;
39
40
  }
40
41
 
41
- export interface ActivityObject {
42
- '@type'?: string;
43
- actor?: string | {
44
- '@type': string;
45
- '@id'?: string;
42
+ export interface ActivityStream {
43
+ type: string;
44
+ context: string;
45
+ actor: {
46
+ id: string;
47
+ type?: string;
48
+ name?: string;
46
49
  },
47
50
  object?: {
48
- '@type': string;
51
+ type: string;
49
52
  content?: any;
50
53
  },
51
- target?: string | {
52
- '@type': string;
53
- '@id'?: string;
54
+ target?: {
55
+ type: string;
56
+ id: string;
57
+ name?: string;
54
58
  },
55
- context: string;
56
- error?: any;
59
+ error?: string;
57
60
  sessionSecret?: string;
58
61
  }
59
62
 
60
- function errorHandler(type, socket, log) {
61
- return function reportError(err, msg) {
62
- log('failure handling ' + type + '. ' + err);
63
- if (typeof msg !== 'object') {
64
- msg = { context: 'error' };
65
- }
66
- msg.error = err;
67
- socket.emit('failure', msg);
68
- };
63
+ function attachError(err, msg) {
64
+ if (typeof msg !== 'object') {
65
+ msg = { context: 'error' };
66
+ }
67
+ msg.error = err.toString();
68
+ delete msg.sessionSecret;
69
+ return msg;
69
70
  }
70
71
 
71
72
  class Sockethub {
@@ -104,31 +105,26 @@ class Sockethub {
104
105
  janitor.clean(); // start cleanup cycle
105
106
  serve.start(); // start external services
106
107
  log('registering handlers');
107
- serve.io.on('connection', this.incomingConnection.bind(this));
108
+ serve.io.on('connection', this.handleIncomingConnection.bind(this));
108
109
  }
109
110
 
110
- removeAllPlatformInstances() {
111
- for (let platform of platformInstances.values()) {
112
- platform.destroy();
111
+ async removeAllPlatformInstances() {
112
+ for (let platform of platformInstances) {
113
+ await platform[1].destroy();
113
114
  }
114
115
  }
115
116
 
116
- private handleIncomingMessage(socket: Socket, sessionLog: Function) {
117
- return (msg, done: Function) => {
118
- const platformInstance = this.processManager.get(msg.context, msg.actor['@id'], socket.id);
119
- const title = `${msg.context}-${(msg['@id']) ? msg['@id'] : this.counter++}`;
120
- sessionLog(`queued to channel ${platformInstance.id}`);
121
- const job: JobDataEncrypted = {
122
- title: title,
123
- sessionId: socket.id,
124
- msg: crypto.encrypt(msg, this.parentSecret1 + this.parentSecret2)
125
- };
126
- platformInstance.queue.add(job);
127
- done(job);
117
+ private createJob(socketId: string, platformInstance: PlatformInstance, msg): JobDataEncrypted {
118
+ const title = `${msg.context}-${(msg.id) ? msg.id : this.counter++}`;
119
+ const job: JobDataEncrypted = {
120
+ title: title,
121
+ sessionId: socketId,
122
+ msg: crypto.encrypt(msg, this.parentSecret1 + this.parentSecret2)
128
123
  };
124
+ return job;
129
125
  };
130
126
 
131
- private incomingConnection(socket: Socket) {
127
+ private handleIncomingConnection(socket: Socket) {
132
128
  const sessionLog = debug('sockethub:core:' + socket.id), // session-specific debug messages
133
129
  sessionSecret = crypto.randToken(16),
134
130
  // store instance is session-specific
@@ -137,40 +133,51 @@ class Sockethub {
137
133
  sessionLog(`socket.io connection`);
138
134
 
139
135
  socket.on('disconnect', () => {
140
- sessionLog('disconnect received from client.');
136
+ sessionLog('disconnect received from client');
141
137
  });
142
138
 
143
139
  socket.on('credentials',
144
- createMiddleware(errorHandler('credentials', socket, sessionLog))(
145
- validate('credentials', socket.id),
146
- storeCredentials(store, sessionLog)
147
- )
148
- );
149
-
150
- socket.on(
151
- 'message',
152
- createMiddleware(errorHandler('message', socket, sessionLog))(
153
- validate('message', socket.id),
154
- (msg, done) => {
155
- // middleware which attaches the sessionSecret to the message. The platform thread
156
- // must find the credentials on their own using the given sessionSecret, which indicates
157
- // that this specific session (socket connection) has provided credentials.
158
- msg.sessionSecret = sessionSecret;
159
- done(msg);
160
- },
161
- this.handleIncomingMessage(socket, sessionLog)
162
- )
163
- );
140
+ middleware('credentials')
141
+ .use(expandActivityStream)
142
+ .use(validate('credentials', socket.id))
143
+ .use(storeCredentials(store, sessionLog))
144
+ .use((err, data, next) => {
145
+ // error handler
146
+ next(attachError(err, data));
147
+ }).use((data, next) => { next(); })
148
+ .done());
164
149
 
165
150
  // when new activity objects are created on the client side, an event is
166
151
  // fired and we receive a copy on the server side.
167
- socket.on(
168
- 'activity-object',
169
- createMiddleware(errorHandler('message', socket, sessionLog))(
170
- validate('activity-object', socket.id),
171
- createActivityObject
172
- )
173
- );
152
+ socket.on('activity-object',
153
+ middleware('activity-object')
154
+ .use(validate('activity-object', socket.id))
155
+ .use(createActivityObject)
156
+ .use((err, data, next) => {
157
+ next(attachError(err, data));
158
+ }).use((data, next) => { next(); })
159
+ .done());
160
+
161
+ socket.on('message',
162
+ middleware('message')
163
+ .use(expandActivityStream)
164
+ .use(validate('message', socket.id))
165
+ .use((msg, next) => {
166
+ // The platform thread must find the credentials on their own using the given
167
+ // sessionSecret, which indicates that this specific session (socket
168
+ // connection) has provided credentials.
169
+ msg.sessionSecret = sessionSecret;
170
+ next(msg);
171
+ }).use((err, data, next) => {
172
+ next(attachError(err, data));
173
+ }).use((msg, next) => {
174
+ const platformInstance = this.processManager.get(msg.context, msg.actor.id, socket.id);
175
+ sessionLog(`queued to channel ${platformInstance.id}`);
176
+ const job = this.createJob(socket.id, platformInstance, msg);
177
+ // job validated and queued, store socket.io callback for when job is completed
178
+ platformInstance.completedJobHandlers.set(job.title, next);
179
+ platformInstance.queue.add(job);
180
+ }).done());
174
181
  }
175
182
  }
176
183