@cueloop/daemon 0.1.0-alpha.56 → 0.1.0-alpha.59
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/package.json +2 -2
- package/src/server.test.ts +11 -0
- package/src/server.ts +91 -81
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cueloop/daemon",
|
|
3
|
-
"version": "0.1.0-alpha.
|
|
3
|
+
"version": "0.1.0-alpha.59",
|
|
4
4
|
"description": "The cueloop session daemon and its client: socket protocol, atomic store, resumable waits",
|
|
5
5
|
"homepage": "https://github.com/mmurakaru/cueloop#readme",
|
|
6
6
|
"bugs": {
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
"access": "public"
|
|
34
34
|
},
|
|
35
35
|
"dependencies": {
|
|
36
|
-
"@cueloop/schema": "0.1.0-alpha.
|
|
36
|
+
"@cueloop/schema": "0.1.0-alpha.59",
|
|
37
37
|
"valibot": "^1.4.2"
|
|
38
38
|
},
|
|
39
39
|
"engines": {
|
package/src/server.test.ts
CHANGED
|
@@ -102,6 +102,17 @@ describe("socket round-trip", () => {
|
|
|
102
102
|
} catch (error) {
|
|
103
103
|
expect((error as DaemonClientError).code).toBe("unknown_method");
|
|
104
104
|
}
|
|
105
|
+
const prototypeMethods = await Promise.allSettled([
|
|
106
|
+
client.request("__proto__", {}),
|
|
107
|
+
client.request("toString", {}),
|
|
108
|
+
client.request("constructor", {}),
|
|
109
|
+
]);
|
|
110
|
+
for (const result of prototypeMethods) {
|
|
111
|
+
expect(result.status).toBe("rejected");
|
|
112
|
+
expect(((result as PromiseRejectedResult).reason as DaemonClientError).code).toBe(
|
|
113
|
+
"unknown_method",
|
|
114
|
+
);
|
|
115
|
+
}
|
|
105
116
|
// the daemon is still fully alive afterwards
|
|
106
117
|
const session = await client.sessionCreate(WS, PLAN);
|
|
107
118
|
expect((await client.sessionGet(session.id)).id).toBe(session.id);
|
package/src/server.ts
CHANGED
|
@@ -17,7 +17,7 @@ import {
|
|
|
17
17
|
import { DaemonCore, type DaemonEvent } from "./api";
|
|
18
18
|
import { DaemonError } from "./errors";
|
|
19
19
|
import { roleAllowsMethod, type DaemonRole } from "./capabilities";
|
|
20
|
-
import { isKnownMethod, parseParams } from "./validate";
|
|
20
|
+
import { isKnownMethod, parseParams, type MethodName } from "./validate";
|
|
21
21
|
import { BackpressureWriter, LineBuffer, type Request } from "./protocol";
|
|
22
22
|
import { cueloopHome, lockPath, pidPath, socketPath } from "./paths";
|
|
23
23
|
|
|
@@ -28,6 +28,8 @@ interface Connection {
|
|
|
28
28
|
role: DaemonRole;
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
+
type MethodHandler = (connection: Connection, request: Request) => unknown;
|
|
32
|
+
|
|
31
33
|
export interface DaemonOptions {
|
|
32
34
|
home?: string;
|
|
33
35
|
/** Idle-exit delay; 0 disables (tests, foreground runs). */
|
|
@@ -222,6 +224,91 @@ export class DaemonServer {
|
|
|
222
224
|
}
|
|
223
225
|
}
|
|
224
226
|
|
|
227
|
+
private readonly handlers: Record<MethodName, MethodHandler> = {
|
|
228
|
+
"daemon.ping": () => ({ pid: process.pid }),
|
|
229
|
+
"daemon.hello": (connection, request) => {
|
|
230
|
+
connection.role = parseParams("daemon.hello", request.params).role;
|
|
231
|
+
return {};
|
|
232
|
+
},
|
|
233
|
+
"daemon.shutdown": () => {
|
|
234
|
+
setTimeout(() => {
|
|
235
|
+
this.stop();
|
|
236
|
+
this.onIdleExit();
|
|
237
|
+
}, 10);
|
|
238
|
+
return {};
|
|
239
|
+
},
|
|
240
|
+
"events.subscribe": (connection) => {
|
|
241
|
+
connection.subscribed = true;
|
|
242
|
+
return {};
|
|
243
|
+
},
|
|
244
|
+
"session.create": (_connection, request) => {
|
|
245
|
+
const params = parseParams("session.create", request.params);
|
|
246
|
+
return this.core.sessionCreate({ workspace: params.workspace, artifact: params.artifact });
|
|
247
|
+
},
|
|
248
|
+
"session.get": (_connection, request) =>
|
|
249
|
+
this.core.sessionGet(parseParams("session.get", request.params).id),
|
|
250
|
+
"session.list": (_connection, request) =>
|
|
251
|
+
this.core.sessionList(parseParams("session.list", request.params).filter),
|
|
252
|
+
"session.wait": (_connection, request) => {
|
|
253
|
+
const params = parseParams("session.wait", request.params);
|
|
254
|
+
return this.core.sessionWait(params.id, params.timeoutMs);
|
|
255
|
+
},
|
|
256
|
+
"session.annotate": (_connection, request) => {
|
|
257
|
+
const params = parseParams("session.annotate", request.params);
|
|
258
|
+
return this.core.sessionAnnotate(params.id, params.annotation, params.authorName);
|
|
259
|
+
},
|
|
260
|
+
"session.removeAnnotation": (_connection, request) => {
|
|
261
|
+
const params = parseParams("session.removeAnnotation", request.params);
|
|
262
|
+
return this.core.sessionRemoveAnnotation(params.id, params.annotationId);
|
|
263
|
+
},
|
|
264
|
+
"session.setWorkingCopy": (_connection, request) => {
|
|
265
|
+
const params = parseParams("session.setWorkingCopy", request.params);
|
|
266
|
+
return this.core.sessionSetWorkingCopy(params.id, params.workingCopy);
|
|
267
|
+
},
|
|
268
|
+
"session.setViewed": (_connection, request) => {
|
|
269
|
+
const params = parseParams("session.setViewed", request.params);
|
|
270
|
+
return this.core.sessionSetViewed(params.id, params.viewedPaths);
|
|
271
|
+
},
|
|
272
|
+
"session.refreshDiff": (_connection, request) => {
|
|
273
|
+
const params = parseParams("session.refreshDiff", request.params);
|
|
274
|
+
return this.core.sessionRefreshDiff(params.id);
|
|
275
|
+
},
|
|
276
|
+
"session.setShareId": (_connection, request) => {
|
|
277
|
+
const params = parseParams("session.setShareId", request.params);
|
|
278
|
+
return this.core.sessionSetShareId(params.id, params.shareId);
|
|
279
|
+
},
|
|
280
|
+
"session.delete": (_connection, request) => {
|
|
281
|
+
this.core.sessionDelete(parseParams("session.delete", request.params).id);
|
|
282
|
+
return {};
|
|
283
|
+
},
|
|
284
|
+
"session.mergeShared": (_connection, request) => {
|
|
285
|
+
const params = parseParams("session.mergeShared", request.params);
|
|
286
|
+
return this.core.sessionMergeShared(params.id, {
|
|
287
|
+
annotations: params.annotations,
|
|
288
|
+
participants: params.participants,
|
|
289
|
+
});
|
|
290
|
+
},
|
|
291
|
+
"session.resolve": (_connection, request) => {
|
|
292
|
+
const params = parseParams("session.resolve", request.params);
|
|
293
|
+
return this.core.sessionResolve(params.id, params.verdictKind, params.summary);
|
|
294
|
+
},
|
|
295
|
+
"session.submitRevision": (_connection, request) => {
|
|
296
|
+
const params = parseParams("session.submitRevision", request.params);
|
|
297
|
+
return this.core.sessionSubmitRevision(
|
|
298
|
+
params.id,
|
|
299
|
+
params.content,
|
|
300
|
+
params.addressedAnnotationIds,
|
|
301
|
+
);
|
|
302
|
+
},
|
|
303
|
+
"herdr.getTab": (_connection, request) =>
|
|
304
|
+
this.core.herdrGetTab(parseParams("herdr.getTab", request.params).id),
|
|
305
|
+
"herdr.setTab": (_connection, request) => {
|
|
306
|
+
const params = parseParams("herdr.setTab", request.params);
|
|
307
|
+
this.core.herdrSetTab(params.id, { tabId: params.tabId, paneId: params.paneId });
|
|
308
|
+
return {};
|
|
309
|
+
},
|
|
310
|
+
};
|
|
311
|
+
|
|
225
312
|
private async dispatch(connection: Connection, request: Request): Promise<unknown> {
|
|
226
313
|
// The wire is untrusted JSON: validate before DaemonCore sees anything.
|
|
227
314
|
if (typeof request.method !== "string" || !isKnownMethod(request.method)) {
|
|
@@ -232,86 +319,9 @@ export class DaemonServer {
|
|
|
232
319
|
if (!roleAllowsMethod(connection.role, request.method)) {
|
|
233
320
|
throw new DaemonError("forbidden", `role ${connection.role} cannot call ${request.method}`);
|
|
234
321
|
}
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
case "daemon.ping":
|
|
238
|
-
return { pid: process.pid };
|
|
239
|
-
case "daemon.hello":
|
|
240
|
-
connection.role = parseParams("daemon.hello", request.params).role;
|
|
241
|
-
return {};
|
|
242
|
-
case "daemon.shutdown":
|
|
243
|
-
setTimeout(() => {
|
|
244
|
-
this.stop();
|
|
245
|
-
this.onIdleExit();
|
|
246
|
-
}, 10);
|
|
247
|
-
return {};
|
|
248
|
-
case "events.subscribe":
|
|
249
|
-
connection.subscribed = true;
|
|
250
|
-
return {};
|
|
251
|
-
case "session.create": {
|
|
252
|
-
const params = parseParams("session.create", request.params);
|
|
253
|
-
return core.sessionCreate({ workspace: params.workspace, artifact: params.artifact });
|
|
254
|
-
}
|
|
255
|
-
case "session.get":
|
|
256
|
-
return core.sessionGet(parseParams("session.get", request.params).id);
|
|
257
|
-
case "session.list":
|
|
258
|
-
return core.sessionList(parseParams("session.list", request.params).filter);
|
|
259
|
-
case "session.wait": {
|
|
260
|
-
const params = parseParams("session.wait", request.params);
|
|
261
|
-
return core.sessionWait(params.id, params.timeoutMs);
|
|
262
|
-
}
|
|
263
|
-
case "session.annotate": {
|
|
264
|
-
const params = parseParams("session.annotate", request.params);
|
|
265
|
-
return core.sessionAnnotate(params.id, params.annotation, params.authorName);
|
|
266
|
-
}
|
|
267
|
-
case "session.removeAnnotation": {
|
|
268
|
-
const params = parseParams("session.removeAnnotation", request.params);
|
|
269
|
-
return core.sessionRemoveAnnotation(params.id, params.annotationId);
|
|
270
|
-
}
|
|
271
|
-
case "session.setWorkingCopy": {
|
|
272
|
-
const params = parseParams("session.setWorkingCopy", request.params);
|
|
273
|
-
return core.sessionSetWorkingCopy(params.id, params.workingCopy);
|
|
274
|
-
}
|
|
275
|
-
case "session.setViewed": {
|
|
276
|
-
const params = parseParams("session.setViewed", request.params);
|
|
277
|
-
return core.sessionSetViewed(params.id, params.viewedPaths);
|
|
278
|
-
}
|
|
279
|
-
case "session.refreshDiff": {
|
|
280
|
-
const params = parseParams("session.refreshDiff", request.params);
|
|
281
|
-
return core.sessionRefreshDiff(params.id);
|
|
282
|
-
}
|
|
283
|
-
case "session.setShareId": {
|
|
284
|
-
const params = parseParams("session.setShareId", request.params);
|
|
285
|
-
return core.sessionSetShareId(params.id, params.shareId);
|
|
286
|
-
}
|
|
287
|
-
case "session.delete": {
|
|
288
|
-
core.sessionDelete(parseParams("session.delete", request.params).id);
|
|
289
|
-
return {};
|
|
290
|
-
}
|
|
291
|
-
case "session.mergeShared": {
|
|
292
|
-
const params = parseParams("session.mergeShared", request.params);
|
|
293
|
-
return core.sessionMergeShared(params.id, {
|
|
294
|
-
annotations: params.annotations,
|
|
295
|
-
participants: params.participants,
|
|
296
|
-
});
|
|
297
|
-
}
|
|
298
|
-
case "session.resolve": {
|
|
299
|
-
const params = parseParams("session.resolve", request.params);
|
|
300
|
-
return core.sessionResolve(params.id, params.verdictKind, params.summary);
|
|
301
|
-
}
|
|
302
|
-
case "session.submitRevision": {
|
|
303
|
-
const params = parseParams("session.submitRevision", request.params);
|
|
304
|
-
return core.sessionSubmitRevision(params.id, params.content, params.addressedAnnotationIds);
|
|
305
|
-
}
|
|
306
|
-
case "herdr.getTab":
|
|
307
|
-
return core.herdrGetTab(parseParams("herdr.getTab", request.params).id);
|
|
308
|
-
case "herdr.setTab": {
|
|
309
|
-
const params = parseParams("herdr.setTab", request.params);
|
|
310
|
-
core.herdrSetTab(params.id, { tabId: params.tabId, paneId: params.paneId });
|
|
311
|
-
return {};
|
|
312
|
-
}
|
|
313
|
-
default:
|
|
314
|
-
throw new DaemonError("unknown_method", `unknown method ${request.method}`);
|
|
322
|
+
if (!Object.hasOwn(this.handlers, request.method)) {
|
|
323
|
+
throw new DaemonError("unknown_method", `unknown method ${request.method}`);
|
|
315
324
|
}
|
|
325
|
+
return this.handlers[request.method](connection, request);
|
|
316
326
|
}
|
|
317
327
|
}
|