@dxos/client-services 0.1.26 → 0.1.27-next.a0dff21
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-R2FEBB66.mjs → chunk-OTSGRZZI.mjs} +796 -579
- package/dist/lib/browser/chunk-OTSGRZZI.mjs.map +7 -0
- package/dist/lib/browser/index.mjs +19 -15
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/packlets/testing/index.mjs +46 -46
- package/dist/lib/browser/packlets/testing/index.mjs.map +4 -4
- package/dist/lib/node/index.cjs +864 -641
- 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 +753 -631
- package/dist/lib/node/packlets/testing/index.cjs.map +4 -4
- package/dist/types/src/index.d.ts +0 -1
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/packlets/deprecated/index.d.ts +0 -3
- package/dist/types/src/packlets/deprecated/index.d.ts.map +1 -1
- package/dist/types/src/packlets/{identity/devices-service-impl.d.ts → devices/devices-service.d.ts} +4 -3
- package/dist/types/src/packlets/devices/devices-service.d.ts.map +1 -0
- package/dist/types/src/packlets/devices/index.d.ts +2 -0
- package/dist/types/src/packlets/devices/index.d.ts.map +1 -0
- package/dist/types/src/packlets/identity/authenticator.d.ts +1 -1
- package/dist/types/src/packlets/identity/authenticator.d.ts.map +1 -1
- package/dist/types/src/packlets/identity/identity-manager.d.ts +2 -2
- package/dist/types/src/packlets/identity/identity-manager.d.ts.map +1 -1
- package/dist/types/src/packlets/identity/identity-service.d.ts +14 -0
- package/dist/types/src/packlets/identity/identity-service.d.ts.map +1 -0
- package/dist/types/src/packlets/identity/identity.d.ts +2 -2
- package/dist/types/src/packlets/identity/identity.d.ts.map +1 -1
- package/dist/types/src/packlets/identity/index.d.ts +1 -0
- package/dist/types/src/packlets/identity/index.d.ts.map +1 -1
- package/dist/types/src/packlets/invitations/{halo-invitations-handler.d.ts → device-invitations-handler.d.ts} +5 -5
- package/dist/types/src/packlets/invitations/device-invitations-handler.d.ts.map +1 -0
- package/dist/types/src/packlets/invitations/device-invitations-handler.test.d.ts +2 -0
- package/dist/types/src/packlets/invitations/device-invitations-handler.test.d.ts.map +1 -0
- package/dist/types/src/packlets/invitations/{halo-invitations-proxy.d.ts → device-invitations-proxy.d.ts} +2 -2
- package/dist/types/src/packlets/invitations/device-invitations-proxy.d.ts.map +1 -0
- package/dist/types/src/packlets/invitations/{halo-invitations-service.d.ts → device-invitations-service.d.ts} +2 -2
- package/dist/types/src/packlets/invitations/device-invitations-service.d.ts.map +1 -0
- package/dist/types/src/packlets/invitations/device-invitations-service.test.d.ts +2 -0
- package/dist/types/src/packlets/invitations/device-invitations-service.test.d.ts.map +1 -0
- package/dist/types/src/packlets/invitations/index.d.ts +3 -3
- package/dist/types/src/packlets/invitations/index.d.ts.map +1 -1
- package/dist/types/src/packlets/invitations/invitations-handler.d.ts +6 -0
- package/dist/types/src/packlets/invitations/invitations-handler.d.ts.map +1 -1
- package/dist/types/src/packlets/invitations/space-invitations-handler.d.ts +1 -1
- package/dist/types/src/packlets/invitations/space-invitations-handler.d.ts.map +1 -1
- package/dist/types/src/packlets/services/index.d.ts +0 -1
- package/dist/types/src/packlets/services/index.d.ts.map +1 -1
- package/dist/types/src/packlets/services/service-context.d.ts +3 -3
- package/dist/types/src/packlets/services/service-context.d.ts.map +1 -1
- package/dist/types/src/packlets/services/service-definitions.d.ts +5 -7
- package/dist/types/src/packlets/services/service-definitions.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 +1 -1
- package/dist/types/src/packlets/spaces/data-space-manager.d.ts.map +1 -1
- package/dist/types/src/packlets/spaces/data-space.d.ts +1 -1
- package/dist/types/src/packlets/spaces/data-space.d.ts.map +1 -1
- package/dist/types/src/packlets/spaces/spaces-service.d.ts +12 -5
- package/dist/types/src/packlets/spaces/spaces-service.d.ts.map +1 -1
- package/dist/types/src/packlets/system/index.d.ts +2 -0
- package/dist/types/src/packlets/system/index.d.ts.map +1 -0
- package/dist/types/src/packlets/system/system-service.d.ts +28 -0
- package/dist/types/src/packlets/system/system-service.d.ts.map +1 -0
- package/dist/types/src/packlets/system/system-service.test.d.ts +2 -0
- package/dist/types/src/packlets/system/system-service.test.d.ts.map +1 -0
- package/dist/types/src/packlets/testing/index.d.ts +1 -1
- package/dist/types/src/packlets/testing/index.d.ts.map +1 -1
- package/dist/types/src/packlets/testing/test-builder.d.ts +1 -1
- package/dist/types/src/packlets/testing/test-builder.d.ts.map +1 -1
- package/dist/types/src/packlets/vault/iframe-host-runtime.d.ts +11 -4
- package/dist/types/src/packlets/vault/iframe-host-runtime.d.ts.map +1 -1
- package/dist/types/src/packlets/vault/iframe-proxy-runtime.d.ts +6 -1
- package/dist/types/src/packlets/vault/iframe-proxy-runtime.d.ts.map +1 -1
- package/dist/types/src/packlets/vault/index.d.ts +2 -0
- package/dist/types/src/packlets/vault/index.d.ts.map +1 -1
- package/dist/types/src/packlets/vault/services.d.ts +9 -1
- package/dist/types/src/packlets/vault/services.d.ts.map +1 -1
- package/dist/types/src/packlets/vault/shell-controller.d.ts +18 -0
- package/dist/types/src/packlets/vault/shell-controller.d.ts.map +1 -0
- package/dist/types/src/packlets/vault/shell-runtime.d.ts +45 -0
- package/dist/types/src/packlets/vault/shell-runtime.d.ts.map +1 -0
- package/dist/types/src/packlets/vault/worker-runtime.d.ts +2 -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 -1
- package/dist/types/src/packlets/vault/worker-session.d.ts.map +1 -1
- package/package.json +29 -28
- package/src/index.ts +0 -1
- package/src/packlets/deprecated/index.ts +0 -3
- package/src/packlets/{identity/devices-service-impl.ts → devices/devices-service.ts} +10 -8
- package/src/packlets/devices/index.ts +5 -0
- package/src/packlets/devtools/spaces.ts +1 -1
- package/src/packlets/identity/authenticator.ts +1 -1
- package/src/packlets/identity/identity-manager.test.ts +1 -1
- package/src/packlets/identity/identity-manager.ts +2 -2
- package/src/packlets/identity/identity-service.ts +67 -0
- package/src/packlets/identity/identity.test.ts +1 -1
- package/src/packlets/identity/identity.ts +1 -1
- package/src/packlets/identity/index.ts +1 -0
- package/src/packlets/invitations/{halo-invitations-handler.test.ts → device-invitations-handler.test.ts} +2 -2
- package/src/packlets/invitations/{halo-invitations-handler.ts → device-invitations-handler.ts} +4 -4
- package/src/packlets/invitations/{halo-invitations-proxy.ts → device-invitations-proxy.ts} +1 -1
- package/src/packlets/invitations/{halo-invitations-service.test.ts → device-invitations-service.test.ts} +10 -10
- package/src/packlets/invitations/{halo-invitations-service.ts → device-invitations-service.ts} +1 -1
- package/src/packlets/invitations/index.ts +3 -3
- package/src/packlets/invitations/invitations-handler.ts +6 -0
- package/src/packlets/invitations/invitations-service.ts +2 -2
- package/src/packlets/invitations/space-invitations-handler.test.ts +1 -1
- package/src/packlets/invitations/space-invitations-handler.ts +55 -20
- package/src/packlets/services/index.ts +0 -1
- package/src/packlets/services/service-context.test.ts +3 -3
- package/src/packlets/services/service-context.ts +5 -5
- package/src/packlets/services/service-definitions.ts +14 -14
- package/src/packlets/services/service-host.test.ts +9 -9
- package/src/packlets/services/service-host.ts +40 -25
- package/src/packlets/spaces/data-space-manager.test.ts +1 -1
- package/src/packlets/spaces/data-space-manager.ts +4 -4
- package/src/packlets/spaces/data-space.ts +3 -3
- package/src/packlets/spaces/spaces-service.ts +93 -11
- package/src/packlets/system/index.ts +5 -0
- package/src/packlets/system/system-service.test.ts +80 -0
- package/src/packlets/system/system-service.ts +70 -0
- package/src/packlets/testing/index.ts +1 -1
- package/src/packlets/testing/test-builder.ts +3 -3
- package/src/packlets/vault/iframe-host-runtime.ts +28 -10
- package/src/packlets/vault/iframe-proxy-runtime.ts +16 -1
- package/src/packlets/vault/index.ts +2 -0
- package/src/packlets/vault/services.ts +17 -1
- package/src/packlets/vault/shell-controller.ts +56 -0
- package/src/packlets/vault/shell-runtime.ts +121 -0
- package/src/packlets/vault/worker-runtime.ts +3 -1
- package/src/packlets/vault/worker-session.ts +28 -19
- package/dist/lib/browser/chunk-R2FEBB66.mjs.map +0 -7
- package/dist/types/src/packlets/deprecated/invitations.d.ts +0 -47
- package/dist/types/src/packlets/deprecated/invitations.d.ts.map +0 -1
- package/dist/types/src/packlets/deprecated/profile.d.ts +0 -18
- package/dist/types/src/packlets/deprecated/profile.d.ts.map +0 -1
- package/dist/types/src/packlets/deprecated/space.d.ts +0 -23
- package/dist/types/src/packlets/deprecated/space.d.ts.map +0 -1
- package/dist/types/src/packlets/deprecated/system.d.ts +0 -24
- package/dist/types/src/packlets/deprecated/system.d.ts.map +0 -1
- package/dist/types/src/packlets/identity/devices-service-impl.d.ts.map +0 -1
- package/dist/types/src/packlets/invitations/halo-invitations-handler.d.ts.map +0 -1
- package/dist/types/src/packlets/invitations/halo-invitations-handler.test.d.ts +0 -2
- package/dist/types/src/packlets/invitations/halo-invitations-handler.test.d.ts.map +0 -1
- package/dist/types/src/packlets/invitations/halo-invitations-proxy.d.ts.map +0 -1
- package/dist/types/src/packlets/invitations/halo-invitations-service.d.ts.map +0 -1
- package/dist/types/src/packlets/invitations/halo-invitations-service.test.d.ts +0 -2
- package/dist/types/src/packlets/invitations/halo-invitations-service.test.d.ts.map +0 -1
- package/dist/types/src/packlets/services/signer.d.ts +0 -6
- package/dist/types/src/packlets/services/signer.d.ts.map +0 -1
- package/src/packlets/deprecated/invitations.ts +0 -63
- package/src/packlets/deprecated/profile.ts +0 -85
- package/src/packlets/deprecated/space.ts +0 -258
- package/src/packlets/deprecated/system.ts +0 -48
- package/src/packlets/services/signer.ts +0 -11
|
@@ -10,10 +10,10 @@ import {
|
|
|
10
10
|
DataPipelineControllerImpl,
|
|
11
11
|
MetadataStore,
|
|
12
12
|
Space,
|
|
13
|
-
SnapshotManager,
|
|
14
13
|
SigningContext,
|
|
15
|
-
createMappedFeedWriter
|
|
16
|
-
|
|
14
|
+
createMappedFeedWriter,
|
|
15
|
+
SnapshotManager
|
|
16
|
+
} from '@dxos/echo-pipeline';
|
|
17
17
|
import { FeedStore } from '@dxos/feed-store';
|
|
18
18
|
import { Keyring } from '@dxos/keyring';
|
|
19
19
|
import { PublicKey } from '@dxos/keys';
|
|
@@ -2,36 +2,98 @@
|
|
|
2
2
|
// Copyright 2022 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import { scheduleTask } from '@dxos/async';
|
|
5
|
+
import { EventSubscriptions, scheduleTask } from '@dxos/async';
|
|
6
6
|
import { Stream } from '@dxos/codec-protobuf';
|
|
7
|
-
import { raise } from '@dxos/debug';
|
|
8
|
-
import { SpaceManager, SpaceNotFoundError } from '@dxos/echo-
|
|
7
|
+
import { raise, todo } from '@dxos/debug';
|
|
8
|
+
import { DataServiceSubscriptions, SpaceManager, SpaceNotFoundError } from '@dxos/echo-pipeline';
|
|
9
|
+
import { log } from '@dxos/log';
|
|
9
10
|
import {
|
|
10
11
|
QueryCredentialsRequest,
|
|
11
|
-
|
|
12
|
-
QueryMembersResponse,
|
|
12
|
+
QuerySpacesResponse,
|
|
13
13
|
Space,
|
|
14
|
+
SpaceMember,
|
|
14
15
|
SpacesService,
|
|
16
|
+
SpaceStatus,
|
|
17
|
+
UpdateSpaceRequest,
|
|
15
18
|
WriteCredentialsRequest
|
|
16
19
|
} from '@dxos/protocols/proto/dxos/client/services';
|
|
17
20
|
import { Credential } from '@dxos/protocols/proto/dxos/halo/credentials';
|
|
21
|
+
import { humanize, Provider } from '@dxos/util';
|
|
22
|
+
|
|
23
|
+
import { IdentityManager } from '../identity';
|
|
24
|
+
import { DataSpace } from './data-space';
|
|
25
|
+
import { DataSpaceManager } from './data-space-manager';
|
|
18
26
|
|
|
19
27
|
/**
|
|
20
28
|
*
|
|
21
29
|
*/
|
|
22
30
|
export class SpacesServiceImpl implements SpacesService {
|
|
23
|
-
constructor(
|
|
31
|
+
constructor(
|
|
32
|
+
private readonly _identityManager: IdentityManager,
|
|
33
|
+
private readonly _spaceManager: SpaceManager,
|
|
34
|
+
private readonly _dataServiceSubscriptions: DataServiceSubscriptions,
|
|
35
|
+
private readonly _getDataSpaceManager: Provider<Promise<DataSpaceManager>>
|
|
36
|
+
) {}
|
|
24
37
|
|
|
25
38
|
async createSpace(): Promise<Space> {
|
|
26
|
-
|
|
39
|
+
if (!this._identityManager.identity) {
|
|
40
|
+
throw new Error('This device has no HALO identity available. See https://docs.dxos.org/guide/halo');
|
|
41
|
+
}
|
|
42
|
+
const dataSpaceManager = await this._getDataSpaceManager();
|
|
43
|
+
const space = await dataSpaceManager.createSpace();
|
|
44
|
+
return this._transformSpace(space);
|
|
27
45
|
}
|
|
28
46
|
|
|
29
|
-
|
|
30
|
-
|
|
47
|
+
async updateSpace(request: UpdateSpaceRequest) {
|
|
48
|
+
todo();
|
|
31
49
|
}
|
|
32
50
|
|
|
33
|
-
|
|
34
|
-
|
|
51
|
+
querySpaces(): Stream<QuerySpacesResponse> {
|
|
52
|
+
return new Stream<QuerySpacesResponse>(({ next, ctx }) => {
|
|
53
|
+
const onUpdate = async () => {
|
|
54
|
+
const dataSpaceManager = await this._getDataSpaceManager();
|
|
55
|
+
const spaces = Array.from(dataSpaceManager.spaces.values())
|
|
56
|
+
// Skip spaces without data service available.
|
|
57
|
+
.filter((space) => this._dataServiceSubscriptions.getDataService(space.key))
|
|
58
|
+
.map((space) => this._transformSpace(space));
|
|
59
|
+
log('update', { spaces });
|
|
60
|
+
next({ spaces });
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
setTimeout(async () => {
|
|
64
|
+
const dataSpaceManager = await this._getDataSpaceManager();
|
|
65
|
+
const subscriptions = new EventSubscriptions();
|
|
66
|
+
// TODO(dmaretskyi): Create a pattern for subscribing to a set of objects.
|
|
67
|
+
const subscribeSpaces = () => {
|
|
68
|
+
subscriptions.clear();
|
|
69
|
+
|
|
70
|
+
for (const space of dataSpaceManager.spaces.values()) {
|
|
71
|
+
if (!this._dataServiceSubscriptions.getDataService(space.key)) {
|
|
72
|
+
// Skip spaces without data service available.
|
|
73
|
+
continue;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
subscriptions.add(space.stateUpdate.on(ctx, onUpdate));
|
|
77
|
+
subscriptions.add(space.presence.updated.on(ctx, onUpdate));
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
dataSpaceManager.updated.on(ctx, () => {
|
|
82
|
+
subscribeSpaces();
|
|
83
|
+
void onUpdate();
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
ctx.onDispose(() => subscriptions.clear());
|
|
87
|
+
scheduleTask(ctx, () => {
|
|
88
|
+
subscribeSpaces();
|
|
89
|
+
void onUpdate();
|
|
90
|
+
});
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
if (!this._identityManager.identity) {
|
|
94
|
+
next({ spaces: [] });
|
|
95
|
+
}
|
|
96
|
+
});
|
|
35
97
|
}
|
|
36
98
|
|
|
37
99
|
queryCredentials({ spaceKey }: QueryCredentialsRequest): Stream<Credential> {
|
|
@@ -54,4 +116,24 @@ export class SpacesServiceImpl implements SpacesService {
|
|
|
54
116
|
await space.controlPipeline.writer.write({ credential: { credential } });
|
|
55
117
|
}
|
|
56
118
|
}
|
|
119
|
+
|
|
120
|
+
private _transformSpace(space: DataSpace): Space {
|
|
121
|
+
return {
|
|
122
|
+
spaceKey: space.key,
|
|
123
|
+
status: space.isOpen ? SpaceStatus.ACTIVE : SpaceStatus.INACTIVE,
|
|
124
|
+
members: Array.from(space.inner.spaceState.members.values()).map((member) => ({
|
|
125
|
+
identity: {
|
|
126
|
+
identityKey: member.key,
|
|
127
|
+
profile: {
|
|
128
|
+
displayName: member.assertion.profile?.displayName ?? humanize(member.key)
|
|
129
|
+
}
|
|
130
|
+
},
|
|
131
|
+
presence:
|
|
132
|
+
this._identityManager.identity?.identityKey.equals(member.key) ||
|
|
133
|
+
space.presence.getPeersOnline().filter(({ identityKey }) => identityKey.equals(member.key)).length > 0
|
|
134
|
+
? SpaceMember.PresenceState.ONLINE
|
|
135
|
+
: SpaceMember.PresenceState.OFFLINE
|
|
136
|
+
}))
|
|
137
|
+
};
|
|
138
|
+
}
|
|
57
139
|
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2023 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { expect } from 'chai';
|
|
6
|
+
|
|
7
|
+
import { Event, Trigger } from '@dxos/async';
|
|
8
|
+
import { Config } from '@dxos/config';
|
|
9
|
+
import { SystemStatus, SystemStatusResponse, SystemService } from '@dxos/protocols/proto/dxos/client/services';
|
|
10
|
+
import { beforeEach, describe, test } from '@dxos/test';
|
|
11
|
+
|
|
12
|
+
import { SystemServiceImpl } from './system-service';
|
|
13
|
+
|
|
14
|
+
describe('SystemService', () => {
|
|
15
|
+
let systemService: SystemService;
|
|
16
|
+
let config: Config;
|
|
17
|
+
let statusUpdate: Event<void>;
|
|
18
|
+
let currentStatus: SystemStatus;
|
|
19
|
+
let updateStatus: Trigger<SystemStatus>;
|
|
20
|
+
let reset: Trigger<boolean>;
|
|
21
|
+
|
|
22
|
+
const changeStatus = (status: SystemStatus) => {
|
|
23
|
+
currentStatus = status;
|
|
24
|
+
statusUpdate.emit();
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
beforeEach(() => {
|
|
28
|
+
config = new Config({ runtime: { client: { log: { filter: 'system-service:debug' } } } });
|
|
29
|
+
statusUpdate = new Event<void>();
|
|
30
|
+
currentStatus = SystemStatus.ACTIVE;
|
|
31
|
+
updateStatus = new Trigger<SystemStatus>();
|
|
32
|
+
reset = new Trigger<boolean>();
|
|
33
|
+
|
|
34
|
+
systemService = new SystemServiceImpl({
|
|
35
|
+
config,
|
|
36
|
+
statusUpdate,
|
|
37
|
+
getCurrentStatus: () => currentStatus,
|
|
38
|
+
onUpdateStatus: (status) => {
|
|
39
|
+
updateStatus.wake(status);
|
|
40
|
+
},
|
|
41
|
+
onReset: () => {
|
|
42
|
+
reset.wake(true);
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
test('getConfig returns config', async () => {
|
|
48
|
+
expect(await systemService.getConfig()).to.deep.equal(config.values);
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
test('updateStatus triggers callback', async () => {
|
|
52
|
+
await systemService.updateStatus({ status: SystemStatus.INACTIVE });
|
|
53
|
+
const result = await updateStatus.wait();
|
|
54
|
+
expect(result).to.equal(SystemStatus.INACTIVE);
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
test('queryStatus returns initial status', async () => {
|
|
58
|
+
const status = new Trigger<SystemStatusResponse>();
|
|
59
|
+
systemService.queryStatus().subscribe((response) => {
|
|
60
|
+
status.wake(response);
|
|
61
|
+
});
|
|
62
|
+
expect(await status.wait()).to.deep.equal({ status: SystemStatus.ACTIVE });
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
test('queryStatus streams status changes', async () => {
|
|
66
|
+
const statuses: SystemStatus[] = [];
|
|
67
|
+
systemService.queryStatus().subscribe(({ status }) => {
|
|
68
|
+
statuses.push(status);
|
|
69
|
+
});
|
|
70
|
+
changeStatus(SystemStatus.INACTIVE);
|
|
71
|
+
changeStatus(SystemStatus.ACTIVE);
|
|
72
|
+
expect(statuses).to.deep.equal([SystemStatus.ACTIVE, SystemStatus.INACTIVE, SystemStatus.ACTIVE]);
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
test('reset triggers callback', async () => {
|
|
76
|
+
await systemService.reset();
|
|
77
|
+
const result = await reset.wait();
|
|
78
|
+
expect(result).to.be.true;
|
|
79
|
+
});
|
|
80
|
+
});
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2022 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { Event } from '@dxos/async';
|
|
6
|
+
import { Stream } from '@dxos/codec-protobuf';
|
|
7
|
+
import { Config } from '@dxos/config';
|
|
8
|
+
import {
|
|
9
|
+
SystemStatus,
|
|
10
|
+
SystemStatusResponse,
|
|
11
|
+
SystemService,
|
|
12
|
+
UpdateSystemStatusRequest
|
|
13
|
+
} from '@dxos/protocols/proto/dxos/client/services';
|
|
14
|
+
import { MaybePromise } from '@dxos/util';
|
|
15
|
+
|
|
16
|
+
export type SystemServiceOptions = {
|
|
17
|
+
config: Config;
|
|
18
|
+
statusUpdate: Event<void>;
|
|
19
|
+
getCurrentStatus: () => SystemStatus;
|
|
20
|
+
onUpdateStatus: (status: SystemStatus) => MaybePromise<void>;
|
|
21
|
+
onReset: () => MaybePromise<void>;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
*
|
|
26
|
+
*/
|
|
27
|
+
export class SystemServiceImpl implements SystemService {
|
|
28
|
+
private readonly _config: SystemServiceOptions['config'];
|
|
29
|
+
private readonly _statusUpdate: SystemServiceOptions['statusUpdate'];
|
|
30
|
+
private readonly _getCurrentStatus: SystemServiceOptions['getCurrentStatus'];
|
|
31
|
+
private readonly _onUpdateStatus: SystemServiceOptions['onUpdateStatus'];
|
|
32
|
+
private readonly _onReset: SystemServiceOptions['onReset'];
|
|
33
|
+
|
|
34
|
+
constructor({ config, statusUpdate, onUpdateStatus, getCurrentStatus, onReset }: SystemServiceOptions) {
|
|
35
|
+
this._config = config;
|
|
36
|
+
this._statusUpdate = statusUpdate;
|
|
37
|
+
this._getCurrentStatus = getCurrentStatus;
|
|
38
|
+
this._onUpdateStatus = onUpdateStatus;
|
|
39
|
+
this._onReset = onReset;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
async getConfig() {
|
|
43
|
+
return this._config.values;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
async updateStatus({ status }: UpdateSystemStatusRequest) {
|
|
47
|
+
await this._onUpdateStatus(status);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
queryStatus(): Stream<SystemStatusResponse> {
|
|
51
|
+
return new Stream(({ next }) => {
|
|
52
|
+
const update = () => {
|
|
53
|
+
next({ status: this._getCurrentStatus() });
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
update();
|
|
57
|
+
const unsubscribe = this._statusUpdate.on(() => update());
|
|
58
|
+
const interval = setInterval(update, 3000);
|
|
59
|
+
|
|
60
|
+
return () => {
|
|
61
|
+
clearInterval(interval);
|
|
62
|
+
unsubscribe();
|
|
63
|
+
};
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
async reset() {
|
|
68
|
+
await this._onReset();
|
|
69
|
+
}
|
|
70
|
+
}
|
|
@@ -5,14 +5,14 @@
|
|
|
5
5
|
import { Config } from '@dxos/config';
|
|
6
6
|
import { createCredentialSignerWithChain, CredentialGenerator } from '@dxos/credentials';
|
|
7
7
|
import {
|
|
8
|
+
SnapshotStore,
|
|
8
9
|
DataPipelineControllerImpl,
|
|
9
10
|
MetadataStore,
|
|
10
11
|
SigningContext,
|
|
11
|
-
SnapshotStore,
|
|
12
12
|
SpaceManager,
|
|
13
13
|
valueEncoding
|
|
14
|
-
} from '@dxos/echo-
|
|
15
|
-
import { testLocalDatabase } from '@dxos/echo-
|
|
14
|
+
} from '@dxos/echo-pipeline';
|
|
15
|
+
import { testLocalDatabase } from '@dxos/echo-pipeline/testing';
|
|
16
16
|
import { FeedFactory, FeedStore } from '@dxos/feed-store';
|
|
17
17
|
import { Keyring } from '@dxos/keyring';
|
|
18
18
|
import { MemorySignalManager, MemorySignalManagerContext } from '@dxos/messaging';
|
|
@@ -8,15 +8,17 @@ import { log, logInfo } from '@dxos/log';
|
|
|
8
8
|
import { MemorySignalManager, MemorySignalManagerContext, WebsocketSignalManager } from '@dxos/messaging';
|
|
9
9
|
import { createWebRTCTransportFactory, NetworkManager } from '@dxos/network-manager';
|
|
10
10
|
import { createProtoRpcPeer, ProtoRpcPeer, RpcPort } from '@dxos/rpc';
|
|
11
|
-
import {
|
|
11
|
+
import { getAsyncValue, Provider } from '@dxos/util';
|
|
12
12
|
|
|
13
13
|
import { clientServiceBundle, ClientServices, ClientServicesHost } from '../services';
|
|
14
|
+
import { ShellRuntime, ShellRuntimeImpl } from './shell-runtime';
|
|
14
15
|
|
|
15
16
|
const LOCK_KEY = 'DXOS_RESOURCE_LOCK';
|
|
16
17
|
|
|
17
18
|
export type IFrameHostRuntimeParams = {
|
|
18
|
-
configProvider:
|
|
19
|
+
configProvider: Config | Provider<Promise<Config>>;
|
|
19
20
|
appPort: RpcPort;
|
|
21
|
+
shellPort?: RpcPort;
|
|
20
22
|
};
|
|
21
23
|
|
|
22
24
|
/**
|
|
@@ -26,7 +28,7 @@ export type IFrameHostRuntimeParams = {
|
|
|
26
28
|
* This should only be used when SharedWorker is not available.
|
|
27
29
|
*/
|
|
28
30
|
export class IFrameHostRuntime {
|
|
29
|
-
private readonly _configProvider:
|
|
31
|
+
private readonly _configProvider: Config | Provider<Promise<Config>>;
|
|
30
32
|
private readonly _transportFactory = createWebRTCTransportFactory();
|
|
31
33
|
private readonly _ready = new Trigger<Error | undefined>();
|
|
32
34
|
private readonly _getService: <Service>(
|
|
@@ -34,16 +36,20 @@ export class IFrameHostRuntime {
|
|
|
34
36
|
) => Promise<Service>;
|
|
35
37
|
|
|
36
38
|
private readonly _appPort: RpcPort;
|
|
39
|
+
private readonly _shellPort?: RpcPort;
|
|
40
|
+
private _config!: Config;
|
|
37
41
|
private _clientServices!: ClientServicesHost;
|
|
38
42
|
private _clientRpc!: ProtoRpcPeer<ClientServices>;
|
|
39
|
-
private
|
|
43
|
+
private _shellRuntime?: ShellRuntimeImpl;
|
|
40
44
|
|
|
41
45
|
@logInfo
|
|
42
46
|
public origin?: string;
|
|
43
47
|
|
|
44
|
-
constructor({ configProvider, appPort }: IFrameHostRuntimeParams) {
|
|
48
|
+
constructor({ configProvider, appPort, shellPort }: IFrameHostRuntimeParams) {
|
|
45
49
|
this._configProvider = configProvider;
|
|
46
50
|
this._appPort = appPort;
|
|
51
|
+
this._shellPort = shellPort;
|
|
52
|
+
|
|
47
53
|
this._getService = async (find) => {
|
|
48
54
|
const error = await this._ready.wait();
|
|
49
55
|
if (error) {
|
|
@@ -57,12 +63,24 @@ export class IFrameHostRuntime {
|
|
|
57
63
|
|
|
58
64
|
return service;
|
|
59
65
|
};
|
|
66
|
+
|
|
67
|
+
if (this._shellPort) {
|
|
68
|
+
this._shellRuntime = new ShellRuntimeImpl(this._shellPort);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
get services() {
|
|
73
|
+
return this._clientServices;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
get shell(): ShellRuntime | undefined {
|
|
77
|
+
return this._shellRuntime;
|
|
60
78
|
}
|
|
61
79
|
|
|
62
80
|
async start() {
|
|
63
81
|
log('starting...');
|
|
64
82
|
try {
|
|
65
|
-
this._config = await this._configProvider
|
|
83
|
+
this._config = await getAsyncValue(this._configProvider);
|
|
66
84
|
const signalServer = this._config.get('runtime.services.signal.server');
|
|
67
85
|
this._clientServices = new ClientServicesHost({
|
|
68
86
|
lockKey: LOCK_KEY,
|
|
@@ -80,13 +98,12 @@ export class IFrameHostRuntime {
|
|
|
80
98
|
exposed: clientServiceBundle,
|
|
81
99
|
handlers: {
|
|
82
100
|
DataService: async () => await this._getService((services) => services.DataService),
|
|
101
|
+
DeviceInvitationsService: async () => await this._getService((services) => services.DeviceInvitationsService),
|
|
83
102
|
DevicesService: async () => await this._getService((services) => services.DevicesService),
|
|
84
103
|
DevtoolsHost: async () => await this._getService((services) => services.DevtoolsHost),
|
|
85
|
-
HaloInvitationsService: async () => await this._getService((services) => services.HaloInvitationsService),
|
|
86
104
|
NetworkService: async () => await this._getService((services) => services.NetworkService),
|
|
87
|
-
|
|
105
|
+
IdentityService: async () => await this._getService((services) => services.IdentityService),
|
|
88
106
|
SpaceInvitationsService: async () => await this._getService((services) => services.SpaceInvitationsService),
|
|
89
|
-
SpaceService: async () => await this._getService((services) => services.SpaceService),
|
|
90
107
|
SpacesService: async () => await this._getService((services) => services.SpacesService),
|
|
91
108
|
SystemService: async () => await this._getService((services) => services.SystemService),
|
|
92
109
|
TracingService: async () => await this._getService((services) => services.TracingService)
|
|
@@ -94,7 +111,7 @@ export class IFrameHostRuntime {
|
|
|
94
111
|
port: this._appPort
|
|
95
112
|
});
|
|
96
113
|
|
|
97
|
-
await Promise.all([this._clientServices.open(), this._clientRpc.open()]);
|
|
114
|
+
await Promise.all([this._clientServices.open(), this._clientRpc.open(), this._shellRuntime?.open()]);
|
|
98
115
|
this._ready.wake(undefined);
|
|
99
116
|
log('started');
|
|
100
117
|
} catch (err: any) {
|
|
@@ -107,6 +124,7 @@ export class IFrameHostRuntime {
|
|
|
107
124
|
log('stopping...');
|
|
108
125
|
await this._clientRpc.close();
|
|
109
126
|
await this._clientServices.close();
|
|
127
|
+
await this._shellRuntime?.close();
|
|
110
128
|
log('stopped');
|
|
111
129
|
}
|
|
112
130
|
}
|
|
@@ -7,12 +7,14 @@ import { BridgeService } from '@dxos/protocols/proto/dxos/mesh/bridge';
|
|
|
7
7
|
import { createProtoRpcPeer, ProtoRpcPeer, RpcPort } from '@dxos/rpc';
|
|
8
8
|
|
|
9
9
|
import { iframeServiceBundle, WorkerServiceBundle, workerServiceBundle } from './services';
|
|
10
|
+
import { ShellRuntime, ShellRuntimeImpl } from './shell-runtime';
|
|
10
11
|
|
|
11
12
|
// NOTE: Keep as RpcPorts to avoid dependency on @dxos/rpc-tunnel so we don't depend on browser-specific apis.
|
|
12
13
|
export type IFrameProxyRuntimeParams = {
|
|
13
14
|
systemPort: RpcPort;
|
|
14
15
|
workerAppPort: RpcPort;
|
|
15
16
|
windowAppPort: RpcPort;
|
|
17
|
+
shellPort?: RpcPort;
|
|
16
18
|
};
|
|
17
19
|
|
|
18
20
|
/**
|
|
@@ -22,13 +24,16 @@ export class IFrameProxyRuntime {
|
|
|
22
24
|
private readonly _systemPort: RpcPort;
|
|
23
25
|
private readonly _windowAppPort: RpcPort;
|
|
24
26
|
private readonly _workerAppPort: RpcPort;
|
|
27
|
+
private readonly _shellPort?: RpcPort;
|
|
25
28
|
private readonly _systemRpc: ProtoRpcPeer<WorkerServiceBundle>;
|
|
29
|
+
private readonly _shellRuntime?: ShellRuntimeImpl;
|
|
26
30
|
private readonly _transportService = new WebRTCTransportService();
|
|
27
31
|
|
|
28
|
-
constructor({ systemPort, workerAppPort, windowAppPort }: IFrameProxyRuntimeParams) {
|
|
32
|
+
constructor({ systemPort, workerAppPort, windowAppPort, shellPort }: IFrameProxyRuntimeParams) {
|
|
29
33
|
this._systemPort = systemPort;
|
|
30
34
|
this._windowAppPort = windowAppPort;
|
|
31
35
|
this._workerAppPort = workerAppPort;
|
|
36
|
+
this._shellPort = shellPort;
|
|
32
37
|
|
|
33
38
|
this._systemRpc = createProtoRpcPeer({
|
|
34
39
|
requested: workerServiceBundle,
|
|
@@ -47,14 +52,24 @@ export class IFrameProxyRuntime {
|
|
|
47
52
|
|
|
48
53
|
this._workerAppPort.subscribe((msg) => this._windowAppPort.send(msg));
|
|
49
54
|
this._windowAppPort.subscribe((msg) => this._workerAppPort.send(msg));
|
|
55
|
+
|
|
56
|
+
if (this._shellPort) {
|
|
57
|
+
this._shellRuntime = new ShellRuntimeImpl(this._shellPort);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
get shell(): ShellRuntime | undefined {
|
|
62
|
+
return this._shellRuntime;
|
|
50
63
|
}
|
|
51
64
|
|
|
52
65
|
async open(origin: string) {
|
|
53
66
|
await this._systemRpc.open();
|
|
54
67
|
await this._systemRpc.rpc.WorkerService.start({ origin });
|
|
68
|
+
await this._shellRuntime?.open();
|
|
55
69
|
}
|
|
56
70
|
|
|
57
71
|
async close() {
|
|
72
|
+
await this._shellRuntime?.close();
|
|
58
73
|
await this._systemRpc.rpc.WorkerService.stop();
|
|
59
74
|
await this._systemRpc.close();
|
|
60
75
|
}
|
|
@@ -5,6 +5,8 @@
|
|
|
5
5
|
export * from './iframe-host-runtime';
|
|
6
6
|
export * from './iframe-proxy-runtime';
|
|
7
7
|
export * from './services';
|
|
8
|
+
export * from './shell-controller';
|
|
9
|
+
export * from './shell-runtime';
|
|
8
10
|
export * from './vault-resource-lock';
|
|
9
11
|
export * from './worker-runtime';
|
|
10
12
|
export * from './worker-session';
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
//
|
|
4
4
|
|
|
5
5
|
import { schema } from '@dxos/protocols';
|
|
6
|
-
import type { IframeService, WorkerService } from '@dxos/protocols/proto/dxos/iframe';
|
|
6
|
+
import type { IframeService, AppService, ShellService, WorkerService } from '@dxos/protocols/proto/dxos/iframe';
|
|
7
7
|
import type { BridgeService } from '@dxos/protocols/proto/dxos/mesh/bridge';
|
|
8
8
|
import { ServiceBundle } from '@dxos/rpc';
|
|
9
9
|
|
|
@@ -24,3 +24,19 @@ export type WorkerServiceBundle = {
|
|
|
24
24
|
export const workerServiceBundle: ServiceBundle<WorkerServiceBundle> = {
|
|
25
25
|
WorkerService: schema.getService('dxos.iframe.WorkerService')
|
|
26
26
|
};
|
|
27
|
+
|
|
28
|
+
export type AppServiceBundle = {
|
|
29
|
+
AppService: AppService;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
export const appServiceBundle: ServiceBundle<AppServiceBundle> = {
|
|
33
|
+
AppService: schema.getService('dxos.iframe.AppService')
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
export type ShellServiceBundle = {
|
|
37
|
+
ShellService: ShellService;
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
export const shellServiceBundle: ServiceBundle<ShellServiceBundle> = {
|
|
41
|
+
ShellService: schema.getService('dxos.iframe.ShellService')
|
|
42
|
+
};
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2023 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { Event } from '@dxos/async';
|
|
6
|
+
import { log } from '@dxos/log';
|
|
7
|
+
import { AppContextRequest, LayoutRequest, ShellDisplay, ShellLayout } from '@dxos/protocols/proto/dxos/iframe';
|
|
8
|
+
import { createProtoRpcPeer, ProtoRpcPeer, RpcPort } from '@dxos/rpc';
|
|
9
|
+
|
|
10
|
+
import { appServiceBundle, shellServiceBundle, ShellServiceBundle } from './services';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Provide access to the shell via RPC connection.
|
|
14
|
+
*/
|
|
15
|
+
export class ShellController {
|
|
16
|
+
readonly contextUpdate = new Event<AppContextRequest>();
|
|
17
|
+
private _shellRpc?: ProtoRpcPeer<ShellServiceBundle>;
|
|
18
|
+
private _display = ShellDisplay.NONE;
|
|
19
|
+
|
|
20
|
+
constructor(private readonly _port: RpcPort) {}
|
|
21
|
+
|
|
22
|
+
get display() {
|
|
23
|
+
return this._display;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
async setLayout(layout: ShellLayout, options: Omit<LayoutRequest, 'layout'> = {}) {
|
|
27
|
+
log('set layout', { layout, ...options });
|
|
28
|
+
this._display = ShellDisplay.FULLSCREEN;
|
|
29
|
+
this.contextUpdate.emit({ display: this._display });
|
|
30
|
+
await this._shellRpc?.rpc.ShellService.setLayout({ layout, ...options });
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
async open() {
|
|
34
|
+
this._shellRpc = createProtoRpcPeer({
|
|
35
|
+
requested: shellServiceBundle,
|
|
36
|
+
exposed: appServiceBundle,
|
|
37
|
+
handlers: {
|
|
38
|
+
AppService: {
|
|
39
|
+
setContext: async (request) => {
|
|
40
|
+
log('set context', request);
|
|
41
|
+
this._display = request.display;
|
|
42
|
+
this.contextUpdate.emit(request);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
port: this._port
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
await this._shellRpc.open();
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
async close() {
|
|
53
|
+
await this._shellRpc?.close();
|
|
54
|
+
this._shellRpc = undefined;
|
|
55
|
+
}
|
|
56
|
+
}
|