@sockethub/server 5.0.0-alpha.4 → 5.0.0-alpha.6
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.
- package/README.md +54 -60
- package/bin/sockethub +4 -3
- package/package.json +42 -54
- package/res/socket.io.js +4908 -0
- package/res/sockethub-client.js +602 -0
- package/res/sockethub-client.min.js +19 -0
- package/sockethub.config.example.json +2 -3
- package/src/bootstrap/init.d.ts +16 -13
- package/src/bootstrap/init.test.ts +211 -0
- package/src/bootstrap/init.ts +152 -76
- package/src/bootstrap/load-platforms.ts +151 -0
- package/src/config.test.ts +27 -22
- package/src/config.ts +82 -86
- package/src/defaults.json +24 -16
- package/src/index.ts +61 -22
- package/src/janitor.test.ts +191 -169
- package/src/janitor.ts +141 -118
- package/src/listener.ts +148 -58
- package/src/middleware/create-activity-object.test.ts +28 -8
- package/src/middleware/create-activity-object.ts +16 -10
- package/src/middleware/expand-activity-stream.test.data.ts +331 -345
- package/src/middleware/expand-activity-stream.test.ts +65 -66
- package/src/middleware/expand-activity-stream.ts +26 -21
- package/src/middleware/store-credentials.test.ts +74 -60
- package/src/middleware/store-credentials.ts +14 -8
- package/src/middleware/validate.test.data.ts +240 -242
- package/src/middleware/validate.test.ts +39 -78
- package/src/middleware/validate.ts +62 -36
- package/src/middleware.test.ts +168 -138
- package/src/middleware.ts +57 -55
- package/src/platform-instance.test.ts +508 -214
- package/src/platform-instance.ts +324 -231
- package/src/platform.test.ts +375 -0
- package/src/platform.ts +306 -117
- package/src/process-manager.ts +75 -51
- package/src/routes.test.ts +43 -89
- package/src/routes.ts +40 -78
- package/src/sentry.test.ts +106 -0
- package/src/sentry.ts +19 -0
- package/src/sockethub.ts +190 -129
- package/src/util.ts +5 -0
- package/coverage/tmp/coverage-39338-1663949520416-0.json +0 -1
- package/dist/bootstrap/init.d.ts +0 -18
- package/dist/bootstrap/init.js +0 -64
- package/dist/bootstrap/init.js.map +0 -1
- package/dist/bootstrap/platforms.js +0 -75
- package/dist/config.d.ts +0 -12
- package/dist/config.js +0 -107
- package/dist/config.js.map +0 -1
- package/dist/defaults.json +0 -28
- package/dist/index.d.ts +0 -1
- package/dist/index.js +0 -29
- package/dist/index.js.map +0 -1
- package/dist/janitor.d.ts +0 -30
- package/dist/janitor.js +0 -120
- package/dist/janitor.js.map +0 -1
- package/dist/listener.d.ts +0 -31
- package/dist/listener.js +0 -94
- package/dist/listener.js.map +0 -1
- package/dist/middleware/create-activity-object.d.ts +0 -8
- package/dist/middleware/create-activity-object.js +0 -19
- package/dist/middleware/create-activity-object.js.map +0 -1
- package/dist/middleware/expand-activity-stream.d.ts +0 -3
- package/dist/middleware/expand-activity-stream.js +0 -36
- package/dist/middleware/expand-activity-stream.js.map +0 -1
- package/dist/middleware/expand-activity-stream.test.data.d.ts +0 -480
- package/dist/middleware/expand-activity-stream.test.data.js +0 -360
- package/dist/middleware/expand-activity-stream.test.data.js.map +0 -1
- package/dist/middleware/store-credentials.d.ts +0 -3
- package/dist/middleware/store-credentials.js +0 -9
- package/dist/middleware/store-credentials.js.map +0 -1
- package/dist/middleware/validate.d.ts +0 -2
- package/dist/middleware/validate.js +0 -56
- package/dist/middleware/validate.js.map +0 -1
- package/dist/middleware/validate.test.data.d.ts +0 -532
- package/dist/middleware/validate.test.data.js +0 -263
- package/dist/middleware/validate.test.data.js.map +0 -1
- package/dist/middleware.d.ts +0 -21
- package/dist/middleware.js +0 -56
- package/dist/middleware.js.map +0 -1
- package/dist/platform-instance.d.ts +0 -78
- package/dist/platform-instance.js +0 -226
- package/dist/platform-instance.js.map +0 -1
- package/dist/platform.d.ts +0 -6
- package/dist/platform.js +0 -176
- package/dist/platform.js.map +0 -1
- package/dist/process-manager.d.ts +0 -11
- package/dist/process-manager.js +0 -82
- package/dist/process-manager.js.map +0 -1
- package/dist/routes.d.ts +0 -13
- package/dist/routes.js +0 -83
- package/dist/routes.js.map +0 -1
- package/dist/sockethub.d.ts +0 -18
- package/dist/sockethub.js +0 -112
- package/dist/sockethub.js.map +0 -1
- package/src/bootstrap/platforms.js +0 -75
- package/test/init-suite.js +0 -41
- package/test/sockethub-suite.js +0 -25
- package/tsconfig.json +0 -18
- package/views/examples/dummy.ejs +0 -95
- package/views/examples/feeds.ejs +0 -90
- package/views/examples/irc.ejs +0 -239
- package/views/examples/shared.js +0 -72
- package/views/examples/xmpp.ejs +0 -217
- package/views/index.ejs +0 -17
package/src/janitor.ts
CHANGED
|
@@ -1,133 +1,156 @@
|
|
|
1
|
-
import debug from
|
|
2
|
-
|
|
3
|
-
import
|
|
4
|
-
import
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
async stop(): Promise<void> {
|
|
32
|
-
this.stopTriggered = true;
|
|
33
|
-
rmLog('stopping, terminating all sessions');
|
|
34
|
-
for (const platformInstance of platformInstances.values()) {
|
|
35
|
-
this.removeStaleSocketSessions(platformInstance);
|
|
36
|
-
await this.removeStalePlatformInstance(platformInstance);
|
|
37
|
-
await platformInstance.shutdown();
|
|
1
|
+
import debug from "debug";
|
|
2
|
+
|
|
3
|
+
import listener, { type SocketInstance } from "./listener.js";
|
|
4
|
+
import type PlatformInstance from "./platform-instance.js";
|
|
5
|
+
import { platformInstances } from "./platform-instance.js";
|
|
6
|
+
|
|
7
|
+
const rmLog = debug("sockethub:server:janitor");
|
|
8
|
+
|
|
9
|
+
export class Janitor {
|
|
10
|
+
cycleInterval = 15000;
|
|
11
|
+
cycleCount = 0; // a counter for each cycleInterval
|
|
12
|
+
reportCount = 0; // number of times a report is printed
|
|
13
|
+
protected stopTriggered = false;
|
|
14
|
+
protected sockets: Array<SocketInstance>;
|
|
15
|
+
private cycleRunning = false;
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Every TICK the `Janitor` will compare existing platform instances with `socket.ids`
|
|
19
|
+
* (aka. `sessionId`). If all the `sessionIds` associated with a `platformInstance` have
|
|
20
|
+
* no corresponding `socket.id` (from the `http.io` `socket.io` instance), then the
|
|
21
|
+
* `platformInstance` will first be flagged, if after the next `cycleInterval` the same
|
|
22
|
+
* state is determined, the platform will be destroyed (this allows for page
|
|
23
|
+
* refreshes not destroying platform instances)
|
|
24
|
+
*/
|
|
25
|
+
start(): void {
|
|
26
|
+
rmLog("initializing");
|
|
27
|
+
this.clean().then(() => {
|
|
28
|
+
rmLog("cleaning cycle started");
|
|
29
|
+
});
|
|
38
30
|
}
|
|
39
|
-
}
|
|
40
31
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
32
|
+
async stop(): Promise<void> {
|
|
33
|
+
this.stopTriggered = true;
|
|
34
|
+
rmLog("stopping, terminating all sessions");
|
|
35
|
+
for (const platformInstance of platformInstances.values()) {
|
|
36
|
+
this.removeStaleSocketSessions(platformInstance);
|
|
37
|
+
await this.removeStalePlatformInstance(platformInstance);
|
|
38
|
+
await platformInstance.shutdown();
|
|
39
|
+
}
|
|
46
40
|
}
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
41
|
+
|
|
42
|
+
private removeSessionCallbacks(
|
|
43
|
+
platformInstance: PlatformInstance,
|
|
44
|
+
sessionId: string,
|
|
45
|
+
): void {
|
|
46
|
+
for (const key in platformInstance.sessionCallbacks) {
|
|
47
|
+
platformInstance.process.removeListener(
|
|
48
|
+
key,
|
|
49
|
+
platformInstance.sessionCallbacks[key].get(sessionId),
|
|
50
|
+
);
|
|
51
|
+
platformInstance.sessionCallbacks[key].delete(sessionId);
|
|
52
|
+
}
|
|
56
53
|
}
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
private async removeStalePlatformInstance(platformInstance: PlatformInstance): Promise<void> {
|
|
69
|
-
if ((platformInstance.flaggedForTermination) || (this.stopTriggered)) {
|
|
70
|
-
rmLog(`terminating platform instance ${platformInstance.id}`);
|
|
71
|
-
await platformInstance.shutdown(); // terminate
|
|
72
|
-
} else {
|
|
73
|
-
rmLog(`flagging for termination platform instance ${platformInstance.id} ` +
|
|
74
|
-
`(no registered sessions found)`);
|
|
75
|
-
platformInstance.flaggedForTermination = true;
|
|
54
|
+
|
|
55
|
+
private removeStaleSocketSessions(
|
|
56
|
+
platformInstance: PlatformInstance,
|
|
57
|
+
): void {
|
|
58
|
+
for (const sessionId of platformInstance.sessions.values()) {
|
|
59
|
+
if (this.stopTriggered || !this.socketExists(sessionId)) {
|
|
60
|
+
this.removeStaleSocketSession(platformInstance, sessionId);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
76
63
|
}
|
|
77
|
-
}
|
|
78
64
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
65
|
+
private removeStaleSocketSession(
|
|
66
|
+
platformInstance: PlatformInstance,
|
|
67
|
+
sessionId: string,
|
|
68
|
+
) {
|
|
69
|
+
rmLog(
|
|
70
|
+
`removing ${
|
|
71
|
+
!this.stopTriggered ? "stale " : ""
|
|
72
|
+
}socket session reference ${sessionId}
|
|
73
|
+
in platform instance ${platformInstance.id}`,
|
|
74
|
+
);
|
|
75
|
+
platformInstance.sessions.delete(sessionId);
|
|
76
|
+
this.removeSessionCallbacks(platformInstance, sessionId);
|
|
84
77
|
}
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
// Static platforms are for global use, not tied to a unique to session / eg. credentials)
|
|
99
|
-
if (!platformInstance.global) {
|
|
100
|
-
if ((!platformInstance.initialized) || (platformInstance.sessions.size === 0)) {
|
|
101
|
-
// either the platform failed to initialize, or there are no more sessions linked to it
|
|
102
|
-
await this.removeStalePlatformInstance(platformInstance);
|
|
103
|
-
}
|
|
78
|
+
|
|
79
|
+
private async removeStalePlatformInstance(
|
|
80
|
+
platformInstance: PlatformInstance,
|
|
81
|
+
): Promise<void> {
|
|
82
|
+
if (platformInstance.flaggedForTermination || this.stopTriggered) {
|
|
83
|
+
rmLog(`terminating platform instance ${platformInstance.id}`);
|
|
84
|
+
await platformInstance.shutdown(); // terminate
|
|
85
|
+
} else {
|
|
86
|
+
rmLog(
|
|
87
|
+
`flagging for termination platform instance ${platformInstance.id} (no registered sessions found)`,
|
|
88
|
+
);
|
|
89
|
+
platformInstance.flaggedForTermination = true;
|
|
90
|
+
}
|
|
104
91
|
}
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
92
|
+
|
|
93
|
+
private socketExists(sessionId: string) {
|
|
94
|
+
for (const socket of this.sockets) {
|
|
95
|
+
if (socket.id === sessionId) {
|
|
96
|
+
return true;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
return false;
|
|
113
100
|
}
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
101
|
+
|
|
102
|
+
private async delay(ms: number): Promise<void> {
|
|
103
|
+
return await new Promise((resolve) => setTimeout(resolve, ms));
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
private async getSockets(): Promise<Array<SocketInstance>> {
|
|
107
|
+
return listener.io.fetchSockets();
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
private async performStaleCheck(platformInstance: PlatformInstance) {
|
|
111
|
+
this.removeStaleSocketSessions(platformInstance);
|
|
112
|
+
// Static platforms are for global use, not tied to a unique to session
|
|
113
|
+
// (e.g. a stateful platform where credentials are supplied)
|
|
114
|
+
if (!platformInstance.global) {
|
|
115
|
+
if (
|
|
116
|
+
(platformInstance.config.persist &&
|
|
117
|
+
!platformInstance.config.initialized) ||
|
|
118
|
+
platformInstance.sessions.size === 0
|
|
119
|
+
) {
|
|
120
|
+
// either the platform failed to initialize, or there are no more sessions linked to it
|
|
121
|
+
await this.removeStalePlatformInstance(platformInstance);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
122
124
|
}
|
|
123
125
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
+
private async clean(): Promise<void> {
|
|
127
|
+
if (this.stopTriggered) {
|
|
128
|
+
this.cycleRunning = false;
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
if (this.cycleRunning) {
|
|
132
|
+
throw new Error(
|
|
133
|
+
"janitor cleanup cycle called while already running",
|
|
134
|
+
);
|
|
135
|
+
}
|
|
136
|
+
this.cycleRunning = true;
|
|
137
|
+
this.cycleCount++;
|
|
138
|
+
this.sockets = await this.getSockets();
|
|
139
|
+
|
|
140
|
+
if (!(this.cycleCount % 4)) {
|
|
141
|
+
this.reportCount++;
|
|
142
|
+
rmLog(
|
|
143
|
+
`socket sessions: ${this.sockets.length} platform instances: ${platformInstances.size}`,
|
|
144
|
+
);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
for (const platformInstance of platformInstances.values()) {
|
|
148
|
+
await this.performStaleCheck(platformInstance);
|
|
149
|
+
}
|
|
150
|
+
this.cycleRunning = false;
|
|
151
|
+
await this.delay(this.cycleInterval);
|
|
152
|
+
return this.clean();
|
|
126
153
|
}
|
|
127
|
-
this.cycleRunning = false;
|
|
128
|
-
await this.delay(this.cycleInterval);
|
|
129
|
-
return this.clean();
|
|
130
|
-
}
|
|
131
154
|
}
|
|
132
155
|
|
|
133
156
|
const janitor = new Janitor();
|
package/src/listener.ts
CHANGED
|
@@ -1,13 +1,18 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
import
|
|
5
|
-
import
|
|
1
|
+
import { existsSync, writeFileSync } from "node:fs";
|
|
2
|
+
import * as HTTP from "node:http";
|
|
3
|
+
import { createRequire } from "node:module";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
import bodyParser from "body-parser";
|
|
6
|
+
import debug from "debug";
|
|
7
|
+
import express from "express";
|
|
8
|
+
import rateLimit from "express-rate-limit";
|
|
9
|
+
import { Server } from "socket.io";
|
|
6
10
|
|
|
7
|
-
import config from
|
|
8
|
-
import routes from
|
|
11
|
+
import config from "./config.js";
|
|
12
|
+
import routes from "./routes.js";
|
|
13
|
+
const require = createRequire(import.meta.url);
|
|
9
14
|
|
|
10
|
-
const log = debug(
|
|
15
|
+
const log = debug("sockethub:server:listener");
|
|
11
16
|
|
|
12
17
|
/**
|
|
13
18
|
* Handles the initialization and access of Sockethub resources.
|
|
@@ -17,67 +22,152 @@ const log = debug('sockethub:server:listener');
|
|
|
17
22
|
* - Socket.io (bidirectional websocket communication)
|
|
18
23
|
*/
|
|
19
24
|
class Listener {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
25
|
+
io: Server;
|
|
26
|
+
http: HTTP.Server;
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Starts the services needed for Sockethub to operate. After this command completes,
|
|
30
|
+
* the `http` and `io` class properties will be set.
|
|
31
|
+
*/
|
|
32
|
+
start() {
|
|
33
|
+
// initialize express and socket.io objects
|
|
34
|
+
const app = Listener.initExpress();
|
|
35
|
+
this.http = new HTTP.Server(app);
|
|
36
|
+
this.io = new Server(this.http, {
|
|
37
|
+
path: config.get("sockethub:path") as string,
|
|
38
|
+
cors: {
|
|
39
|
+
origin: "*",
|
|
40
|
+
methods: ["GET", "POST"],
|
|
41
|
+
},
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
routes.setup(app);
|
|
45
|
+
|
|
46
|
+
if (config.get("examples")) {
|
|
47
|
+
this.addExamplesRoutes(app);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
this.startHttp();
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Resolves the path to the examples static files from @sockethub/examples package.
|
|
55
|
+
* Returns null if the package is not installed.
|
|
56
|
+
*/
|
|
57
|
+
private resolveExamplesPath(): string | null {
|
|
58
|
+
try {
|
|
59
|
+
const examplesPkgPath = require.resolve(
|
|
60
|
+
"@sockethub/examples/package.json",
|
|
61
|
+
);
|
|
62
|
+
const examplesDir = path.join(
|
|
63
|
+
path.dirname(examplesPkgPath),
|
|
64
|
+
"build",
|
|
65
|
+
);
|
|
66
|
+
if (existsSync(examplesDir)) {
|
|
67
|
+
log(
|
|
68
|
+
`examples resolved from @sockethub/examples: ${examplesDir}`,
|
|
69
|
+
);
|
|
70
|
+
return examplesDir;
|
|
71
|
+
}
|
|
72
|
+
log(
|
|
73
|
+
`@sockethub/examples found but build directory missing: ${examplesDir}`,
|
|
74
|
+
);
|
|
75
|
+
return null;
|
|
76
|
+
} catch {
|
|
77
|
+
return null;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
private addExamplesRoutes(app) {
|
|
82
|
+
const examplesPath = this.resolveExamplesPath();
|
|
83
|
+
|
|
84
|
+
if (!examplesPath) {
|
|
85
|
+
console.error(
|
|
86
|
+
"\n❌ Error: --examples flag requires @sockethub/examples package\n\n" +
|
|
87
|
+
"The examples package is not installed. To use the examples feature, install it:\n\n" +
|
|
88
|
+
" bun add @sockethub/examples\n\n" +
|
|
89
|
+
"Or run sockethub without the --examples flag.\n",
|
|
90
|
+
);
|
|
91
|
+
process.exit(1);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Set up rate limiter to prevent DoS attacks on file system access
|
|
95
|
+
const limiter = rateLimit({
|
|
96
|
+
windowMs: 1 * 60 * 1000, // 1 minute
|
|
97
|
+
max: 60, // max 60 requests per windowMs
|
|
98
|
+
standardHeaders: true,
|
|
99
|
+
legacyHeaders: false,
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
// Write runtime config for the examples app
|
|
103
|
+
writeFileSync(
|
|
104
|
+
path.join(examplesPath, "config.json"),
|
|
105
|
+
JSON.stringify({
|
|
106
|
+
sockethub: config.get("sockethub"),
|
|
107
|
+
public: config.get("public"),
|
|
108
|
+
}),
|
|
109
|
+
);
|
|
110
|
+
|
|
111
|
+
app.use(express.static(examplesPath));
|
|
112
|
+
|
|
113
|
+
const examplesIndex = path.join(examplesPath, "index.html");
|
|
114
|
+
app.get("*", limiter, (req, res) => {
|
|
115
|
+
res.sendFile(examplesIndex);
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
log(
|
|
119
|
+
`examples served at http://${config.get("sockethub:host")}:${config.get(
|
|
120
|
+
"sockethub:port",
|
|
121
|
+
)}`,
|
|
122
|
+
);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
private startHttp() {
|
|
126
|
+
this.http.listen(
|
|
127
|
+
config.get("sockethub:port"),
|
|
128
|
+
config.get("sockethub:host") as number,
|
|
129
|
+
() => {
|
|
130
|
+
log(
|
|
131
|
+
`sockethub listening on ws://${config.get("sockethub:host")}:${config.get(
|
|
132
|
+
"sockethub:port",
|
|
133
|
+
)}`,
|
|
134
|
+
);
|
|
135
|
+
},
|
|
136
|
+
);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
private static initExpress() {
|
|
140
|
+
const app = express();
|
|
141
|
+
// templating engines
|
|
142
|
+
app.set("view engine", "ejs");
|
|
143
|
+
// use bodyParser
|
|
144
|
+
app.use(bodyParser.urlencoded({ extended: true }));
|
|
145
|
+
app.use(bodyParser.json());
|
|
146
|
+
return app;
|
|
147
|
+
}
|
|
58
148
|
}
|
|
59
149
|
|
|
60
150
|
const listener = new Listener();
|
|
61
151
|
|
|
62
152
|
interface EmitFunction {
|
|
63
|
-
|
|
153
|
+
(type: string, data: unknown);
|
|
64
154
|
}
|
|
65
155
|
|
|
66
156
|
export interface SocketInstance {
|
|
67
|
-
|
|
68
|
-
|
|
157
|
+
id: string;
|
|
158
|
+
emit: EmitFunction;
|
|
69
159
|
}
|
|
70
160
|
|
|
71
161
|
export async function getSocket(sessionId: string): Promise<SocketInstance> {
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
162
|
+
const sockets: Array<SocketInstance> = await listener.io.fetchSockets();
|
|
163
|
+
return new Promise((resolve, reject) => {
|
|
164
|
+
for (const socket of sockets) {
|
|
165
|
+
if (sessionId === socket.id) {
|
|
166
|
+
return resolve(socket);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
return reject(`unable to find socket for sessionId ${sessionId}`);
|
|
170
|
+
});
|
|
81
171
|
}
|
|
82
172
|
|
|
83
173
|
export default listener;
|
|
@@ -1,10 +1,30 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { describe, expect, it } from "bun:test";
|
|
2
|
+
import createActivityObject from "./create-activity-object.js";
|
|
2
3
|
|
|
3
|
-
describe(
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
4
|
+
describe("Middleware: createActivityObject", () => {
|
|
5
|
+
it("Calls activity.Object.create and fails with invalid property", async () => {
|
|
6
|
+
expect(() => {
|
|
7
|
+
createActivityObject({ foo: "bar" }, (o) => {
|
|
8
|
+
expect(o).not.toEqual({ foo: "bar" });
|
|
9
|
+
});
|
|
10
|
+
}).toThrow("ActivityStreams validation failed: the \"object\" property requires an 'id' property. Example: { id: \"user@example.com\", type: \"person\" }");
|
|
8
11
|
});
|
|
9
|
-
|
|
10
|
-
|
|
12
|
+
it("Calls activity.Object.create with incoming data", async () => {
|
|
13
|
+
createActivityObject(
|
|
14
|
+
{
|
|
15
|
+
id: "test",
|
|
16
|
+
context: "foo",
|
|
17
|
+
type: "bar",
|
|
18
|
+
content: "some text",
|
|
19
|
+
},
|
|
20
|
+
(o) => {
|
|
21
|
+
expect(o).toEqual({
|
|
22
|
+
id: "test",
|
|
23
|
+
context: "foo",
|
|
24
|
+
type: "bar",
|
|
25
|
+
content: "some text",
|
|
26
|
+
});
|
|
27
|
+
},
|
|
28
|
+
);
|
|
29
|
+
});
|
|
30
|
+
});
|
|
@@ -1,16 +1,22 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
|
|
4
|
-
import
|
|
5
|
-
|
|
1
|
+
import { ASFactory } from "@sockethub/activity-streams";
|
|
2
|
+
import type { ActivityObject } from "@sockethub/schemas";
|
|
3
|
+
|
|
4
|
+
import config from "../config.js";
|
|
5
|
+
import type { MiddlewareChainInterface } from "../middleware.js";
|
|
6
|
+
|
|
7
|
+
const activity = ASFactory(
|
|
8
|
+
config.get("packageConfig:@sockethub/activity-streams"),
|
|
9
|
+
);
|
|
6
10
|
|
|
7
11
|
/**
|
|
8
|
-
* A simple middleware wrapper for the activity-streams Object.create method.
|
|
12
|
+
* A simple middleware wrapper for the activity-streams `Object.create` method.
|
|
9
13
|
* @param obj
|
|
10
14
|
* @param done
|
|
11
15
|
*/
|
|
12
|
-
export default function createActivityObject(
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
+
export default function createActivityObject(
|
|
17
|
+
obj: ActivityObject,
|
|
18
|
+
done: MiddlewareChainInterface,
|
|
19
|
+
) {
|
|
20
|
+
activity.Object.create(obj);
|
|
21
|
+
done(obj);
|
|
16
22
|
}
|