socket-function 0.8.39 → 0.9.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.
- package/SocketFunction.ts +7 -0
- package/hot/HotReloadController.ts +43 -8
- package/package.json +3 -3
- package/require/require.js +2 -0
- package/src/CallFactory.ts +33 -8
- package/src/batching.ts +13 -10
- package/src/caching.ts +5 -1
- package/src/callHTTPHandler.ts +1 -1
- package/src/certStore.ts +7 -3
- package/src/fixLargeNetworkCalls.ts +1 -1
- package/src/misc.ts +24 -0
- package/src/profiling/measure.ts +4 -4
- package/src/webSocketServer.ts +18 -4
- package/src/websocketFactory.ts +1 -1
- package/test/shared.ts +2 -8
package/SocketFunction.ts
CHANGED
|
@@ -201,6 +201,8 @@ export class SocketFunction {
|
|
|
201
201
|
public static mountedNodeId: string = "";
|
|
202
202
|
public static mountedIP: string = "";
|
|
203
203
|
private static hasMounted = false;
|
|
204
|
+
private static onMountCallback: () => void = () => { };
|
|
205
|
+
public static mountPromise: Promise<void> = new Promise(r => this.onMountCallback = r);
|
|
204
206
|
public static async mount(config: SocketServerConfig) {
|
|
205
207
|
if (this.mountedNodeId) {
|
|
206
208
|
throw new Error("SocketFunction already mounted, mounting twice in one thread is not allowed.");
|
|
@@ -223,6 +225,7 @@ export class SocketFunction {
|
|
|
223
225
|
await callback();
|
|
224
226
|
}
|
|
225
227
|
}
|
|
228
|
+
this.onMountCallback();
|
|
226
229
|
return this.mountedNodeId;
|
|
227
230
|
}
|
|
228
231
|
|
|
@@ -246,6 +249,10 @@ export class SocketFunction {
|
|
|
246
249
|
return getNodeId(location.address, location.port);
|
|
247
250
|
}
|
|
248
251
|
|
|
252
|
+
public static locationNode() {
|
|
253
|
+
return SocketFunction.connect({ address: location.hostname, port: +location.port });
|
|
254
|
+
}
|
|
255
|
+
|
|
249
256
|
public static addGlobalHook(hook: SocketFunctionHook<SocketExposedInterface>) {
|
|
250
257
|
registerGlobalHook(hook as SocketFunctionHook);
|
|
251
258
|
}
|
|
@@ -5,12 +5,25 @@ module.allowclient = true;
|
|
|
5
5
|
import { SocketFunction } from "../SocketFunction";
|
|
6
6
|
import { cache, lazy } from "../src/caching";
|
|
7
7
|
import * as fs from "fs";
|
|
8
|
+
import debugbreak from "debugbreak";
|
|
9
|
+
import { isNode } from "../src/misc";
|
|
10
|
+
import { red } from "../src/formatting/logColors";
|
|
8
11
|
|
|
9
|
-
/**
|
|
10
|
-
*
|
|
11
|
-
* -
|
|
12
|
+
/** Enables some hot reload functionality.
|
|
13
|
+
* - Triggers a refresh clientside
|
|
14
|
+
* - Triggers a reload server, for modules marked with `module.hotreload`
|
|
12
15
|
*/
|
|
13
|
-
export function watchFilesAndTriggerHotReloading() {
|
|
16
|
+
export function watchFilesAndTriggerHotReloading(noAutomaticBrowserWatch = false) {
|
|
17
|
+
|
|
18
|
+
SocketFunction.expose(HotReloadController);
|
|
19
|
+
if (!isNode()) {
|
|
20
|
+
if (!noAutomaticBrowserWatch) {
|
|
21
|
+
HotReloadController.nodes[SocketFunction.locationNode()]
|
|
22
|
+
.watchFiles()
|
|
23
|
+
.catch(e => console.error("watchFiles error", e))
|
|
24
|
+
;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
14
27
|
setInterval(() => {
|
|
15
28
|
for (let module of Object.values(require.cache)) {
|
|
16
29
|
if (!module) continue;
|
|
@@ -19,6 +32,14 @@ export function watchFilesAndTriggerHotReloading() {
|
|
|
19
32
|
}, 5000);
|
|
20
33
|
}
|
|
21
34
|
|
|
35
|
+
declare global {
|
|
36
|
+
namespace NodeJS {
|
|
37
|
+
interface Module {
|
|
38
|
+
hotreload?: boolean;
|
|
39
|
+
noserverhotreload?: boolean;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
22
43
|
|
|
23
44
|
const hotReloadModule = cache((module: NodeJS.Module) => {
|
|
24
45
|
if (!module.updateContents) return;
|
|
@@ -26,6 +47,23 @@ const hotReloadModule = cache((module: NodeJS.Module) => {
|
|
|
26
47
|
if (curr.mtime.getTime() === prev.mtime.getTime()) return;
|
|
27
48
|
console.log(`Hot reloading due to change: ${module.filename}`);
|
|
28
49
|
module.updateContents?.();
|
|
50
|
+
if (isNode()) {
|
|
51
|
+
if (
|
|
52
|
+
module.hotreload
|
|
53
|
+
// A fairly big hack (as this could just be in a string, or something similar), but... it also VERY useful
|
|
54
|
+
|| module.moduleContents?.includes("\nmodule.hotreload = true;" + "\n")
|
|
55
|
+
|| module.moduleContents?.includes("\r\nmodule.hotreload = true;" + "\r\n")
|
|
56
|
+
) {
|
|
57
|
+
console.log(`Reloading ${module.id}`);
|
|
58
|
+
try {
|
|
59
|
+
module.loaded = false;
|
|
60
|
+
module.load(module.id);
|
|
61
|
+
} catch (e) {
|
|
62
|
+
console.error(red(`Error hot reloading ${module.id}`));
|
|
63
|
+
console.error(e);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
29
67
|
triggerClientSideReload();
|
|
30
68
|
});
|
|
31
69
|
});
|
|
@@ -50,10 +88,7 @@ class HotReloadControllerBase {
|
|
|
50
88
|
// TODO: Also hot reload when we reconnect to the server, as it is likely setup will need to
|
|
51
89
|
// be rerun in that case as well (for example, we need to call watchFiles again!)
|
|
52
90
|
async watchFiles() {
|
|
53
|
-
let callerId =
|
|
54
|
-
if (!callerId) {
|
|
55
|
-
throw new Error("No nodeId?");
|
|
56
|
-
}
|
|
91
|
+
let callerId = SocketFunction.getCaller().nodeId;
|
|
57
92
|
clientWatcherNodes.add(callerId);
|
|
58
93
|
}
|
|
59
94
|
async fileUpdated() {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "socket-function",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.0",
|
|
4
4
|
"main": "index.js",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"note1": "note on node-forge fork, see https://github.com/digitalbazaar/forge/issues/744 for details",
|
|
@@ -9,8 +9,8 @@
|
|
|
9
9
|
"mobx": "^6.6.2",
|
|
10
10
|
"node-forge": "https://github.com/sliftist/forge#name",
|
|
11
11
|
"preact": "^10.10.6",
|
|
12
|
-
"rdtsc-now": "^0.3.
|
|
13
|
-
"typenode": "^4.9.4-
|
|
12
|
+
"rdtsc-now": "^0.3.1",
|
|
13
|
+
"typenode": "^4.9.4-g",
|
|
14
14
|
"ws": "^8.8.0"
|
|
15
15
|
},
|
|
16
16
|
"scripts": {
|
package/require/require.js
CHANGED
package/src/CallFactory.ts
CHANGED
|
@@ -10,8 +10,9 @@ import { getClientNodeId, getNodeIdLocation, registerNodeClient } from "./nodeCa
|
|
|
10
10
|
import debugbreak from "debugbreak";
|
|
11
11
|
import { lazy } from "./caching";
|
|
12
12
|
import { JSONLACKS } from "./JSONLACKS/JSONLACKS";
|
|
13
|
-
import { red } from "./formatting/logColors";
|
|
14
|
-
import { isSplitableArray } from "./fixLargeNetworkCalls";
|
|
13
|
+
import { red, yellow } from "./formatting/logColors";
|
|
14
|
+
import { isSplitableArray, markArrayAsSplitable } from "./fixLargeNetworkCalls";
|
|
15
|
+
import { delay } from "./batching";
|
|
15
16
|
|
|
16
17
|
const MIN_RETRY_DELAY = 1000;
|
|
17
18
|
|
|
@@ -56,6 +57,8 @@ export interface SenderInterface {
|
|
|
56
57
|
addEventListener(event: "message", listener: (data: ws.RawData | ws.MessageEvent | string) => void): void;
|
|
57
58
|
|
|
58
59
|
readyState: number;
|
|
60
|
+
|
|
61
|
+
ping?(): void;
|
|
59
62
|
}
|
|
60
63
|
|
|
61
64
|
export async function createCallFactory(
|
|
@@ -82,6 +85,18 @@ export async function createCallFactory(
|
|
|
82
85
|
// in return calls.
|
|
83
86
|
let nextSeqNum = Date.now() + Math.random();
|
|
84
87
|
|
|
88
|
+
// NOTE: I'm not sure if this is needed, I thought it was, but... now I think
|
|
89
|
+
// it probably isn't...
|
|
90
|
+
// if (webSocketBase?.readyState === 1 /* OPEN */ && webSocketBase.ping) {
|
|
91
|
+
// // Heartbeat loop, otherwise onDisconnect is never called.
|
|
92
|
+
// ((async () => {
|
|
93
|
+
// while (webSocketBase?.readyState === 1 /* OPEN */ && webSocketBase.ping) {
|
|
94
|
+
// await delay(1000 * 60);
|
|
95
|
+
// webSocketBase.ping?.();
|
|
96
|
+
// }
|
|
97
|
+
// }))().catch(() => { });
|
|
98
|
+
// }
|
|
99
|
+
|
|
85
100
|
let lastConnectionAttempt = 0;
|
|
86
101
|
|
|
87
102
|
let callerContext: CallerContextBase = {
|
|
@@ -120,6 +135,7 @@ export async function createCallFactory(
|
|
|
120
135
|
if (data.byteLength > SocketFunction.MAX_MESSAGE_SIZE * 1.5) {
|
|
121
136
|
let splitArgIndex = call.args.findIndex(isSplitableArray);
|
|
122
137
|
if (splitArgIndex >= 0) {
|
|
138
|
+
console.log(yellow(`Splitting large call due to large args: ${call.classGuid}.${call.functionName}`));
|
|
123
139
|
let SPLIT_GROUPS = 10;
|
|
124
140
|
let splitArg = call.args[splitArgIndex] as unknown[];
|
|
125
141
|
let subCalls = list(SPLIT_GROUPS).map(index => {
|
|
@@ -127,12 +143,15 @@ export async function createCallFactory(
|
|
|
127
143
|
let end = Math.floor((index + 1) / SPLIT_GROUPS * splitArg.length);
|
|
128
144
|
return splitArg.slice(start, end);
|
|
129
145
|
}).filter(x => x.length > 0);
|
|
130
|
-
|
|
146
|
+
|
|
147
|
+
let calls = subCalls.map(async splitList => {
|
|
131
148
|
let subCall = { ...call };
|
|
132
149
|
subCall.args = subCall.args.slice();
|
|
133
|
-
subCall.args[splitArgIndex] = splitList;
|
|
150
|
+
subCall.args[splitArgIndex] = markArrayAsSplitable(splitList);
|
|
134
151
|
await callFactory.performCall(subCall);
|
|
135
|
-
}
|
|
152
|
+
});
|
|
153
|
+
await Promise.allSettled(calls);
|
|
154
|
+
await Promise.all(calls);
|
|
136
155
|
// Eh... we COULD return the array of results, but... then the result would sometimes be an array,
|
|
137
156
|
// some times not, so, it is better to return a string which will make it more clear why it sometimes varies.
|
|
138
157
|
return "CALLS_SPLIT_DUE_TO_LARGE_ARGS";
|
|
@@ -355,9 +374,15 @@ export async function createCallFactory(
|
|
|
355
374
|
}
|
|
356
375
|
throw new Error(`Unhandled data type ${typeof message}`);
|
|
357
376
|
} catch (e: any) {
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
377
|
+
// NOTE: I'm looking for all types of errors here (specifically, .send errors), in case
|
|
378
|
+
// there are errors I should be handling.
|
|
379
|
+
if (e.stack.startsWith("Error: Cannot send data to") && e.stack.includes("as the connection has closed")) {
|
|
380
|
+
// This is fine, just ignore it
|
|
381
|
+
} else {
|
|
382
|
+
debugbreak(2);
|
|
383
|
+
debugger;
|
|
384
|
+
console.error(e.stack);
|
|
385
|
+
}
|
|
361
386
|
}
|
|
362
387
|
}
|
|
363
388
|
|
package/src/batching.ts
CHANGED
|
@@ -113,15 +113,18 @@ export async function runInfinitePollCallAtStart(
|
|
|
113
113
|
delayTime: number,
|
|
114
114
|
fnc: () => Promise<void> | void
|
|
115
115
|
) {
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
116
|
+
try {
|
|
117
|
+
return await fnc();
|
|
118
|
+
} finally {
|
|
119
|
+
void (async () => {
|
|
120
|
+
while (true) {
|
|
121
|
+
await delay(delayTime);
|
|
122
|
+
try {
|
|
123
|
+
await fnc();
|
|
124
|
+
} catch (e: any) {
|
|
125
|
+
console.error(`Error in infinite poll ${fnc.name} (continuing poll loop)\n${e.stack}`);
|
|
126
|
+
}
|
|
123
127
|
}
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
return await fnc();
|
|
128
|
+
})();
|
|
129
|
+
}
|
|
127
130
|
}
|
package/src/caching.ts
CHANGED
|
@@ -3,7 +3,6 @@ import { AnyFunction, Args, canHaveChildren } from "./types";
|
|
|
3
3
|
|
|
4
4
|
export function lazy<T>(factory: () => T): () => T {
|
|
5
5
|
let value: { value: T } | undefined = undefined;
|
|
6
|
-
|
|
7
6
|
return () => {
|
|
8
7
|
if (!value) {
|
|
9
8
|
value = { value: factory() };
|
|
@@ -33,8 +32,10 @@ export function cacheEmptyArray<T>(array: T[]): T[] {
|
|
|
33
32
|
|
|
34
33
|
export function cache<Output, Key>(getValue: (key: Key) => Output): {
|
|
35
34
|
(key: Key): Output;
|
|
35
|
+
// NOTE: If you want to clear all, just make a new cache!
|
|
36
36
|
clear(key: Key): void;
|
|
37
37
|
forceSet(key: Key, value: Output): void;
|
|
38
|
+
getAllKeys(): Key[];
|
|
38
39
|
} {
|
|
39
40
|
let startingCalculating = new Set<Key>();
|
|
40
41
|
let values = new Map<Key, Output>();
|
|
@@ -61,6 +62,9 @@ export function cache<Output, Key>(getValue: (key: Key) => Output): {
|
|
|
61
62
|
values.set(key, value);
|
|
62
63
|
startingCalculating.add(key);
|
|
63
64
|
};
|
|
65
|
+
cache.getAllKeys = () => {
|
|
66
|
+
return [...values.keys()];
|
|
67
|
+
};
|
|
64
68
|
return cache;
|
|
65
69
|
}
|
|
66
70
|
|
package/src/callHTTPHandler.ts
CHANGED
|
@@ -158,7 +158,7 @@ export async function httpCallHandler(request: http.IncomingMessage, response: h
|
|
|
158
158
|
|
|
159
159
|
|
|
160
160
|
// NOTE: Our ETag caching is only to reduce data sent on the wire, we evaluate the calls
|
|
161
|
-
// every time (so it is strictly a wire cache, not a computation cache)
|
|
161
|
+
// every time (so it is strictly a wire cache for HTTP, not a computation cache)
|
|
162
162
|
if (SocketFunction.httpETagCache) {
|
|
163
163
|
response.setHeader("cache-control", "private, max-age=0, must-revalidate");
|
|
164
164
|
let hash = sha256Hash(resultBuffer);
|
package/src/certStore.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as tls from "tls";
|
|
2
|
-
import { sha256Hash } from "./misc";
|
|
2
|
+
import { isNode, sha256Hash } from "./misc";
|
|
3
3
|
|
|
4
4
|
let trustedCerts = new Set<string>();
|
|
5
5
|
let watchCallbacks = new Set<(certs: string[]) => void>();
|
|
@@ -15,8 +15,12 @@ export function trustCertificate(cert: string | Buffer) {
|
|
|
15
15
|
}
|
|
16
16
|
}
|
|
17
17
|
export function getTrustedCertificates(): string[] {
|
|
18
|
-
|
|
19
|
-
|
|
18
|
+
let certs: string[] = [];
|
|
19
|
+
if (isNode()) {
|
|
20
|
+
certs.push(...tls.rootCertificates);
|
|
21
|
+
}
|
|
22
|
+
certs.push(...Array.from(trustedCerts));
|
|
23
|
+
return certs;
|
|
20
24
|
}
|
|
21
25
|
|
|
22
26
|
export function watchTrustedCertificates(callback: (certs: string[]) => void) {
|
|
@@ -5,5 +5,5 @@ export function markArrayAsSplitable<T>(data: T[]): T[] {
|
|
|
5
5
|
}
|
|
6
6
|
export function isSplitableArray<T>(data: T): data is T & (unknown[]) {
|
|
7
7
|
if (!Array.isArray(data)) return false;
|
|
8
|
-
return (data as any)[arrayIsSplitable]
|
|
8
|
+
return !!(data as any)[arrayIsSplitable];
|
|
9
9
|
}
|
package/src/misc.ts
CHANGED
|
@@ -139,10 +139,34 @@ export function getKeys(obj: unknown) {
|
|
|
139
139
|
}
|
|
140
140
|
return keyArray;
|
|
141
141
|
}
|
|
142
|
+
export function getStringKeys<T extends {}>(obj: T): ((keyof T) & string)[] {
|
|
143
|
+
return Object.keys(obj) as any;
|
|
144
|
+
}
|
|
142
145
|
|
|
143
146
|
if (isNode()) {
|
|
144
147
|
// TODO: Find a better place for this...
|
|
145
148
|
process.on("unhandledRejection", async (reason: any, promise) => {
|
|
146
149
|
console.error(`Uncaught promise rejection: ${String(reason.stack || reason)}`);
|
|
147
150
|
});
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
export function keyBy<T, K>(arr: T[], getKey: (value: T) => K): Map<K, T> {
|
|
154
|
+
let map = new Map<K, T>();
|
|
155
|
+
for (let item of arr) {
|
|
156
|
+
map.set(getKey(item), item);
|
|
157
|
+
}
|
|
158
|
+
return map;
|
|
159
|
+
}
|
|
160
|
+
export function keyByArray<T, K>(arr: T[], getKey: (value: T) => K): Map<K, T[]> {
|
|
161
|
+
let map = new Map<K, T[]>();
|
|
162
|
+
for (let item of arr) {
|
|
163
|
+
let key = getKey(item);
|
|
164
|
+
let arr = map.get(key);
|
|
165
|
+
if (!arr) {
|
|
166
|
+
arr = [];
|
|
167
|
+
map.set(key, arr);
|
|
168
|
+
}
|
|
169
|
+
arr.push(item);
|
|
170
|
+
}
|
|
171
|
+
return map;
|
|
148
172
|
}
|
package/src/profiling/measure.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import debugbreak from "debugbreak";
|
|
2
2
|
import { formatTime, formatNumber } from "../formatting/format";
|
|
3
|
-
import { red, yellow, blue } from "../formatting/logColors";
|
|
3
|
+
import { red, yellow, blue, magenta } from "../formatting/logColors";
|
|
4
4
|
|
|
5
5
|
import { getOwnTime, getPendingOwnTimeInstances, getPendingOwnTimeObjs, OwnTimeObj } from "./getOwnTime";
|
|
6
6
|
import { addToStats, addToStatsValue, createStatsValue, getStatsTop, StatsValue } from "./stats";
|
|
@@ -108,9 +108,9 @@ export function logMeasureTable(
|
|
|
108
108
|
let totalTime = entries.map(x => getTime(x).sum).reduce((a, b) => a + b, 0);
|
|
109
109
|
|
|
110
110
|
console.log();
|
|
111
|
-
let title = yellow(`Profiled ${formatTime(totalTime)}`);
|
|
111
|
+
let title = yellow(`Profiled ${formatTime(totalTime)} (logged at ${new Date().toISOString()})`);
|
|
112
112
|
if (name) {
|
|
113
|
-
title
|
|
113
|
+
title = `(${blue(name)}) ${title}`;
|
|
114
114
|
}
|
|
115
115
|
console.log(title);
|
|
116
116
|
function percent(value: number) {
|
|
@@ -142,7 +142,7 @@ export function logMeasureTable(
|
|
|
142
142
|
|
|
143
143
|
let ownTimeTop = getStatsTop(getTime(entry));
|
|
144
144
|
if (ownTimeTop.topHeavy) {
|
|
145
|
-
output += red(` TOP ${percent(ownTimeTop.valueFraction)} of the time is owned by ${percent(ownTimeTop.countFraction)} of the calls`);
|
|
145
|
+
output += red(` TOP ${percent(ownTimeTop.valueFraction)} of the time is owned by ${percent(ownTimeTop.countFraction)} of the calls (${formatTime(ownTimeTop.value / ownTimeTop.count)} per * ${formatNumber(ownTimeTop.count)} = ${formatTime(ownTimeTop.value)})`);
|
|
146
146
|
}
|
|
147
147
|
|
|
148
148
|
if (entry.stillOpenCount > 0) {
|
package/src/webSocketServer.ts
CHANGED
|
@@ -12,6 +12,10 @@ import debugbreak from "debugbreak";
|
|
|
12
12
|
import { getNodeId } from "./nodeCache";
|
|
13
13
|
import crypto from "crypto";
|
|
14
14
|
import { Watchable } from "./misc";
|
|
15
|
+
import { delay, runInfinitePoll } from "./batching";
|
|
16
|
+
import { magenta } from "./formatting/logColors";
|
|
17
|
+
import { yellow } from "./formatting/logColors";
|
|
18
|
+
import { green } from "./formatting/logColors";
|
|
15
19
|
|
|
16
20
|
export type SocketServerConfig = (
|
|
17
21
|
https.ServerOptions & {
|
|
@@ -27,6 +31,11 @@ export type SocketServerConfig = (
|
|
|
27
31
|
public?: boolean;
|
|
28
32
|
ip?: string;
|
|
29
33
|
|
|
34
|
+
// NOTE: Any same origin accesses are allowed (header.origin === header.host)
|
|
35
|
+
// For example, to allow "letx.ca" to access the server (when the hosted domain
|
|
36
|
+
// may be, "querysub.com", for example), use ["letx.ca"]
|
|
37
|
+
allowHostnames?: string[];
|
|
38
|
+
|
|
30
39
|
/** If the SNI matches this domain, we use a different key/cert. */
|
|
31
40
|
SNICerts?: {
|
|
32
41
|
[domain: string]: Watchable<https.ServerOptions>;
|
|
@@ -58,6 +67,11 @@ export async function startSocketServer(
|
|
|
58
67
|
});
|
|
59
68
|
let httpsServer = await httpServerPromise;
|
|
60
69
|
|
|
70
|
+
let allowedHostnames = new Set<string>();
|
|
71
|
+
for (let hostname of config.allowHostnames || []) {
|
|
72
|
+
allowedHostnames.add(hostname);
|
|
73
|
+
}
|
|
74
|
+
|
|
61
75
|
watchTrustedCertificates(() => {
|
|
62
76
|
lastOptions.ca = getTrustedCertificates();
|
|
63
77
|
httpsServer.setSecureContext(lastOptions);
|
|
@@ -99,8 +113,8 @@ export async function startSocketServer(
|
|
|
99
113
|
try {
|
|
100
114
|
let host = new URL("ws://" + request.headers["host"]).hostname;
|
|
101
115
|
let origin = new URL(originHeader).hostname;
|
|
102
|
-
if (host !== origin) {
|
|
103
|
-
throw new Error(`Invalid cross
|
|
116
|
+
if (host !== origin && !allowedHostnames.has(origin)) {
|
|
117
|
+
throw new Error(`Invalid cross domain request, ${JSON.stringify(host)} !== ${JSON.stringify(origin)} (also not config.allowedHostnames ${JSON.stringify(config.allowHostnames)})`);
|
|
104
118
|
}
|
|
105
119
|
} catch (e) {
|
|
106
120
|
console.error(e);
|
|
@@ -213,7 +227,7 @@ export async function startSocketServer(
|
|
|
213
227
|
}
|
|
214
228
|
|
|
215
229
|
if (!SocketFunction.silent) {
|
|
216
|
-
console.log(`Trying to listening on ${host}:${port}`);
|
|
230
|
+
console.log(yellow(`Trying to listening on ${host}:${port}`));
|
|
217
231
|
}
|
|
218
232
|
realServer.listen(port, host);
|
|
219
233
|
|
|
@@ -222,7 +236,7 @@ export async function startSocketServer(
|
|
|
222
236
|
port = (realServer.address() as net.AddressInfo).port;
|
|
223
237
|
let nodeId = getNodeId(getCommonName(config.cert), port);
|
|
224
238
|
if (!SocketFunction.silent) {
|
|
225
|
-
console.log(`Started Listening on ${nodeId}`);
|
|
239
|
+
console.log(green(`Started Listening on ${nodeId}`));
|
|
226
240
|
}
|
|
227
241
|
|
|
228
242
|
return nodeId;
|
package/src/websocketFactory.ts
CHANGED
|
@@ -38,7 +38,7 @@ export function createWebsocketFactory(): (nodeId: string) => SenderInterface {
|
|
|
38
38
|
console.log(`Connecting to ${address}:${port}`);
|
|
39
39
|
}
|
|
40
40
|
let webSocket = new ws.WebSocket(`wss://${address}:${port}`, {
|
|
41
|
-
ca:
|
|
41
|
+
ca: getTrustedCertificates()
|
|
42
42
|
});
|
|
43
43
|
let result = Object.assign(webSocket, { socket: undefined as tls.TLSSocket | undefined });
|
|
44
44
|
webSocket.once("upgrade", e => {
|
package/test/shared.ts
CHANGED
|
@@ -8,19 +8,13 @@ class TestBase {
|
|
|
8
8
|
memberVariable = 5;
|
|
9
9
|
|
|
10
10
|
async add(lhs: number, rhs: number) {
|
|
11
|
-
let caller =
|
|
12
|
-
if (!caller) {
|
|
13
|
-
throw new Error("No caller?");
|
|
14
|
-
}
|
|
11
|
+
let caller = SocketFunction.getCaller().nodeId;
|
|
15
12
|
console.log(`Caller is ${caller}`);
|
|
16
13
|
return lhs + rhs;
|
|
17
14
|
}
|
|
18
15
|
|
|
19
16
|
async callMe() {
|
|
20
|
-
let caller =
|
|
21
|
-
if (!caller) {
|
|
22
|
-
throw new Error("No caller?");
|
|
23
|
-
}
|
|
17
|
+
let caller = SocketFunction.getCaller().nodeId;
|
|
24
18
|
console.log(`Caller is ${caller}`);
|
|
25
19
|
void (async () => {
|
|
26
20
|
let seqNum = 1;
|