@dxos/client-services 0.1.29-next.ed4ce05 → 0.1.29
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-ILMYW75X.mjs → chunk-ZIQUYEJS.mjs} +183 -94
- package/dist/lib/browser/{chunk-ILMYW75X.mjs.map → chunk-ZIQUYEJS.mjs.map} +4 -4
- package/dist/lib/browser/index.mjs +1 -1
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/packlets/testing/index.mjs +1 -1
- package/dist/lib/node/index.cjs +191 -104
- package/dist/lib/node/index.cjs.map +4 -4
- package/dist/lib/node/meta.json +1 -1
- package/dist/lib/node/packlets/testing/index.cjs +196 -100
- package/dist/lib/node/packlets/testing/index.cjs.map +4 -4
- package/dist/types/src/packlets/services/client-rpc-server.d.ts +22 -0
- package/dist/types/src/packlets/services/client-rpc-server.d.ts.map +1 -0
- package/dist/types/src/packlets/services/local-client-services.d.ts +2 -1
- package/dist/types/src/packlets/services/local-client-services.d.ts.map +1 -1
- package/dist/types/src/packlets/services/service-host.d.ts +21 -6
- package/dist/types/src/packlets/services/service-host.d.ts.map +1 -1
- package/dist/types/src/packlets/services/service-registry.d.ts +3 -1
- package/dist/types/src/packlets/services/service-registry.d.ts.map +1 -1
- package/dist/types/src/packlets/system/system-service.d.ts +2 -2
- package/dist/types/src/packlets/system/system-service.d.ts.map +1 -1
- package/dist/types/src/packlets/vault/iframe-host-runtime.d.ts +0 -1
- package/dist/types/src/packlets/vault/iframe-host-runtime.d.ts.map +1 -1
- package/dist/types/src/packlets/vault/worker-runtime.d.ts.map +1 -1
- package/dist/types/src/packlets/vault/worker-session.d.ts +4 -4
- package/dist/types/src/packlets/vault/worker-session.d.ts.map +1 -1
- package/package.json +30 -30
- package/src/packlets/services/client-rpc-server.ts +91 -0
- package/src/packlets/services/local-client-services.ts +4 -0
- package/src/packlets/services/service-host.ts +51 -10
- package/src/packlets/services/service-registry.ts +9 -1
- package/src/packlets/system/system-service.ts +3 -3
- package/src/packlets/tests/shared-worker.test.ts +39 -42
- package/src/packlets/vault/iframe-host-runtime.ts +25 -34
- package/src/packlets/vault/worker-runtime.ts +5 -15
- package/src/packlets/vault/worker-session.ts +40 -28
|
@@ -10,34 +10,41 @@ import { Client, ClientServicesProxy, fromIFrame } from '@dxos/client';
|
|
|
10
10
|
import { Config } from '@dxos/config';
|
|
11
11
|
import { createLinkedPorts } from '@dxos/rpc';
|
|
12
12
|
import { describe, test, afterTest } from '@dxos/test';
|
|
13
|
+
import { MaybePromise } from '@dxos/util';
|
|
13
14
|
|
|
14
15
|
import { TestBuilder } from '../testing';
|
|
15
16
|
import { IFrameProxyRuntime, WorkerRuntime } from '../vault';
|
|
16
17
|
|
|
17
18
|
chai.use(chaiAsPromised);
|
|
18
19
|
|
|
20
|
+
const setup = (getConfig: () => MaybePromise<Config>) => {
|
|
21
|
+
const workerRuntime = new WorkerRuntime(getConfig);
|
|
22
|
+
|
|
23
|
+
const systemPorts = createLinkedPorts();
|
|
24
|
+
const workerProxyPorts = createLinkedPorts();
|
|
25
|
+
const proxyWindowPorts = createLinkedPorts();
|
|
26
|
+
const shellPorts = createLinkedPorts();
|
|
27
|
+
void workerRuntime.createSession({
|
|
28
|
+
systemPort: systemPorts[1],
|
|
29
|
+
appPort: workerProxyPorts[1],
|
|
30
|
+
shellPort: shellPorts[1]
|
|
31
|
+
});
|
|
32
|
+
const clientProxy = new IFrameProxyRuntime({
|
|
33
|
+
systemPort: systemPorts[0],
|
|
34
|
+
windowAppPort: proxyWindowPorts[0],
|
|
35
|
+
workerAppPort: workerProxyPorts[0],
|
|
36
|
+
shellPort: shellPorts[0]
|
|
37
|
+
});
|
|
38
|
+
const client = new Client({
|
|
39
|
+
services: new ClientServicesProxy(proxyWindowPorts[1])
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
return { workerRuntime, clientProxy, client };
|
|
43
|
+
};
|
|
44
|
+
|
|
19
45
|
describe('Shared worker', () => {
|
|
20
46
|
test('client connects to the worker', async () => {
|
|
21
|
-
const workerRuntime =
|
|
22
|
-
|
|
23
|
-
const systemPorts = createLinkedPorts();
|
|
24
|
-
const workerProxyPorts = createLinkedPorts();
|
|
25
|
-
const proxyWindowPorts = createLinkedPorts();
|
|
26
|
-
const shellPorts = createLinkedPorts();
|
|
27
|
-
void workerRuntime.createSession({
|
|
28
|
-
systemPort: systemPorts[1],
|
|
29
|
-
appPort: workerProxyPorts[1],
|
|
30
|
-
shellPort: shellPorts[1]
|
|
31
|
-
});
|
|
32
|
-
const clientProxy = new IFrameProxyRuntime({
|
|
33
|
-
systemPort: systemPorts[0],
|
|
34
|
-
windowAppPort: proxyWindowPorts[0],
|
|
35
|
-
workerAppPort: workerProxyPorts[0],
|
|
36
|
-
shellPort: shellPorts[0]
|
|
37
|
-
});
|
|
38
|
-
const client = new Client({
|
|
39
|
-
services: new ClientServicesProxy(proxyWindowPorts[1])
|
|
40
|
-
});
|
|
47
|
+
const { workerRuntime, clientProxy, client } = setup(() => new Config({}));
|
|
41
48
|
|
|
42
49
|
await Promise.all([workerRuntime.start(), clientProxy.open('*'), client.initialize()]);
|
|
43
50
|
|
|
@@ -45,32 +52,11 @@ describe('Shared worker', () => {
|
|
|
45
52
|
});
|
|
46
53
|
|
|
47
54
|
test('initialization errors get propagated to the client', async () => {
|
|
48
|
-
const workerRuntime =
|
|
55
|
+
const { workerRuntime, clientProxy, client } = setup(async () => {
|
|
49
56
|
await sleep(1);
|
|
50
57
|
throw new Error('Test error');
|
|
51
58
|
});
|
|
52
59
|
|
|
53
|
-
const systemPorts = createLinkedPorts();
|
|
54
|
-
const workerProxyPorts = createLinkedPorts();
|
|
55
|
-
const proxyWindowPorts = createLinkedPorts();
|
|
56
|
-
const shellPorts = createLinkedPorts();
|
|
57
|
-
void workerRuntime.createSession({
|
|
58
|
-
systemPort: systemPorts[1],
|
|
59
|
-
appPort: workerProxyPorts[1],
|
|
60
|
-
shellPort: shellPorts[1]
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
const clientProxy = new IFrameProxyRuntime({
|
|
64
|
-
systemPort: systemPorts[0],
|
|
65
|
-
windowAppPort: proxyWindowPorts[0],
|
|
66
|
-
workerAppPort: workerProxyPorts[0],
|
|
67
|
-
shellPort: shellPorts[0]
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
const client = new Client({
|
|
71
|
-
services: new ClientServicesProxy(proxyWindowPorts[1])
|
|
72
|
-
});
|
|
73
|
-
|
|
74
60
|
const promise = Promise.all([
|
|
75
61
|
workerRuntime.start().catch(() => {}), // This error should be propagated to client.initialize() call.
|
|
76
62
|
clientProxy.open('*')
|
|
@@ -81,6 +67,17 @@ describe('Shared worker', () => {
|
|
|
81
67
|
await promise;
|
|
82
68
|
});
|
|
83
69
|
|
|
70
|
+
test('host can be initialized after client', async () => {
|
|
71
|
+
const { workerRuntime, clientProxy, client } = setup(async () => {
|
|
72
|
+
await sleep(5);
|
|
73
|
+
return new Config({});
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
await Promise.all([workerRuntime.start(), clientProxy.open('*'), client.initialize()]);
|
|
77
|
+
|
|
78
|
+
await client.halo.createIdentity();
|
|
79
|
+
});
|
|
80
|
+
|
|
84
81
|
// TODO(burdon): Browser-only.
|
|
85
82
|
test.skip('creates client with remote iframe', async () => {
|
|
86
83
|
const testBuilder = new TestBuilder();
|
|
@@ -3,15 +3,15 @@
|
|
|
3
3
|
//
|
|
4
4
|
|
|
5
5
|
import { Trigger } from '@dxos/async';
|
|
6
|
-
import { clientServiceBundle, ClientServices } from '@dxos/client';
|
|
7
6
|
import { Config } from '@dxos/config';
|
|
8
7
|
import { log, logInfo } from '@dxos/log';
|
|
9
8
|
import { MemorySignalManager, MemorySignalManagerContext, WebsocketSignalManager } from '@dxos/messaging';
|
|
10
9
|
import { createWebRTCTransportFactory, NetworkManager } from '@dxos/network-manager';
|
|
11
|
-
import {
|
|
10
|
+
import { RpcPort } from '@dxos/rpc';
|
|
12
11
|
import { getAsyncValue, Provider } from '@dxos/util';
|
|
13
12
|
|
|
14
13
|
import { LocalClientServices } from '../services';
|
|
14
|
+
import { ClientRpcServer, ClientRpcServerParams } from '../services/client-rpc-server';
|
|
15
15
|
import { ShellRuntime, ShellRuntimeImpl } from './shell-runtime';
|
|
16
16
|
|
|
17
17
|
const LOCK_KEY = 'DXOS_RESOURCE_LOCK';
|
|
@@ -32,9 +32,6 @@ export class IFrameHostRuntime {
|
|
|
32
32
|
private readonly _configProvider: Config | Provider<Promise<Config>>;
|
|
33
33
|
private readonly _transportFactory = createWebRTCTransportFactory();
|
|
34
34
|
private readonly _ready = new Trigger<Error | undefined>();
|
|
35
|
-
private readonly _getService: <Service>(
|
|
36
|
-
find: (services: Partial<ClientServices>) => Service | undefined
|
|
37
|
-
) => Promise<Service>;
|
|
38
35
|
|
|
39
36
|
private readonly _appPort: RpcPort;
|
|
40
37
|
private readonly _shellPort?: RpcPort;
|
|
@@ -42,7 +39,7 @@ export class IFrameHostRuntime {
|
|
|
42
39
|
|
|
43
40
|
// TODO(dmaretskyi): Replace with host and figure out how to return services provider here.
|
|
44
41
|
private _clientServices!: LocalClientServices;
|
|
45
|
-
private _clientRpc!:
|
|
42
|
+
private _clientRpc!: ClientRpcServer;
|
|
46
43
|
private _shellRuntime?: ShellRuntimeImpl;
|
|
47
44
|
|
|
48
45
|
@logInfo
|
|
@@ -53,20 +50,6 @@ export class IFrameHostRuntime {
|
|
|
53
50
|
this._appPort = appPort;
|
|
54
51
|
this._shellPort = shellPort;
|
|
55
52
|
|
|
56
|
-
this._getService = async (find) => {
|
|
57
|
-
const error = await this._ready.wait();
|
|
58
|
-
if (error) {
|
|
59
|
-
throw error;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
const service = await find(this._clientServices.services);
|
|
63
|
-
if (!service) {
|
|
64
|
-
throw new Error('Service not found');
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
return service;
|
|
68
|
-
};
|
|
69
|
-
|
|
70
53
|
if (this._shellPort) {
|
|
71
54
|
this._shellRuntime = new ShellRuntimeImpl(this._shellPort);
|
|
72
55
|
}
|
|
@@ -97,21 +80,29 @@ export class IFrameHostRuntime {
|
|
|
97
80
|
})
|
|
98
81
|
});
|
|
99
82
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
IdentityService: async () => await this._getService((services) => services.IdentityService),
|
|
109
|
-
SpaceInvitationsService: async () => await this._getService((services) => services.SpaceInvitationsService),
|
|
110
|
-
SpacesService: async () => await this._getService((services) => services.SpacesService),
|
|
111
|
-
SystemService: async () => await this._getService((services) => services.SystemService),
|
|
112
|
-
TracingService: async () => await this._getService((services) => services.TracingService)
|
|
83
|
+
const middleware: Pick<ClientRpcServerParams, 'handleCall' | 'handleStream'> = {
|
|
84
|
+
handleCall: async (method, params, handler) => {
|
|
85
|
+
const error = await this._ready.wait({ timeout: 3_000 });
|
|
86
|
+
if (error) {
|
|
87
|
+
throw error;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
return handler(method, params);
|
|
113
91
|
},
|
|
114
|
-
|
|
92
|
+
handleStream: async (method, params, handler) => {
|
|
93
|
+
const error = await this._ready.wait({ timeout: 3_000 });
|
|
94
|
+
if (error) {
|
|
95
|
+
throw error;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
return handler(method, params);
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
this._clientRpc = new ClientRpcServer({
|
|
103
|
+
serviceRegistry: this._clientServices.host.serviceRegistry,
|
|
104
|
+
port: this._appPort,
|
|
105
|
+
...middleware
|
|
115
106
|
});
|
|
116
107
|
|
|
117
108
|
await Promise.all([this._clientServices.open(), this._clientRpc.open(), this._shellRuntime?.open()]);
|
|
@@ -36,14 +36,16 @@ export class WorkerRuntime {
|
|
|
36
36
|
// prettier-ignore
|
|
37
37
|
constructor(
|
|
38
38
|
private readonly _configProvider: () => MaybePromise<Config>
|
|
39
|
-
) {
|
|
39
|
+
) {
|
|
40
|
+
this._clientServices = new ClientServicesHost();
|
|
41
|
+
}
|
|
40
42
|
|
|
41
43
|
async start() {
|
|
42
44
|
log('starting...');
|
|
43
45
|
try {
|
|
44
46
|
this._config = await this._configProvider();
|
|
45
47
|
const signalServer = this._config.get('runtime.services.signal.server');
|
|
46
|
-
this._clientServices
|
|
48
|
+
this._clientServices.initialize({
|
|
47
49
|
config: this._config,
|
|
48
50
|
networkManager: new NetworkManager({
|
|
49
51
|
log: true,
|
|
@@ -73,19 +75,7 @@ export class WorkerRuntime {
|
|
|
73
75
|
*/
|
|
74
76
|
async createSession({ appPort, systemPort, shellPort }: CreateSessionParams) {
|
|
75
77
|
const session = new WorkerSession({
|
|
76
|
-
|
|
77
|
-
const error = await this._ready.wait();
|
|
78
|
-
if (error) {
|
|
79
|
-
throw error;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
const service = find(this._clientServices.services);
|
|
83
|
-
if (!service) {
|
|
84
|
-
throw new Error('Service not found');
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
return service;
|
|
88
|
-
},
|
|
78
|
+
serviceHost: this._clientServices,
|
|
89
79
|
appPort,
|
|
90
80
|
systemPort,
|
|
91
81
|
shellPort,
|
|
@@ -5,20 +5,17 @@
|
|
|
5
5
|
import assert from 'node:assert';
|
|
6
6
|
|
|
7
7
|
import { asyncTimeout, Trigger } from '@dxos/async';
|
|
8
|
-
import {
|
|
9
|
-
clientServiceBundle,
|
|
10
|
-
ClientServices,
|
|
11
|
-
iframeServiceBundle,
|
|
12
|
-
IframeServiceBundle,
|
|
13
|
-
workerServiceBundle
|
|
14
|
-
} from '@dxos/client';
|
|
8
|
+
import { iframeServiceBundle, IframeServiceBundle, workerServiceBundle } from '@dxos/client';
|
|
15
9
|
import { log, logInfo } from '@dxos/log';
|
|
16
10
|
import { BridgeService } from '@dxos/protocols/proto/dxos/mesh/bridge';
|
|
17
11
|
import { createProtoRpcPeer, ProtoRpcPeer, RpcPort } from '@dxos/rpc';
|
|
18
12
|
import { Callback } from '@dxos/util';
|
|
19
13
|
|
|
14
|
+
import { ClientServicesHost } from '../services';
|
|
15
|
+
import { ClientRpcServer, ClientRpcServerParams } from '../services/client-rpc-server';
|
|
16
|
+
|
|
20
17
|
export type WorkerSessionParams = {
|
|
21
|
-
|
|
18
|
+
serviceHost: ClientServicesHost;
|
|
22
19
|
systemPort: RpcPort;
|
|
23
20
|
appPort: RpcPort;
|
|
24
21
|
shellPort: RpcPort;
|
|
@@ -32,11 +29,11 @@ export type WorkerSessionParams = {
|
|
|
32
29
|
* Represents a tab connection within the worker.
|
|
33
30
|
*/
|
|
34
31
|
export class WorkerSession {
|
|
35
|
-
private readonly _clientRpc:
|
|
36
|
-
private readonly _shellClientRpc:
|
|
32
|
+
private readonly _clientRpc: ClientRpcServer;
|
|
33
|
+
private readonly _shellClientRpc: ClientRpcServer;
|
|
37
34
|
private readonly _iframeRpc: ProtoRpcPeer<IframeServiceBundle>;
|
|
38
35
|
private readonly _startTrigger = new Trigger();
|
|
39
|
-
private readonly
|
|
36
|
+
private readonly _serviceHost: ClientServicesHost;
|
|
40
37
|
private readonly _options: NonNullable<WorkerSessionParams['options']>;
|
|
41
38
|
private _heartbeatTimer?: NodeJS.Timeout;
|
|
42
39
|
|
|
@@ -48,34 +45,49 @@ export class WorkerSession {
|
|
|
48
45
|
public bridgeService?: BridgeService;
|
|
49
46
|
|
|
50
47
|
constructor({
|
|
51
|
-
|
|
48
|
+
serviceHost,
|
|
52
49
|
systemPort,
|
|
53
50
|
appPort,
|
|
54
51
|
shellPort,
|
|
52
|
+
readySignal,
|
|
55
53
|
options = {
|
|
56
54
|
heartbeatInterval: 1_000
|
|
57
55
|
}
|
|
58
56
|
}: WorkerSessionParams) {
|
|
59
57
|
assert(options);
|
|
60
|
-
assert(
|
|
58
|
+
assert(serviceHost);
|
|
61
59
|
this._options = options;
|
|
62
|
-
this.
|
|
63
|
-
|
|
64
|
-
const
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
60
|
+
this._serviceHost = serviceHost;
|
|
61
|
+
|
|
62
|
+
const middleware: Pick<ClientRpcServerParams, 'handleCall' | 'handleStream'> = {
|
|
63
|
+
handleCall: async (method, params, handler) => {
|
|
64
|
+
const error = await readySignal.wait({ timeout: 3_000 });
|
|
65
|
+
if (error) {
|
|
66
|
+
throw error;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return handler(method, params);
|
|
70
|
+
},
|
|
71
|
+
handleStream: async (method, params, handler) => {
|
|
72
|
+
const error = await readySignal.wait({ timeout: 3_000 });
|
|
73
|
+
if (error) {
|
|
74
|
+
throw error;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
return handler(method, params);
|
|
78
|
+
}
|
|
75
79
|
};
|
|
76
80
|
|
|
77
|
-
this._clientRpc =
|
|
78
|
-
|
|
81
|
+
this._clientRpc = new ClientRpcServer({
|
|
82
|
+
serviceRegistry: this._serviceHost.serviceRegistry,
|
|
83
|
+
port: appPort,
|
|
84
|
+
...middleware
|
|
85
|
+
});
|
|
86
|
+
this._shellClientRpc = new ClientRpcServer({
|
|
87
|
+
serviceRegistry: this._serviceHost.serviceRegistry,
|
|
88
|
+
port: shellPort,
|
|
89
|
+
...middleware
|
|
90
|
+
});
|
|
79
91
|
|
|
80
92
|
this._iframeRpc = createProtoRpcPeer({
|
|
81
93
|
requested: iframeServiceBundle,
|