@scp-dev/broker 0.1.0 → 0.1.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/dist/index.d.ts +2 -1
- package/dist/index.js +39 -8
- package/package.json +3 -3
- package/src/client.ts +2 -1
- package/src/server.ts +52 -7
package/dist/index.d.ts
CHANGED
|
@@ -143,7 +143,8 @@ declare class RelayClient {
|
|
|
143
143
|
}>;
|
|
144
144
|
/**
|
|
145
145
|
* at a stop: the spawned workers' unread messages, held for the hook to print, waiting up to `wait_s` while workers still run, none came,
|
|
146
|
-
* pushes are left and no prompt moved the `prompts` mark inject handed out
|
|
146
|
+
* pushes are left and no prompt moved the `prompts` mark inject handed out; with `wait_s` above 0 and other workers still running, the
|
|
147
|
+
* broker gathers more of their results into the same push for up to ${LIMITS.pushGraceS} s, which may run past `wait_s`
|
|
147
148
|
*/
|
|
148
149
|
stopWait(waitS?: number, prompts?: number): Promise<StopWaitResult>;
|
|
149
150
|
group(params: GroupParams): Promise<unknown>;
|
package/dist/index.js
CHANGED
|
@@ -408,7 +408,8 @@ var RelayClient = class _RelayClient {
|
|
|
408
408
|
}
|
|
409
409
|
/**
|
|
410
410
|
* at a stop: the spawned workers' unread messages, held for the hook to print, waiting up to `wait_s` while workers still run, none came,
|
|
411
|
-
* pushes are left and no prompt moved the `prompts` mark inject handed out
|
|
411
|
+
* pushes are left and no prompt moved the `prompts` mark inject handed out; with `wait_s` above 0 and other workers still running, the
|
|
412
|
+
* broker gathers more of their results into the same push for up to ${LIMITS.pushGraceS} s, which may run past `wait_s`
|
|
412
413
|
*/
|
|
413
414
|
stopWait(waitS = 0, prompts) {
|
|
414
415
|
return this.request("stop_wait", { wait_s: waitS, ...prompts !== void 0 ? { prompts } : {} });
|
|
@@ -1598,6 +1599,13 @@ var ASK_RECHECK_MS = 1e3;
|
|
|
1598
1599
|
var STOP_RECHECK_MS = 1e3;
|
|
1599
1600
|
var TRANSIENT_METHODS = /* @__PURE__ */ new Set(["event", "status", "whoami", "inject", "injected", "peek_turn", "stop_wait", "prompted"]);
|
|
1600
1601
|
var GRANT_UNBOUND = `a spawn-env grant binds only a new harness process: run the harness with it, or name the child (${CLI_NAME} spawn-env --name / --as)`;
|
|
1602
|
+
function workerResults(result) {
|
|
1603
|
+
return result.messages.length - (result.others_shown ?? 0) + result.more;
|
|
1604
|
+
}
|
|
1605
|
+
function othersRunning(result) {
|
|
1606
|
+
const senders = new Set(result.messages.slice(0, result.messages.length - (result.others_shown ?? 0)).map((m) => m.from.address));
|
|
1607
|
+
return result.workers.filter((address) => !senders.has(address)).length + result.starting;
|
|
1608
|
+
}
|
|
1601
1609
|
function running(pid) {
|
|
1602
1610
|
try {
|
|
1603
1611
|
process.kill(pid, 0);
|
|
@@ -1886,6 +1894,21 @@ async function startBroker(options) {
|
|
|
1886
1894
|
if (s.data.closed) done();
|
|
1887
1895
|
});
|
|
1888
1896
|
}
|
|
1897
|
+
async function gather(me, result, peek, s) {
|
|
1898
|
+
const gathering = (r) => workerResults(r) > 0 && !r.more && !r.prompted && othersRunning(r) > 0;
|
|
1899
|
+
const cap = Date.now() + LIMITS2.pushGraceS * 1e3;
|
|
1900
|
+
let quiet = Date.now() + LIMITS2.pushQuietS * 1e3;
|
|
1901
|
+
let results = workerResults(result);
|
|
1902
|
+
while (gathering(result) && !s.data.closed && Date.now() < Math.min(quiet, cap)) {
|
|
1903
|
+
await waitFor(me, Math.min(quiet, cap) - Date.now(), s);
|
|
1904
|
+
if (closing) throw new RelayError4("unauthorized", "the relay broker is stopping");
|
|
1905
|
+
result = core.stopWait(me, peek);
|
|
1906
|
+
if (workerResults(result) > results) {
|
|
1907
|
+
results = workerResults(result);
|
|
1908
|
+
quiet = Date.now() + LIMITS2.pushQuietS * 1e3;
|
|
1909
|
+
}
|
|
1910
|
+
}
|
|
1911
|
+
}
|
|
1889
1912
|
function onData(s, chunk) {
|
|
1890
1913
|
const { lines, tooLong } = s.data.reader.push(chunk);
|
|
1891
1914
|
for (const line of lines) s.data.queue.push(line);
|
|
@@ -2206,22 +2229,28 @@ async function startBroker(options) {
|
|
|
2206
2229
|
...hookOf(s)
|
|
2207
2230
|
});
|
|
2208
2231
|
case "stop_wait": {
|
|
2209
|
-
const
|
|
2232
|
+
const waitMs = waitSeconds(params.wait_s);
|
|
2233
|
+
const deadline = Date.now() + waitMs;
|
|
2210
2234
|
const options2 = { ...hookOf(s), ...typeof params.prompts === "number" ? { prompts: params.prompts } : {} };
|
|
2211
|
-
|
|
2235
|
+
const peek = { ...options2, peek: true };
|
|
2236
|
+
let result = core.stopWait(me, peek);
|
|
2212
2237
|
const idle = (r) => !r.messages.length && !r.more && r.workers.length + r.starting > 0 && r.pushes_left > 0 && !r.prompted;
|
|
2213
2238
|
while (idle(result) && !s.data.closed && Date.now() < deadline) {
|
|
2214
2239
|
await waitFor(me, Math.min(STOP_RECHECK_MS, deadline - Date.now()), s);
|
|
2215
2240
|
if (closing) throw new RelayError4("unauthorized", "the relay broker is stopping");
|
|
2216
|
-
result = core.stopWait(me,
|
|
2241
|
+
result = core.stopWait(me, peek);
|
|
2217
2242
|
}
|
|
2218
|
-
|
|
2243
|
+
if (waitMs > 0) await gather(me, result, peek, s);
|
|
2244
|
+
return core.stopWait(me, options2);
|
|
2245
|
+
}
|
|
2246
|
+
case "prompted": {
|
|
2247
|
+
const prompted = core.prompted(me, hookOf(s));
|
|
2248
|
+
if (prompted) wake(me);
|
|
2249
|
+
return { prompted };
|
|
2219
2250
|
}
|
|
2220
|
-
case "prompted":
|
|
2221
|
-
return { prompted: core.prompted(me, hookOf(s)) };
|
|
2222
2251
|
case "injected":
|
|
2223
2252
|
return {
|
|
2224
|
-
injected: core.injected(params.seqs, params.hold, { endpoint: me, read: params.read }),
|
|
2253
|
+
injected: core.injected(params.seqs, params.hold, { endpoint: me, read: params.read, deferred: params.deferred === true }),
|
|
2225
2254
|
...params.stop === true ? { held: core.stopHeld(me, hookOf(s)) } : {},
|
|
2226
2255
|
...params.push === true ? { pushed: core.pushed(me, params.read, hookOf(s)) } : {},
|
|
2227
2256
|
...params.nudged !== void 0 ? { nudged: core.nudged(me, params.nudged, hookOf(s)) } : {},
|
|
@@ -2231,6 +2260,8 @@ async function startBroker(options) {
|
|
|
2231
2260
|
};
|
|
2232
2261
|
case "message":
|
|
2233
2262
|
return { message: core.delivered(me, params.id) ?? (params.member === true ? core.threadMessage(me, params.id) : null) };
|
|
2263
|
+
case "receipts":
|
|
2264
|
+
return core.receipts(me, params.id);
|
|
2234
2265
|
}
|
|
2235
2266
|
throw new RelayError4("method_not_found", `no method ${method}`);
|
|
2236
2267
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@scp-dev/broker",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"description": "Swarm Communication Protocol local broker: a unix socket JSON-RPC daemon over the relay core, its client and the bridge to an account hub.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"homepage": "https://scp.dev",
|
|
@@ -37,8 +37,8 @@
|
|
|
37
37
|
"typecheck": "tsc -p ."
|
|
38
38
|
},
|
|
39
39
|
"dependencies": {
|
|
40
|
-
"@scp-dev/core": "0.1.
|
|
41
|
-
"@scp-dev/hub": "0.1.
|
|
40
|
+
"@scp-dev/core": "0.1.1",
|
|
41
|
+
"@scp-dev/hub": "0.1.1"
|
|
42
42
|
},
|
|
43
43
|
"devDependencies": {
|
|
44
44
|
"tsup": "^8.5.1"
|
package/src/client.ts
CHANGED
|
@@ -196,7 +196,8 @@ export class RelayClient {
|
|
|
196
196
|
|
|
197
197
|
/**
|
|
198
198
|
* at a stop: the spawned workers' unread messages, held for the hook to print, waiting up to `wait_s` while workers still run, none came,
|
|
199
|
-
* pushes are left and no prompt moved the `prompts` mark inject handed out
|
|
199
|
+
* pushes are left and no prompt moved the `prompts` mark inject handed out; with `wait_s` above 0 and other workers still running, the
|
|
200
|
+
* broker gathers more of their results into the same push for up to ${LIMITS.pushGraceS} s, which may run past `wait_s`
|
|
200
201
|
*/
|
|
201
202
|
stopWait(waitS = 0, prompts?: number): Promise<StopWaitResult> {
|
|
202
203
|
return this.request<StopWaitResult>("stop_wait", { wait_s: waitS, ...(prompts !== undefined ? { prompts } : {}) })
|
package/src/server.ts
CHANGED
|
@@ -135,6 +135,17 @@ const STOP_RECHECK_MS = 1000
|
|
|
135
135
|
const TRANSIENT_METHODS = new Set(["event", "status", "whoami", "inject", "injected", "peek_turn", "stop_wait", "prompted"])
|
|
136
136
|
const GRANT_UNBOUND = `a spawn-env grant binds only a new harness process: run the harness with it, or name the child (${CLI_NAME} spawn-env --name / --as)`
|
|
137
137
|
|
|
138
|
+
/** the workers' messages and handbacks a stop's push would show, and those of theirs left unread past it */
|
|
139
|
+
function workerResults(result: StopWaitResult): number {
|
|
140
|
+
return result.messages.length - (result.others_shown ?? 0) + result.more
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/** the workers still running that sent none of the messages a stop's push would show, and those not joined yet */
|
|
144
|
+
function othersRunning(result: StopWaitResult): number {
|
|
145
|
+
const senders = new Set(result.messages.slice(0, result.messages.length - (result.others_shown ?? 0)).map((m) => m.from.address))
|
|
146
|
+
return result.workers.filter((address) => !senders.has(address)).length + result.starting
|
|
147
|
+
}
|
|
148
|
+
|
|
138
149
|
type Request = { jsonrpc?: string; id?: string | number | null; method?: unknown; params?: unknown }
|
|
139
150
|
|
|
140
151
|
/** whether a process runs (one of another user's counts too) */
|
|
@@ -461,6 +472,32 @@ export async function startBroker(options: BrokerOptions): Promise<Broker> {
|
|
|
461
472
|
})
|
|
462
473
|
}
|
|
463
474
|
|
|
475
|
+
/**
|
|
476
|
+
* a stop's push with worker results to show while other workers still run: waits on, peeking, for more of theirs to show with them until
|
|
477
|
+
* none came for ${LIMITS.pushQuietS} s, ${LIMITS.pushGraceS} s after it began (which may run past the stop's wait), the push budget is
|
|
478
|
+
* full (`more`), no other worker runs ({@link othersRunning}), a prompt came or the connection closed
|
|
479
|
+
*/
|
|
480
|
+
async function gather(
|
|
481
|
+
me: string,
|
|
482
|
+
result: StopWaitResult,
|
|
483
|
+
peek: ReturnType<typeof hookOf> & { prompts?: number; peek: boolean },
|
|
484
|
+
s: Conn<Connection>,
|
|
485
|
+
): Promise<void> {
|
|
486
|
+
const gathering = (r: StopWaitResult) => workerResults(r) > 0 && !r.more && !r.prompted && othersRunning(r) > 0
|
|
487
|
+
const cap = Date.now() + LIMITS.pushGraceS * 1000
|
|
488
|
+
let quiet = Date.now() + LIMITS.pushQuietS * 1000
|
|
489
|
+
let results = workerResults(result)
|
|
490
|
+
while (gathering(result) && !s.data.closed && Date.now() < Math.min(quiet, cap)) {
|
|
491
|
+
await waitFor(me, Math.min(quiet, cap) - Date.now(), s)
|
|
492
|
+
if (closing) throw new RelayError("unauthorized", "the relay broker is stopping")
|
|
493
|
+
result = core.stopWait(me, peek)
|
|
494
|
+
if (workerResults(result) > results) {
|
|
495
|
+
results = workerResults(result)
|
|
496
|
+
quiet = Date.now() + LIMITS.pushQuietS * 1000
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
|
|
464
501
|
function onData(s: Conn<Connection>, chunk: Uint8Array) {
|
|
465
502
|
const { lines, tooLong } = s.data.reader.push(chunk)
|
|
466
503
|
for (const line of lines) s.data.queue.push(line)
|
|
@@ -796,22 +833,28 @@ export async function startBroker(options: BrokerOptions): Promise<Broker> {
|
|
|
796
833
|
...hookOf(s),
|
|
797
834
|
})
|
|
798
835
|
case "stop_wait": {
|
|
799
|
-
const
|
|
836
|
+
const waitMs = waitSeconds(params.wait_s)
|
|
837
|
+
const deadline = Date.now() + waitMs
|
|
800
838
|
const options = { ...hookOf(s), ...(typeof params.prompts === "number" ? { prompts: params.prompts } : {}) }
|
|
801
|
-
|
|
839
|
+
const peek = { ...options, peek: true }
|
|
840
|
+
let result = core.stopWait(me, peek)
|
|
802
841
|
const idle = (r: StopWaitResult) => !r.messages.length && !r.more && r.workers.length + r.starting > 0 && r.pushes_left > 0 && !r.prompted
|
|
803
842
|
while (idle(result) && !s.data.closed && Date.now() < deadline) {
|
|
804
843
|
await waitFor(me, Math.min(STOP_RECHECK_MS, deadline - Date.now()), s)
|
|
805
844
|
if (closing) throw new RelayError("unauthorized", "the relay broker is stopping")
|
|
806
|
-
result = core.stopWait(me,
|
|
845
|
+
result = core.stopWait(me, peek)
|
|
807
846
|
}
|
|
808
|
-
|
|
847
|
+
if (waitMs > 0) await gather(me, result, peek, s)
|
|
848
|
+
return core.stopWait(me, options)
|
|
849
|
+
}
|
|
850
|
+
case "prompted": {
|
|
851
|
+
const prompted = core.prompted(me, hookOf(s))
|
|
852
|
+
if (prompted) wake(me)
|
|
853
|
+
return { prompted }
|
|
809
854
|
}
|
|
810
|
-
case "prompted":
|
|
811
|
-
return { prompted: core.prompted(me, hookOf(s)) }
|
|
812
855
|
case "injected":
|
|
813
856
|
return {
|
|
814
|
-
injected: core.injected(params.seqs, params.hold, { endpoint: me, read: params.read }),
|
|
857
|
+
injected: core.injected(params.seqs, params.hold, { endpoint: me, read: params.read, deferred: params.deferred === true }),
|
|
815
858
|
...(params.stop === true ? { held: core.stopHeld(me, hookOf(s)) } : {}),
|
|
816
859
|
...(params.push === true ? { pushed: core.pushed(me, params.read, hookOf(s)) } : {}),
|
|
817
860
|
...(params.nudged !== undefined ? { nudged: core.nudged(me, params.nudged, hookOf(s)) } : {}),
|
|
@@ -821,6 +864,8 @@ export async function startBroker(options: BrokerOptions): Promise<Broker> {
|
|
|
821
864
|
}
|
|
822
865
|
case "message":
|
|
823
866
|
return { message: core.delivered(me, params.id) ?? (params.member === true ? core.threadMessage(me, params.id) : null) }
|
|
867
|
+
case "receipts":
|
|
868
|
+
return core.receipts(me, params.id)
|
|
824
869
|
}
|
|
825
870
|
throw new RelayError("method_not_found", `no method ${method}`)
|
|
826
871
|
}
|