@dxos/client-services 0.4.10-main.ec8b427 → 0.4.10-main.ef6fbc2
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-4NKBBUMB.mjs → chunk-2B66DLAB.mjs} +202 -89
- package/dist/lib/browser/{chunk-4NKBBUMB.mjs.map → chunk-2B66DLAB.mjs.map} +4 -4
- package/dist/lib/browser/index.mjs +50 -20
- package/dist/lib/browser/index.mjs.map +3 -3
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/packlets/testing/index.mjs +6 -4
- package/dist/lib/browser/packlets/testing/index.mjs.map +3 -3
- package/dist/lib/node/{chunk-5YRLBMIC.cjs → chunk-Y7UTCQRW.cjs} +200 -92
- package/dist/lib/node/chunk-Y7UTCQRW.cjs.map +7 -0
- package/dist/lib/node/index.cjs +87 -57
- package/dist/lib/node/index.cjs.map +3 -3
- package/dist/lib/node/meta.json +1 -1
- package/dist/lib/node/packlets/testing/index.cjs +10 -8
- package/dist/lib/node/packlets/testing/index.cjs.map +3 -3
- package/dist/types/src/packlets/indexing/util.d.ts +2 -2
- package/dist/types/src/packlets/indexing/util.d.ts.map +1 -1
- package/dist/types/src/packlets/services/service-context.d.ts +7 -5
- 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.d.ts.map +1 -1
- package/dist/types/src/packlets/storage/index.d.ts +1 -0
- package/dist/types/src/packlets/storage/index.d.ts.map +1 -1
- package/dist/types/src/packlets/storage/level.d.ts +4 -0
- package/dist/types/src/packlets/storage/level.d.ts.map +1 -0
- package/dist/types/src/packlets/storage/storage.d.ts.map +1 -1
- package/dist/types/src/packlets/storage/util.d.ts +4 -0
- package/dist/types/src/packlets/storage/util.d.ts.map +1 -0
- 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/shared-worker-connection.d.ts +5 -5
- package/dist/types/src/packlets/vault/shared-worker-connection.d.ts.map +1 -1
- package/dist/types/src/packlets/vault/worker-runtime.d.ts +2 -0
- package/dist/types/src/packlets/vault/worker-runtime.d.ts.map +1 -1
- package/dist/types/src/packlets/vault/worker-session.d.ts +2 -0
- package/dist/types/src/packlets/vault/worker-session.d.ts.map +1 -1
- package/dist/types/src/version.d.ts +1 -1
- package/package.json +35 -34
- package/src/packlets/devices/devices-service.test.ts +1 -1
- package/src/packlets/identity/identity-service.test.ts +1 -1
- package/src/packlets/indexing/util.ts +4 -4
- package/src/packlets/invitations/device-invitation-protocol.test.ts +1 -1
- package/src/packlets/network/network-service.test.ts +1 -1
- package/src/packlets/services/service-context.test.ts +5 -5
- package/src/packlets/services/service-context.ts +13 -8
- package/src/packlets/services/service-host.ts +32 -8
- package/src/packlets/services/service-registry.test.ts +1 -1
- package/src/packlets/spaces/data-space.ts +51 -2
- package/src/packlets/spaces/spaces-service.test.ts +1 -1
- package/src/packlets/storage/index.ts +1 -0
- package/src/packlets/storage/level.ts +19 -0
- package/src/packlets/storage/storage.ts +3 -9
- package/src/packlets/storage/util.ts +19 -0
- package/src/packlets/testing/test-builder.ts +5 -3
- package/src/packlets/vault/shared-worker-connection.ts +3 -8
- package/src/packlets/vault/worker-runtime.ts +27 -2
- package/src/packlets/vault/worker-session.ts +6 -0
- package/src/version.ts +1 -1
- package/dist/lib/node/chunk-5YRLBMIC.cjs.map +0 -7
|
@@ -2,8 +2,10 @@
|
|
|
2
2
|
// Copyright 2022 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
+
import { type Level } from 'level';
|
|
6
|
+
|
|
5
7
|
import { Trigger } from '@dxos/async';
|
|
6
|
-
import { Context } from '@dxos/context';
|
|
8
|
+
import { Context, Resource } from '@dxos/context';
|
|
7
9
|
import { getCredentialAssertion, type CredentialProcessor } from '@dxos/credentials';
|
|
8
10
|
import { failUndefined } from '@dxos/debug';
|
|
9
11
|
import { AutomergeHost, MetadataStore, SnapshotStore, SpaceManager, valueEncoding } from '@dxos/echo-pipeline';
|
|
@@ -30,7 +32,7 @@ import {
|
|
|
30
32
|
type IdentityManagerRuntimeParams,
|
|
31
33
|
type JoinIdentityParams,
|
|
32
34
|
} from '../identity';
|
|
33
|
-
import {
|
|
35
|
+
import { createDocumentsIterator, createSelectedDocumentsIterator } from '../indexing';
|
|
34
36
|
import {
|
|
35
37
|
DeviceInvitationProtocol,
|
|
36
38
|
InvitationsHandler,
|
|
@@ -47,7 +49,7 @@ export type ServiceContextRuntimeParams = IdentityManagerRuntimeParams & DataSpa
|
|
|
47
49
|
// TODO(dmaretskyi): Gets duplicated in CJS build between normal and testing bundles.
|
|
48
50
|
@safeInstanceof('dxos.client-services.ServiceContext')
|
|
49
51
|
@Trace.resource()
|
|
50
|
-
export class ServiceContext {
|
|
52
|
+
export class ServiceContext extends Resource {
|
|
51
53
|
public readonly initialized = new Trigger();
|
|
52
54
|
public readonly metadataStore: MetadataStore;
|
|
53
55
|
/**
|
|
@@ -78,10 +80,13 @@ export class ServiceContext {
|
|
|
78
80
|
|
|
79
81
|
constructor(
|
|
80
82
|
public readonly storage: Storage,
|
|
83
|
+
public readonly level: Level<string, string>,
|
|
81
84
|
public readonly networkManager: NetworkManager,
|
|
82
85
|
public readonly signalManager: SignalManager,
|
|
83
86
|
public readonly _runtimeParams?: IdentityManagerRuntimeParams & DataSpaceManagerRuntimeParams,
|
|
84
87
|
) {
|
|
88
|
+
super();
|
|
89
|
+
|
|
85
90
|
// TODO(burdon): Move strings to constants.
|
|
86
91
|
this.metadataStore = new MetadataStore(storage.createDirectory('metadata'));
|
|
87
92
|
this.snapshotStore = new SnapshotStore(storage.createDirectory('snapshots'));
|
|
@@ -115,7 +120,7 @@ export class ServiceContext {
|
|
|
115
120
|
this._runtimeParams as IdentityManagerRuntimeParams,
|
|
116
121
|
);
|
|
117
122
|
|
|
118
|
-
this.indexMetadata = new IndexMetadataStore({
|
|
123
|
+
this.indexMetadata = new IndexMetadataStore({ db: level.sublevel('index-metadata') });
|
|
119
124
|
|
|
120
125
|
this.automergeHost = new AutomergeHost({
|
|
121
126
|
directory: storage.createDirectory('automerge'),
|
|
@@ -125,8 +130,8 @@ export class ServiceContext {
|
|
|
125
130
|
this.indexer = new Indexer({
|
|
126
131
|
indexStore: new IndexStore({ directory: storage.createDirectory('index-store') }),
|
|
127
132
|
metadataStore: this.indexMetadata,
|
|
128
|
-
loadDocuments:
|
|
129
|
-
getAllDocuments:
|
|
133
|
+
loadDocuments: createSelectedDocumentsIterator(this.automergeHost),
|
|
134
|
+
getAllDocuments: createDocumentsIterator(this.automergeHost),
|
|
130
135
|
});
|
|
131
136
|
|
|
132
137
|
this.invitations = new InvitationsHandler(this.networkManager);
|
|
@@ -145,7 +150,7 @@ export class ServiceContext {
|
|
|
145
150
|
}
|
|
146
151
|
|
|
147
152
|
@Trace.span()
|
|
148
|
-
async
|
|
153
|
+
protected override async _open(ctx: Context) {
|
|
149
154
|
await this._checkStorageVersion();
|
|
150
155
|
|
|
151
156
|
log('opening...');
|
|
@@ -163,7 +168,7 @@ export class ServiceContext {
|
|
|
163
168
|
log('opened');
|
|
164
169
|
}
|
|
165
170
|
|
|
166
|
-
async
|
|
171
|
+
protected override async _close() {
|
|
167
172
|
log('closing...');
|
|
168
173
|
if (this._deviceSpaceSync && this.identityManager.identity) {
|
|
169
174
|
await this.identityManager.identity.space.spaceState.removeCredentialProcessor(this._deviceSpaceSync);
|
|
@@ -2,12 +2,14 @@
|
|
|
2
2
|
// Copyright 2021 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
+
import { type Level } from 'level';
|
|
6
|
+
|
|
5
7
|
import { Event, synchronized } from '@dxos/async';
|
|
6
|
-
import {
|
|
8
|
+
import { clientServiceBundle, defaultKey, type ClientServices, Properties } from '@dxos/client-protocol';
|
|
7
9
|
import { type Config } from '@dxos/config';
|
|
8
10
|
import { Context } from '@dxos/context';
|
|
9
|
-
import { DataServiceImpl } from '@dxos/echo-pipeline';
|
|
10
|
-
import
|
|
11
|
+
import { DataServiceImpl, type ObjectStructure, encodeReference, type SpaceDoc } from '@dxos/echo-pipeline';
|
|
12
|
+
import * as E from '@dxos/echo-schema';
|
|
11
13
|
import { IndexServiceImpl } from '@dxos/indexing';
|
|
12
14
|
import { invariant } from '@dxos/invariant';
|
|
13
15
|
import { PublicKey } from '@dxos/keys';
|
|
@@ -32,7 +34,7 @@ import { Lock, type ResourceLock } from '../locks';
|
|
|
32
34
|
import { LoggingServiceImpl } from '../logging';
|
|
33
35
|
import { NetworkServiceImpl } from '../network';
|
|
34
36
|
import { SpacesServiceImpl } from '../spaces';
|
|
35
|
-
import { createStorageObjects } from '../storage';
|
|
37
|
+
import { createLevel, createStorageObjects } from '../storage';
|
|
36
38
|
import { SystemServiceImpl } from '../system';
|
|
37
39
|
|
|
38
40
|
export type ClientServicesHostParams = {
|
|
@@ -76,6 +78,7 @@ export class ClientServicesHost {
|
|
|
76
78
|
private _signalManager?: SignalManager;
|
|
77
79
|
private _networkManager?: NetworkManager;
|
|
78
80
|
private _storage?: Storage;
|
|
81
|
+
private _level?: Level<string, string>;
|
|
79
82
|
private _callbacks?: ClientServicesHostCallbacks;
|
|
80
83
|
private _devtoolsProxy?: WebsocketRpcClient<{}, ClientServices>;
|
|
81
84
|
|
|
@@ -187,6 +190,9 @@ export class ClientServicesHost {
|
|
|
187
190
|
}
|
|
188
191
|
}
|
|
189
192
|
|
|
193
|
+
if (!options.signalManager) {
|
|
194
|
+
log.warn('running signaling without telemetry metadata.');
|
|
195
|
+
}
|
|
190
196
|
const {
|
|
191
197
|
connectionLog = true,
|
|
192
198
|
transportFactory = createSimplePeerTransportFactory({
|
|
@@ -223,12 +229,17 @@ export class ClientServicesHost {
|
|
|
223
229
|
|
|
224
230
|
this._opening = true;
|
|
225
231
|
log('opening...', { lockKey: this._resourceLock?.lockKey });
|
|
232
|
+
|
|
233
|
+
if (!this._level) {
|
|
234
|
+
this._level = await createLevel(this._config.get('runtime.client.storage', {})!);
|
|
235
|
+
}
|
|
226
236
|
await this._resourceLock?.acquire();
|
|
227
237
|
|
|
228
238
|
await this._loggingService.open();
|
|
229
239
|
|
|
230
240
|
this._serviceContext = new ServiceContext(
|
|
231
241
|
this._storage,
|
|
242
|
+
this._level,
|
|
232
243
|
this._networkManager,
|
|
233
244
|
this._signalManager,
|
|
234
245
|
this._runtimeParams,
|
|
@@ -320,6 +331,7 @@ export class ClientServicesHost {
|
|
|
320
331
|
this._serviceRegistry.setServices({ SystemService: this._systemService });
|
|
321
332
|
await this._loggingService.close();
|
|
322
333
|
await this._serviceContext.close();
|
|
334
|
+
await this._level?.close();
|
|
323
335
|
this._open = false;
|
|
324
336
|
this._statusUpdate.emit();
|
|
325
337
|
log('closed', { deviceKey });
|
|
@@ -344,18 +356,30 @@ export class ClientServicesHost {
|
|
|
344
356
|
await this._serviceContext.initialized.wait();
|
|
345
357
|
const space = await this._serviceContext.dataSpaceManager!.createSpace();
|
|
346
358
|
|
|
347
|
-
const obj: TypedObject = new Properties(undefined);
|
|
348
|
-
obj[defaultKey] = identity.identityKey.toHex();
|
|
349
|
-
|
|
350
359
|
const automergeIndex = space.automergeSpaceState.rootUrl;
|
|
351
360
|
invariant(automergeIndex);
|
|
352
361
|
const document = await this._serviceContext.automergeHost.repo.find<SpaceDoc>(automergeIndex as any);
|
|
353
362
|
await document.whenReady();
|
|
354
363
|
|
|
364
|
+
// TODO(dmaretskyi): Better API for low-level data access.
|
|
365
|
+
const properties: ObjectStructure = {
|
|
366
|
+
system: {
|
|
367
|
+
type: encodeReference(E.getTypeReference(Properties)!),
|
|
368
|
+
},
|
|
369
|
+
data: {
|
|
370
|
+
[defaultKey]: identity.identityKey.toHex(),
|
|
371
|
+
},
|
|
372
|
+
meta: {
|
|
373
|
+
keys: [],
|
|
374
|
+
},
|
|
375
|
+
};
|
|
376
|
+
const propertiesId = PublicKey.random().toHex();
|
|
355
377
|
document.change((doc: SpaceDoc) => {
|
|
356
|
-
assignDeep(doc, ['objects',
|
|
378
|
+
assignDeep(doc, ['objects', propertiesId], properties);
|
|
357
379
|
});
|
|
358
380
|
|
|
381
|
+
await this._serviceContext.automergeHost.repo.flush();
|
|
382
|
+
|
|
359
383
|
return identity;
|
|
360
384
|
}
|
|
361
385
|
}
|
|
@@ -31,7 +31,7 @@ const serviceBundle = createServiceBundle<TestServices>({
|
|
|
31
31
|
describe('service registry', () => {
|
|
32
32
|
test('builds a service registry', async () => {
|
|
33
33
|
const remoteSource = 'https://remote.source';
|
|
34
|
-
const serviceContext = createServiceContext();
|
|
34
|
+
const serviceContext = await createServiceContext();
|
|
35
35
|
await serviceContext.open(new Context());
|
|
36
36
|
|
|
37
37
|
const serviceRegistry = new ServiceRegistry(serviceBundle, {
|
|
@@ -6,7 +6,15 @@ import { Event, asyncTimeout, scheduleTask, sleep, synchronized, trackLeaks } fr
|
|
|
6
6
|
import { AUTH_TIMEOUT } from '@dxos/client-protocol';
|
|
7
7
|
import { cancelWithContext, Context, ContextDisposedError } from '@dxos/context';
|
|
8
8
|
import { timed, warnAfterTimeout } from '@dxos/debug';
|
|
9
|
-
import {
|
|
9
|
+
import { TYPE_PROPERTIES } from '@dxos/echo-db';
|
|
10
|
+
import {
|
|
11
|
+
type MetadataStore,
|
|
12
|
+
type Space,
|
|
13
|
+
createMappedFeedWriter,
|
|
14
|
+
type AutomergeHost,
|
|
15
|
+
type SpaceDoc,
|
|
16
|
+
} from '@dxos/echo-pipeline';
|
|
17
|
+
import { AutomergeDocumentLoaderImpl } from '@dxos/echo-pipeline';
|
|
10
18
|
import { type FeedStore } from '@dxos/feed-store';
|
|
11
19
|
import { failedInvariant, invariant } from '@dxos/invariant';
|
|
12
20
|
import { type Keyring } from '@dxos/keyring';
|
|
@@ -26,7 +34,7 @@ import { type GossipMessage } from '@dxos/protocols/proto/dxos/mesh/teleport/gos
|
|
|
26
34
|
import { type Gossip, type Presence } from '@dxos/teleport-extension-gossip';
|
|
27
35
|
import { Timeframe } from '@dxos/timeframe';
|
|
28
36
|
import { trace } from '@dxos/tracing';
|
|
29
|
-
import { ComplexSet } from '@dxos/util';
|
|
37
|
+
import { ComplexSet, assignDeep } from '@dxos/util';
|
|
30
38
|
|
|
31
39
|
import { AutomergeSpaceState } from './automerge-space-state';
|
|
32
40
|
import { type SigningContext } from './data-space-manager';
|
|
@@ -437,6 +445,47 @@ export class DataSpace {
|
|
|
437
445
|
};
|
|
438
446
|
}
|
|
439
447
|
break;
|
|
448
|
+
case CreateEpochRequest.Migration.FRAGMENT_AUTOMERGE_ROOT:
|
|
449
|
+
{
|
|
450
|
+
log.info('Fragmenting');
|
|
451
|
+
|
|
452
|
+
const currentRootUrl = this._automergeSpaceState.rootUrl;
|
|
453
|
+
const rootHandle = this._automergeHost.repo.find<SpaceDoc>(currentRootUrl as any);
|
|
454
|
+
await cancelWithContext(this._ctx, asyncTimeout(rootHandle.whenReady(), 10_000));
|
|
455
|
+
|
|
456
|
+
// Find properties object.
|
|
457
|
+
const objects = Object.entries((rootHandle.docSync() as SpaceDoc).objects!);
|
|
458
|
+
const properties = objects.find(([_, value]) => value.system.type?.itemId === TYPE_PROPERTIES);
|
|
459
|
+
const otherObjects = objects.filter(([key]) => key !== properties?.[0]);
|
|
460
|
+
invariant(properties, 'Properties not found');
|
|
461
|
+
|
|
462
|
+
// Create a new space doc with the properties object.
|
|
463
|
+
const newSpaceDoc: SpaceDoc = { ...rootHandle.docSync(), objects: Object.fromEntries([properties]) };
|
|
464
|
+
const newRoot = this._automergeHost.repo.create(newSpaceDoc);
|
|
465
|
+
invariant(typeof newRoot.url === 'string' && newRoot.url.length > 0);
|
|
466
|
+
|
|
467
|
+
// Create new automerge documents for all objects.
|
|
468
|
+
const docLoader = new AutomergeDocumentLoaderImpl(this.key, this._automergeHost.repo);
|
|
469
|
+
await docLoader.loadSpaceRootDocHandle(this._ctx, { rootUrl: newRoot.url });
|
|
470
|
+
|
|
471
|
+
otherObjects.forEach(([key, value]) => {
|
|
472
|
+
const handle = docLoader.createDocumentForObject(key);
|
|
473
|
+
handle.change((doc: any) => {
|
|
474
|
+
assignDeep(doc, ['objects', key], value);
|
|
475
|
+
});
|
|
476
|
+
});
|
|
477
|
+
|
|
478
|
+
// TODO(mykola): Delete old root.
|
|
479
|
+
|
|
480
|
+
// TODO(dmaretskyi): Unify epoch construction.
|
|
481
|
+
epoch = {
|
|
482
|
+
previousId: this._automergeSpaceState.lastEpoch?.id,
|
|
483
|
+
number: (this._automergeSpaceState.lastEpoch?.subject.assertion.number ?? -1) + 1,
|
|
484
|
+
timeframe: this._automergeSpaceState.lastEpoch?.subject.assertion.timeframe ?? new Timeframe(),
|
|
485
|
+
automergeRoot: newRoot.url,
|
|
486
|
+
};
|
|
487
|
+
}
|
|
488
|
+
break;
|
|
440
489
|
}
|
|
441
490
|
|
|
442
491
|
if (!epoch) {
|
|
@@ -22,7 +22,7 @@ describe('SpacesService', () => {
|
|
|
22
22
|
let spacesService: SpacesService;
|
|
23
23
|
|
|
24
24
|
beforeEach(async () => {
|
|
25
|
-
serviceContext = createServiceContext();
|
|
25
|
+
serviceContext = await createServiceContext();
|
|
26
26
|
await serviceContext.open(new Context());
|
|
27
27
|
spacesService = new SpacesServiceImpl(serviceContext.identityManager, serviceContext.spaceManager, async () => {
|
|
28
28
|
await serviceContext.initialized.wait();
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2024 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { Level } from 'level';
|
|
6
|
+
import path from 'node:path';
|
|
7
|
+
|
|
8
|
+
import { PublicKey } from '@dxos/keys';
|
|
9
|
+
import { type Runtime } from '@dxos/protocols/proto/dxos/config';
|
|
10
|
+
|
|
11
|
+
import { getRootPath, isPersistent } from './util';
|
|
12
|
+
|
|
13
|
+
export const createLevel = async (config: Runtime.Client.Storage) => {
|
|
14
|
+
const persistent = isPersistent(config);
|
|
15
|
+
const storagePath = persistent ? getRootPath(config) : path.join('tmp', 'level', PublicKey.random().toHex());
|
|
16
|
+
const level = new Level<string, string>(storagePath);
|
|
17
|
+
await level.open();
|
|
18
|
+
return level;
|
|
19
|
+
};
|
|
@@ -4,22 +4,16 @@
|
|
|
4
4
|
// Copyright 2023 DXOS.org
|
|
5
5
|
//
|
|
6
6
|
|
|
7
|
-
import { DX_DATA } from '@dxos/client-protocol';
|
|
8
7
|
import { InvalidConfigError } from '@dxos/protocols';
|
|
9
8
|
import { Runtime } from '@dxos/protocols/proto/dxos/config';
|
|
10
9
|
import { createStorage, StorageType } from '@dxos/random-access-storage';
|
|
11
|
-
import { isNode } from '@dxos/util';
|
|
12
10
|
|
|
13
11
|
import StorageDriver = Runtime.Client.Storage.StorageDriver;
|
|
12
|
+
import { getRootPath } from './util';
|
|
14
13
|
|
|
15
14
|
// TODO(burdon): Factor out.
|
|
16
15
|
export const createStorageObjects = (config: Runtime.Client.Storage) => {
|
|
17
|
-
const {
|
|
18
|
-
persistent = false,
|
|
19
|
-
keyStore,
|
|
20
|
-
dataStore,
|
|
21
|
-
dataRoot = isNode() ? DX_DATA : 'dxos/storage', // TODO(burdon): Factor out const.
|
|
22
|
-
} = config ?? {};
|
|
16
|
+
const { persistent = false, keyStore, dataStore } = config ?? {};
|
|
23
17
|
|
|
24
18
|
if (persistent && dataStore === StorageDriver.RAM) {
|
|
25
19
|
throw new InvalidConfigError('RAM storage cannot be used in persistent mode.');
|
|
@@ -37,7 +31,7 @@ export const createStorageObjects = (config: Runtime.Client.Storage) => {
|
|
|
37
31
|
return {
|
|
38
32
|
storage: createStorage({
|
|
39
33
|
type: persistent ? toStorageType(dataStore) : StorageType.RAM,
|
|
40
|
-
root:
|
|
34
|
+
root: getRootPath(config),
|
|
41
35
|
}),
|
|
42
36
|
};
|
|
43
37
|
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2024 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { DX_DATA } from '@dxos/client-protocol';
|
|
6
|
+
import { Runtime } from '@dxos/protocols/proto/dxos/config';
|
|
7
|
+
import { isNode } from '@dxos/util';
|
|
8
|
+
|
|
9
|
+
export const getRootPath = (config: Runtime.Client.Storage) => {
|
|
10
|
+
const { dataRoot = isNode() ? DX_DATA : 'dxos/storage' } = config ?? {};
|
|
11
|
+
return `${dataRoot}/`;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export const isPersistent = (config: Runtime.Client.Storage) => {
|
|
15
|
+
const { persistent = false } = config ?? {};
|
|
16
|
+
return (
|
|
17
|
+
(config.dataStore !== undefined && config.dataStore !== Runtime.Client.Storage.StorageDriver.RAM) || persistent
|
|
18
|
+
);
|
|
19
|
+
};
|
|
@@ -8,6 +8,7 @@ import { createCredentialSignerWithChain, CredentialGenerator } from '@dxos/cred
|
|
|
8
8
|
import { failUndefined } from '@dxos/debug';
|
|
9
9
|
import { AutomergeHost, MetadataStore, SnapshotStore, SpaceManager, valueEncoding } from '@dxos/echo-pipeline';
|
|
10
10
|
import { FeedFactory, FeedStore } from '@dxos/feed-store';
|
|
11
|
+
import { createTestLevel } from '@dxos/indexing/testing';
|
|
11
12
|
import { Keyring } from '@dxos/keyring';
|
|
12
13
|
import { MemorySignalManager, MemorySignalManagerContext } from '@dxos/messaging';
|
|
13
14
|
import { MemoryTransportFactory, NetworkManager } from '@dxos/network-manager';
|
|
@@ -29,7 +30,7 @@ export const createServiceHost = (config: Config, signalManagerContext: MemorySi
|
|
|
29
30
|
});
|
|
30
31
|
};
|
|
31
32
|
|
|
32
|
-
export const createServiceContext = ({
|
|
33
|
+
export const createServiceContext = async ({
|
|
33
34
|
signalContext = new MemorySignalManagerContext(),
|
|
34
35
|
storage = createStorage({ type: StorageType.RAM }),
|
|
35
36
|
}: {
|
|
@@ -41,8 +42,9 @@ export const createServiceContext = ({
|
|
|
41
42
|
signalManager,
|
|
42
43
|
transportFactory: MemoryTransportFactory,
|
|
43
44
|
});
|
|
45
|
+
const level = await createTestLevel();
|
|
44
46
|
|
|
45
|
-
return new ServiceContext(storage, networkManager, signalManager);
|
|
47
|
+
return new ServiceContext(storage, level, networkManager, signalManager);
|
|
46
48
|
};
|
|
47
49
|
|
|
48
50
|
export const createPeers = async (numPeers: number) => {
|
|
@@ -50,7 +52,7 @@ export const createPeers = async (numPeers: number) => {
|
|
|
50
52
|
|
|
51
53
|
return await Promise.all(
|
|
52
54
|
Array.from(Array(numPeers)).map(async () => {
|
|
53
|
-
const peer = createServiceContext({ signalContext });
|
|
55
|
+
const peer = await createServiceContext({ signalContext });
|
|
54
56
|
await peer.open(new Context());
|
|
55
57
|
return peer;
|
|
56
58
|
}),
|
|
@@ -57,12 +57,7 @@ export class SharedWorkerConnection {
|
|
|
57
57
|
return this._shellRuntime;
|
|
58
58
|
}
|
|
59
59
|
|
|
60
|
-
async open(
|
|
61
|
-
/**
|
|
62
|
-
* @deprecated Only used with iframes.
|
|
63
|
-
*/
|
|
64
|
-
origin: string,
|
|
65
|
-
) {
|
|
60
|
+
async open(params: { origin: string; observabilityGroup?: string; signalTelemetryEnabled?: boolean }) {
|
|
66
61
|
this._config = await getAsyncValue(this._configProvider);
|
|
67
62
|
|
|
68
63
|
this._transportService = new SimplePeerTransportService({
|
|
@@ -83,7 +78,7 @@ export class SharedWorkerConnection {
|
|
|
83
78
|
|
|
84
79
|
let lockKey: string | undefined;
|
|
85
80
|
if (typeof navigator !== 'undefined') {
|
|
86
|
-
lockKey = this._lockKey(origin);
|
|
81
|
+
lockKey = this._lockKey(params.origin);
|
|
87
82
|
this._release = new Trigger();
|
|
88
83
|
const ready = new Trigger();
|
|
89
84
|
void navigator.locks.request(lockKey, async () => {
|
|
@@ -95,7 +90,7 @@ export class SharedWorkerConnection {
|
|
|
95
90
|
|
|
96
91
|
try {
|
|
97
92
|
await this._systemRpc.open();
|
|
98
|
-
await this._systemRpc.rpc.WorkerService.start({
|
|
93
|
+
await this._systemRpc.rpc.WorkerService.start({ lockKey, ...params });
|
|
99
94
|
} catch (err) {
|
|
100
95
|
log.catch(err);
|
|
101
96
|
throw new RemoteServiceConnectionError('Failed to connect to worker');
|
|
@@ -5,8 +5,14 @@
|
|
|
5
5
|
import { Trigger } from '@dxos/async';
|
|
6
6
|
import { type Config } from '@dxos/config';
|
|
7
7
|
import { Context } from '@dxos/context';
|
|
8
|
+
import { invariant } from '@dxos/invariant';
|
|
8
9
|
import { log } from '@dxos/log';
|
|
9
|
-
import {
|
|
10
|
+
import {
|
|
11
|
+
MemorySignalManager,
|
|
12
|
+
MemorySignalManagerContext,
|
|
13
|
+
WebsocketSignalManager,
|
|
14
|
+
setIdentityTags,
|
|
15
|
+
} from '@dxos/messaging';
|
|
10
16
|
import { SimplePeerTransportProxyFactory } from '@dxos/network-manager';
|
|
11
17
|
import { type RpcPort } from '@dxos/rpc';
|
|
12
18
|
import { type MaybePromise } from '@dxos/util';
|
|
@@ -41,6 +47,8 @@ export class WorkerRuntime {
|
|
|
41
47
|
private readonly _clientServices!: ClientServicesHost;
|
|
42
48
|
private _sessionForNetworking?: WorkerSession; // TODO(burdon): Expose to client QueryStatusResponse.
|
|
43
49
|
private _config!: Config;
|
|
50
|
+
private _signalMetadataTags: any = { runtime: 'worker-runtime' };
|
|
51
|
+
private _signalTelemetryEnabled: boolean = false;
|
|
44
52
|
|
|
45
53
|
constructor(
|
|
46
54
|
private readonly _configProvider: () => MaybePromise<Config>,
|
|
@@ -68,7 +76,7 @@ export class WorkerRuntime {
|
|
|
68
76
|
this._clientServices.initialize({
|
|
69
77
|
config: this._config,
|
|
70
78
|
signalManager: signals
|
|
71
|
-
? new WebsocketSignalManager(signals)
|
|
79
|
+
? new WebsocketSignalManager(signals, () => (this._signalTelemetryEnabled ? this._signalMetadataTags : {}))
|
|
72
80
|
: new MemorySignalManager(new MemorySignalManagerContext()), // TODO(dmaretskyi): Inject this context.
|
|
73
81
|
transportFactory: this._transportFactory,
|
|
74
82
|
});
|
|
@@ -76,6 +84,13 @@ export class WorkerRuntime {
|
|
|
76
84
|
await this._clientServices.open(new Context());
|
|
77
85
|
this._ready.wake(undefined);
|
|
78
86
|
log('started');
|
|
87
|
+
setIdentityTags({
|
|
88
|
+
identityService: this._clientServices.services.IdentityService!,
|
|
89
|
+
devicesService: this._clientServices.services.DevicesService!,
|
|
90
|
+
setTag: (k: string, v: string) => {
|
|
91
|
+
this._signalMetadataTags[k] = v;
|
|
92
|
+
},
|
|
93
|
+
});
|
|
79
94
|
} catch (err: any) {
|
|
80
95
|
this._ready.wake(err);
|
|
81
96
|
log.error('starting', err);
|
|
@@ -112,6 +127,16 @@ export class WorkerRuntime {
|
|
|
112
127
|
});
|
|
113
128
|
|
|
114
129
|
await session.open();
|
|
130
|
+
// A worker can only service one origin currently
|
|
131
|
+
invariant(
|
|
132
|
+
!this._signalMetadataTags.origin || this._signalMetadataTags.origin === session.origin,
|
|
133
|
+
`worker origin changed from ${this._signalMetadataTags.origin} to ${session.origin}?`,
|
|
134
|
+
);
|
|
135
|
+
if (session.observabilityGroup) {
|
|
136
|
+
this._signalMetadataTags.group = session.observabilityGroup;
|
|
137
|
+
}
|
|
138
|
+
this._signalTelemetryEnabled = session.signalTelemetryEnabled ?? false;
|
|
139
|
+
this._signalMetadataTags.origin = session.origin;
|
|
115
140
|
this._sessions.add(session);
|
|
116
141
|
|
|
117
142
|
this._reconnectWebrtc();
|
|
@@ -41,6 +41,10 @@ export class WorkerSession {
|
|
|
41
41
|
@logInfo
|
|
42
42
|
public origin?: string;
|
|
43
43
|
|
|
44
|
+
// TODO(nf): factor out?
|
|
45
|
+
public observabilityGroup?: string;
|
|
46
|
+
public signalTelemetryEnabled?: boolean;
|
|
47
|
+
|
|
44
48
|
@logInfo
|
|
45
49
|
public lockKey?: string;
|
|
46
50
|
|
|
@@ -91,6 +95,8 @@ export class WorkerSession {
|
|
|
91
95
|
start: async (request) => {
|
|
92
96
|
this.origin = request.origin;
|
|
93
97
|
this.lockKey = request.lockKey;
|
|
98
|
+
this.observabilityGroup = request.observabilityGroup;
|
|
99
|
+
this.signalTelemetryEnabled = request.signalTelemetryEnabled;
|
|
94
100
|
this._startTrigger.wake();
|
|
95
101
|
},
|
|
96
102
|
|
package/src/version.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const DXOS_VERSION = "0.4.10-main.
|
|
1
|
+
export const DXOS_VERSION = "0.4.10-main.ef6fbc2";
|