@epicgames-ps/lib-pixelstreamingsignalling-ue5.8 0.2.0 → 0.2.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.
- package/CHANGELOG.md +11 -0
- package/dist/cjs/Logger.js +23 -9
- package/dist/cjs/Logger.js.map +1 -1
- package/dist/cjs/SFUConnection.js +5 -0
- package/dist/cjs/SFUConnection.js.map +1 -1
- package/dist/cjs/SignallingServer.js +11 -4
- package/dist/cjs/SignallingServer.js.map +1 -1
- package/dist/cjs/StreamerConnection.js +6 -1
- package/dist/cjs/StreamerConnection.js.map +1 -1
- package/dist/cjs/StreamerRegistry.js +6 -3
- package/dist/cjs/StreamerRegistry.js.map +1 -1
- package/dist/cjs/Utils.js +25 -0
- package/dist/cjs/Utils.js.map +1 -1
- package/dist/esm/Logger.js +24 -10
- package/dist/esm/Logger.js.map +1 -1
- package/dist/esm/SFUConnection.js +5 -0
- package/dist/esm/SFUConnection.js.map +1 -1
- package/dist/esm/SignallingServer.js +10 -3
- package/dist/esm/SignallingServer.js.map +1 -1
- package/dist/esm/StreamerConnection.js +6 -1
- package/dist/esm/StreamerConnection.js.map +1 -1
- package/dist/esm/StreamerRegistry.js +6 -3
- package/dist/esm/StreamerRegistry.js.map +1 -1
- package/dist/esm/Utils.js +22 -0
- package/dist/esm/Utils.js.map +1 -1
- package/dist/types/Logger.d.ts +2 -0
- package/dist/types/SignallingServer.d.ts +7 -0
- package/dist/types/Utils.d.ts +14 -0
- package/package.json +14 -14
- package/src/Logger.test.ts +109 -0
- package/src/Logger.ts +30 -9
- package/src/SFUConnection.test.ts +45 -0
- package/src/SFUConnection.ts +5 -0
- package/src/SignallingServer.maxPayload.test.ts +69 -0
- package/src/SignallingServer.ts +11 -0
- package/src/StreamerConnection.test.ts +48 -0
- package/src/StreamerConnection.ts +7 -1
- package/src/StreamerRegistry.test.ts +27 -0
- package/src/StreamerRegistry.ts +7 -3
- package/src/Utils.test.ts +31 -0
- package/src/Utils.ts +25 -0
|
@@ -121,7 +121,12 @@ export class StreamerConnection extends EventEmitter {
|
|
|
121
121
|
}
|
|
122
122
|
const player = this.server.playerRegistry.get(message.playerId);
|
|
123
123
|
if (player) {
|
|
124
|
-
|
|
124
|
+
// ws throws on a reason over 123 bytes or one that is not a string, which would crash the
|
|
125
|
+
// server. Such a reason is dropped; the player is still closed.
|
|
126
|
+
const reason = typeof message.reason === 'string' && Buffer.byteLength(message.reason) <= 123
|
|
127
|
+
? message.reason
|
|
128
|
+
: undefined;
|
|
129
|
+
player.protocol.disconnect(1011, reason);
|
|
125
130
|
}
|
|
126
131
|
}
|
|
127
132
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"StreamerConnection.js","sourceRoot":"","sources":["../../src/StreamerConnection.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"StreamerConnection.js","sourceRoot":"","sources":["../../src/StreamerConnection.ts"],"names":[],"mappings":"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"}
|
|
@@ -83,17 +83,20 @@ export class StreamerRegistry extends EventEmitter {
|
|
|
83
83
|
}
|
|
84
84
|
onEndpointId(streamer, message) {
|
|
85
85
|
const oldId = streamer.streamerId;
|
|
86
|
+
// The id arrives as any JSON value. A non-string one is treated as no id, because sanitizing it
|
|
87
|
+
// would store a value that later lookups cannot handle.
|
|
88
|
+
const requestedId = typeof message.id === 'string' ? message.id : '';
|
|
86
89
|
// id might conflict or be invalid so here we sanitize it
|
|
87
|
-
const sanitizedId = this.sanitizeStreamerId(
|
|
90
|
+
const sanitizedId = this.sanitizeStreamerId(requestedId);
|
|
88
91
|
let committedId = sanitizedId;
|
|
89
92
|
if (this.authorizeStreamerId) {
|
|
90
93
|
// Let the consumer accept the default id, override it (e.g. namespace per tenant), or
|
|
91
94
|
// reject the registration entirely. This is where anti-squatting policy lives.
|
|
92
95
|
committedId = this.authorizeStreamerId({
|
|
93
96
|
streamer,
|
|
94
|
-
requestedId
|
|
97
|
+
requestedId,
|
|
95
98
|
sanitizedId,
|
|
96
|
-
collided: !!
|
|
99
|
+
collided: !!requestedId && sanitizedId !== requestedId
|
|
97
100
|
});
|
|
98
101
|
if (committedId === null) {
|
|
99
102
|
Logger.warn(`StreamerRegistry: streamer id '${message.id}' (was ${oldId}) rejected by authorizer. Disconnecting.`);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"StreamerRegistry.js","sourceRoot":"","sources":["../../src/StreamerRegistry.ts"],"names":[],"mappings":"AAAA,kDAAkD;AAClD,OAAO,EAGH,QAAQ,EACR,cAAc,EAEd,YAAY,EACf,MAAM,8CAA8C,CAAC;AAEtD,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AA+DlC;;;;;;;GAOG;AACH,MAAM,OAAO,gBAAiB,SAAQ,YAAY;IAQ9C,YAAY,mBAA0C;QAClD,KAAK,EAAE,CAAC;QAPZ,4BAAuB,GAAW,iBAAiB,CAAC;QAQhD,IAAI,CAAC,SAAS,GAAG,EAAE,CAAC;QACpB,IAAI,CAAC,mBAAmB,GAAG,mBAAmB,CAAC;IACnD,CAAC;IAED;;;;;;OAMG;IACH,GAAG,CAAC,QAAmB;QACnB,QAAQ,CAAC,UAAU,GAAG,IAAI,CAAC,kBAAkB,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC;QAEnE,IAAI,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC;YACjC,MAAM,CAAC,KAAK,CACR,gDAAgD,QAAQ,CAAC,UAAU,8BAA8B,CACpG,CAAC;YACF,OAAO,KAAK,CAAC;QACjB,CAAC;QAED,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAE9B,2CAA2C;QAC3C,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC,QAAQ,CAAC,UAAU,CAAC,QAAQ,EAAE,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAC;QAC3F,QAAQ,CAAC,WAAW,CAAC,cAAc,CAAC,aAAa,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC;QAEtE,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,QAAQ,CAAC,UAAU,CAAC,CAAC;QAExC,OAAO,IAAI,CAAC;IAChB,CAAC;IAED;;;;OAIG;IACH,MAAM,CAAC,QAAmB;QACtB,MAAM,KAAK,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;QAC/C,IAAI,KAAK,KAAK,CAAC,CAAC,EAAE,CAAC;YACf,MAAM,CAAC,KAAK,CACR,8CAA8C,QAAQ,CAAC,UAAU,uBAAuB,CAC3F,CAAC;YACF,OAAO,KAAK,CAAC;QACjB,CAAC;QACD,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;QAChC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,QAAQ,CAAC,UAAU,CAAC,CAAC;QAC1C,OAAO,IAAI,CAAC;IAChB,CAAC;IAED;;OAEG;IACH,IAAI,CAAC,UAAkB;QACnB,OAAO,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,QAAQ,CAAC,UAAU,KAAK,UAAU,CAAC,CAAC;IACjF,CAAC;IAED;;;;;OAKG;IACH,kBAAkB;QACd,IAAI,IAAI,CAAC,KAAK,EAAE,EAAE,CAAC;YACf,OAAO,IAAI,CAAC;QAChB,CAAC;QACD,OAAO,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC;IACxC,CAAC;IAED;;OAEG;IACH,KAAK;QACD,OAAO,IAAI,CAAC,SAAS,CAAC,MAAM,KAAK,CAAC,CAAC;IACvC,CAAC;IAED;;OAEG;IACH,KAAK;QACD,OAAO,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC;IACjC,CAAC;IAEO,YAAY,CAAC,QAAmB,EAAE,OAA4B;QAClE,MAAM,KAAK,GAAG,QAAQ,CAAC,UAAU,CAAC;QAElC,
|
|
1
|
+
{"version":3,"file":"StreamerRegistry.js","sourceRoot":"","sources":["../../src/StreamerRegistry.ts"],"names":[],"mappings":"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"}
|
package/dist/esm/Utils.js
CHANGED
|
@@ -12,4 +12,26 @@ export function stringify(obj) {
|
|
|
12
12
|
export function beautify(obj) {
|
|
13
13
|
return jsonc.stringify(obj, undefined, '\t');
|
|
14
14
|
}
|
|
15
|
+
/**
|
|
16
|
+
* The longest text, or protocol message as JSON, that the logger writes whole. A client chooses the
|
|
17
|
+
* size of what it sends, so anything longer is cut rather than written to the log in full.
|
|
18
|
+
*/
|
|
19
|
+
export const MAX_LOGGED_LENGTH = 16 * 1024;
|
|
20
|
+
/**
|
|
21
|
+
* Returns the text, or if it is longer than MAX_LOGGED_LENGTH, its start and its full length.
|
|
22
|
+
*/
|
|
23
|
+
export function limitLogText(text) {
|
|
24
|
+
if (text.length <= MAX_LOGGED_LENGTH) {
|
|
25
|
+
return text;
|
|
26
|
+
}
|
|
27
|
+
return `${text.slice(0, MAX_LOGGED_LENGTH)}... (${text.length} characters)`;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Returns a protocol message as the log file should hold it: the message itself while its JSON fits in
|
|
31
|
+
* MAX_LOGGED_LENGTH, otherwise its JSON text cut by limitLogText.
|
|
32
|
+
*/
|
|
33
|
+
export function limitLoggedMessage(message) {
|
|
34
|
+
const text = JSON.stringify(message);
|
|
35
|
+
return text.length <= MAX_LOGGED_LENGTH ? message : limitLogText(text);
|
|
36
|
+
}
|
|
15
37
|
//# sourceMappingURL=Utils.js.map
|
package/dist/esm/Utils.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Utils.js","sourceRoot":"","sources":["../../src/Utils.ts"],"names":[],"mappings":"AAAA,kDAAkD;AAClD,OAAO,EAAE,KAAK,EAAE,MAAM,OAAO,CAAC;AAE9B;;GAEG;AACH,MAAM,UAAU,SAAS,CAAC,GAAQ;IAC9B,OAAO,KAAK,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;AAChC,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,QAAQ,CAAC,GAAQ;IAC7B,OAAO,KAAK,CAAC,SAAS,CAAC,GAAG,EAAE,SAAS,EAAE,IAAI,CAAC,CAAC;AACjD,CAAC"}
|
|
1
|
+
{"version":3,"file":"Utils.js","sourceRoot":"","sources":["../../src/Utils.ts"],"names":[],"mappings":"AAAA,kDAAkD;AAClD,OAAO,EAAE,KAAK,EAAE,MAAM,OAAO,CAAC;AAE9B;;GAEG;AACH,MAAM,UAAU,SAAS,CAAC,GAAQ;IAC9B,OAAO,KAAK,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;AAChC,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,QAAQ,CAAC,GAAQ;IAC7B,OAAO,KAAK,CAAC,SAAS,CAAC,GAAG,EAAE,SAAS,EAAE,IAAI,CAAC,CAAC;AACjD,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,EAAE,GAAG,IAAI,CAAC;AAE3C;;GAEG;AACH,MAAM,UAAU,YAAY,CAAC,IAAY;IACrC,IAAI,IAAI,CAAC,MAAM,IAAI,iBAAiB,EAAE,CAAC;QACnC,OAAO,IAAI,CAAC;IAChB,CAAC;IACD,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,iBAAiB,CAAC,QAAQ,IAAI,CAAC,MAAM,cAAc,CAAC;AAChF,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,kBAAkB,CAAC,OAAe;IAC9C,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;IACrC,OAAO,IAAI,CAAC,MAAM,IAAI,iBAAiB,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC;AAC3E,CAAC"}
|
package/dist/types/Logger.d.ts
CHANGED
|
@@ -45,6 +45,13 @@ export interface IPeerOptionsRequest {
|
|
|
45
45
|
* own. A provider that throws is treated as having no answer, and the static peerOptions are sent.
|
|
46
46
|
*/
|
|
47
47
|
export type PeerOptionsProvider = (request: IPeerOptionsRequest) => unknown;
|
|
48
|
+
/**
|
|
49
|
+
* The largest websocket message, in bytes, accepted on the streamer, player and SFU ports. Signalling
|
|
50
|
+
* messages are a few kilobytes, and ws would otherwise accept up to 100 MiB in one message. A
|
|
51
|
+
* connection that sends more is closed with code 1009. Setting maxPayload in streamerWsOptions,
|
|
52
|
+
* playerWsOptions or sfuWsOptions overrides it for that port.
|
|
53
|
+
*/
|
|
54
|
+
export declare const DEFAULT_MAX_PAYLOAD: number;
|
|
48
55
|
/**
|
|
49
56
|
* The main signalling server object.
|
|
50
57
|
* Contains a streamer and player registry and handles setting up of websockets
|
package/dist/types/Utils.d.ts
CHANGED
|
@@ -6,3 +6,17 @@ export declare function stringify(obj: any): string;
|
|
|
6
6
|
* Circular reference save version of JSON.stringify with extra formatting.
|
|
7
7
|
*/
|
|
8
8
|
export declare function beautify(obj: any): string;
|
|
9
|
+
/**
|
|
10
|
+
* The longest text, or protocol message as JSON, that the logger writes whole. A client chooses the
|
|
11
|
+
* size of what it sends, so anything longer is cut rather than written to the log in full.
|
|
12
|
+
*/
|
|
13
|
+
export declare const MAX_LOGGED_LENGTH: number;
|
|
14
|
+
/**
|
|
15
|
+
* Returns the text, or if it is longer than MAX_LOGGED_LENGTH, its start and its full length.
|
|
16
|
+
*/
|
|
17
|
+
export declare function limitLogText(text: string): string;
|
|
18
|
+
/**
|
|
19
|
+
* Returns a protocol message as the log file should hold it: the message itself while its JSON fits in
|
|
20
|
+
* MAX_LOGGED_LENGTH, otherwise its JSON text cut by limitLogText.
|
|
21
|
+
*/
|
|
22
|
+
export declare function limitLoggedMessage(message: object): object | string;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@epicgames-ps/lib-pixelstreamingsignalling-ue5.8",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"description": "Basic signalling library for developers wishing to build applications that signal a Pixel Streaming application.",
|
|
5
5
|
"main": "dist/cjs/pixelstreamingsignalling.js",
|
|
6
6
|
"module": "dist/esm/pixelstreamingsignalling.js",
|
|
@@ -19,31 +19,31 @@
|
|
|
19
19
|
"author": "Epic Games",
|
|
20
20
|
"license": "MIT",
|
|
21
21
|
"devDependencies": {
|
|
22
|
-
"@eslint/js": "^9.
|
|
22
|
+
"@eslint/js": "^9.39.5",
|
|
23
23
|
"@types/cors": "^2.8.17",
|
|
24
24
|
"@types/express": "^5.0.0",
|
|
25
25
|
"@types/jest": "^29.5.14",
|
|
26
|
-
"@types/node": "^22.
|
|
26
|
+
"@types/node": "^22.20.5",
|
|
27
27
|
"@types/ws": "^8.5.14",
|
|
28
28
|
"eslint": "^9.39.0",
|
|
29
29
|
"eslint-config-prettier": "^10.0.1",
|
|
30
|
-
"eslint-plugin-prettier": "^5.
|
|
31
|
-
"eslint-plugin-tsdoc": "^0.4
|
|
30
|
+
"eslint-plugin-prettier": "^5.5.7",
|
|
31
|
+
"eslint-plugin-tsdoc": "^0.5.4",
|
|
32
32
|
"nodemon": "^3.1.9",
|
|
33
33
|
"jest": "^29.7.0",
|
|
34
34
|
"rimraf": "^6.0.1",
|
|
35
|
-
"typedoc": "^0.28.
|
|
36
|
-
"typedoc-plugin-markdown": "^4.
|
|
37
|
-
"ts-jest": "^29.
|
|
35
|
+
"typedoc": "^0.28.20",
|
|
36
|
+
"typedoc-plugin-markdown": "^4.14.1",
|
|
37
|
+
"ts-jest": "^29.4.15",
|
|
38
38
|
"typescript": "^5.7.3",
|
|
39
|
-
"typescript-eslint": "8.
|
|
39
|
+
"typescript-eslint": "8.72.1"
|
|
40
40
|
},
|
|
41
41
|
"dependencies": {
|
|
42
|
-
"body-parser": "^
|
|
42
|
+
"body-parser": "^2.4.0",
|
|
43
43
|
"cors": "^2.8.5",
|
|
44
|
-
"express": "^
|
|
45
|
-
"express-rate-limit": "^8.
|
|
46
|
-
"helmet": "^8.
|
|
44
|
+
"express": "^5.3.0",
|
|
45
|
+
"express-rate-limit": "^8.7.2",
|
|
46
|
+
"helmet": "^8.3.0",
|
|
47
47
|
"hsts": "^2.2.0",
|
|
48
48
|
"jsonc": "^2.0.0",
|
|
49
49
|
"logform": "^2.7.0",
|
|
@@ -52,7 +52,7 @@
|
|
|
52
52
|
"ws": "^8.18.0"
|
|
53
53
|
},
|
|
54
54
|
"peerDependencies": {
|
|
55
|
-
"@epicgames-ps/lib-pixelstreamingcommon-ue5.8": "^0.1.
|
|
55
|
+
"@epicgames-ps/lib-pixelstreamingcommon-ue5.8": "^0.1.1"
|
|
56
56
|
},
|
|
57
57
|
"repository": {
|
|
58
58
|
"type": "git",
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
2
|
+
import fs from 'fs';
|
|
3
|
+
import os from 'os';
|
|
4
|
+
import path from 'path';
|
|
5
|
+
import { IConfig, InitLogging, Logger } from './Logger';
|
|
6
|
+
import { MAX_LOGGED_LENGTH } from './Utils';
|
|
7
|
+
|
|
8
|
+
type Transport = (typeof Logger.transports)[number];
|
|
9
|
+
|
|
10
|
+
const LEVEL = Symbol.for('level');
|
|
11
|
+
const MESSAGE = Symbol.for('message');
|
|
12
|
+
|
|
13
|
+
// Runs a log call through a transport's format and returns the line it would write. Formatting does no
|
|
14
|
+
// I/O, so this reads exactly what the logger produces without waiting on the file.
|
|
15
|
+
function lineFor(transport: Transport, message: unknown): string {
|
|
16
|
+
const info = transport.format?.transform({ level: 'info', message, [LEVEL]: 'info' });
|
|
17
|
+
if (!info || info === true) {
|
|
18
|
+
throw new Error('the format dropped the line');
|
|
19
|
+
}
|
|
20
|
+
return info[MESSAGE] as string;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// InitLogging opens the day's file, so every logger a test creates is closed before its folder is removed.
|
|
24
|
+
async function withLogger(config: IConfig, check: (console: Transport, file: Transport) => void) {
|
|
25
|
+
InitLogging(config);
|
|
26
|
+
const [consoleTransport, fileTransport] = Logger.transports;
|
|
27
|
+
try {
|
|
28
|
+
check(consoleTransport, fileTransport);
|
|
29
|
+
} finally {
|
|
30
|
+
await new Promise((resolve) => {
|
|
31
|
+
fileTransport.once('finish', resolve);
|
|
32
|
+
fileTransport.close?.();
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
describe('InitLogging', () => {
|
|
38
|
+
let logDir: string;
|
|
39
|
+
|
|
40
|
+
beforeEach(() => {
|
|
41
|
+
logDir = fs.mkdtempSync(path.join(os.tmpdir(), 'signalling-log-'));
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
afterEach(() => {
|
|
45
|
+
fs.rmSync(logDir, { recursive: true, force: true });
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it('refuses a file size that the file transport would take as no limit', () => {
|
|
49
|
+
expect(() => InitLogging({ logDir, logMaxSize: '100mb' })).toThrow('logMaxSize');
|
|
50
|
+
expect(() => InitLogging({ logDir, logMaxSize: '0m' })).toThrow('logMaxSize');
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
it('refuses a file count that the file transport would take as no limit', () => {
|
|
54
|
+
expect(() => InitLogging({ logDir, logMaxFiles: 0 })).toThrow('logMaxFiles');
|
|
55
|
+
expect(() => InitLogging({ logDir, logMaxFiles: NaN })).toThrow('logMaxFiles');
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it('limits the size of each log file and how many are kept', async () => {
|
|
59
|
+
await withLogger({ logDir }, (_console, file) => {
|
|
60
|
+
const { options } = file as unknown as { options: { maxSize: unknown; maxFiles: unknown } };
|
|
61
|
+
expect(options.maxSize).toBe('100m');
|
|
62
|
+
expect(options.maxFiles).toBe(14);
|
|
63
|
+
});
|
|
64
|
+
await withLogger({ logDir, logMaxSize: '5m', logMaxFiles: 3 }, (_console, file) => {
|
|
65
|
+
const { options } = file as unknown as { options: { maxSize: unknown; maxFiles: unknown } };
|
|
66
|
+
expect(options.maxSize).toBe('5m');
|
|
67
|
+
expect(options.maxFiles).toBe(3);
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
it('cuts long text on the console and in the file', async () => {
|
|
72
|
+
const text = 'x'.repeat(100000);
|
|
73
|
+
await withLogger({ logDir }, (console, file) => {
|
|
74
|
+
const consoleLine = lineFor(console, text);
|
|
75
|
+
expect(consoleLine.endsWith('... (100000 characters)')).toBe(true);
|
|
76
|
+
expect(consoleLine.length).toBeLessThan(MAX_LOGGED_LENGTH + 100);
|
|
77
|
+
|
|
78
|
+
const fileLine = lineFor(file, text);
|
|
79
|
+
expect(
|
|
80
|
+
(JSON.parse(fileLine) as { message: string }).message.endsWith('... (100000 characters)')
|
|
81
|
+
).toBe(true);
|
|
82
|
+
expect(fileLine.length).toBeLessThan(MAX_LOGGED_LENGTH + 200);
|
|
83
|
+
});
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
it('writes a protocol message to the file whole, or as cut JSON text when it is too long', async () => {
|
|
87
|
+
const logObj = (protoMessage: object) => ({
|
|
88
|
+
event: 'proto_message',
|
|
89
|
+
direction: 'incoming',
|
|
90
|
+
receiver: 'Player0',
|
|
91
|
+
protoMessage
|
|
92
|
+
});
|
|
93
|
+
await withLogger({ logDir }, (_console, file) => {
|
|
94
|
+
const short = JSON.parse(lineFor(file, logObj({ type: 'ping', time: 1 }))) as {
|
|
95
|
+
protoMessage: unknown;
|
|
96
|
+
};
|
|
97
|
+
expect(short.protoMessage).toEqual({ type: 'ping', time: 1 });
|
|
98
|
+
|
|
99
|
+
const long = { type: 'ping', pad: 'a'.repeat(100000) };
|
|
100
|
+
const longLine = lineFor(file, logObj(long));
|
|
101
|
+
const parsed = JSON.parse(longLine) as { protoMessage: string };
|
|
102
|
+
expect(parsed.protoMessage.startsWith('{"type":"ping"')).toBe(true);
|
|
103
|
+
expect(parsed.protoMessage.endsWith(`... (${JSON.stringify(long).length} characters)`)).toBe(
|
|
104
|
+
true
|
|
105
|
+
);
|
|
106
|
+
expect(longLine.length).toBeLessThan(MAX_LOGGED_LENGTH + 300);
|
|
107
|
+
});
|
|
108
|
+
});
|
|
109
|
+
});
|
package/src/Logger.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
2
|
-
import { stringify, beautify } from './Utils';
|
|
2
|
+
import { stringify, beautify, limitLogText, limitLoggedMessage } from './Utils';
|
|
3
3
|
import { IProtoLogObj } from './LoggingUtils';
|
|
4
4
|
import path from 'path';
|
|
5
5
|
import winston from 'winston';
|
|
@@ -30,6 +30,12 @@ export interface IConfig {
|
|
|
30
30
|
|
|
31
31
|
// the minimum log level for file messages
|
|
32
32
|
logLevelFile?: string;
|
|
33
|
+
|
|
34
|
+
// the size at which a log file is closed and a new one started, as a whole number followed by k, m or g
|
|
35
|
+
logMaxSize?: string;
|
|
36
|
+
|
|
37
|
+
// the number of log files to keep. The oldest is deleted when a new one is started.
|
|
38
|
+
logMaxFiles?: number;
|
|
33
39
|
}
|
|
34
40
|
|
|
35
41
|
/**
|
|
@@ -70,10 +76,23 @@ export function InitLogging(config: IConfig): void {
|
|
|
70
76
|
const logDir = config.logDir || 'logs';
|
|
71
77
|
const logLevelConsole = config.logLevelConsole || 'info';
|
|
72
78
|
const logLevelFile = config.logLevelFile || 'info';
|
|
79
|
+
const logMaxSize = config.logMaxSize || '100m';
|
|
80
|
+
const logMaxFiles = config.logMaxFiles ?? 14;
|
|
73
81
|
logMessagesToConsole = config.logMessagesToConsole || 'none';
|
|
74
82
|
|
|
83
|
+
// winston-daily-rotate-file takes a size it cannot parse, or a count of 0, as no limit at all.
|
|
84
|
+
if (!/^[1-9]\d*[kmg]$/i.test(logMaxSize)) {
|
|
85
|
+
throw new Error(`logMaxSize must be a whole number followed by k, m or g, not "${logMaxSize}".`);
|
|
86
|
+
}
|
|
87
|
+
if (!Number.isInteger(logMaxFiles) || logMaxFiles < 1) {
|
|
88
|
+
throw new Error(`logMaxFiles must be a whole number of at least 1, not "${logMaxFiles}".`);
|
|
89
|
+
}
|
|
90
|
+
|
|
75
91
|
Logger = winston.createLogger({
|
|
76
|
-
transports: [
|
|
92
|
+
transports: [
|
|
93
|
+
createConsoleTransport(logLevelConsole),
|
|
94
|
+
createFileTransport(logDir, logLevelFile, logMaxSize, logMaxFiles)
|
|
95
|
+
]
|
|
77
96
|
});
|
|
78
97
|
|
|
79
98
|
const commonLogger = new CommonLogger(Logger);
|
|
@@ -118,7 +137,7 @@ function createConsoleFormat() {
|
|
|
118
137
|
return printf((logObj: TransformableInfo) => {
|
|
119
138
|
const prefix = `[${String(logObj['timestamp'])}] ${logObj.level}: `;
|
|
120
139
|
if (typeof logObj.message === 'string') {
|
|
121
|
-
return prefix + logObj.message;
|
|
140
|
+
return prefix + limitLogText(logObj.message);
|
|
122
141
|
} else if (isLogObject(logObj.message)) {
|
|
123
142
|
const { direction, receiver, sender, target, protoMessage } = logObj.message;
|
|
124
143
|
switch (direction) {
|
|
@@ -139,9 +158,9 @@ function createConsoleFormat() {
|
|
|
139
158
|
function formatMessageForConsole(message: BaseMessage) {
|
|
140
159
|
switch (logMessagesToConsole) {
|
|
141
160
|
case 'verbose':
|
|
142
|
-
return stringify(message);
|
|
161
|
+
return limitLogText(stringify(message));
|
|
143
162
|
case 'formatted':
|
|
144
|
-
return beautify(message);
|
|
163
|
+
return limitLogText(beautify(message));
|
|
145
164
|
default:
|
|
146
165
|
return `[${message.type}]`;
|
|
147
166
|
}
|
|
@@ -156,12 +175,13 @@ function createProtoMessageFilter() {
|
|
|
156
175
|
});
|
|
157
176
|
}
|
|
158
177
|
|
|
159
|
-
function createFileTransport(logDirPath: string, logLevel: string) {
|
|
178
|
+
function createFileTransport(logDirPath: string, logLevel: string, maxSize: string, maxFiles: number) {
|
|
160
179
|
return new winston.transports.DailyRotateFile({
|
|
161
180
|
level: logLevel,
|
|
162
181
|
filename: path.join(logDirPath, 'server-%DATE%.log'),
|
|
163
182
|
datePattern: 'YYYY-MM-DD',
|
|
164
|
-
|
|
183
|
+
maxSize,
|
|
184
|
+
maxFiles,
|
|
165
185
|
format: combine(timestamp({ format: 'YYYY-MM-DD HH:mm:ss.SSS' }), splat(), createFileFormat())
|
|
166
186
|
});
|
|
167
187
|
}
|
|
@@ -174,14 +194,15 @@ function createFileFormat() {
|
|
|
174
194
|
timestamp,
|
|
175
195
|
level,
|
|
176
196
|
event: 'message',
|
|
177
|
-
message
|
|
197
|
+
message: limitLogText(message)
|
|
178
198
|
});
|
|
179
199
|
} else if (isLogObject(logObj.message)) {
|
|
180
200
|
const { timestamp, level, message } = logObj;
|
|
181
201
|
return JSON.stringify({
|
|
182
202
|
timestamp,
|
|
183
203
|
level,
|
|
184
|
-
...message
|
|
204
|
+
...message,
|
|
205
|
+
protoMessage: limitLoggedMessage(message.protoMessage)
|
|
185
206
|
});
|
|
186
207
|
}
|
|
187
208
|
return '';
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
2
|
+
import type WebSocket from 'ws';
|
|
3
|
+
import { Messages } from '@epicgames-ps/lib-pixelstreamingcommon-ue5.8';
|
|
4
|
+
import { SFUConnection } from './SFUConnection';
|
|
5
|
+
import { StreamerConnection } from './StreamerConnection';
|
|
6
|
+
import { StreamerRegistry } from './StreamerRegistry';
|
|
7
|
+
import { PlayerRegistry } from './PlayerRegistry';
|
|
8
|
+
import { SignallingServer } from './SignallingServer';
|
|
9
|
+
|
|
10
|
+
// A streamer the SFU can subscribe to, with no socket behind it.
|
|
11
|
+
function unconnectedStreamer(streamerId: string): StreamerConnection {
|
|
12
|
+
const streamer = new StreamerConnection({} as unknown as SignallingServer, {} as unknown as WebSocket);
|
|
13
|
+
streamer.streamerId = streamerId;
|
|
14
|
+
return streamer;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
describe('SFUConnection subscribe', () => {
|
|
18
|
+
it('leaves the previous streamer when it subscribes to another', () => {
|
|
19
|
+
const a = unconnectedStreamer('A');
|
|
20
|
+
const b = unconnectedStreamer('B');
|
|
21
|
+
const streamerRegistry = new StreamerRegistry();
|
|
22
|
+
streamerRegistry.streamers.push(a, b);
|
|
23
|
+
const server = {
|
|
24
|
+
streamerRegistry,
|
|
25
|
+
playerRegistry: new PlayerRegistry()
|
|
26
|
+
} as unknown as SignallingServer;
|
|
27
|
+
const sfu = new SFUConnection(server, {} as unknown as WebSocket);
|
|
28
|
+
sfu.playerId = 'SFU1';
|
|
29
|
+
|
|
30
|
+
sfu.protocol.emit(Messages.subscribe.typeName, {
|
|
31
|
+
type: Messages.subscribe.typeName,
|
|
32
|
+
streamerId: 'A'
|
|
33
|
+
});
|
|
34
|
+
sfu.protocol.emit(Messages.subscribe.typeName, {
|
|
35
|
+
type: Messages.subscribe.typeName,
|
|
36
|
+
streamerId: 'B'
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
expect(a.subscribers.has('SFU1')).toBe(false);
|
|
40
|
+
expect(b.subscribers.has('SFU1')).toBe(true);
|
|
41
|
+
// A disconnect from the old streamer must not detach the SFU from the one it is on now.
|
|
42
|
+
a.emit('disconnect');
|
|
43
|
+
expect(sfu.subscribedStreamer).toBe(b);
|
|
44
|
+
});
|
|
45
|
+
});
|
package/src/SFUConnection.ts
CHANGED
|
@@ -184,6 +184,11 @@ export class SFUConnection extends EventEmitter implements IPlayer, IStreamer, L
|
|
|
184
184
|
return;
|
|
185
185
|
}
|
|
186
186
|
|
|
187
|
+
// Leave the previous streamer first, as PlayerConnection does, so it stops forwarding to this SFU
|
|
188
|
+
// and a later disconnect of it cannot detach the SFU from the streamer it is now on.
|
|
189
|
+
if (this.subscribedStreamer) {
|
|
190
|
+
this.unsubscribe();
|
|
191
|
+
}
|
|
187
192
|
this.subscribedStreamer = streamer;
|
|
188
193
|
// Register as a subscriber of the upstream streamer so it will forward signalling messages
|
|
189
194
|
// back to this SFU (the streamer's forwardMessage only sends to subscribed players).
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
2
|
+
import * as wslib from 'ws';
|
|
3
|
+
import { SignallingServer, DEFAULT_MAX_PAYLOAD, IServerConfig } from './SignallingServer';
|
|
4
|
+
|
|
5
|
+
// The constructor binds real listening sockets and the class offers no way to close them, so the
|
|
6
|
+
// websocket servers are replaced here and only the options they are created with are checked.
|
|
7
|
+
jest.mock('ws', () => {
|
|
8
|
+
const actual = jest.requireActual<typeof wslib>('ws');
|
|
9
|
+
return {
|
|
10
|
+
...actual,
|
|
11
|
+
WebSocketServer: jest.fn().mockImplementation(() => ({ on: jest.fn() }))
|
|
12
|
+
};
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
const STREAMER_PORT = 8888;
|
|
16
|
+
const PLAYER_PORT = 80;
|
|
17
|
+
const SFU_PORT = 8889;
|
|
18
|
+
|
|
19
|
+
function createdOptions(config: Partial<IServerConfig>): Map<number | undefined, wslib.ServerOptions> {
|
|
20
|
+
const constructor = jest.mocked(wslib.WebSocketServer);
|
|
21
|
+
constructor.mockClear();
|
|
22
|
+
new SignallingServer({
|
|
23
|
+
streamerPort: STREAMER_PORT,
|
|
24
|
+
playerPort: PLAYER_PORT,
|
|
25
|
+
sfuPort: SFU_PORT,
|
|
26
|
+
peerOptions: {},
|
|
27
|
+
...config
|
|
28
|
+
});
|
|
29
|
+
const byPort = new Map<number | undefined, wslib.ServerOptions>();
|
|
30
|
+
for (const [options] of constructor.mock.calls) {
|
|
31
|
+
byPort.set(options?.port, options ?? {});
|
|
32
|
+
}
|
|
33
|
+
return byPort;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
describe('SignallingServer websocket message size', () => {
|
|
37
|
+
it('limits every port to DEFAULT_MAX_PAYLOAD', () => {
|
|
38
|
+
const options = createdOptions({});
|
|
39
|
+
|
|
40
|
+
expect(options.size).toBe(3);
|
|
41
|
+
expect(options.get(STREAMER_PORT)?.maxPayload).toBe(DEFAULT_MAX_PAYLOAD);
|
|
42
|
+
expect(options.get(PLAYER_PORT)?.maxPayload).toBe(DEFAULT_MAX_PAYLOAD);
|
|
43
|
+
expect(options.get(SFU_PORT)?.maxPayload).toBe(DEFAULT_MAX_PAYLOAD);
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it('is 1 MiB', () => {
|
|
47
|
+
expect(DEFAULT_MAX_PAYLOAD).toBe(1024 * 1024);
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it('lets the websocket options of each port override the limit', () => {
|
|
51
|
+
const options = createdOptions({
|
|
52
|
+
streamerWsOptions: { maxPayload: 4 * 1024 * 1024 },
|
|
53
|
+
playerWsOptions: { maxPayload: 64 * 1024 },
|
|
54
|
+
sfuWsOptions: { maxPayload: 0 }
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
expect(options.get(STREAMER_PORT)?.maxPayload).toBe(4 * 1024 * 1024);
|
|
58
|
+
expect(options.get(PLAYER_PORT)?.maxPayload).toBe(64 * 1024);
|
|
59
|
+
expect(options.get(SFU_PORT)?.maxPayload).toBe(0);
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it('keeps the other websocket options it is given', () => {
|
|
63
|
+
const verifyClient = jest.fn();
|
|
64
|
+
const options = createdOptions({ playerWsOptions: { verifyClient } });
|
|
65
|
+
|
|
66
|
+
expect(options.get(PLAYER_PORT)?.verifyClient).toBe(verifyClient);
|
|
67
|
+
expect(options.get(PLAYER_PORT)?.maxPayload).toBe(DEFAULT_MAX_PAYLOAD);
|
|
68
|
+
});
|
|
69
|
+
});
|
package/src/SignallingServer.ts
CHANGED
|
@@ -100,6 +100,14 @@ export interface IPeerOptionsRequest {
|
|
|
100
100
|
*/
|
|
101
101
|
export type PeerOptionsProvider = (request: IPeerOptionsRequest) => unknown;
|
|
102
102
|
|
|
103
|
+
/**
|
|
104
|
+
* The largest websocket message, in bytes, accepted on the streamer, player and SFU ports. Signalling
|
|
105
|
+
* messages are a few kilobytes, and ws would otherwise accept up to 100 MiB in one message. A
|
|
106
|
+
* connection that sends more is closed with code 1009. Setting maxPayload in streamerWsOptions,
|
|
107
|
+
* playerWsOptions or sfuWsOptions overrides it for that port.
|
|
108
|
+
*/
|
|
109
|
+
export const DEFAULT_MAX_PAYLOAD = 1024 * 1024;
|
|
110
|
+
|
|
103
111
|
/**
|
|
104
112
|
* The main signalling server object.
|
|
105
113
|
* Contains a streamer and player registry and handles setting up of websockets
|
|
@@ -138,6 +146,7 @@ export class SignallingServer {
|
|
|
138
146
|
const streamerServer = new wslib.WebSocketServer({
|
|
139
147
|
port: config.streamerPort,
|
|
140
148
|
backlog: 1,
|
|
149
|
+
maxPayload: DEFAULT_MAX_PAYLOAD,
|
|
141
150
|
...config.streamerWsOptions
|
|
142
151
|
});
|
|
143
152
|
streamerServer.on('connection', this.onStreamerConnected.bind(this));
|
|
@@ -148,6 +157,7 @@ export class SignallingServer {
|
|
|
148
157
|
const playerServer = new wslib.WebSocketServer({
|
|
149
158
|
server: server,
|
|
150
159
|
port: server ? undefined : config.playerPort,
|
|
160
|
+
maxPayload: DEFAULT_MAX_PAYLOAD,
|
|
151
161
|
...config.playerWsOptions
|
|
152
162
|
});
|
|
153
163
|
playerServer.on('connection', this.onPlayerConnected.bind(this));
|
|
@@ -160,6 +170,7 @@ export class SignallingServer {
|
|
|
160
170
|
const sfuServer = new wslib.WebSocketServer({
|
|
161
171
|
port: config.sfuPort,
|
|
162
172
|
backlog: 1,
|
|
173
|
+
maxPayload: DEFAULT_MAX_PAYLOAD,
|
|
163
174
|
...config.sfuWsOptions
|
|
164
175
|
});
|
|
165
176
|
sfuServer.on('connection', this.onSFUConnected.bind(this));
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
2
|
+
import type WebSocket from 'ws';
|
|
3
|
+
import { StreamerConnection } from './StreamerConnection';
|
|
4
|
+
import { SignallingServer } from './SignallingServer';
|
|
5
|
+
|
|
6
|
+
describe('StreamerConnection disconnectPlayer reason', () => {
|
|
7
|
+
// A streamer with one subscribed player whose protocol records the close it is asked for.
|
|
8
|
+
function streamerWithPlayer() {
|
|
9
|
+
const disconnect = jest.fn();
|
|
10
|
+
const player = { protocol: { disconnect } };
|
|
11
|
+
const server = { playerRegistry: { get: () => player } } as unknown as SignallingServer;
|
|
12
|
+
const streamer = new StreamerConnection(server, {} as unknown as WebSocket);
|
|
13
|
+
streamer.subscribers = new Set(['player-1']);
|
|
14
|
+
return { streamer, disconnect };
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function disconnectPlayer(streamer: StreamerConnection, reason: unknown): void {
|
|
18
|
+
streamer.protocol.emit('disconnectPlayer', {
|
|
19
|
+
type: 'disconnectPlayer',
|
|
20
|
+
playerId: 'player-1',
|
|
21
|
+
reason
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
it('passes a short string reason through', () => {
|
|
26
|
+
const { streamer, disconnect } = streamerWithPlayer();
|
|
27
|
+
disconnectPlayer(streamer, 'bye');
|
|
28
|
+
expect(disconnect).toHaveBeenCalledWith(1011, 'bye');
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it('closes without a reason when the reason is over 123 bytes', () => {
|
|
32
|
+
const { streamer, disconnect } = streamerWithPlayer();
|
|
33
|
+
disconnectPlayer(streamer, 'x'.repeat(124));
|
|
34
|
+
expect(disconnect).toHaveBeenCalledWith(1011, undefined);
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it('counts the reason in bytes, not characters', () => {
|
|
38
|
+
const { streamer, disconnect } = streamerWithPlayer();
|
|
39
|
+
disconnectPlayer(streamer, String.fromCharCode(0xe9).repeat(62)); // 124 bytes in UTF-8
|
|
40
|
+
expect(disconnect).toHaveBeenCalledWith(1011, undefined);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it('closes without a reason when the reason is not a string', () => {
|
|
44
|
+
const { streamer, disconnect } = streamerWithPlayer();
|
|
45
|
+
disconnectPlayer(streamer, { length: 1 });
|
|
46
|
+
expect(disconnect).toHaveBeenCalledWith(1011, undefined);
|
|
47
|
+
});
|
|
48
|
+
});
|