obsbot-mcp 0.6.3 → 0.8.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/README.md +97 -20
  2. package/dist/build-info.json +5 -0
  3. package/dist/device/manager.d.ts +8 -0
  4. package/dist/device/manager.js +37 -4
  5. package/dist/device/manager.js.map +1 -1
  6. package/dist/geometry/aim.d.ts +24 -13
  7. package/dist/geometry/aim.js +26 -13
  8. package/dist/geometry/aim.js.map +1 -1
  9. package/dist/ipc/build-id.d.ts +25 -0
  10. package/dist/ipc/build-id.js +60 -0
  11. package/dist/ipc/build-id.js.map +1 -0
  12. package/dist/ipc/client.d.ts +36 -0
  13. package/dist/ipc/client.js +106 -4
  14. package/dist/ipc/client.js.map +1 -1
  15. package/dist/ipc/coordinator.d.ts +91 -12
  16. package/dist/ipc/coordinator.js +293 -57
  17. package/dist/ipc/coordinator.js.map +1 -1
  18. package/dist/ipc/gate.d.ts +14 -0
  19. package/dist/ipc/gate.js +45 -0
  20. package/dist/ipc/gate.js.map +1 -0
  21. package/dist/ipc/owner.d.ts +27 -1
  22. package/dist/ipc/owner.js +67 -4
  23. package/dist/ipc/owner.js.map +1 -1
  24. package/dist/ipc/protocol.d.ts +30 -0
  25. package/dist/ipc/protocol.js +40 -0
  26. package/dist/ipc/protocol.js.map +1 -1
  27. package/dist/ipc/rendezvous.d.ts +37 -11
  28. package/dist/ipc/rendezvous.js +143 -30
  29. package/dist/ipc/rendezvous.js.map +1 -1
  30. package/dist/mcp/server.js +40 -12
  31. package/dist/mcp/server.js.map +1 -1
  32. package/dist/mcp/tools.d.ts +6 -0
  33. package/dist/mcp/tools.js +123 -17
  34. package/dist/mcp/tools.js.map +1 -1
  35. package/dist/tail2/api.d.ts +218 -0
  36. package/dist/tail2/api.js +267 -0
  37. package/dist/tail2/api.js.map +1 -0
  38. package/dist/tail2/mdns.d.ts +48 -0
  39. package/dist/tail2/mdns.js +216 -0
  40. package/dist/tail2/mdns.js.map +1 -0
  41. package/dist/tail2/registry.d.ts +100 -0
  42. package/dist/tail2/registry.js +200 -0
  43. package/dist/tail2/registry.js.map +1 -0
  44. package/dist/tail2/snapshot.d.ts +54 -0
  45. package/dist/tail2/snapshot.js +157 -0
  46. package/dist/tail2/snapshot.js.map +1 -0
  47. package/dist/tail2/tools.d.ts +7 -0
  48. package/dist/tail2/tools.js +370 -0
  49. package/dist/tail2/tools.js.map +1 -0
  50. package/dist/transport/helper-process.d.ts +11 -0
  51. package/dist/transport/helper-process.js +10 -0
  52. package/dist/transport/helper-process.js.map +1 -1
  53. package/dist/transport/linux.d.ts +59 -9
  54. package/dist/transport/linux.js +163 -21
  55. package/dist/transport/linux.js.map +1 -1
  56. package/dist/transport/macos.d.ts +8 -0
  57. package/dist/transport/macos.js +11 -0
  58. package/dist/transport/macos.js.map +1 -1
  59. package/dist/transport/transport.d.ts +22 -0
  60. package/dist/transport/transport.js +20 -0
  61. package/dist/transport/transport.js.map +1 -1
  62. package/dist/transport/windows.d.ts +6 -0
  63. package/dist/transport/windows.js +9 -0
  64. package/dist/transport/windows.js.map +1 -1
  65. package/dist/version.d.ts +1 -1
  66. package/dist/version.js +1 -1
  67. package/native/prebuilt/darwin-arm64/obsbot-helper +0 -0
  68. package/native/prebuilt/darwin-x64/obsbot-helper +0 -0
  69. package/native/prebuilt/linux-x64/obsbot-helper +0 -0
  70. package/native/prebuilt/win32-x64/obsbot-helper.exe +0 -0
  71. package/package.json +4 -1
@@ -1,31 +1,49 @@
1
- import { elect, rendezvousPath } from "./rendezvous.js";
1
+ import { elect as electEndpoint, rendezvousPath } from "./rendezvous.js";
2
2
  import { OwnerServer } from "./owner.js";
3
3
  import { OwnerClient } from "./client.js";
4
- /**
5
- * Wrap a tool runner so calls execute strictly one-at-a-time. This is THE
6
- * single-camera lock: it must guard both the owner's own MCP calls AND the
7
- * calls forwarded from clients, because the owner's local path does not pass
8
- * through OwnerServer's queue. Errors don't break the chain.
9
- */
10
- export function serialize(fn) {
11
- let tail = Promise.resolve();
12
- return (tool, args) => {
13
- const run = tail.then(() => fn(tool, args));
14
- tail = run.then(() => undefined, () => undefined);
15
- return run;
16
- };
17
- }
4
+ import { CallGate, StepDownError } from "./gate.js";
5
+ import { buildLabel, compareBuilds, unstampedBuild } from "./build-id.js";
6
+ export const DEFAULT_TIMING = {
7
+ helloTimeoutMs: 2000,
8
+ stepDownGraceMs: 500,
9
+ electionJitterMs: 100,
10
+ stepDownTimeoutMs: 15000,
11
+ releaseTimeoutMs: 10000,
12
+ maxTakeoverRounds: 5,
13
+ };
14
+ const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
15
+ const errText = (e) => (e instanceof Error ? e.message : String(e));
18
16
  export class Coordinator {
19
17
  runLocal;
20
- path;
21
18
  role = "none";
22
19
  client;
23
20
  ownerServer;
24
- electing;
25
- /** `runLocal` should already be serialize()-wrapped by the caller. */
26
- constructor(runLocal, path = rendezvousPath()) {
21
+ steppingDown = false;
22
+ /** Client of an owner that is older than us and could not be made to hand over. */
23
+ blocked = false;
24
+ /** Counts the owners this instance has been a client of. Tells one connection from the next. */
25
+ connection = 0;
26
+ closing = false;
27
+ /** A role change in progress — an election, or stepping down. Never rejects. */
28
+ pending;
29
+ /** THE single-camera lock: the owner's own calls and the ones forwarded to it. */
30
+ gate = new CallGate();
31
+ path;
32
+ build;
33
+ pid;
34
+ release;
35
+ log;
36
+ t;
37
+ elect;
38
+ constructor(runLocal, opts = {}) {
27
39
  this.runLocal = runLocal;
28
- this.path = path;
40
+ this.path = opts.path ?? rendezvousPath();
41
+ this.build = opts.build ?? unstampedBuild();
42
+ this.pid = opts.pid ?? process.pid;
43
+ this.release = opts.release ?? (async () => { });
44
+ this.log = opts.log ?? (() => { });
45
+ this.t = { ...DEFAULT_TIMING, ...opts.timing };
46
+ this.elect = opts.elect ?? electEndpoint;
29
47
  }
30
48
  /** Establish the initial role eagerly at startup. */
31
49
  start() {
@@ -35,59 +53,277 @@ export class Coordinator {
35
53
  return this.role;
36
54
  }
37
55
  async dispatch(tool, args) {
38
- await this.ensureRole();
39
- try {
40
- return await this.runByRole(tool, args);
41
- }
42
- catch (e) {
43
- if (this.role === "client" && this.client?.closed) {
44
- // The owner went away mid-call → re-elect and retry exactly once.
45
- this.reset();
46
- await this.ensureRole();
47
- return this.runByRole(tool, args);
56
+ let failure;
57
+ // Twice at most: a call that lost its owner is retried exactly once.
58
+ for (let attempt = 0; attempt < 2; attempt++) {
59
+ const target = await this.settle();
60
+ try {
61
+ return target === "local"
62
+ ? await this.gate.run(() => this.runLocal(tool, args))
63
+ : await target.request({ tool, args });
64
+ }
65
+ catch (e) {
66
+ if (e instanceof StepDownError) {
67
+ // We were the owner and are handing over; this call had not started.
68
+ // settle() waits the handover out, and the retry forwards it.
69
+ failure = e;
70
+ continue;
71
+ }
72
+ if (target !== "local" && target.closed) {
73
+ failure = e;
74
+ this.ownerLost(target);
75
+ continue;
76
+ }
77
+ throw e; // a genuine owner-side error → surface it unchanged
48
78
  }
49
- throw e; // a genuine owner-side error → surface it unchanged
50
79
  }
80
+ throw failure;
51
81
  }
52
- runByRole(tool, args) {
53
- return this.role === "owner"
54
- ? this.runLocal(tool, args)
55
- : this.client.request({ tool, args });
82
+ /**
83
+ * Wait until this instance has a role it may use, and say where a call goes:
84
+ * run here, or forward over this connection.
85
+ *
86
+ * The answer is taken in the same tick the decision is made and handed to the
87
+ * caller. Calls arrive in parallel, and one of them may be reconnecting while
88
+ * another resumes: a caller that re-read `this.client` after an await could
89
+ * find it gone, or pointing at an owner nobody has checked yet.
90
+ */
91
+ async settle() {
92
+ let asked = false;
93
+ for (let round = 0; round < 8; round++) {
94
+ await this.ensureRole();
95
+ if (this.role === "owner")
96
+ return "local";
97
+ if (this.role !== "client" || !this.client)
98
+ continue; // a role change began while we waited
99
+ if (!this.blocked)
100
+ return this.client;
101
+ // An older owner that could not hand over. Ask once more, then give up:
102
+ // a call that succeeds on code the caller did not expect is worse than
103
+ // one that fails and says why.
104
+ if (asked)
105
+ throw new Error(this.blockedMessage());
106
+ asked = true;
107
+ await this.tryAgain(this.connection);
108
+ }
109
+ throw new Error(`obsbot-mcp: ipc role did not settle for ${this.path}`);
56
110
  }
57
111
  async close() {
58
- if (this.ownerServer)
59
- await this.ownerServer.close();
60
- this.client?.close();
112
+ this.closing = true;
113
+ const server = this.ownerServer;
114
+ const client = this.client;
61
115
  this.reset();
116
+ client?.close();
117
+ if (server)
118
+ await server.close();
119
+ // A role change that was under way sees `closing` and cleans up after itself.
120
+ while (this.pending)
121
+ await this.pending;
62
122
  }
63
123
  reset() {
64
124
  this.role = "none";
65
125
  this.client = undefined;
66
126
  this.ownerServer = undefined;
127
+ this.steppingDown = false;
128
+ this.blocked = false;
129
+ }
130
+ jitter() {
131
+ return Math.floor(Math.random() * (this.t.electionJitterMs + 1));
67
132
  }
68
- ensureRole() {
133
+ /** Queue a role change behind any already under way. The result never rejects. */
134
+ begin(work) {
135
+ const prev = this.pending ?? Promise.resolve();
136
+ const p = prev
137
+ .then(work)
138
+ .catch((e) => this.log(`obsbot-mcp: ipc role change failed: ${errText(e)}`))
139
+ .finally(() => {
140
+ if (this.pending === p)
141
+ this.pending = undefined;
142
+ });
143
+ this.pending = p;
144
+ return p;
145
+ }
146
+ async ensureRole() {
147
+ while (this.pending)
148
+ await this.pending;
69
149
  if (this.role !== "none")
70
- return Promise.resolve();
71
- // Collapse concurrent callers onto one election.
72
- if (!this.electing) {
73
- this.electing = this.doElect().finally(() => {
74
- this.electing = undefined;
75
- });
76
- }
77
- return this.electing;
150
+ return;
151
+ if (this.closing)
152
+ throw new Error("obsbot-mcp: ipc coordinator is closed");
153
+ let failed = false;
154
+ let failure;
155
+ await this.begin(async () => {
156
+ try {
157
+ await this.doElect();
158
+ }
159
+ catch (e) {
160
+ failed = true;
161
+ failure = e;
162
+ }
163
+ });
164
+ if (failed)
165
+ throw failure;
78
166
  }
167
+ /**
168
+ * Settle on a role: bind the endpoint, or connect to whoever holds it and
169
+ * compare builds. If ours is newer, ask for the endpoint and go round again.
170
+ */
79
171
  async doElect() {
80
- const r = await elect(this.path);
81
- if (r.role === "owner") {
82
- this.ownerServer = new OwnerServer(r.server, (body) => {
83
- const { tool, args } = body;
84
- return this.runLocal(tool, args);
85
- });
86
- this.role = "owner";
172
+ let takeovers = 0;
173
+ for (let attempt = 0; attempt < this.t.maxTakeoverRounds + 3; attempt++) {
174
+ if (this.closing || this.role !== "none")
175
+ return;
176
+ const r = await this.elect(this.path);
177
+ if (r.role === "owner")
178
+ return this.becomeOwner(r.server);
179
+ const client = OwnerClient.adopt(r.socket);
180
+ let peer;
181
+ try {
182
+ peer = await client.hello(this.build, this.pid, this.t.helloTimeoutMs);
183
+ }
184
+ catch {
185
+ client.close(); // the owner went away between connect and hello
186
+ continue;
187
+ }
188
+ // An owner that cannot take part in a handover is older than anything that can.
189
+ if (peer.kind !== "peer")
190
+ return this.becomeClient(client, peer, true);
191
+ if (compareBuilds(this.build, peer.build) <= 0)
192
+ return this.becomeClient(client, peer, false);
193
+ // From here on the owner is older than us, so settling as its client means refusing to use it.
194
+ if (takeovers >= this.t.maxTakeoverRounds)
195
+ return this.becomeClient(client, peer, true);
196
+ takeovers++;
197
+ this.log(`obsbot-mcp: ipc takeover requested from pid ${peer.pid}`);
198
+ let granted;
199
+ try {
200
+ granted = await client.takeover(this.build, this.pid, this.t.helloTimeoutMs);
201
+ }
202
+ catch {
203
+ granted = true; // closed before it could answer: the endpoint is free either way
204
+ }
205
+ if (!granted || !(await client.waitClosed(this.t.stepDownTimeoutMs))) {
206
+ return this.becomeClient(client, peer, true);
207
+ }
208
+ // The old owner has let go. Go round again and bind.
209
+ }
210
+ throw new Error(`obsbot-mcp: ipc could not settle on an owner for ${this.path}`);
211
+ }
212
+ becomeOwner(server) {
213
+ if (this.closing) {
214
+ server.close();
215
+ return;
216
+ }
217
+ this.ownerServer = new OwnerServer(server, (body) => {
218
+ const { tool, args } = body;
219
+ return this.gate.run(() => this.runLocal(tool, args));
220
+ }, {
221
+ identity: () => ({ build: this.build, pid: this.pid }),
222
+ takeover: (build, pid) => this.onTakeover(build, pid),
223
+ });
224
+ this.role = "owner";
225
+ this.log("obsbot-mcp: ipc role=owner");
226
+ }
227
+ becomeClient(client, peer, blocked) {
228
+ if (this.closing) {
229
+ client.close();
230
+ return;
231
+ }
232
+ this.client = client;
233
+ this.role = "client";
234
+ this.blocked = blocked;
235
+ this.connection++;
236
+ // Re-elect when the connection closes, not when we next have something to
237
+ // send: an idle newer build must not sit disconnected while an older one
238
+ // takes the endpoint and runs calls.
239
+ client.onClose(() => this.ownerLost(client));
240
+ const owner = peer.kind === "peer"
241
+ ? `owner-pid=${peer.pid} owner-build=${buildLabel(peer.build)}`
242
+ : "owner-pid=unknown owner-build=legacy";
243
+ this.log(`obsbot-mcp: ipc role=client ${owner}`);
244
+ if (blocked) {
245
+ this.log("obsbot-mcp: ipc owner is older and cannot hand over; tool calls will fail until it exits");
246
+ }
247
+ }
248
+ /**
249
+ * The owner is older and still there. Try once more: a fresh connection,
250
+ * hello, takeover.
251
+ *
252
+ * Queued like any other role change, so calls that arrive together wait for
253
+ * it instead of finding the role half torn down. `seen` is the connection the
254
+ * caller was looking at: if that is no longer the current one, someone has
255
+ * asked again since, and asking a second time would tell us nothing new.
256
+ */
257
+ tryAgain(seen) {
258
+ return this.begin(async () => {
259
+ if (this.role !== "client" || !this.blocked || this.connection !== seen)
260
+ return;
261
+ const client = this.client;
262
+ this.reset(); // first, so closing our own connection is not mistaken for losing the owner
263
+ client?.close();
264
+ await this.doElect();
265
+ });
266
+ }
267
+ blockedMessage() {
268
+ return ("obsbot-mcp: an older instance owns the camera endpoint and cannot hand it over. " +
269
+ "This instance will not run calls on older code. " +
270
+ `Stop the process listening on ${this.path}; the next call will take over.`);
271
+ }
272
+ /**
273
+ * The owner has gone. Re-elect — after the grace period if it stepped down
274
+ * for someone, so the successor binds first; after jitter alone if it simply
275
+ * went, so clients that all lost it at once do not stampede.
276
+ */
277
+ ownerLost(client) {
278
+ if (this.client !== client || this.closing)
279
+ return;
280
+ const delay = (client.noticed ? this.t.stepDownGraceMs : 0) + this.jitter();
281
+ this.reset();
282
+ void this.begin(async () => {
283
+ await sleep(delay);
284
+ await this.doElect();
285
+ });
286
+ }
287
+ /** A client asks for the endpoint. Both sides run the same comparison, so this cannot disagree with it. */
288
+ onTakeover(build, pid) {
289
+ if (compareBuilds(build, this.build) <= 0) {
290
+ return { ipc: "takeover", granted: false, reason: "not-newer" };
291
+ }
292
+ this.stepDown(pid);
293
+ return { ipc: "takeover", granted: true };
294
+ }
295
+ stepDown(successorPid) {
296
+ if (this.steppingDown)
297
+ return; // a second request while stepping down needs nothing more
298
+ this.steppingDown = true;
299
+ const server = this.ownerServer;
300
+ this.log(`obsbot-mcp: ipc stepping down for pid ${successorPid}`);
301
+ void this.begin(async () => {
302
+ await this.gate.close(); // the call in flight finishes; nothing else starts
303
+ await server.idle(); // …and its reply has been written
304
+ await this.releaseBounded(); // the successor cannot open the camera until this is done
305
+ await server.stepDown({ ipc: "stepping-down", successorPid });
306
+ this.reset();
307
+ this.gate.open();
308
+ // Let the successor bind before we look for an owner to be a client of.
309
+ await sleep(this.t.stepDownGraceMs + this.jitter());
310
+ await this.doElect();
311
+ });
312
+ }
313
+ /** A release that throws or never settles must not stop the handover. */
314
+ async releaseBounded() {
315
+ let timer;
316
+ const timeout = new Promise((_, reject) => {
317
+ timer = setTimeout(() => reject(new Error(`release did not finish in ${this.t.releaseTimeoutMs} ms`)), this.t.releaseTimeoutMs);
318
+ });
319
+ try {
320
+ await Promise.race([this.release(), timeout]);
321
+ }
322
+ catch (e) {
323
+ this.log(`obsbot-mcp: ipc release failed while stepping down: ${errText(e)}`);
87
324
  }
88
- else {
89
- this.client = OwnerClient.adopt(r.socket);
90
- this.role = "client";
325
+ finally {
326
+ clearTimeout(timer);
91
327
  }
92
328
  }
93
329
  }
@@ -1 +1 @@
1
- {"version":3,"file":"coordinator.js","sourceRoot":"","sources":["../../src/ipc/coordinator.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"coordinator.js","sourceRoot":"","sources":["../../src/ipc/coordinator.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ /** Thrown to a call that had not started when the gate closed. */
2
+ export declare class StepDownError extends Error {
3
+ constructor();
4
+ }
5
+ export declare class CallGate {
6
+ private tail;
7
+ private closed;
8
+ /** Run `fn` after every call queued before it. Rejects with StepDownError if the gate closes first. */
9
+ run<T>(fn: () => Promise<T>): Promise<T>;
10
+ /** Refuse calls that have not started; resolve when the running one has finished. */
11
+ close(): Promise<void>;
12
+ /** Accept calls again. */
13
+ open(): void;
14
+ }
@@ -0,0 +1,45 @@
1
+ // ---------------------------------------------------------------------------
2
+ // The single-camera lock, with a way to close it.
3
+ //
4
+ // Tool calls run strictly one at a time: the camera is one device and the XU
5
+ // selector-2 reply mailbox is a single shared slot, so two calls in flight at
6
+ // once would interleave on the wire. That part is unchanged from the old
7
+ // serialize() wrapper.
8
+ //
9
+ // What is new is close(). An owner that is handing the endpoint to a newer
10
+ // build must let the call that is RUNNING finish, and must stop every call that
11
+ // has not started — those belong to the new owner now. close() does both, and
12
+ // resolves once nothing is running.
13
+ // ---------------------------------------------------------------------------
14
+ /** Thrown to a call that had not started when the gate closed. */
15
+ export class StepDownError extends Error {
16
+ constructor() {
17
+ super("obsbot-mcp: this instance is handing the camera to a newer build");
18
+ this.name = "StepDownError";
19
+ }
20
+ }
21
+ export class CallGate {
22
+ tail = Promise.resolve();
23
+ closed = false;
24
+ /** Run `fn` after every call queued before it. Rejects with StepDownError if the gate closes first. */
25
+ run(fn) {
26
+ const run = this.tail.then(() => {
27
+ if (this.closed)
28
+ throw new StepDownError();
29
+ return fn();
30
+ });
31
+ // Errors don't break the chain.
32
+ this.tail = run.then(() => undefined, () => undefined);
33
+ return run;
34
+ }
35
+ /** Refuse calls that have not started; resolve when the running one has finished. */
36
+ async close() {
37
+ this.closed = true;
38
+ await this.tail;
39
+ }
40
+ /** Accept calls again. */
41
+ open() {
42
+ this.closed = false;
43
+ }
44
+ }
45
+ //# sourceMappingURL=gate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gate.js","sourceRoot":"","sources":["../../src/ipc/gate.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,kDAAkD;AAClD,EAAE;AACF,6EAA6E;AAC7E,8EAA8E;AAC9E,yEAAyE;AACzE,uBAAuB;AACvB,EAAE;AACF,2EAA2E;AAC3E,gFAAgF;AAChF,8EAA8E;AAC9E,oCAAoC;AACpC,8EAA8E;AAE9E,kEAAkE;AAClE,MAAM,OAAO,aAAc,SAAQ,KAAK;IACtC;QACE,KAAK,CAAC,kEAAkE,CAAC,CAAC;QAC1E,IAAI,CAAC,IAAI,GAAG,eAAe,CAAC;IAC9B,CAAC;CACF;AAED,MAAM,OAAO,QAAQ;IACX,IAAI,GAAqB,OAAO,CAAC,OAAO,EAAE,CAAC;IAC3C,MAAM,GAAG,KAAK,CAAC;IAEvB,uGAAuG;IACvG,GAAG,CAAI,EAAoB;QACzB,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE;YAC9B,IAAI,IAAI,CAAC,MAAM;gBAAE,MAAM,IAAI,aAAa,EAAE,CAAC;YAC3C,OAAO,EAAE,EAAE,CAAC;QACd,CAAC,CAAC,CAAC;QACH,gCAAgC;QAChC,IAAI,CAAC,IAAI,GAAG,GAAG,CAAC,IAAI,CAClB,GAAG,EAAE,CAAC,SAAS,EACf,GAAG,EAAE,CAAC,SAAS,CAChB,CAAC;QACF,OAAO,GAAG,CAAC;IACb,CAAC;IAED,qFAAqF;IACrF,KAAK,CAAC,KAAK;QACT,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC;QACnB,MAAM,IAAI,CAAC,IAAI,CAAC;IAClB,CAAC;IAED,0BAA0B;IAC1B,IAAI;QACF,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC;IACtB,CAAC;CACF"}
@@ -1,4 +1,6 @@
1
1
  import net from "node:net";
2
+ import type { BuildId } from "./build-id.js";
3
+ import { type SteppingDownBody, type TakeoverResult } from "./protocol.js";
2
4
  export type Handler = (body: unknown) => Promise<unknown>;
3
5
  export type ReplyBody = {
4
6
  ok: true;
@@ -7,15 +9,39 @@ export type ReplyBody = {
7
9
  ok: false;
8
10
  error: string;
9
11
  };
12
+ export interface ControlHandlers {
13
+ /** This instance's identity, for the hello reply. */
14
+ identity: () => {
15
+ build: BuildId;
16
+ pid: number;
17
+ };
18
+ /** A client asks for the endpoint. Decide; if granted, the caller starts stepping down. */
19
+ takeover: (build: BuildId, pid: number) => TakeoverResult;
20
+ }
10
21
  export declare class OwnerServer {
11
22
  private readonly server;
12
23
  private readonly handle;
24
+ private readonly control;
13
25
  /** Single promise chain → exactly one handler call runs at a time. */
14
26
  private queue;
15
27
  private readonly sockets;
16
- constructor(server: net.Server, handle: Handler);
28
+ constructor(server: net.Server, handle: Handler, control: ControlHandlers);
17
29
  private accept;
30
+ /** Answer a control message at once, outside the queue. False if `msg` is not one. */
31
+ private answerControl;
18
32
  private enqueue;
33
+ /** The reply for a request, or undefined when the request must go unanswered. */
19
34
  private run;
35
+ /** Resolves once every request received so far has been answered or dropped. */
36
+ idle(): Promise<void>;
37
+ /**
38
+ * Give up the endpoint in an orderly way: free the name, tell every client
39
+ * why, and let what is already written reach them.
40
+ *
41
+ * end(), not destroy(): destroy() discards whatever is still buffered, which
42
+ * would lose the notice and could truncate the reply to the call that just
43
+ * finished — a snapshot is megabytes.
44
+ */
45
+ stepDown(notice: SteppingDownBody): Promise<void>;
20
46
  close(): Promise<void>;
21
47
  }
package/dist/ipc/owner.js CHANGED
@@ -1,13 +1,18 @@
1
- import { encodeFrame, FrameDecoder } from "./protocol.js";
1
+ import { StepDownError } from "./gate.js";
2
+ import { encodeFrame, FrameDecoder, NOTICE_ID, asHello, asTakeover, } from "./protocol.js";
3
+ /** How long a client gets to close its end after we have ended ours. */
4
+ const STRAGGLER_MS = 1000;
2
5
  export class OwnerServer {
3
6
  server;
4
7
  handle;
8
+ control;
5
9
  /** Single promise chain → exactly one handler call runs at a time. */
6
10
  queue = Promise.resolve();
7
11
  sockets = new Set();
8
- constructor(server, handle) {
12
+ constructor(server, handle, control) {
9
13
  this.server = server;
10
14
  this.handle = handle;
15
+ this.control = control;
11
16
  this.server.on("connection", (sock) => this.accept(sock));
12
17
  }
13
18
  accept(sock) {
@@ -22,8 +27,10 @@ export class OwnerServer {
22
27
  sock.destroy(); // unrecoverable framing error → drop this client
23
28
  return;
24
29
  }
25
- for (const msg of msgs)
26
- this.enqueue(sock, msg);
30
+ for (const msg of msgs) {
31
+ if (!this.answerControl(sock, msg))
32
+ this.enqueue(sock, msg);
33
+ }
27
34
  });
28
35
  const drop = () => {
29
36
  this.sockets.delete(sock);
@@ -31,24 +38,80 @@ export class OwnerServer {
31
38
  sock.on("close", drop);
32
39
  sock.on("error", drop);
33
40
  }
41
+ /** Answer a control message at once, outside the queue. False if `msg` is not one. */
42
+ answerControl(sock, msg) {
43
+ const reply = (result) => {
44
+ if (!sock.destroyed)
45
+ sock.write(encodeFrame({ id: msg.id, body: { ok: true, result } }));
46
+ };
47
+ if (asHello(msg.body)) {
48
+ reply({ ipc: "hello", ...this.control.identity() });
49
+ return true;
50
+ }
51
+ const takeover = asTakeover(msg.body);
52
+ if (takeover) {
53
+ // Written before anything the grant sets in motion can close this socket.
54
+ reply(this.control.takeover(takeover.build, takeover.pid));
55
+ return true;
56
+ }
57
+ return false;
58
+ }
34
59
  enqueue(sock, msg) {
35
60
  // Chain onto the shared queue so requests run one-at-a-time across all
36
61
  // clients. The chain never rejects (errors become error replies), so one
37
62
  // failing op can't stall the rest.
38
63
  this.queue = this.queue.then(async () => {
39
64
  const body = await this.run(msg.body);
65
+ if (body === undefined)
66
+ return;
40
67
  if (!sock.destroyed)
41
68
  sock.write(encodeFrame({ id: msg.id, body }));
42
69
  });
43
70
  }
71
+ /** The reply for a request, or undefined when the request must go unanswered. */
44
72
  async run(reqBody) {
45
73
  try {
46
74
  return { ok: true, result: await this.handle(reqBody) };
47
75
  }
48
76
  catch (e) {
77
+ // The gate closed before this call started: it belongs to the next owner.
78
+ // An error reply would be wrong — the client would surface it. Left
79
+ // unanswered, the closing socket makes the client retry it there.
80
+ if (e instanceof StepDownError)
81
+ return undefined;
49
82
  return { ok: false, error: e instanceof Error ? e.message : String(e) };
50
83
  }
51
84
  }
85
+ /** Resolves once every request received so far has been answered or dropped. */
86
+ idle() {
87
+ return this.queue;
88
+ }
89
+ /**
90
+ * Give up the endpoint in an orderly way: free the name, tell every client
91
+ * why, and let what is already written reach them.
92
+ *
93
+ * end(), not destroy(): destroy() discards whatever is still buffered, which
94
+ * would lose the notice and could truncate the reply to the call that just
95
+ * finished — a snapshot is megabytes.
96
+ */
97
+ async stepDown(notice) {
98
+ // Stops listening now, which frees the endpoint for the successor; the
99
+ // callback waits for the connections below to finish closing.
100
+ const closed = new Promise((resolve) => this.server.close(() => resolve()));
101
+ for (const s of this.sockets) {
102
+ if (s.destroyed)
103
+ continue;
104
+ s.write(encodeFrame({ id: NOTICE_ID, body: notice }));
105
+ s.end();
106
+ }
107
+ const stragglers = setTimeout(() => {
108
+ for (const s of this.sockets)
109
+ s.destroy();
110
+ }, STRAGGLER_MS);
111
+ await closed;
112
+ clearTimeout(stragglers);
113
+ this.sockets.clear();
114
+ }
52
115
  async close() {
53
116
  for (const s of this.sockets)
54
117
  s.destroy();
@@ -1 +1 @@
1
- {"version":3,"file":"owner.js","sourceRoot":"","sources":["../../src/ipc/owner.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"owner.js","sourceRoot":"","sources":["../../src/ipc/owner.ts"],"names":[],"mappings":"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"}