@dxos/client-services 0.6.5 → 0.6.6-main.e1a6e1f
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/lib/browser/{chunk-GIAH3RXX.mjs → chunk-DR3GOD3O.mjs} +907 -442
- package/dist/lib/browser/chunk-DR3GOD3O.mjs.map +7 -0
- package/dist/lib/browser/index.mjs +28 -13
- package/dist/lib/browser/index.mjs.map +3 -3
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/testing/index.mjs +21 -4
- package/dist/lib/browser/testing/index.mjs.map +3 -3
- package/dist/lib/node/{chunk-NDXK2NIM.cjs → chunk-DRNEKKQP.cjs} +1065 -607
- package/dist/lib/node/chunk-DRNEKKQP.cjs.map +7 -0
- package/dist/lib/node/index.cjs +77 -62
- package/dist/lib/node/index.cjs.map +3 -3
- package/dist/lib/node/meta.json +1 -1
- package/dist/lib/node/testing/index.cjs +27 -8
- package/dist/lib/node/testing/index.cjs.map +3 -3
- package/dist/types/src/packlets/invitations/invitations-handler.d.ts.map +1 -1
- package/dist/types/src/packlets/services/service-context.d.ts +6 -1
- package/dist/types/src/packlets/services/service-context.d.ts.map +1 -1
- package/dist/types/src/packlets/services/service-host.d.ts +1 -0
- package/dist/types/src/packlets/services/service-host.d.ts.map +1 -1
- package/dist/types/src/packlets/spaces/data-space-manager.d.ts +29 -12
- package/dist/types/src/packlets/spaces/data-space-manager.d.ts.map +1 -1
- package/dist/types/src/packlets/spaces/data-space.d.ts +7 -0
- package/dist/types/src/packlets/spaces/data-space.d.ts.map +1 -1
- package/dist/types/src/packlets/spaces/edge-feed-replicator.d.ts +35 -0
- package/dist/types/src/packlets/spaces/edge-feed-replicator.d.ts.map +1 -0
- package/dist/types/src/packlets/spaces/index.d.ts +1 -0
- package/dist/types/src/packlets/spaces/index.d.ts.map +1 -1
- package/dist/types/src/packlets/testing/invitation-utils.d.ts +2 -0
- package/dist/types/src/packlets/testing/invitation-utils.d.ts.map +1 -1
- package/dist/types/src/packlets/testing/test-builder.d.ts +3 -1
- package/dist/types/src/packlets/testing/test-builder.d.ts.map +1 -1
- package/dist/types/src/packlets/worker/worker-runtime.d.ts +8 -3
- package/dist/types/src/packlets/worker/worker-runtime.d.ts.map +1 -1
- package/dist/types/src/version.d.ts +1 -1
- package/dist/types/src/version.d.ts.map +1 -1
- package/package.json +38 -36
- package/src/packlets/invitations/invitations-handler.test.ts +1 -0
- package/src/packlets/invitations/invitations-handler.ts +12 -0
- package/src/packlets/invitations/space-invitation-protocol.test.ts +23 -1
- package/src/packlets/services/service-context.ts +44 -12
- package/src/packlets/services/service-host.ts +26 -4
- package/src/packlets/spaces/data-space-manager.test.ts +6 -0
- package/src/packlets/spaces/data-space-manager.ts +80 -36
- package/src/packlets/spaces/data-space.ts +36 -2
- package/src/packlets/spaces/edge-feed-replicator.ts +249 -0
- package/src/packlets/spaces/index.ts +1 -0
- package/src/packlets/testing/invitation-utils.ts +2 -2
- package/src/packlets/testing/test-builder.ts +20 -12
- package/src/packlets/worker/worker-runtime.ts +32 -10
- package/src/version.ts +1 -5
- package/dist/lib/browser/chunk-GIAH3RXX.mjs.map +0 -7
- package/dist/lib/node/chunk-NDXK2NIM.cjs.map +0 -7
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
DevtoolsHostEvents,
|
|
9
9
|
DevtoolsServiceImpl,
|
|
10
10
|
DiagnosticsCollector,
|
|
11
|
+
EdgeFeedReplicator,
|
|
11
12
|
Identity,
|
|
12
13
|
IdentityManager,
|
|
13
14
|
IdentityServiceImpl,
|
|
@@ -40,10 +41,11 @@ import {
|
|
|
40
41
|
subscribeToSignal,
|
|
41
42
|
subscribeToSpaces,
|
|
42
43
|
subscribeToSwarmInfo
|
|
43
|
-
} from "./chunk-
|
|
44
|
+
} from "./chunk-DR3GOD3O.mjs";
|
|
44
45
|
|
|
45
46
|
// packages/sdk/client-services/src/packlets/worker/worker-runtime.ts
|
|
46
47
|
import { Trigger as Trigger2 } from "@dxos/async";
|
|
48
|
+
import { DEFAULT_WORKER_BROADCAST_CHANNEL } from "@dxos/client-protocol";
|
|
47
49
|
import { Context } from "@dxos/context";
|
|
48
50
|
import { invariant as invariant2 } from "@dxos/invariant";
|
|
49
51
|
import { log as log2 } from "@dxos/log";
|
|
@@ -225,8 +227,7 @@ _ts_decorate([
|
|
|
225
227
|
// packages/sdk/client-services/src/packlets/worker/worker-runtime.ts
|
|
226
228
|
var __dxlog_file2 = "/home/runner/work/dxos/dxos/packages/sdk/client-services/src/packlets/worker/worker-runtime.ts";
|
|
227
229
|
var WorkerRuntime = class {
|
|
228
|
-
constructor(
|
|
229
|
-
this._configProvider = _configProvider;
|
|
230
|
+
constructor({ channel = DEFAULT_WORKER_BROADCAST_CHANNEL, configProvider, acquireLock, releaseLock, onStop }) {
|
|
230
231
|
this._transportFactory = new SimplePeerTransportProxyFactory();
|
|
231
232
|
this._ready = new Trigger2();
|
|
232
233
|
this._sessions = /* @__PURE__ */ new Set();
|
|
@@ -234,11 +235,14 @@ var WorkerRuntime = class {
|
|
|
234
235
|
runtime: "worker-runtime"
|
|
235
236
|
};
|
|
236
237
|
this._signalTelemetryEnabled = false;
|
|
238
|
+
this._configProvider = configProvider;
|
|
237
239
|
this._acquireLock = acquireLock;
|
|
238
240
|
this._releaseLock = releaseLock;
|
|
241
|
+
this._onStop = onStop;
|
|
242
|
+
this._channel = channel;
|
|
239
243
|
this._clientServices = new ClientServicesHost({
|
|
240
244
|
callbacks: {
|
|
241
|
-
onReset: async () =>
|
|
245
|
+
onReset: async () => this.stop()
|
|
242
246
|
}
|
|
243
247
|
});
|
|
244
248
|
}
|
|
@@ -248,11 +252,20 @@ var WorkerRuntime = class {
|
|
|
248
252
|
async start() {
|
|
249
253
|
log2("starting...", void 0, {
|
|
250
254
|
F: __dxlog_file2,
|
|
251
|
-
L:
|
|
255
|
+
L: 84,
|
|
252
256
|
S: this,
|
|
253
257
|
C: (f, a) => f(...a)
|
|
254
258
|
});
|
|
255
259
|
try {
|
|
260
|
+
this._broadcastChannel = new BroadcastChannel(this._channel);
|
|
261
|
+
this._broadcastChannel.postMessage({
|
|
262
|
+
action: "stop"
|
|
263
|
+
});
|
|
264
|
+
this._broadcastChannel.onmessage = async (event) => {
|
|
265
|
+
if (event.data?.action === "stop") {
|
|
266
|
+
await this.stop();
|
|
267
|
+
}
|
|
268
|
+
};
|
|
256
269
|
await this._acquireLock();
|
|
257
270
|
this._config = await this._configProvider();
|
|
258
271
|
const signals = this._config.get("runtime.services.signaling");
|
|
@@ -263,12 +276,12 @@ var WorkerRuntime = class {
|
|
|
263
276
|
});
|
|
264
277
|
await this._clientServices.open(new Context(void 0, {
|
|
265
278
|
F: __dxlog_file2,
|
|
266
|
-
L:
|
|
279
|
+
L: 105
|
|
267
280
|
}));
|
|
268
281
|
this._ready.wake(void 0);
|
|
269
282
|
log2("started", void 0, {
|
|
270
283
|
F: __dxlog_file2,
|
|
271
|
-
L:
|
|
284
|
+
L: 107,
|
|
272
285
|
S: this,
|
|
273
286
|
C: (f, a) => f(...a)
|
|
274
287
|
});
|
|
@@ -283,7 +296,7 @@ var WorkerRuntime = class {
|
|
|
283
296
|
this._ready.wake(err);
|
|
284
297
|
log2.error("starting", err, {
|
|
285
298
|
F: __dxlog_file2,
|
|
286
|
-
L:
|
|
299
|
+
L: 117,
|
|
287
300
|
S: this,
|
|
288
301
|
C: (f, a) => f(...a)
|
|
289
302
|
});
|
|
@@ -291,7 +304,10 @@ var WorkerRuntime = class {
|
|
|
291
304
|
}
|
|
292
305
|
async stop() {
|
|
293
306
|
this._releaseLock();
|
|
307
|
+
this._broadcastChannel?.close();
|
|
308
|
+
this._broadcastChannel = void 0;
|
|
294
309
|
await this._clientServices.close();
|
|
310
|
+
await this._onStop?.();
|
|
295
311
|
}
|
|
296
312
|
/**
|
|
297
313
|
* Create a new session.
|
|
@@ -307,9 +323,7 @@ var WorkerRuntime = class {
|
|
|
307
323
|
session.onClose.set(async () => {
|
|
308
324
|
this._sessions.delete(session);
|
|
309
325
|
if (this._sessions.size === 0) {
|
|
310
|
-
|
|
311
|
-
self.close();
|
|
312
|
-
}
|
|
326
|
+
await this.stop();
|
|
313
327
|
} else {
|
|
314
328
|
this._reconnectWebrtc();
|
|
315
329
|
}
|
|
@@ -317,7 +331,7 @@ var WorkerRuntime = class {
|
|
|
317
331
|
await session.open();
|
|
318
332
|
invariant2(!this._signalMetadataTags.origin || this._signalMetadataTags.origin === session.origin, `worker origin changed from ${this._signalMetadataTags.origin} to ${session.origin}?`, {
|
|
319
333
|
F: __dxlog_file2,
|
|
320
|
-
L:
|
|
334
|
+
L: 155,
|
|
321
335
|
S: this,
|
|
322
336
|
A: [
|
|
323
337
|
"!this._signalMetadataTags.origin || this._signalMetadataTags.origin === session.origin",
|
|
@@ -338,7 +352,7 @@ var WorkerRuntime = class {
|
|
|
338
352
|
_reconnectWebrtc() {
|
|
339
353
|
log2("reconnecting webrtc...", void 0, {
|
|
340
354
|
F: __dxlog_file2,
|
|
341
|
-
L:
|
|
355
|
+
L: 173,
|
|
342
356
|
S: this,
|
|
343
357
|
C: (f, a) => f(...a)
|
|
344
358
|
});
|
|
@@ -367,6 +381,7 @@ export {
|
|
|
367
381
|
DevtoolsHostEvents,
|
|
368
382
|
DevtoolsServiceImpl,
|
|
369
383
|
DiagnosticsCollector,
|
|
384
|
+
EdgeFeedReplicator,
|
|
370
385
|
Identity,
|
|
371
386
|
IdentityManager,
|
|
372
387
|
IdentityServiceImpl,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/packlets/worker/worker-runtime.ts", "../../../src/packlets/worker/worker-session.ts"],
|
|
4
|
-
"sourcesContent": ["//\n// Copyright 2022 DXOS.org\n//\n\nimport { Trigger } from '@dxos/async';\nimport { type Config } from '@dxos/config';\nimport { Context } from '@dxos/context';\nimport { invariant } from '@dxos/invariant';\nimport { log } from '@dxos/log';\nimport {\n MemorySignalManager,\n MemorySignalManagerContext,\n WebsocketSignalManager,\n setIdentityTags,\n} from '@dxos/messaging';\nimport { SimplePeerTransportProxyFactory } from '@dxos/network-manager';\nimport { type RpcPort } from '@dxos/rpc';\nimport { type MaybePromise } from '@dxos/util';\n\nimport { WorkerSession } from './worker-session';\nimport { ClientServicesHost } from '../services';\n\n// NOTE: Keep as RpcPorts to avoid dependency on @dxos/rpc-tunnel so we don't depend on browser-specific apis.\nexport type CreateSessionParams = {\n appPort: RpcPort;\n systemPort: RpcPort;\n shellPort?: RpcPort;\n};\n\nexport type WorkerRuntimeCallbacks = {\n acquireLock: () => Promise<void>;\n releaseLock: () => void;\n onReset: () => Promise<void>;\n};\n\n/**\n * Runtime for the shared worker.\n * Manages connections from proxies (in tabs).\n * Tabs make requests to the `ClientServicesHost`, and provide a WebRTC gateway.\n */\nexport class WorkerRuntime {\n private readonly _acquireLock: () => Promise<void>;\n private readonly _releaseLock: () => void;\n private readonly _transportFactory = new SimplePeerTransportProxyFactory();\n private readonly _ready = new Trigger<Error | undefined>();\n private readonly _sessions = new Set<WorkerSession>();\n private readonly _clientServices!: ClientServicesHost;\n private _sessionForNetworking?: WorkerSession; // TODO(burdon): Expose to client QueryStatusResponse.\n private _config!: Config;\n private _signalMetadataTags: any = { runtime: 'worker-runtime' };\n private _signalTelemetryEnabled: boolean = false;\n\n constructor(\n private readonly _configProvider: () => MaybePromise<Config>,\n { acquireLock, releaseLock, onReset }: WorkerRuntimeCallbacks,\n ) {\n this._acquireLock = acquireLock;\n this._releaseLock = releaseLock;\n this._clientServices = new ClientServicesHost({\n callbacks: {\n onReset: async () => onReset(),\n },\n });\n }\n\n get host() {\n return this._clientServices;\n }\n\n async start() {\n log('starting...');\n try {\n await this._acquireLock();\n this._config = await this._configProvider();\n const signals = this._config.get('runtime.services.signaling');\n this._clientServices.initialize({\n config: this._config,\n signalManager: signals\n ? new WebsocketSignalManager(signals, () => (this._signalTelemetryEnabled ? this._signalMetadataTags : {}))\n : new MemorySignalManager(new MemorySignalManagerContext()), // TODO(dmaretskyi): Inject this context.\n transportFactory: this._transportFactory,\n });\n\n await this._clientServices.open(new Context());\n this._ready.wake(undefined);\n log('started');\n setIdentityTags({\n identityService: this._clientServices.services.IdentityService!,\n devicesService: this._clientServices.services.DevicesService!,\n setTag: (k: string, v: string) => {\n this._signalMetadataTags[k] = v;\n },\n });\n } catch (err: any) {\n this._ready.wake(err);\n log.error('starting', err);\n }\n }\n\n async stop() {\n // Release the lock to notify remote clients that the worker is terminating.\n this._releaseLock();\n await this._clientServices.close();\n }\n\n /**\n * Create a new session.\n */\n async createSession({ appPort, systemPort, shellPort }: CreateSessionParams) {\n const session = new WorkerSession({\n serviceHost: this._clientServices,\n appPort,\n systemPort,\n shellPort,\n readySignal: this._ready,\n });\n\n // When tab is closed or client is destroyed.\n session.onClose.set(async () => {\n this._sessions.delete(session);\n if (this._sessions.size === 0) {\n // Terminate the worker when all sessions are closed.\n if (globalThis.self) {\n self.close();\n }\n } else {\n this._reconnectWebrtc();\n }\n });\n\n await session.open();\n // A worker can only service one origin currently\n invariant(\n !this._signalMetadataTags.origin || this._signalMetadataTags.origin === session.origin,\n `worker origin changed from ${this._signalMetadataTags.origin} to ${session.origin}?`,\n );\n if (session.observabilityGroup) {\n this._signalMetadataTags.group = session.observabilityGroup;\n }\n this._signalTelemetryEnabled = session.signalTelemetryEnabled ?? false;\n this._signalMetadataTags.origin = session.origin;\n this._sessions.add(session);\n\n this._reconnectWebrtc();\n }\n\n /**\n * Selects one of the existing session for WebRTC networking.\n */\n private _reconnectWebrtc() {\n log('reconnecting webrtc...');\n // Check if current session is already closed.\n if (this._sessionForNetworking) {\n if (!this._sessions.has(this._sessionForNetworking)) {\n this._sessionForNetworking = undefined;\n }\n }\n\n // Select existing session.\n if (!this._sessionForNetworking) {\n const selected = Array.from(this._sessions).find((session) => session.bridgeService);\n if (selected) {\n this._sessionForNetworking = selected;\n this._transportFactory.setBridgeService(selected.bridgeService);\n } else {\n this._transportFactory.setBridgeService(undefined);\n }\n }\n }\n}\n", "//\n// Copyright 2022 DXOS.org\n//\n\nimport { asyncTimeout, Trigger } from '@dxos/async';\nimport {\n iframeServiceBundle,\n type IframeServiceBundle,\n PROXY_CONNECTION_TIMEOUT,\n workerServiceBundle,\n} from '@dxos/client-protocol';\nimport { invariant } from '@dxos/invariant';\nimport { log, logInfo } from '@dxos/log';\nimport { type BridgeService } from '@dxos/protocols/proto/dxos/mesh/bridge';\nimport { createProtoRpcPeer, type ProtoRpcPeer, type RpcPort } from '@dxos/rpc';\nimport { Callback, type MaybePromise } from '@dxos/util';\n\nimport { type ClientServicesHost, ClientRpcServer, type ClientRpcServerParams } from '../services';\n\nexport type WorkerSessionParams = {\n serviceHost: ClientServicesHost;\n systemPort: RpcPort;\n appPort: RpcPort;\n // TODO(wittjosiah): Remove shellPort.\n shellPort?: RpcPort;\n readySignal: Trigger<Error | undefined>;\n};\n\n/**\n * Represents a tab connection within the worker.\n */\nexport class WorkerSession {\n private readonly _clientRpc: ClientRpcServer;\n private readonly _shellClientRpc?: ClientRpcServer;\n private readonly _iframeRpc: ProtoRpcPeer<IframeServiceBundle>;\n private readonly _startTrigger = new Trigger();\n private readonly _serviceHost: ClientServicesHost;\n\n public readonly onClose = new Callback<() => Promise<void>>();\n\n @logInfo\n public origin?: string;\n\n // TODO(nf): factor out?\n public observabilityGroup?: string;\n public signalTelemetryEnabled?: boolean;\n\n @logInfo\n public lockKey?: string;\n\n public bridgeService?: BridgeService;\n\n constructor({ serviceHost, systemPort, appPort, shellPort, readySignal }: WorkerSessionParams) {\n invariant(serviceHost);\n this._serviceHost = serviceHost;\n\n const middleware: Pick<ClientRpcServerParams, 'handleCall' | 'handleStream'> = {\n handleCall: async (method, params, handler) => {\n const error = await readySignal.wait({ timeout: PROXY_CONNECTION_TIMEOUT });\n if (error) {\n throw error;\n }\n\n return handler(method, params);\n },\n handleStream: async (method, params, handler) => {\n const error = await readySignal.wait({ timeout: PROXY_CONNECTION_TIMEOUT });\n if (error) {\n throw error;\n }\n\n return handler(method, params);\n },\n };\n\n this._clientRpc = new ClientRpcServer({\n serviceRegistry: this._serviceHost.serviceRegistry,\n port: appPort,\n ...middleware,\n });\n\n this._shellClientRpc = shellPort\n ? new ClientRpcServer({\n serviceRegistry: this._serviceHost.serviceRegistry,\n port: shellPort,\n ...middleware,\n })\n : undefined;\n\n this._iframeRpc = createProtoRpcPeer({\n requested: iframeServiceBundle,\n exposed: workerServiceBundle,\n handlers: {\n WorkerService: {\n start: async (request) => {\n this.origin = request.origin;\n this.lockKey = request.lockKey;\n this.observabilityGroup = request.observabilityGroup;\n this.signalTelemetryEnabled = request.signalTelemetryEnabled;\n this._startTrigger.wake();\n },\n\n stop: async () => {\n setTimeout(async () => {\n try {\n await this.close();\n } catch (err: any) {\n log.catch(err);\n }\n });\n },\n },\n },\n port: systemPort,\n timeout: 1_000, // With low timeout heartbeat may fail if the tab's thread is saturated.\n });\n\n this.bridgeService = this._iframeRpc.rpc.BridgeService;\n }\n\n async open() {\n log.info('opening...');\n await Promise.all([this._clientRpc.open(), this._iframeRpc.open(), this._maybeOpenShell()]);\n\n // Wait until the worker's RPC service has started.\n await this._startTrigger.wait({ timeout: PROXY_CONNECTION_TIMEOUT });\n\n // TODO(burdon): Comment required.\n if (this.lockKey) {\n void this._afterLockReleases(this.lockKey, () => this.close());\n }\n\n log.info('opened');\n }\n\n async close() {\n log.info('closing...');\n try {\n await this.onClose.callIfSet();\n } catch (err: any) {\n log.catch(err);\n }\n\n await Promise.all([this._clientRpc.close(), this._iframeRpc.close()]);\n log.info('closed');\n }\n\n private async _maybeOpenShell() {\n try {\n this._shellClientRpc && (await asyncTimeout(this._shellClientRpc.open(), 1_000));\n } catch {\n log.info('No shell connected.');\n }\n }\n\n private _afterLockReleases(lockKey: string, callback: () => MaybePromise<void>): Promise<void> {\n return navigator.locks\n .request(lockKey, () => {\n // No-op.\n })\n .then(callback);\n }\n}\n"],
|
|
5
|
-
"mappings": "
|
|
6
|
-
"names": ["Trigger", "Context", "invariant", "log", "MemorySignalManager", "MemorySignalManagerContext", "WebsocketSignalManager", "setIdentityTags", "SimplePeerTransportProxyFactory", "asyncTimeout", "Trigger", "iframeServiceBundle", "PROXY_CONNECTION_TIMEOUT", "workerServiceBundle", "invariant", "log", "logInfo", "createProtoRpcPeer", "Callback", "WorkerSession", "constructor", "serviceHost", "systemPort", "appPort", "shellPort", "readySignal", "_startTrigger", "Trigger", "onClose", "Callback", "invariant", "_serviceHost", "middleware", "handleCall", "method", "params", "handler", "error", "wait", "timeout", "PROXY_CONNECTION_TIMEOUT", "handleStream", "_clientRpc", "ClientRpcServer", "serviceRegistry", "port", "_shellClientRpc", "undefined", "_iframeRpc", "createProtoRpcPeer", "requested", "iframeServiceBundle", "exposed", "workerServiceBundle", "handlers", "WorkerService", "start", "request", "origin", "lockKey", "observabilityGroup", "signalTelemetryEnabled", "wake", "stop", "setTimeout", "close", "err", "log", "catch", "bridgeService", "rpc", "BridgeService", "open", "info", "Promise", "all", "_maybeOpenShell", "_afterLockReleases", "callIfSet", "asyncTimeout", "callback", "navigator", "locks", "then", "logInfo", "WorkerRuntime", "constructor", "
|
|
4
|
+
"sourcesContent": ["//\n// Copyright 2022 DXOS.org\n//\n\nimport { Trigger } from '@dxos/async';\nimport { DEFAULT_WORKER_BROADCAST_CHANNEL } from '@dxos/client-protocol';\nimport { type Config } from '@dxos/config';\nimport { Context } from '@dxos/context';\nimport { invariant } from '@dxos/invariant';\nimport { log } from '@dxos/log';\nimport {\n MemorySignalManager,\n MemorySignalManagerContext,\n WebsocketSignalManager,\n setIdentityTags,\n} from '@dxos/messaging';\nimport { SimplePeerTransportProxyFactory } from '@dxos/network-manager';\nimport { type RpcPort } from '@dxos/rpc';\nimport { type MaybePromise } from '@dxos/util';\n\nimport { WorkerSession } from './worker-session';\nimport { ClientServicesHost } from '../services';\n\n// NOTE: Keep as RpcPorts to avoid dependency on @dxos/rpc-tunnel so we don't depend on browser-specific apis.\nexport type CreateSessionParams = {\n appPort: RpcPort;\n systemPort: RpcPort;\n shellPort?: RpcPort;\n};\n\nexport type WorkerRuntimeOptions = {\n channel?: string;\n configProvider: () => MaybePromise<Config>;\n acquireLock: () => Promise<void>;\n releaseLock: () => void;\n onStop?: () => Promise<void>;\n};\n\n/**\n * Runtime for the shared worker.\n * Manages connections from proxies (in tabs).\n * Tabs make requests to the `ClientServicesHost`, and provide a WebRTC gateway.\n */\nexport class WorkerRuntime {\n private readonly _configProvider: () => MaybePromise<Config>;\n private readonly _acquireLock: () => Promise<void>;\n private readonly _releaseLock: () => void;\n private readonly _onStop?: () => Promise<void>;\n private readonly _transportFactory = new SimplePeerTransportProxyFactory();\n private readonly _ready = new Trigger<Error | undefined>();\n private readonly _sessions = new Set<WorkerSession>();\n private readonly _clientServices!: ClientServicesHost;\n private readonly _channel: string;\n private _broadcastChannel?: BroadcastChannel;\n private _sessionForNetworking?: WorkerSession; // TODO(burdon): Expose to client QueryStatusResponse.\n private _config!: Config;\n private _signalMetadataTags: any = { runtime: 'worker-runtime' };\n private _signalTelemetryEnabled: boolean = false;\n\n constructor({\n channel = DEFAULT_WORKER_BROADCAST_CHANNEL,\n configProvider,\n acquireLock,\n releaseLock,\n onStop,\n }: WorkerRuntimeOptions) {\n this._configProvider = configProvider;\n this._acquireLock = acquireLock;\n this._releaseLock = releaseLock;\n this._onStop = onStop;\n this._channel = channel;\n this._clientServices = new ClientServicesHost({\n callbacks: {\n onReset: async () => this.stop(),\n },\n });\n }\n\n get host() {\n return this._clientServices;\n }\n\n async start() {\n log('starting...');\n try {\n this._broadcastChannel = new BroadcastChannel(this._channel);\n this._broadcastChannel.postMessage({ action: 'stop' });\n this._broadcastChannel.onmessage = async (event) => {\n if (event.data?.action === 'stop') {\n await this.stop();\n }\n };\n\n await this._acquireLock();\n this._config = await this._configProvider();\n const signals = this._config.get('runtime.services.signaling');\n this._clientServices.initialize({\n config: this._config,\n signalManager: signals\n ? new WebsocketSignalManager(signals, () => (this._signalTelemetryEnabled ? this._signalMetadataTags : {}))\n : new MemorySignalManager(new MemorySignalManagerContext()), // TODO(dmaretskyi): Inject this context.\n transportFactory: this._transportFactory,\n });\n\n await this._clientServices.open(new Context());\n this._ready.wake(undefined);\n log('started');\n setIdentityTags({\n identityService: this._clientServices.services.IdentityService!,\n devicesService: this._clientServices.services.DevicesService!,\n setTag: (k: string, v: string) => {\n this._signalMetadataTags[k] = v;\n },\n });\n } catch (err: any) {\n this._ready.wake(err);\n log.error('starting', err);\n }\n }\n\n async stop() {\n // Release the lock to notify remote clients that the worker is terminating.\n this._releaseLock();\n this._broadcastChannel?.close();\n this._broadcastChannel = undefined;\n await this._clientServices.close();\n await this._onStop?.();\n }\n\n /**\n * Create a new session.\n */\n async createSession({ appPort, systemPort, shellPort }: CreateSessionParams) {\n const session = new WorkerSession({\n serviceHost: this._clientServices,\n appPort,\n systemPort,\n shellPort,\n readySignal: this._ready,\n });\n\n // When tab is closed or client is destroyed.\n session.onClose.set(async () => {\n this._sessions.delete(session);\n if (this._sessions.size === 0) {\n // Terminate the worker when all sessions are closed.\n await this.stop();\n } else {\n this._reconnectWebrtc();\n }\n });\n\n await session.open();\n // A worker can only service one origin currently\n invariant(\n !this._signalMetadataTags.origin || this._signalMetadataTags.origin === session.origin,\n `worker origin changed from ${this._signalMetadataTags.origin} to ${session.origin}?`,\n );\n if (session.observabilityGroup) {\n this._signalMetadataTags.group = session.observabilityGroup;\n }\n this._signalTelemetryEnabled = session.signalTelemetryEnabled ?? false;\n this._signalMetadataTags.origin = session.origin;\n this._sessions.add(session);\n\n this._reconnectWebrtc();\n }\n\n /**\n * Selects one of the existing session for WebRTC networking.\n */\n private _reconnectWebrtc() {\n log('reconnecting webrtc...');\n // Check if current session is already closed.\n if (this._sessionForNetworking) {\n if (!this._sessions.has(this._sessionForNetworking)) {\n this._sessionForNetworking = undefined;\n }\n }\n\n // Select existing session.\n if (!this._sessionForNetworking) {\n const selected = Array.from(this._sessions).find((session) => session.bridgeService);\n if (selected) {\n this._sessionForNetworking = selected;\n this._transportFactory.setBridgeService(selected.bridgeService);\n } else {\n this._transportFactory.setBridgeService(undefined);\n }\n }\n }\n}\n", "//\n// Copyright 2022 DXOS.org\n//\n\nimport { asyncTimeout, Trigger } from '@dxos/async';\nimport {\n iframeServiceBundle,\n type IframeServiceBundle,\n PROXY_CONNECTION_TIMEOUT,\n workerServiceBundle,\n} from '@dxos/client-protocol';\nimport { invariant } from '@dxos/invariant';\nimport { log, logInfo } from '@dxos/log';\nimport { type BridgeService } from '@dxos/protocols/proto/dxos/mesh/bridge';\nimport { createProtoRpcPeer, type ProtoRpcPeer, type RpcPort } from '@dxos/rpc';\nimport { Callback, type MaybePromise } from '@dxos/util';\n\nimport { type ClientServicesHost, ClientRpcServer, type ClientRpcServerParams } from '../services';\n\nexport type WorkerSessionParams = {\n serviceHost: ClientServicesHost;\n systemPort: RpcPort;\n appPort: RpcPort;\n // TODO(wittjosiah): Remove shellPort.\n shellPort?: RpcPort;\n readySignal: Trigger<Error | undefined>;\n};\n\n/**\n * Represents a tab connection within the worker.\n */\nexport class WorkerSession {\n private readonly _clientRpc: ClientRpcServer;\n private readonly _shellClientRpc?: ClientRpcServer;\n private readonly _iframeRpc: ProtoRpcPeer<IframeServiceBundle>;\n private readonly _startTrigger = new Trigger();\n private readonly _serviceHost: ClientServicesHost;\n\n public readonly onClose = new Callback<() => Promise<void>>();\n\n @logInfo\n public origin?: string;\n\n // TODO(nf): factor out?\n public observabilityGroup?: string;\n public signalTelemetryEnabled?: boolean;\n\n @logInfo\n public lockKey?: string;\n\n public bridgeService?: BridgeService;\n\n constructor({ serviceHost, systemPort, appPort, shellPort, readySignal }: WorkerSessionParams) {\n invariant(serviceHost);\n this._serviceHost = serviceHost;\n\n const middleware: Pick<ClientRpcServerParams, 'handleCall' | 'handleStream'> = {\n handleCall: async (method, params, handler) => {\n const error = await readySignal.wait({ timeout: PROXY_CONNECTION_TIMEOUT });\n if (error) {\n throw error;\n }\n\n return handler(method, params);\n },\n handleStream: async (method, params, handler) => {\n const error = await readySignal.wait({ timeout: PROXY_CONNECTION_TIMEOUT });\n if (error) {\n throw error;\n }\n\n return handler(method, params);\n },\n };\n\n this._clientRpc = new ClientRpcServer({\n serviceRegistry: this._serviceHost.serviceRegistry,\n port: appPort,\n ...middleware,\n });\n\n this._shellClientRpc = shellPort\n ? new ClientRpcServer({\n serviceRegistry: this._serviceHost.serviceRegistry,\n port: shellPort,\n ...middleware,\n })\n : undefined;\n\n this._iframeRpc = createProtoRpcPeer({\n requested: iframeServiceBundle,\n exposed: workerServiceBundle,\n handlers: {\n WorkerService: {\n start: async (request) => {\n this.origin = request.origin;\n this.lockKey = request.lockKey;\n this.observabilityGroup = request.observabilityGroup;\n this.signalTelemetryEnabled = request.signalTelemetryEnabled;\n this._startTrigger.wake();\n },\n\n stop: async () => {\n setTimeout(async () => {\n try {\n await this.close();\n } catch (err: any) {\n log.catch(err);\n }\n });\n },\n },\n },\n port: systemPort,\n timeout: 1_000, // With low timeout heartbeat may fail if the tab's thread is saturated.\n });\n\n this.bridgeService = this._iframeRpc.rpc.BridgeService;\n }\n\n async open() {\n log.info('opening...');\n await Promise.all([this._clientRpc.open(), this._iframeRpc.open(), this._maybeOpenShell()]);\n\n // Wait until the worker's RPC service has started.\n await this._startTrigger.wait({ timeout: PROXY_CONNECTION_TIMEOUT });\n\n // TODO(burdon): Comment required.\n if (this.lockKey) {\n void this._afterLockReleases(this.lockKey, () => this.close());\n }\n\n log.info('opened');\n }\n\n async close() {\n log.info('closing...');\n try {\n await this.onClose.callIfSet();\n } catch (err: any) {\n log.catch(err);\n }\n\n await Promise.all([this._clientRpc.close(), this._iframeRpc.close()]);\n log.info('closed');\n }\n\n private async _maybeOpenShell() {\n try {\n this._shellClientRpc && (await asyncTimeout(this._shellClientRpc.open(), 1_000));\n } catch {\n log.info('No shell connected.');\n }\n }\n\n private _afterLockReleases(lockKey: string, callback: () => MaybePromise<void>): Promise<void> {\n return navigator.locks\n .request(lockKey, () => {\n // No-op.\n })\n .then(callback);\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["Trigger", "DEFAULT_WORKER_BROADCAST_CHANNEL", "Context", "invariant", "log", "MemorySignalManager", "MemorySignalManagerContext", "WebsocketSignalManager", "setIdentityTags", "SimplePeerTransportProxyFactory", "asyncTimeout", "Trigger", "iframeServiceBundle", "PROXY_CONNECTION_TIMEOUT", "workerServiceBundle", "invariant", "log", "logInfo", "createProtoRpcPeer", "Callback", "WorkerSession", "constructor", "serviceHost", "systemPort", "appPort", "shellPort", "readySignal", "_startTrigger", "Trigger", "onClose", "Callback", "invariant", "_serviceHost", "middleware", "handleCall", "method", "params", "handler", "error", "wait", "timeout", "PROXY_CONNECTION_TIMEOUT", "handleStream", "_clientRpc", "ClientRpcServer", "serviceRegistry", "port", "_shellClientRpc", "undefined", "_iframeRpc", "createProtoRpcPeer", "requested", "iframeServiceBundle", "exposed", "workerServiceBundle", "handlers", "WorkerService", "start", "request", "origin", "lockKey", "observabilityGroup", "signalTelemetryEnabled", "wake", "stop", "setTimeout", "close", "err", "log", "catch", "bridgeService", "rpc", "BridgeService", "open", "info", "Promise", "all", "_maybeOpenShell", "_afterLockReleases", "callIfSet", "asyncTimeout", "callback", "navigator", "locks", "then", "logInfo", "WorkerRuntime", "constructor", "channel", "DEFAULT_WORKER_BROADCAST_CHANNEL", "configProvider", "acquireLock", "releaseLock", "onStop", "_transportFactory", "SimplePeerTransportProxyFactory", "_ready", "Trigger", "_sessions", "Set", "_signalMetadataTags", "runtime", "_signalTelemetryEnabled", "_configProvider", "_acquireLock", "_releaseLock", "_onStop", "_channel", "_clientServices", "ClientServicesHost", "callbacks", "onReset", "stop", "host", "start", "log", "_broadcastChannel", "BroadcastChannel", "postMessage", "action", "onmessage", "event", "data", "_config", "signals", "get", "initialize", "config", "signalManager", "WebsocketSignalManager", "MemorySignalManager", "MemorySignalManagerContext", "transportFactory", "open", "Context", "wake", "undefined", "setIdentityTags", "identityService", "services", "IdentityService", "devicesService", "DevicesService", "setTag", "k", "v", "err", "error", "close", "createSession", "appPort", "systemPort", "shellPort", "session", "WorkerSession", "serviceHost", "readySignal", "onClose", "set", "delete", "size", "_reconnectWebrtc", "invariant", "origin", "observabilityGroup", "group", "signalTelemetryEnabled", "add", "_sessionForNetworking", "has", "selected", "Array", "from", "find", "bridgeService", "setBridgeService"]
|
|
7
7
|
}
|