@dxos/client-services 0.8.4-main.ef1bc66f44 → 0.8.4-main.f466a3d56e
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/LICENSE +102 -5
- package/README.md +1 -1
- package/dist/lib/browser/{chunk-NTZOEM4P.mjs → chunk-SNHT4M6V.mjs} +1731 -3089
- package/dist/lib/browser/chunk-SNHT4M6V.mjs.map +7 -0
- package/dist/lib/browser/{chunk-NQSC7HOE.mjs → chunk-XJRPB3GA.mjs} +1 -1
- package/dist/lib/browser/index.mjs +106 -194
- package/dist/lib/browser/index.mjs.map +3 -3
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/packlets/diagnostics/browser-diagnostics-broadcast.mjs +1 -6
- package/dist/lib/browser/packlets/diagnostics/browser-diagnostics-broadcast.mjs.map +2 -2
- package/dist/lib/browser/packlets/diagnostics/diagnostics-broadcast.mjs +1 -1
- package/dist/lib/browser/packlets/locks/browser.mjs +9 -49
- package/dist/lib/browser/packlets/locks/browser.mjs.map +2 -2
- package/dist/lib/browser/packlets/locks/node.mjs +4 -22
- package/dist/lib/browser/packlets/locks/node.mjs.map +2 -2
- package/dist/lib/browser/testing/index.mjs +9 -22
- package/dist/lib/browser/testing/index.mjs.map +3 -3
- package/dist/lib/node-esm/{chunk-PKEGMOQ4.mjs → chunk-2DT3MZRL.mjs} +1 -1
- package/dist/lib/node-esm/{chunk-DQWA5ILA.mjs → chunk-2TVKX6UU.mjs} +1731 -3089
- package/dist/lib/node-esm/chunk-2TVKX6UU.mjs.map +7 -0
- package/dist/lib/node-esm/index.mjs +106 -194
- package/dist/lib/node-esm/index.mjs.map +3 -3
- package/dist/lib/node-esm/meta.json +1 -1
- package/dist/lib/node-esm/packlets/diagnostics/browser-diagnostics-broadcast.mjs +1 -6
- package/dist/lib/node-esm/packlets/diagnostics/browser-diagnostics-broadcast.mjs.map +2 -2
- package/dist/lib/node-esm/packlets/diagnostics/diagnostics-broadcast.mjs +1 -1
- package/dist/lib/node-esm/packlets/locks/browser.mjs +9 -49
- package/dist/lib/node-esm/packlets/locks/browser.mjs.map +2 -2
- package/dist/lib/node-esm/packlets/locks/node.mjs +4 -22
- package/dist/lib/node-esm/packlets/locks/node.mjs.map +2 -2
- package/dist/lib/node-esm/testing/index.mjs +9 -22
- package/dist/lib/node-esm/testing/index.mjs.map +3 -3
- package/dist/types/src/index.d.ts +1 -0
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/packlets/agents/edge-agent-manager.d.ts +3 -2
- package/dist/types/src/packlets/agents/edge-agent-manager.d.ts.map +1 -1
- package/dist/types/src/packlets/agents/edge-agent-service.d.ts +2 -1
- package/dist/types/src/packlets/agents/edge-agent-service.d.ts.map +1 -1
- package/dist/types/src/packlets/devices/devices-service.d.ts.map +1 -1
- package/dist/types/src/packlets/devtools/devtools.d.ts.map +1 -1
- package/dist/types/src/packlets/devtools/feeds.d.ts.map +1 -1
- package/dist/types/src/packlets/devtools/keys.d.ts.map +1 -1
- package/dist/types/src/packlets/devtools/metadata.d.ts.map +1 -1
- package/dist/types/src/packlets/devtools/network.d.ts.map +1 -1
- package/dist/types/src/packlets/devtools/spaces.d.ts.map +1 -1
- package/dist/types/src/packlets/diagnostics/browser-diagnostics-broadcast.d.ts.map +1 -1
- package/dist/types/src/packlets/diagnostics/diagnostics-broadcast.d.ts.map +1 -1
- package/dist/types/src/packlets/diagnostics/diagnostics-collector.d.ts.map +1 -1
- package/dist/types/src/packlets/diagnostics/diagnostics.d.ts +2 -3
- package/dist/types/src/packlets/diagnostics/diagnostics.d.ts.map +1 -1
- package/dist/types/src/packlets/identity/authenticator.d.ts.map +1 -1
- package/dist/types/src/packlets/identity/contacts-service.d.ts.map +1 -1
- package/dist/types/src/packlets/identity/identity-manager.d.ts +3 -3
- package/dist/types/src/packlets/identity/identity-manager.d.ts.map +1 -1
- package/dist/types/src/packlets/identity/identity-recovery-manager.d.ts +6 -5
- package/dist/types/src/packlets/identity/identity-recovery-manager.d.ts.map +1 -1
- package/dist/types/src/packlets/identity/identity-service.d.ts +6 -10
- package/dist/types/src/packlets/identity/identity-service.d.ts.map +1 -1
- package/dist/types/src/packlets/identity/identity.d.ts +6 -9
- package/dist/types/src/packlets/identity/identity.d.ts.map +1 -1
- package/dist/types/src/packlets/invitations/device-invitation-protocol.d.ts +2 -1
- package/dist/types/src/packlets/invitations/device-invitation-protocol.d.ts.map +1 -1
- package/dist/types/src/packlets/invitations/edge-invitation-handler.d.ts +1 -1
- package/dist/types/src/packlets/invitations/edge-invitation-handler.d.ts.map +1 -1
- package/dist/types/src/packlets/invitations/invitation-guest-extenstion.d.ts.map +1 -1
- package/dist/types/src/packlets/invitations/invitation-host-extension.d.ts.map +1 -1
- package/dist/types/src/packlets/invitations/invitation-protocol.d.ts +5 -1
- package/dist/types/src/packlets/invitations/invitation-protocol.d.ts.map +1 -1
- package/dist/types/src/packlets/invitations/invitation-state.d.ts.map +1 -1
- package/dist/types/src/packlets/invitations/invitation-topology.d.ts.map +1 -1
- package/dist/types/src/packlets/invitations/invitations-handler.d.ts.map +1 -1
- package/dist/types/src/packlets/invitations/invitations-manager.d.ts +3 -3
- package/dist/types/src/packlets/invitations/invitations-manager.d.ts.map +1 -1
- package/dist/types/src/packlets/invitations/invitations-service.d.ts +3 -3
- package/dist/types/src/packlets/invitations/invitations-service.d.ts.map +1 -1
- package/dist/types/src/packlets/invitations/space-invitation-protocol.d.ts +2 -1
- package/dist/types/src/packlets/invitations/space-invitation-protocol.d.ts.map +1 -1
- package/dist/types/src/packlets/invitations/utils.d.ts.map +1 -1
- package/dist/types/src/packlets/locks/browser.d.ts.map +1 -1
- package/dist/types/src/packlets/locks/node.d.ts.map +1 -1
- package/dist/types/src/packlets/logging/logging-service.d.ts.map +1 -1
- package/dist/types/src/packlets/network/network-service.d.ts +5 -4
- package/dist/types/src/packlets/network/network-service.d.ts.map +1 -1
- package/dist/types/src/packlets/services/client-rpc-server.d.ts +3 -3
- package/dist/types/src/packlets/services/client-rpc-server.d.ts.map +1 -1
- package/dist/types/src/packlets/services/feed-syncer.d.ts +22 -4
- package/dist/types/src/packlets/services/feed-syncer.d.ts.map +1 -1
- package/dist/types/src/packlets/services/feed-syncer.test.d.ts +2 -0
- package/dist/types/src/packlets/services/feed-syncer.test.d.ts.map +1 -0
- package/dist/types/src/packlets/services/service-context.d.ts +2 -4
- package/dist/types/src/packlets/services/service-context.d.ts.map +1 -1
- package/dist/types/src/packlets/services/service-host.d.ts +2 -3
- package/dist/types/src/packlets/services/service-host.d.ts.map +1 -1
- package/dist/types/src/packlets/services/service-registry.d.ts.map +1 -1
- package/dist/types/src/packlets/services/util.d.ts.map +1 -1
- package/dist/types/src/packlets/space-export/archive-format.d.ts +9 -0
- package/dist/types/src/packlets/space-export/archive-format.d.ts.map +1 -0
- package/dist/types/src/packlets/space-export/index.d.ts +4 -1
- package/dist/types/src/packlets/space-export/index.d.ts.map +1 -1
- package/dist/types/src/packlets/space-export/serialized-space-reader.d.ts +23 -0
- package/dist/types/src/packlets/space-export/serialized-space-reader.d.ts.map +1 -0
- package/dist/types/src/packlets/space-export/serialized-space-writer.d.ts +36 -0
- package/dist/types/src/packlets/space-export/serialized-space-writer.d.ts.map +1 -0
- package/dist/types/src/packlets/space-export/space-archive-reader.d.ts +9 -1
- package/dist/types/src/packlets/space-export/space-archive-reader.d.ts.map +1 -1
- package/dist/types/src/packlets/space-export/space-archive-writer.d.ts +7 -1
- package/dist/types/src/packlets/space-export/space-archive-writer.d.ts.map +1 -1
- package/dist/types/src/packlets/space-export/space-archive.test.d.ts +2 -0
- package/dist/types/src/packlets/space-export/space-archive.test.d.ts.map +1 -0
- package/dist/types/src/packlets/spaces/automerge-space-state.d.ts.map +1 -1
- package/dist/types/src/packlets/spaces/data-space-manager.d.ts +20 -14
- package/dist/types/src/packlets/spaces/data-space-manager.d.ts.map +1 -1
- package/dist/types/src/packlets/spaces/data-space.d.ts +24 -7
- package/dist/types/src/packlets/spaces/data-space.d.ts.map +1 -1
- package/dist/types/src/packlets/spaces/edge-feed-replicator.d.ts.map +1 -1
- package/dist/types/src/packlets/spaces/epoch-migrations.d.ts.map +1 -1
- package/dist/types/src/packlets/spaces/genesis.d.ts +2 -1
- package/dist/types/src/packlets/spaces/genesis.d.ts.map +1 -1
- package/dist/types/src/packlets/spaces/notarization-plugin.d.ts +1 -4
- package/dist/types/src/packlets/spaces/notarization-plugin.d.ts.map +1 -1
- package/dist/types/src/packlets/spaces/spaces-service.d.ts +10 -7
- package/dist/types/src/packlets/spaces/spaces-service.d.ts.map +1 -1
- package/dist/types/src/packlets/storage/level.d.ts.map +1 -1
- package/dist/types/src/packlets/storage/profile-archive.d.ts.map +1 -1
- package/dist/types/src/packlets/storage/storage.d.ts.map +1 -1
- package/dist/types/src/packlets/storage/util.d.ts.map +1 -1
- package/dist/types/src/packlets/system/system-service.d.ts +1 -1
- package/dist/types/src/packlets/system/system-service.d.ts.map +1 -1
- package/dist/types/src/packlets/testing/credential-utils.d.ts.map +1 -1
- package/dist/types/src/packlets/testing/invitation-utils.d.ts.map +1 -1
- package/dist/types/src/packlets/testing/test-builder.d.ts.map +1 -1
- package/dist/types/src/packlets/worker/worker-runtime.d.ts +11 -1
- package/dist/types/src/packlets/worker/worker-runtime.d.ts.map +1 -1
- package/dist/types/src/packlets/worker/worker-session.d.ts +0 -2
- package/dist/types/src/packlets/worker/worker-session.d.ts.map +1 -1
- package/dist/types/src/testing/setup.d.ts.map +1 -1
- package/dist/types/src/version.d.ts +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +43 -50
- package/src/index.ts +1 -0
- package/src/packlets/agents/edge-agent-manager.ts +8 -5
- package/src/packlets/agents/edge-agent-service.ts +4 -2
- package/src/packlets/devices/devices-service.test.ts +0 -1
- package/src/packlets/devtools/devtools.ts +0 -1
- package/src/packlets/diagnostics/diagnostics.ts +1 -2
- package/src/packlets/identity/contacts-service.ts +0 -1
- package/src/packlets/identity/identity-manager.test.ts +5 -5
- package/src/packlets/identity/identity-manager.ts +18 -17
- package/src/packlets/identity/identity-recovery-manager.ts +20 -16
- package/src/packlets/identity/identity-service.test.ts +6 -27
- package/src/packlets/identity/identity-service.ts +13 -81
- package/src/packlets/identity/identity.test.ts +2 -2
- package/src/packlets/identity/identity.ts +9 -32
- package/src/packlets/invitations/device-invitation-protocol.ts +3 -2
- package/src/packlets/invitations/edge-invitation-handler.ts +9 -5
- package/src/packlets/invitations/invitation-host-extension.ts +7 -10
- package/src/packlets/invitations/invitation-protocol.ts +5 -1
- package/src/packlets/invitations/invitation-state.ts +1 -15
- package/src/packlets/invitations/invitations-handler.test.ts +4 -5
- package/src/packlets/invitations/invitations-handler.ts +67 -15
- package/src/packlets/invitations/invitations-manager.ts +40 -15
- package/src/packlets/invitations/invitations-service.ts +9 -9
- package/src/packlets/invitations/space-invitation-protocol.test.ts +17 -16
- package/src/packlets/invitations/space-invitation-protocol.ts +4 -3
- package/src/packlets/logging/logging-service.ts +15 -15
- package/src/packlets/network/network-service.test.ts +0 -1
- package/src/packlets/network/network-service.ts +10 -8
- package/src/packlets/services/client-rpc-server.ts +15 -12
- package/src/packlets/services/feed-syncer.test.ts +340 -0
- package/src/packlets/services/feed-syncer.ts +175 -25
- package/src/packlets/services/service-context.test.ts +3 -2
- package/src/packlets/services/service-context.ts +113 -47
- package/src/packlets/services/service-host.test.ts +8 -8
- package/src/packlets/services/service-host.ts +17 -27
- package/src/packlets/services/service-registry.test.ts +0 -1
- package/src/packlets/space-export/archive-format.ts +42 -0
- package/src/packlets/space-export/index.ts +4 -1
- package/src/packlets/space-export/serialized-space-reader.ts +111 -0
- package/src/packlets/space-export/serialized-space-writer.ts +252 -0
- package/src/packlets/space-export/space-archive-reader.ts +64 -3
- package/src/packlets/space-export/space-archive-writer.ts +38 -2
- package/src/packlets/space-export/space-archive.test.ts +461 -0
- package/src/packlets/spaces/data-space-manager.test.ts +79 -13
- package/src/packlets/spaces/data-space-manager.ts +80 -115
- package/src/packlets/spaces/data-space.ts +55 -31
- package/src/packlets/spaces/edge-feed-replicator.test.ts +1 -1
- package/src/packlets/spaces/edge-feed-replicator.ts +9 -7
- package/src/packlets/spaces/epoch-migrations.ts +4 -3
- package/src/packlets/spaces/genesis.ts +6 -1
- package/src/packlets/spaces/notarization-plugin.ts +2 -1
- package/src/packlets/spaces/spaces-service.test.ts +18 -11
- package/src/packlets/spaces/spaces-service.ts +115 -17
- package/src/packlets/testing/invitation-utils.ts +3 -2
- package/src/packlets/worker/worker-runtime.ts +39 -6
- package/src/packlets/worker/worker-session.ts +8 -14
- package/src/version.ts +1 -1
- package/dist/lib/browser/chunk-NTZOEM4P.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-DQWA5ILA.mjs.map +0 -7
- package/dist/types/src/packlets/identity/default-space-state-machine.d.ts +0 -19
- package/dist/types/src/packlets/identity/default-space-state-machine.d.ts.map +0 -1
- package/src/packlets/identity/default-space-state-machine.ts +0 -44
- /package/dist/lib/browser/{chunk-NQSC7HOE.mjs.map → chunk-XJRPB3GA.mjs.map} +0 -0
- /package/dist/lib/node-esm/{chunk-PKEGMOQ4.mjs.map → chunk-2DT3MZRL.mjs.map} +0 -0
|
@@ -8,11 +8,13 @@ import * as Effect from 'effect/Effect';
|
|
|
8
8
|
import * as Schema from 'effect/Schema';
|
|
9
9
|
|
|
10
10
|
import { AsyncTask, scheduleTask } from '@dxos/async';
|
|
11
|
-
import { Resource } from '@dxos/context';
|
|
11
|
+
import { Context, Resource } from '@dxos/context';
|
|
12
12
|
import { type EdgeConnection, MessageSchema } from '@dxos/edge-client';
|
|
13
13
|
import { RuntimeProvider } from '@dxos/effect';
|
|
14
14
|
import { type FeedStore, SyncClient } from '@dxos/feed';
|
|
15
|
-
import {
|
|
15
|
+
import { invariant } from '@dxos/invariant';
|
|
16
|
+
import { SpaceId } from '@dxos/keys';
|
|
17
|
+
import { log } from '@dxos/log';
|
|
16
18
|
import { FeedProtocol } from '@dxos/protocols';
|
|
17
19
|
import { EdgeService } from '@dxos/protocols';
|
|
18
20
|
import { createBuf } from '@dxos/protocols/buf';
|
|
@@ -24,7 +26,9 @@ const encoder = new Encoder({ tagUint8Array: false, useRecords: false });
|
|
|
24
26
|
|
|
25
27
|
const DEFAULT_MESSAGE_BLOCKS_LIMIT = 50;
|
|
26
28
|
const DEFAULT_SYNC_CONCURRENCY = 5;
|
|
27
|
-
const DEFAULT_POLLING_INTERVAL =
|
|
29
|
+
const DEFAULT_POLLING_INTERVAL = 5_000;
|
|
30
|
+
const DEFAULT_POLL_REQUEST_THROTTLE_MS = 250;
|
|
31
|
+
const MAX_BLOCKING_SYNC_ITERATIONS = 100;
|
|
28
32
|
|
|
29
33
|
interface FeedSyncerOptions {
|
|
30
34
|
runtime: RuntimeProvider.RuntimeProvider<SqlClient.SqlClient | SqlTransaction.SqlTransaction>;
|
|
@@ -34,10 +38,9 @@ interface FeedSyncerOptions {
|
|
|
34
38
|
getSpaceIds: () => SpaceId[];
|
|
35
39
|
|
|
36
40
|
/**
|
|
37
|
-
*
|
|
41
|
+
* Namespaces to sync.
|
|
38
42
|
*/
|
|
39
|
-
|
|
40
|
-
syncNamespace: string;
|
|
43
|
+
syncNamespaces: string[];
|
|
41
44
|
|
|
42
45
|
/**
|
|
43
46
|
* Maximum number of blocks to sync in a single message.
|
|
@@ -56,13 +59,20 @@ interface FeedSyncerOptions {
|
|
|
56
59
|
* @default 10 seconds
|
|
57
60
|
*/
|
|
58
61
|
pollingInterval?: number;
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Minimum delay between externally requested best-effort polls.
|
|
65
|
+
* @default 250 ms
|
|
66
|
+
*/
|
|
67
|
+
pollRequestThrottleMs?: number;
|
|
59
68
|
}
|
|
60
69
|
|
|
61
70
|
export class FeedSyncer extends Resource {
|
|
62
|
-
readonly #
|
|
71
|
+
readonly #syncNamespaces: string[];
|
|
63
72
|
readonly #messageBlocksLimit: number;
|
|
64
73
|
readonly #syncConcurrency: number;
|
|
65
74
|
readonly #pollingInterval: number;
|
|
75
|
+
readonly #pollRequestThrottleMs: number;
|
|
66
76
|
|
|
67
77
|
readonly #runtime: RuntimeProvider.RuntimeProvider<SqlClient.SqlClient | SqlTransaction.SqlTransaction>;
|
|
68
78
|
readonly #feedStore: FeedStore;
|
|
@@ -73,6 +83,8 @@ export class FeedSyncer extends Resource {
|
|
|
73
83
|
#spacesToPoll = new Set<SpaceId>();
|
|
74
84
|
/** Last time full poll was completed. */
|
|
75
85
|
#lastFullPoll: number | null = null;
|
|
86
|
+
#throttledPollScheduled = false;
|
|
87
|
+
#lastRequestedPollAt: number | null = null;
|
|
76
88
|
|
|
77
89
|
constructor(options: FeedSyncerOptions) {
|
|
78
90
|
super();
|
|
@@ -85,10 +97,11 @@ export class FeedSyncer extends Resource {
|
|
|
85
97
|
sendMessage: this.#sendMessage.bind(this),
|
|
86
98
|
});
|
|
87
99
|
this.#getSpaceIds = options.getSpaceIds;
|
|
88
|
-
this.#
|
|
100
|
+
this.#syncNamespaces = options.syncNamespaces;
|
|
89
101
|
this.#messageBlocksLimit = options.messageBlocksLimit ?? DEFAULT_MESSAGE_BLOCKS_LIMIT;
|
|
90
102
|
this.#syncConcurrency = options.syncConcurrency ?? DEFAULT_SYNC_CONCURRENCY;
|
|
91
103
|
this.#pollingInterval = options.pollingInterval ?? DEFAULT_POLLING_INTERVAL;
|
|
104
|
+
this.#pollRequestThrottleMs = options.pollRequestThrottleMs ?? DEFAULT_POLL_REQUEST_THROTTLE_MS;
|
|
92
105
|
}
|
|
93
106
|
|
|
94
107
|
protected override async _open(): Promise<void> {
|
|
@@ -101,14 +114,28 @@ export class FeedSyncer extends Resource {
|
|
|
101
114
|
if (service !== EdgeService.QUEUE_REPLICATOR) {
|
|
102
115
|
return;
|
|
103
116
|
}
|
|
117
|
+
log('feed sync edge ingress', {
|
|
118
|
+
serviceId: msg.serviceId,
|
|
119
|
+
payloadByteLength: msg.payload?.value?.byteLength,
|
|
120
|
+
});
|
|
104
121
|
const handleMessageEffect = Effect.gen(this, function* () {
|
|
105
122
|
const decoded = yield* Effect.try({
|
|
106
123
|
try: () => cborXdecode(msg.payload!.value),
|
|
107
124
|
catch: (error) => new Error(`Failed to decode feed sync message: ${error}`),
|
|
108
125
|
});
|
|
109
|
-
const payload = yield* Schema.
|
|
126
|
+
const payload = yield* Schema.validate(FeedProtocol.ProtocolMessage)(decoded);
|
|
110
127
|
yield* this.#syncClient.handleMessage(payload);
|
|
111
|
-
})
|
|
128
|
+
}).pipe(
|
|
129
|
+
Effect.tapError((cause) =>
|
|
130
|
+
Effect.sync(() =>
|
|
131
|
+
log('feed sync edge message handling failed', {
|
|
132
|
+
serviceId: msg.serviceId,
|
|
133
|
+
payloadByteLength: msg.payload?.value?.byteLength,
|
|
134
|
+
cause: cause instanceof Error ? cause.message : String(cause),
|
|
135
|
+
}),
|
|
136
|
+
),
|
|
137
|
+
),
|
|
138
|
+
);
|
|
112
139
|
|
|
113
140
|
void RuntimeProvider.runPromise(this.#runtime)(handleMessageEffect);
|
|
114
141
|
}),
|
|
@@ -116,7 +143,12 @@ export class FeedSyncer extends Resource {
|
|
|
116
143
|
|
|
117
144
|
this._ctx.onDispose(
|
|
118
145
|
// NOTE: This will fire immediately if the connection is already open.
|
|
119
|
-
this.#edgeClient.onReconnected(async () => {
|
|
146
|
+
this.#edgeClient.onReconnected(async () => {
|
|
147
|
+
log('feed sync edge reconnected', {
|
|
148
|
+
peerKey: this.#edgeClient.peerKey,
|
|
149
|
+
identityKey: this.#edgeClient.identityKey,
|
|
150
|
+
});
|
|
151
|
+
}),
|
|
120
152
|
);
|
|
121
153
|
|
|
122
154
|
this.#feedStore.onNewBlocks.on(this._ctx, () => {
|
|
@@ -127,6 +159,7 @@ export class FeedSyncer extends Resource {
|
|
|
127
159
|
await this.#pushTask.open();
|
|
128
160
|
|
|
129
161
|
this.#resetSpacesToPoll();
|
|
162
|
+
this.#pollTask.schedule();
|
|
130
163
|
}
|
|
131
164
|
|
|
132
165
|
protected override async _close(): Promise<void> {
|
|
@@ -134,6 +167,87 @@ export class FeedSyncer extends Resource {
|
|
|
134
167
|
await this.#pushTask.close();
|
|
135
168
|
}
|
|
136
169
|
|
|
170
|
+
/**
|
|
171
|
+
* Schedules a best-effort pull without blocking the caller.
|
|
172
|
+
*/
|
|
173
|
+
schedulePoll(): void {
|
|
174
|
+
this.#resetSpacesToPoll();
|
|
175
|
+
if (this.#throttledPollScheduled) {
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
const now = Date.now();
|
|
180
|
+
const delay =
|
|
181
|
+
this.#lastRequestedPollAt == null
|
|
182
|
+
? 0
|
|
183
|
+
: Math.max(this.#pollRequestThrottleMs - (now - this.#lastRequestedPollAt), 0);
|
|
184
|
+
this.#throttledPollScheduled = true;
|
|
185
|
+
scheduleTask(
|
|
186
|
+
this._ctx,
|
|
187
|
+
() => {
|
|
188
|
+
this.#throttledPollScheduled = false;
|
|
189
|
+
this.#lastRequestedPollAt = Date.now();
|
|
190
|
+
this.#pollTask.schedule();
|
|
191
|
+
},
|
|
192
|
+
delay,
|
|
193
|
+
);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* Performs queue sync and blocks until there are no pending sync batches.
|
|
198
|
+
*/
|
|
199
|
+
async syncBlocking(
|
|
200
|
+
ctx: Context,
|
|
201
|
+
{
|
|
202
|
+
spaceId,
|
|
203
|
+
subspaceTag,
|
|
204
|
+
shouldPush = true,
|
|
205
|
+
shouldPull = true,
|
|
206
|
+
}: {
|
|
207
|
+
spaceId: SpaceId;
|
|
208
|
+
subspaceTag: string;
|
|
209
|
+
shouldPush?: boolean;
|
|
210
|
+
shouldPull?: boolean;
|
|
211
|
+
},
|
|
212
|
+
): Promise<void> {
|
|
213
|
+
invariant(SpaceId.isValid(spaceId));
|
|
214
|
+
invariant(FeedProtocol.isWellKnownNamespace(subspaceTag));
|
|
215
|
+
if (!shouldPush && !shouldPull) {
|
|
216
|
+
return;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
await RuntimeProvider.runPromise(this.#runtime)(
|
|
220
|
+
Effect.gen(this, function* () {
|
|
221
|
+
let done = false;
|
|
222
|
+
let iterations = 0;
|
|
223
|
+
while (!done) {
|
|
224
|
+
done = true;
|
|
225
|
+
if (shouldPull) {
|
|
226
|
+
const pullResult = yield* this.#syncClient.pull(ctx, {
|
|
227
|
+
spaceId,
|
|
228
|
+
feedNamespace: subspaceTag,
|
|
229
|
+
limit: this.#messageBlocksLimit,
|
|
230
|
+
});
|
|
231
|
+
done &&= pullResult.done;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
if (shouldPush) {
|
|
235
|
+
const pushResult = yield* this.#syncClient.push(ctx, {
|
|
236
|
+
spaceId,
|
|
237
|
+
feedNamespace: subspaceTag,
|
|
238
|
+
limit: this.#messageBlocksLimit,
|
|
239
|
+
});
|
|
240
|
+
done &&= pushResult.done;
|
|
241
|
+
}
|
|
242
|
+
iterations++;
|
|
243
|
+
if (iterations > MAX_BLOCKING_SYNC_ITERATIONS) {
|
|
244
|
+
throw new Error('Blocking sync exceeded max iterations.');
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
}),
|
|
248
|
+
);
|
|
249
|
+
}
|
|
250
|
+
|
|
137
251
|
#resetSpacesToPoll(): void {
|
|
138
252
|
this.#spacesToPoll.clear();
|
|
139
253
|
this.#getSpaceIds().forEach((spaceId) => {
|
|
@@ -142,20 +256,44 @@ export class FeedSyncer extends Resource {
|
|
|
142
256
|
this.#lastFullPoll = Date.now();
|
|
143
257
|
}
|
|
144
258
|
|
|
145
|
-
#sendMessage(
|
|
259
|
+
#sendMessage(
|
|
260
|
+
ctx: Context,
|
|
261
|
+
message: FeedProtocol.QueryRequest | FeedProtocol.AppendRequest,
|
|
262
|
+
): Effect.Effect<void, unknown, never> {
|
|
146
263
|
return Effect.gen(this, function* () {
|
|
147
264
|
const encoded = encoder.encode(message);
|
|
265
|
+
const serviceId = this.#getTargetServiceId(message);
|
|
266
|
+
const rpcTag = 'blocks' in message ? 'AppendRequest' : 'QueryRequest';
|
|
267
|
+
log('feed sync edge rpc outgoing', {
|
|
268
|
+
tag: rpcTag,
|
|
269
|
+
serviceId,
|
|
270
|
+
payloadByteLength: encoded.byteLength,
|
|
271
|
+
spaceId: message.spaceId,
|
|
272
|
+
feedNamespace: message.feedNamespace,
|
|
273
|
+
requestId: message.requestId,
|
|
274
|
+
});
|
|
148
275
|
yield* Effect.tryPromise(async () =>
|
|
149
276
|
this.#edgeClient.send(
|
|
277
|
+
ctx,
|
|
150
278
|
createBuf(MessageSchema, {
|
|
151
279
|
source: {
|
|
152
280
|
identityKey: this.#edgeClient.identityKey,
|
|
153
281
|
peerKey: this.#edgeClient.peerKey,
|
|
154
282
|
},
|
|
155
|
-
serviceId
|
|
283
|
+
serviceId,
|
|
156
284
|
payload: { value: bufferToArray(encoded) },
|
|
157
285
|
}),
|
|
158
286
|
),
|
|
287
|
+
).pipe(
|
|
288
|
+
Effect.tapError((cause) =>
|
|
289
|
+
Effect.sync(() =>
|
|
290
|
+
log('feed sync edge send failed', {
|
|
291
|
+
serviceId,
|
|
292
|
+
tag: rpcTag,
|
|
293
|
+
cause: cause instanceof Error ? cause.message : String(cause),
|
|
294
|
+
}),
|
|
295
|
+
),
|
|
296
|
+
),
|
|
159
297
|
);
|
|
160
298
|
});
|
|
161
299
|
}
|
|
@@ -173,12 +311,18 @@ export class FeedSyncer extends Resource {
|
|
|
173
311
|
this.#spacesToPoll,
|
|
174
312
|
(spaceId) =>
|
|
175
313
|
Effect.gen(this, function* () {
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
314
|
+
let doneForAllNamespaces = true;
|
|
315
|
+
for (const feedNamespace of this.#syncNamespaces) {
|
|
316
|
+
const { done } = yield* this.#syncClient.pull(this._ctx, {
|
|
317
|
+
spaceId,
|
|
318
|
+
feedNamespace,
|
|
319
|
+
limit: this.#messageBlocksLimit,
|
|
320
|
+
});
|
|
321
|
+
if (!done) {
|
|
322
|
+
doneForAllNamespaces = false;
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
if (doneForAllNamespaces) {
|
|
182
326
|
this.#spacesToPoll.delete(spaceId);
|
|
183
327
|
}
|
|
184
328
|
}),
|
|
@@ -210,12 +354,18 @@ export class FeedSyncer extends Resource {
|
|
|
210
354
|
this.#getSpaceIds(),
|
|
211
355
|
(spaceId) =>
|
|
212
356
|
Effect.gen(this, function* () {
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
357
|
+
let doneForAllNamespaces = true;
|
|
358
|
+
for (const feedNamespace of this.#syncNamespaces) {
|
|
359
|
+
const { done } = yield* this.#syncClient.push(this._ctx, {
|
|
360
|
+
spaceId,
|
|
361
|
+
feedNamespace,
|
|
362
|
+
limit: this.#messageBlocksLimit,
|
|
363
|
+
});
|
|
364
|
+
if (!done) {
|
|
365
|
+
doneForAllNamespaces = false;
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
if (!doneForAllNamespaces) {
|
|
219
369
|
// Keep pushing until all blocks are pushed.
|
|
220
370
|
this.#pushTask.schedule();
|
|
221
371
|
}
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
import { describe, test } from 'vitest';
|
|
6
6
|
|
|
7
|
+
import { Context } from '@dxos/context';
|
|
7
8
|
import { MemorySignalManager, MemorySignalManagerContext } from '@dxos/messaging';
|
|
8
9
|
import { Invitation } from '@dxos/protocols/proto/dxos/client/services';
|
|
9
10
|
import { openAndClose } from '@dxos/test-utils';
|
|
@@ -19,7 +20,7 @@ describe('services/ServiceContext', () => {
|
|
|
19
20
|
const device2 = await createOpenServiceContext(networkContext);
|
|
20
21
|
await Promise.all(performInvitation({ host: device1, guest: device2, options: { kind: Invitation.Kind.DEVICE } }));
|
|
21
22
|
|
|
22
|
-
const space1 = await device1.dataSpaceManager!.createSpace();
|
|
23
|
+
const space1 = await device1.dataSpaceManager!.createSpace(new Context());
|
|
23
24
|
await device2.dataSpaceManager!.waitUntilSpaceReady(space1!.key);
|
|
24
25
|
const space2 = await device2.dataSpaceManager!.spaces.get(space1.key);
|
|
25
26
|
await space2!.inner.controlPipeline.state.waitUntilTimeframe(space1.inner.controlPipeline.state.timeframe);
|
|
@@ -35,7 +36,7 @@ describe('services/ServiceContext', () => {
|
|
|
35
36
|
|
|
36
37
|
const identity2 = await createOpenServiceContext(networkContext);
|
|
37
38
|
await identity2.createIdentity();
|
|
38
|
-
const space1 = await identity2.dataSpaceManager!.createSpace();
|
|
39
|
+
const space1 = await identity2.dataSpaceManager!.createSpace(new Context());
|
|
39
40
|
await Promise.all(
|
|
40
41
|
performInvitation({
|
|
41
42
|
host: identity2,
|