@dxos/echo-db 2.33.5-dev.b7c9d504 → 2.33.5-dev.bbe0c471
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/src/api/selection/queries.d.ts.map +1 -1
- package/dist/src/api/selection/queries.js +13 -17
- package/dist/src/api/selection/queries.js.map +1 -1
- package/dist/src/api/selection/selection.d.ts.map +1 -1
- package/dist/src/api/selection/selection.js +1 -3
- package/dist/src/api/selection/selection.js.map +1 -1
- package/dist/src/api/selection/selection.test.js +4 -12
- package/dist/src/api/selection/selection.test.js.map +1 -1
- package/dist/src/database/item-demuxer.d.ts +1 -1
- package/dist/src/database/item-demuxer.d.ts.map +1 -1
- package/dist/src/database/item-demuxer.js +3 -5
- package/dist/src/database/item-demuxer.js.map +1 -1
- package/dist/src/database/item-manager.js +2 -2
- package/dist/src/database/item-manager.js.map +1 -1
- package/dist/src/database/testing.js +1 -1
- package/dist/src/database/testing.js.map +1 -1
- package/dist/src/echo.d.ts +1 -0
- package/dist/src/echo.d.ts.map +1 -1
- package/dist/src/echo.js +7 -18
- package/dist/src/echo.js.map +1 -1
- package/dist/src/halo/halo-factory.d.ts.map +1 -1
- package/dist/src/halo/halo-factory.js +5 -11
- package/dist/src/halo/halo-factory.js.map +1 -1
- package/dist/src/halo/halo-party.d.ts +1 -1
- package/dist/src/halo/halo-party.d.ts.map +1 -1
- package/dist/src/halo/halo-party.js +8 -6
- package/dist/src/halo/halo-party.js.map +1 -1
- package/dist/src/halo/halo.test.js +4 -3
- package/dist/src/halo/halo.test.js.map +1 -1
- package/dist/src/halo/identity.js +2 -2
- package/dist/src/halo/identity.js.map +1 -1
- package/dist/src/halo/party-opener.d.ts +1 -1
- package/dist/src/halo/party-opener.d.ts.map +1 -1
- package/dist/src/halo/party-opener.js +2 -2
- package/dist/src/halo/party-opener.js.map +1 -1
- package/dist/src/halo/preferences.d.ts.map +1 -1
- package/dist/src/halo/preferences.js +7 -10
- package/dist/src/halo/preferences.js.map +1 -1
- package/dist/src/invitations/greeting-protocol-provider.d.ts.map +1 -1
- package/dist/src/invitations/greeting-protocol-provider.js +5 -9
- package/dist/src/invitations/greeting-protocol-provider.js.map +1 -1
- package/dist/src/invitations/greeting-responder.d.ts +6 -4
- package/dist/src/invitations/greeting-responder.d.ts.map +1 -1
- package/dist/src/invitations/greeting-responder.js +11 -14
- package/dist/src/invitations/greeting-responder.js.map +1 -1
- package/dist/src/invitations/invitation-factory.d.ts +5 -2
- package/dist/src/invitations/invitation-factory.d.ts.map +1 -1
- package/dist/src/invitations/invitation-factory.js +4 -3
- package/dist/src/invitations/invitation-factory.js.map +1 -1
- package/dist/src/invitations/offline-invitation-claimer.d.ts.map +1 -1
- package/dist/src/invitations/offline-invitation-claimer.js +5 -7
- package/dist/src/invitations/offline-invitation-claimer.js.map +1 -1
- package/dist/src/parties/data-party.d.ts +5 -3
- package/dist/src/parties/data-party.d.ts.map +1 -1
- package/dist/src/parties/data-party.js +13 -10
- package/dist/src/parties/data-party.js.map +1 -1
- package/dist/src/parties/data-party.test.js +18 -17
- package/dist/src/parties/data-party.test.js.map +1 -1
- package/dist/src/parties/party-factory.d.ts +0 -6
- package/dist/src/parties/party-factory.d.ts.map +1 -1
- package/dist/src/parties/party-factory.js +17 -45
- package/dist/src/parties/party-factory.js.map +1 -1
- package/dist/src/parties/party-manager.d.ts.map +1 -1
- package/dist/src/parties/party-manager.js +2 -1
- package/dist/src/parties/party-manager.js.map +1 -1
- package/dist/src/parties/party-manager.test.js +7 -6
- package/dist/src/parties/party-manager.test.js.map +1 -1
- package/dist/src/pipeline/message-selector.d.ts +2 -2
- package/dist/src/pipeline/message-selector.d.ts.map +1 -1
- package/dist/src/pipeline/message-selector.js +29 -29
- package/dist/src/pipeline/message-selector.js.map +1 -1
- package/dist/src/pipeline/metadata-store.d.ts +3 -3
- package/dist/src/pipeline/metadata-store.d.ts.map +1 -1
- package/dist/src/pipeline/metadata-store.js +5 -5
- package/dist/src/pipeline/metadata-store.js.map +1 -1
- package/dist/src/pipeline/metadata-store.test.js +8 -4
- package/dist/src/pipeline/metadata-store.test.js.map +1 -1
- package/dist/src/pipeline/party-core.d.ts +3 -2
- package/dist/src/pipeline/party-core.d.ts.map +1 -1
- package/dist/src/pipeline/party-core.js +5 -4
- package/dist/src/pipeline/party-core.js.map +1 -1
- package/dist/src/pipeline/party-core.test.js +17 -16
- package/dist/src/pipeline/party-core.test.js.map +1 -1
- package/dist/src/pipeline/party-processor.d.ts +21 -9
- package/dist/src/pipeline/party-processor.d.ts.map +1 -1
- package/dist/src/pipeline/party-processor.js +0 -8
- package/dist/src/pipeline/party-processor.js.map +1 -1
- package/dist/src/pipeline/pipeline.d.ts +2 -4
- package/dist/src/pipeline/pipeline.d.ts.map +1 -1
- package/dist/src/pipeline/pipeline.js +0 -3
- package/dist/src/pipeline/pipeline.js.map +1 -1
- package/dist/src/pipeline/pipeline.test.js +2 -2
- package/dist/src/pipeline/pipeline.test.js.map +1 -1
- package/dist/src/protocol/auth-plugin.d.ts +1 -1
- package/dist/src/protocol/auth-plugin.d.ts.map +1 -1
- package/dist/src/protocol/auth-plugin.js +1 -3
- package/dist/src/protocol/auth-plugin.js.map +1 -1
- package/dist/src/protocol/authenticator.d.ts +4 -4
- package/dist/src/protocol/authenticator.d.ts.map +1 -1
- package/dist/src/protocol/authenticator.js +12 -16
- package/dist/src/protocol/authenticator.js.map +1 -1
- package/dist/src/protocol/authenticator.test.js +1 -4
- package/dist/src/protocol/authenticator.test.js.map +1 -1
- package/dist/src/protocol/halo-recovery-plugin.d.ts +1 -1
- package/dist/src/protocol/halo-recovery-plugin.d.ts.map +1 -1
- package/dist/src/protocol/halo-recovery-plugin.js +1 -3
- package/dist/src/protocol/halo-recovery-plugin.js.map +1 -1
- package/dist/src/protocol/identity-credentials.d.ts +2 -2
- package/dist/src/protocol/identity-credentials.d.ts.map +1 -1
- package/dist/src/protocol/identity-credentials.js +4 -4
- package/dist/src/protocol/identity-credentials.js.map +1 -1
- package/dist/src/protocol/offline-invitation-plugin.d.ts +1 -1
- package/dist/src/protocol/offline-invitation-plugin.d.ts.map +1 -1
- package/dist/src/protocol/offline-invitation-plugin.js +1 -3
- package/dist/src/protocol/offline-invitation-plugin.js.map +1 -1
- package/dist/src/protocol/party-protocol-factory.d.ts +1 -14
- package/dist/src/protocol/party-protocol-factory.d.ts.map +1 -1
- package/dist/src/protocol/party-protocol-factory.js +2 -55
- package/dist/src/protocol/party-protocol-factory.js.map +1 -1
- package/dist/src/protocol/replicator-plugin.d.ts +7 -0
- package/dist/src/protocol/replicator-plugin.d.ts.map +1 -0
- package/dist/src/protocol/replicator-plugin.js +36 -0
- package/dist/src/protocol/replicator-plugin.js.map +1 -0
- package/dist/src/snapshots/snapshot-generator.d.ts +1 -1
- package/dist/src/snapshots/snapshot-generator.d.ts.map +1 -1
- package/dist/src/snapshots/snapshot-generator.js +13 -15
- package/dist/src/snapshots/snapshot-generator.js.map +1 -1
- package/dist/src/snapshots/snapshot-store.d.ts +3 -3
- package/dist/src/snapshots/snapshot-store.d.ts.map +1 -1
- package/dist/src/snapshots/snapshot-store.js +5 -5
- package/dist/src/snapshots/snapshot-store.js.map +1 -1
- package/dist/src/snapshots/snapshot-store.test.js +1 -1
- package/dist/src/snapshots/snapshot-store.test.js.map +1 -1
- package/dist/src/testing/benchmark.test.d.ts +2 -0
- package/dist/src/testing/benchmark.test.d.ts.map +1 -0
- package/dist/src/testing/benchmark.test.js +25 -0
- package/dist/src/testing/benchmark.test.js.map +1 -0
- package/dist/src/testing/testing-factories.js +2 -2
- package/dist/src/testing/testing-factories.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +18 -18
- package/src/api/selection/queries.ts +14 -18
- package/src/api/selection/selection.test.ts +4 -12
- package/src/api/selection/selection.ts +1 -7
- package/src/database/item-demuxer.ts +2 -4
- package/src/database/item-manager.ts +2 -2
- package/src/database/testing.ts +1 -1
- package/src/echo.ts +8 -18
- package/src/halo/halo-factory.ts +6 -18
- package/src/halo/halo-party.ts +12 -6
- package/src/halo/halo.test.ts +4 -3
- package/src/halo/identity.ts +2 -2
- package/src/halo/party-opener.ts +2 -2
- package/src/halo/preferences.ts +7 -10
- package/src/invitations/greeting-protocol-provider.ts +5 -9
- package/src/invitations/greeting-responder.ts +15 -17
- package/src/invitations/invitation-factory.ts +8 -5
- package/src/invitations/offline-invitation-claimer.ts +5 -7
- package/src/parties/data-party.test.ts +19 -17
- package/src/parties/data-party.ts +15 -10
- package/src/parties/party-factory.ts +23 -69
- package/src/parties/party-manager.test.ts +9 -6
- package/src/parties/party-manager.ts +2 -1
- package/src/pipeline/message-selector.ts +30 -34
- package/src/pipeline/metadata-store.test.ts +8 -4
- package/src/pipeline/metadata-store.ts +5 -5
- package/src/pipeline/party-core.test.ts +19 -22
- package/src/pipeline/party-core.ts +7 -7
- package/src/pipeline/party-processor.ts +23 -15
- package/src/pipeline/pipeline.test.ts +2 -2
- package/src/pipeline/pipeline.ts +2 -6
- package/src/protocol/auth-plugin.ts +1 -3
- package/src/protocol/authenticator.test.ts +1 -4
- package/src/protocol/authenticator.ts +33 -33
- package/src/protocol/halo-recovery-plugin.ts +4 -6
- package/src/protocol/identity-credentials.ts +4 -4
- package/src/protocol/offline-invitation-plugin.ts +4 -6
- package/src/protocol/party-protocol-factory.ts +3 -56
- package/src/protocol/replicator-plugin.ts +37 -0
- package/src/snapshots/snapshot-generator.ts +12 -16
- package/src/snapshots/snapshot-store.test.ts +1 -1
- package/src/snapshots/snapshot-store.ts +5 -6
- package/src/testing/benchmark.test.ts +30 -0
- package/src/testing/testing-factories.ts +2 -2
|
@@ -12,22 +12,40 @@ import {
|
|
|
12
12
|
PartyState,
|
|
13
13
|
Message as HaloMessage,
|
|
14
14
|
IdentityEventType,
|
|
15
|
-
PartyEventType
|
|
15
|
+
PartyEventType,
|
|
16
|
+
SignedMessage
|
|
16
17
|
} from '@dxos/credentials';
|
|
17
18
|
import { PublicKey } from '@dxos/crypto';
|
|
18
|
-
import { FeedKey,
|
|
19
|
+
import { FeedKey, IHaloStream, PartyKey, HaloStateSnapshot } from '@dxos/echo-protocol';
|
|
19
20
|
import { jsonReplacer } from '@dxos/util';
|
|
20
21
|
|
|
21
22
|
const log = debug('dxos:echo-db:party-processor');
|
|
22
23
|
|
|
24
|
+
export interface CredentialProcessor {
|
|
25
|
+
processMessage (message: IHaloStream): Promise<void>
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export interface PartyStateProvider {
|
|
29
|
+
partyKey: PublicKey
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Whether PartyGenesis was already processed.
|
|
33
|
+
*/
|
|
34
|
+
genesisRequired: boolean
|
|
35
|
+
memberKeys: PublicKey[]
|
|
36
|
+
feedKeys: PublicKey[]
|
|
37
|
+
getFeedOwningMember (feedKey: FeedKey): PublicKey | undefined
|
|
38
|
+
isFeedAdmitted (feedKey: FeedKey): boolean
|
|
39
|
+
|
|
40
|
+
getOfflineInvitation (invitationID: Buffer): SignedMessage | undefined
|
|
41
|
+
}
|
|
42
|
+
|
|
23
43
|
/**
|
|
24
44
|
* TODO(burdon): Wrapper/Bridge between HALO APIs.
|
|
25
45
|
*/
|
|
26
|
-
export class PartyProcessor {
|
|
46
|
+
export class PartyProcessor implements CredentialProcessor, PartyStateProvider {
|
|
27
47
|
private readonly _state: PartyState;
|
|
28
48
|
|
|
29
|
-
private _outboundHaloStream: FeedWriter<HaloMessage> | undefined;
|
|
30
|
-
|
|
31
49
|
readonly feedAdded = new Event<FeedKey>()
|
|
32
50
|
|
|
33
51
|
public readonly keyOrInfoAdded = new Event<PublicKey>();
|
|
@@ -124,16 +142,6 @@ export class PartyProcessor {
|
|
|
124
142
|
await this._state.processMessages([data]);
|
|
125
143
|
}
|
|
126
144
|
|
|
127
|
-
setOutboundStream (stream: FeedWriter<HaloMessage>) {
|
|
128
|
-
this._outboundHaloStream = stream;
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
async writeHaloMessage (message: HaloMessage): Promise<WriteReceipt> {
|
|
132
|
-
assert(this._outboundHaloStream, 'Party is closed or read-only');
|
|
133
|
-
// TODO(marik-d): Wait for the message to be processed?
|
|
134
|
-
return this._outboundHaloStream.write(message);
|
|
135
|
-
}
|
|
136
|
-
|
|
137
145
|
makeSnapshot (): HaloStateSnapshot {
|
|
138
146
|
return {
|
|
139
147
|
messages: this._haloMessages
|
|
@@ -25,7 +25,7 @@ const log = debug('dxos:echo:pipeline:test');
|
|
|
25
25
|
describe('pipeline', () => {
|
|
26
26
|
test('streams', async () => {
|
|
27
27
|
const storage = createStorage('', StorageType.RAM);
|
|
28
|
-
const feedStore = new FeedStore(storage, { valueEncoding: codec });
|
|
28
|
+
const feedStore = new FeedStore(storage.directory('feed'), { valueEncoding: codec });
|
|
29
29
|
const feedKeys: Uint8Array[] = [];
|
|
30
30
|
const feedSelector: FeedSelector = descriptor => !!feedKeys.find(key => descriptor.key.equals(key));
|
|
31
31
|
const feedReadStream = new FeedStoreIterator(feedSelector, () => 0, new Timeframe());
|
|
@@ -87,7 +87,7 @@ describe('pipeline', () => {
|
|
|
87
87
|
|
|
88
88
|
test('writing', async () => {
|
|
89
89
|
const storage = createStorage('', StorageType.RAM);
|
|
90
|
-
const feedStore = new FeedStore(storage, { valueEncoding: codec });
|
|
90
|
+
const feedStore = new FeedStore(storage.directory('feed'), { valueEncoding: codec });
|
|
91
91
|
const feedReadStream = new FeedStoreIterator(() => true, () => 0, new Timeframe());
|
|
92
92
|
|
|
93
93
|
const { publicKey, secretKey } = createKeyPair();
|
package/src/pipeline/pipeline.ts
CHANGED
|
@@ -17,7 +17,7 @@ import { createReadable } from '@dxos/feed-store';
|
|
|
17
17
|
import { jsonReplacer } from '@dxos/util';
|
|
18
18
|
|
|
19
19
|
import { TimeframeClock } from '../database';
|
|
20
|
-
import {
|
|
20
|
+
import { CredentialProcessor, PartyStateProvider } from './party-processor';
|
|
21
21
|
|
|
22
22
|
interface Options {
|
|
23
23
|
readLogger?: (msg: any) => void
|
|
@@ -55,17 +55,13 @@ export class Pipeline {
|
|
|
55
55
|
* @param _options
|
|
56
56
|
*/
|
|
57
57
|
constructor (
|
|
58
|
-
private readonly _partyProcessor:
|
|
58
|
+
private readonly _partyProcessor: CredentialProcessor & PartyStateProvider,
|
|
59
59
|
private readonly _feedStorIterator: FeedStoreIterator,
|
|
60
60
|
private readonly _timeframeClock: TimeframeClock,
|
|
61
61
|
private readonly _feedWriter?: FeedWriter<FeedMessage>,
|
|
62
62
|
private readonly _options: Options = {}
|
|
63
63
|
) {}
|
|
64
64
|
|
|
65
|
-
get partyKey () {
|
|
66
|
-
return this._partyProcessor.partyKey;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
65
|
get isOpen () {
|
|
70
66
|
return this._inboundEchoStream !== undefined;
|
|
71
67
|
}
|
|
@@ -9,6 +9,4 @@ import { Replicator } from '@dxos/protocol-plugin-replicator';
|
|
|
9
9
|
/**
|
|
10
10
|
* Creates authenticator network-protocol plugin that guards access to the replicator.
|
|
11
11
|
*/
|
|
12
|
-
export
|
|
13
|
-
return new AuthPlugin(peerId.asBuffer(), authenticator, [Replicator.extension]);
|
|
14
|
-
}
|
|
12
|
+
export const createAuthPlugin = (authenticator: Authenticator, peerId: PublicKey) => new AuthPlugin(peerId.asBuffer(), authenticator, [Replicator.extension]);
|
|
@@ -6,7 +6,6 @@ import expect from 'expect';
|
|
|
6
6
|
import { it as test } from 'mocha';
|
|
7
7
|
|
|
8
8
|
import { createAuthMessage, createKeyAdmitMessage, createPartyGenesisMessage, Keyring, KeyType } from '@dxos/credentials';
|
|
9
|
-
import { MockFeedWriter } from '@dxos/echo-protocol';
|
|
10
9
|
|
|
11
10
|
import { PartyProcessor } from '../pipeline';
|
|
12
11
|
import { createAuthenticator } from './authenticator';
|
|
@@ -23,8 +22,6 @@ describe('authenticator', () => {
|
|
|
23
22
|
const signer = CredentialsSigner.createDirectDeviceSigner(keyring);
|
|
24
23
|
|
|
25
24
|
const partyProcessor = new PartyProcessor(partyKey.publicKey);
|
|
26
|
-
const feed = new MockFeedWriter();
|
|
27
|
-
partyProcessor.setOutboundStream(feed);
|
|
28
25
|
await partyProcessor.processMessage({
|
|
29
26
|
data: createPartyGenesisMessage(
|
|
30
27
|
keyring,
|
|
@@ -53,7 +50,7 @@ describe('authenticator', () => {
|
|
|
53
50
|
meta: {} as any
|
|
54
51
|
});
|
|
55
52
|
|
|
56
|
-
const authenticator = createAuthenticator(partyProcessor, signer);
|
|
53
|
+
const authenticator = createAuthenticator(partyProcessor, signer, null as any);
|
|
57
54
|
const credential = createAuthMessage(
|
|
58
55
|
keyring,
|
|
59
56
|
partyKey.publicKey,
|
|
@@ -4,27 +4,29 @@
|
|
|
4
4
|
|
|
5
5
|
import debug from 'debug';
|
|
6
6
|
|
|
7
|
-
import { Authenticator, codec, createAuthMessage, createEnvelopeMessage, createFeedAdmitMessage, PartyAuthenticator } from '@dxos/credentials';
|
|
8
|
-
import { FeedKey, PartyKey } from '@dxos/echo-protocol';
|
|
7
|
+
import { Message as HaloMessage, Authenticator, codec, createAuthMessage, createEnvelopeMessage, createFeedAdmitMessage, PartyAuthenticator } from '@dxos/credentials';
|
|
8
|
+
import { FeedKey, FeedWriter, PartyKey } from '@dxos/echo-protocol';
|
|
9
9
|
|
|
10
10
|
import { PartyProcessor } from '../pipeline';
|
|
11
11
|
import { CredentialsSigner } from './credentials-signer';
|
|
12
12
|
|
|
13
13
|
const log = debug('dxos:echo-db:authenticator');
|
|
14
14
|
|
|
15
|
-
export
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
15
|
+
export const createAuthenticator = (
|
|
16
|
+
partyProcessor: PartyProcessor,
|
|
17
|
+
credentialsSigner: CredentialsSigner,
|
|
18
|
+
credentialsWriter: FeedWriter<HaloMessage>
|
|
19
|
+
): Authenticator => new PartyAuthenticator(partyProcessor.state, async auth => {
|
|
20
|
+
if (auth.feedAdmit && auth.feedKey && !partyProcessor.isFeedAdmitted(auth.feedKey)) {
|
|
21
|
+
log(`Admitting feed of authenticated member: ${auth.feedKey}`);
|
|
22
|
+
await credentialsWriter.write(createEnvelopeMessage(
|
|
23
|
+
credentialsSigner.signer,
|
|
24
|
+
partyProcessor.partyKey,
|
|
25
|
+
auth.feedAdmit,
|
|
26
|
+
[credentialsSigner.getDeviceSigningKeys()]
|
|
27
|
+
));
|
|
28
|
+
}
|
|
29
|
+
});
|
|
28
30
|
|
|
29
31
|
export interface CredentialsProvider {
|
|
30
32
|
/**
|
|
@@ -33,24 +35,22 @@ export interface CredentialsProvider {
|
|
|
33
35
|
get (): Buffer
|
|
34
36
|
}
|
|
35
37
|
|
|
36
|
-
export
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
38
|
+
export const createCredentialsProvider = (credentialsSigner: CredentialsSigner, partyKey: PartyKey, feedKey: FeedKey): CredentialsProvider => ({
|
|
39
|
+
get: () => {
|
|
40
|
+
const authMessage = createAuthMessage(
|
|
41
|
+
credentialsSigner.signer,
|
|
42
|
+
partyKey,
|
|
43
|
+
credentialsSigner.getIdentityKey(),
|
|
44
|
+
credentialsSigner.getDeviceSigningKeys(),
|
|
45
|
+
feedKey,
|
|
46
|
+
undefined,
|
|
47
|
+
createFeedAdmitMessage(
|
|
40
48
|
credentialsSigner.signer,
|
|
41
49
|
partyKey,
|
|
42
|
-
credentialsSigner.getIdentityKey(),
|
|
43
|
-
credentialsSigner.getDeviceSigningKeys(),
|
|
44
50
|
feedKey,
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
)
|
|
52
|
-
);
|
|
53
|
-
return Buffer.from(codec.encode(authMessage));
|
|
54
|
-
}
|
|
55
|
-
};
|
|
56
|
-
}
|
|
51
|
+
[feedKey, credentialsSigner.getDeviceSigningKeys()]
|
|
52
|
+
)
|
|
53
|
+
);
|
|
54
|
+
return Buffer.from(codec.encode(authMessage));
|
|
55
|
+
}
|
|
56
|
+
});
|
|
@@ -12,9 +12,7 @@ import { HaloRecoveryInitiator, InvitationFactory } from '../invitations';
|
|
|
12
12
|
* Plugin is intended to be used in HALO party swarm.
|
|
13
13
|
*
|
|
14
14
|
*/
|
|
15
|
-
export
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
);
|
|
20
|
-
}
|
|
15
|
+
export const createHaloRecoveryPlugin = (identityKey: PublicKey, invitationFactory: InvitationFactory, peerId: PublicKey) => new GreetingCommandPlugin(
|
|
16
|
+
peerId.asBuffer(),
|
|
17
|
+
HaloRecoveryInitiator.createHaloInvitationClaimHandler(identityKey, invitationFactory)
|
|
18
|
+
);
|
|
@@ -25,7 +25,7 @@ export interface IdentityCredentials {
|
|
|
25
25
|
|
|
26
26
|
export type IdentityCredentialsProvider = () => IdentityCredentials | undefined
|
|
27
27
|
|
|
28
|
-
export
|
|
28
|
+
export const createTestIdentityCredentials = async (keyring: Keyring): Promise<IdentityCredentials> => {
|
|
29
29
|
const identityKey = await keyring.createKeyRecord({ type: KeyType.IDENTITY });
|
|
30
30
|
const deviceKey = await keyring.createKeyRecord({ type: KeyType.DEVICE });
|
|
31
31
|
const feedKey = await keyring.createKeyRecord({ type: KeyType.FEED });
|
|
@@ -53,9 +53,9 @@ export async function createTestIdentityCredentials (keyring: Keyring): Promise<
|
|
|
53
53
|
preferences: undefined,
|
|
54
54
|
contacts: undefined
|
|
55
55
|
};
|
|
56
|
-
}
|
|
56
|
+
};
|
|
57
57
|
|
|
58
|
-
export
|
|
58
|
+
export const deriveTestDeviceCredentials = async (identity: IdentityCredentials): Promise<IdentityCredentials> => {
|
|
59
59
|
const deviceKey = await identity.keyring.createKeyRecord({ type: KeyType.DEVICE });
|
|
60
60
|
const keyAdmit = createKeyAdmitMessage(identity.keyring, identity.identityKey.publicKey, deviceKey, [identity.identityKey]);
|
|
61
61
|
|
|
@@ -75,4 +75,4 @@ export async function deriveTestDeviceCredentials (identity: IdentityCredentials
|
|
|
75
75
|
deviceKeyChain
|
|
76
76
|
)
|
|
77
77
|
};
|
|
78
|
-
}
|
|
78
|
+
};
|
|
@@ -11,9 +11,7 @@ import { InvitationFactory, OfflineInvitationClaimer } from '../invitations';
|
|
|
11
11
|
* Creates network protocol plugin that allows peers to claim offline invitations.
|
|
12
12
|
* Plugin is intended to be used in data-party swarms.
|
|
13
13
|
*/
|
|
14
|
-
export
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
);
|
|
19
|
-
}
|
|
14
|
+
export const createOfflineInvitationPlugin = (invitationFactory: InvitationFactory, peerId: PublicKey) => new GreetingCommandPlugin(
|
|
15
|
+
peerId.asBuffer(),
|
|
16
|
+
OfflineInvitationClaimer.createOfflineInvitationClaimHandler(invitationFactory)
|
|
17
|
+
);
|
|
@@ -4,17 +4,13 @@
|
|
|
4
4
|
|
|
5
5
|
import debug from 'debug';
|
|
6
6
|
|
|
7
|
-
import { synchronized } from '@dxos/async';
|
|
8
7
|
import { discoveryKey, keyToString, PublicKey } from '@dxos/crypto';
|
|
9
|
-
import {
|
|
10
|
-
import type { HypercoreFeed } from '@dxos/feed-store';
|
|
8
|
+
import { PartyKey } from '@dxos/echo-protocol';
|
|
11
9
|
import { Protocol } from '@dxos/mesh-protocol';
|
|
12
10
|
import { MMSTTopology, NetworkManager, Plugin } from '@dxos/network-manager';
|
|
13
11
|
import { PresencePlugin } from '@dxos/protocol-plugin-presence';
|
|
14
|
-
import { Replicator } from '@dxos/protocol-plugin-replicator';
|
|
15
12
|
|
|
16
13
|
import { CredentialsProvider } from '.';
|
|
17
|
-
import { PartyFeedProvider } from '../pipeline/party-feed-provider';
|
|
18
14
|
|
|
19
15
|
const log = debug('dxos:echo-db:party-protocol-factory');
|
|
20
16
|
|
|
@@ -23,21 +19,15 @@ const log = debug('dxos:echo-db:party-protocol-factory');
|
|
|
23
19
|
*/
|
|
24
20
|
export class PartyProtocolFactory {
|
|
25
21
|
private readonly _presencePlugin = new PresencePlugin(this._peerId.asBuffer());
|
|
26
|
-
private readonly _replicatorProtocolPluginFactory: ReplicatorProtocolPluginFactory;
|
|
27
22
|
|
|
28
23
|
private _started = false;
|
|
29
24
|
|
|
30
25
|
constructor (
|
|
31
26
|
private readonly _partyKey: PartyKey,
|
|
32
27
|
private readonly _networkManager: NetworkManager,
|
|
33
|
-
private readonly _feedProvider: PartyFeedProvider,
|
|
34
28
|
private readonly _peerId: PublicKey,
|
|
35
29
|
private readonly _credentials: CredentialsProvider
|
|
36
|
-
) {
|
|
37
|
-
// Replication.
|
|
38
|
-
this._replicatorProtocolPluginFactory =
|
|
39
|
-
new ReplicatorProtocolPluginFactory(this._feedProvider);
|
|
40
|
-
}
|
|
30
|
+
) {}
|
|
41
31
|
|
|
42
32
|
async start (plugins: Plugin[]) {
|
|
43
33
|
if (this._started) {
|
|
@@ -73,9 +63,8 @@ export class PartyProtocolFactory {
|
|
|
73
63
|
await this._networkManager.leaveProtocolSwarm(this._partyKey);
|
|
74
64
|
}
|
|
75
65
|
|
|
76
|
-
private _createProtocol (channel: any, opts: {initiator: boolean}, extraPlugins: Plugin[]) {
|
|
66
|
+
private _createProtocol (channel: any, opts: { initiator: boolean }, extraPlugins: Plugin[]) {
|
|
77
67
|
const plugins: Plugin[] = [
|
|
78
|
-
...this._replicatorProtocolPluginFactory.createPlugins(),
|
|
79
68
|
...extraPlugins,
|
|
80
69
|
this._presencePlugin
|
|
81
70
|
];
|
|
@@ -118,45 +107,3 @@ export class PartyProtocolFactory {
|
|
|
118
107
|
return protocol;
|
|
119
108
|
}
|
|
120
109
|
}
|
|
121
|
-
|
|
122
|
-
/**
|
|
123
|
-
* Creates the protocol plugin for feed replication.
|
|
124
|
-
*/
|
|
125
|
-
export class ReplicatorProtocolPluginFactory {
|
|
126
|
-
constructor (
|
|
127
|
-
private readonly _feedProvider: PartyFeedProvider
|
|
128
|
-
) {}
|
|
129
|
-
|
|
130
|
-
createPlugins () {
|
|
131
|
-
return [
|
|
132
|
-
new Replicator({
|
|
133
|
-
load: async () => {
|
|
134
|
-
const feeds = this._feedProvider.getFeeds();
|
|
135
|
-
log(`Loading feeds: ${feeds.map(feed => keyToString(feed.key))}`);
|
|
136
|
-
return feeds.map((feed) => ({ discoveryKey: feed.feed.discoveryKey }));
|
|
137
|
-
},
|
|
138
|
-
|
|
139
|
-
subscribe: (addFeedToReplicatedSet: (feed: any) => void) => {
|
|
140
|
-
return this._feedProvider.feedOpened.on(async (feed) => {
|
|
141
|
-
log(`Adding feed: ${feed.key.toHex()}`);
|
|
142
|
-
addFeedToReplicatedSet({ discoveryKey: feed.feed.discoveryKey });
|
|
143
|
-
});
|
|
144
|
-
},
|
|
145
|
-
|
|
146
|
-
replicate: async (remoteFeeds, info) => {
|
|
147
|
-
// We can ignore remoteFeeds entirely, since the set of feeds we want to replicate is dictated by the Party.
|
|
148
|
-
// TODO(telackey): Why are we opening feeds? Necessary or belt/braces thinking, or because open party does it?
|
|
149
|
-
const feeds = this._feedProvider.getFeeds();
|
|
150
|
-
log(`Replicating: peerId=${info.session}; feeds=${feeds.map(feed => feed.key.toHex())}`);
|
|
151
|
-
return feeds.map(feed => feed.feed);
|
|
152
|
-
}
|
|
153
|
-
})
|
|
154
|
-
];
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
@synchronized
|
|
158
|
-
private async _openFeed (key: FeedKey): Promise<HypercoreFeed> {
|
|
159
|
-
const descriptor = await this._feedProvider.createOrOpenReadOnlyFeed(key);
|
|
160
|
-
return descriptor.feed;
|
|
161
|
-
}
|
|
162
|
-
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2022 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import debug from 'debug';
|
|
6
|
+
|
|
7
|
+
import { keyToString } from '@dxos/crypto';
|
|
8
|
+
import { Replicator } from '@dxos/protocol-plugin-replicator';
|
|
9
|
+
|
|
10
|
+
import { PartyFeedProvider } from '../pipeline';
|
|
11
|
+
|
|
12
|
+
const log = debug('dxos:echo-db:protocol:replicator');
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Creates the protocol plugin for feed replication.
|
|
16
|
+
*/
|
|
17
|
+
export const createReplicatorPlugin = (feedProvider: PartyFeedProvider) =>
|
|
18
|
+
new Replicator({
|
|
19
|
+
load: async () => {
|
|
20
|
+
const feeds = feedProvider.getFeeds();
|
|
21
|
+
log(`Loading feeds: ${feeds.map(feed => keyToString(feed.key))}`);
|
|
22
|
+
return feeds.map((feed) => ({ discoveryKey: feed.feed.discoveryKey }));
|
|
23
|
+
},
|
|
24
|
+
|
|
25
|
+
subscribe: (addFeedToReplicatedSet: (feed: any) => void) => feedProvider.feedOpened.on(async (feed) => {
|
|
26
|
+
log(`Adding feed: ${feed.key.toHex()}`);
|
|
27
|
+
addFeedToReplicatedSet({ discoveryKey: feed.feed.discoveryKey });
|
|
28
|
+
}),
|
|
29
|
+
|
|
30
|
+
replicate: async (remoteFeeds, info) => {
|
|
31
|
+
// We can ignore remoteFeeds entirely, since the set of feeds we want to replicate is dictated by the Party.
|
|
32
|
+
// TODO(telackey): Why are we opening feeds? Necessary or belt/braces thinking, or because open party does it?
|
|
33
|
+
const feeds = feedProvider.getFeeds();
|
|
34
|
+
log(`Replicating: peerId=${info.session}; feeds=${feeds.map(feed => feed.key.toHex())}`);
|
|
35
|
+
return feeds.map(feed => feed.feed);
|
|
36
|
+
}
|
|
37
|
+
});
|
|
@@ -10,20 +10,16 @@ import { SnapshotStore } from './snapshot-store';
|
|
|
10
10
|
|
|
11
11
|
const log = debug('dxos:snapshot-generator');
|
|
12
12
|
|
|
13
|
-
export
|
|
14
|
-
|
|
15
|
-
) {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
} catch (err: any) {
|
|
24
|
-
console.error('Failed to save snapshot');
|
|
25
|
-
console.error(err);
|
|
26
|
-
}
|
|
13
|
+
export const createAutomaticSnapshots = (party: PartyCore, clock: TimeframeClock, store: SnapshotStore, interval: number) => clock.update.on(async timeframe => {
|
|
14
|
+
const totalMessages = timeframe.totalMessages();
|
|
15
|
+
if (totalMessages > 0 && totalMessages % interval === 0) {
|
|
16
|
+
log(`Saving snapshot of ${party.key.humanize()}...`);
|
|
17
|
+
try {
|
|
18
|
+
const snapshot = party.createSnapshot();
|
|
19
|
+
await store.save(snapshot);
|
|
20
|
+
} catch (err: any) {
|
|
21
|
+
console.error('Failed to save snapshot');
|
|
22
|
+
console.error(err);
|
|
27
23
|
}
|
|
28
|
-
}
|
|
29
|
-
}
|
|
24
|
+
}
|
|
25
|
+
});
|
|
@@ -15,7 +15,7 @@ const createPublicKey = () => PublicKey.from(createKeyPair().publicKey);
|
|
|
15
15
|
|
|
16
16
|
describe('SnapshotStore', () => {
|
|
17
17
|
test('in-memory', async () => {
|
|
18
|
-
const store = new SnapshotStore(createStorage('
|
|
18
|
+
const store = new SnapshotStore(createStorage('', StorageType.RAM).directory('snapshots'));
|
|
19
19
|
|
|
20
20
|
const key1 = createPublicKey();
|
|
21
21
|
const key2 = createPublicKey();
|
|
@@ -7,10 +7,9 @@ import debug from 'debug';
|
|
|
7
7
|
|
|
8
8
|
import { keyToString } from '@dxos/crypto';
|
|
9
9
|
import { schema, PartyKey, PartySnapshot } from '@dxos/echo-protocol';
|
|
10
|
-
import {
|
|
10
|
+
import { Directory } from '@dxos/random-access-multi-storage';
|
|
11
11
|
|
|
12
12
|
const log = debug('dxos:snapshot-store');
|
|
13
|
-
|
|
14
13
|
/**
|
|
15
14
|
* Stores party snapshots. Takes any `random-access-storage` compatible backend.
|
|
16
15
|
*
|
|
@@ -18,11 +17,11 @@ const log = debug('dxos:snapshot-store');
|
|
|
18
17
|
*/
|
|
19
18
|
export class SnapshotStore {
|
|
20
19
|
constructor (
|
|
21
|
-
private readonly
|
|
20
|
+
private readonly _directory: Directory
|
|
22
21
|
) {}
|
|
23
22
|
|
|
24
23
|
async load (partyKey: PartyKey): Promise<PartySnapshot | undefined> {
|
|
25
|
-
const file = this.
|
|
24
|
+
const file = this._directory.createOrOpen(partyKey.toHex());
|
|
26
25
|
|
|
27
26
|
try {
|
|
28
27
|
const { size } = await file.stat();
|
|
@@ -45,7 +44,7 @@ export class SnapshotStore {
|
|
|
45
44
|
|
|
46
45
|
async save (snapshot: PartySnapshot) {
|
|
47
46
|
assert(snapshot.partyKey);
|
|
48
|
-
const file = this.
|
|
47
|
+
const file = this._directory.createOrOpen(keyToString(snapshot.partyKey), { truncate: true, size: 0 });
|
|
49
48
|
|
|
50
49
|
try {
|
|
51
50
|
const data = schema.getCodecForType('dxos.echo.snapshot.PartySnapshot').encode(snapshot);
|
|
@@ -60,6 +59,6 @@ export class SnapshotStore {
|
|
|
60
59
|
*/
|
|
61
60
|
async clear () {
|
|
62
61
|
log('Clearing all snapshots..');
|
|
63
|
-
await this.
|
|
62
|
+
await this._directory.destroy();
|
|
64
63
|
}
|
|
65
64
|
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2022 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { ObjectModel } from '@dxos/object-model';
|
|
6
|
+
|
|
7
|
+
import { ECHO } from '../echo';
|
|
8
|
+
|
|
9
|
+
const ITEMS = 100;
|
|
10
|
+
const MUTATIONS = 1000;
|
|
11
|
+
|
|
12
|
+
it.skip('Database benchmark', async () => {
|
|
13
|
+
const echo = new ECHO({ snapshots: false });
|
|
14
|
+
await echo.open();
|
|
15
|
+
await echo.halo.createProfile();
|
|
16
|
+
const party = await echo.createParty();
|
|
17
|
+
|
|
18
|
+
const start = Date.now();
|
|
19
|
+
for (let i = 0; i < ITEMS; i++) {
|
|
20
|
+
const item = await party.database.createItem({ model: ObjectModel, type: 'test:item' });
|
|
21
|
+
|
|
22
|
+
for (let j = 0; j < MUTATIONS; j++) {
|
|
23
|
+
await item.model.set(`key${j % 100}`, `value-${j}`);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
console.log(`${i * MUTATIONS}/${ITEMS * MUTATIONS} ${((Date.now() - start) / ((i + 1) * MUTATIONS / 1000)).toFixed(1)} µs/mut ${((i + 1) * MUTATIONS / (Date.now() - start) * 1000).toFixed(1)} mut/s`);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
await echo.close();
|
|
30
|
+
});
|
|
@@ -22,10 +22,10 @@ export type TestPeer = Awaited<ReturnType<typeof createTestInstance>>;
|
|
|
22
22
|
|
|
23
23
|
export type WithTestMeta<T> = T & { testMeta: TestPeer }
|
|
24
24
|
|
|
25
|
-
|
|
25
|
+
const addTestMeta = <T>(obj: T, meta: TestPeer): WithTestMeta<T> => {
|
|
26
26
|
(obj as any).testMeta = meta;
|
|
27
27
|
return obj as any;
|
|
28
|
-
}
|
|
28
|
+
};
|
|
29
29
|
|
|
30
30
|
/**
|
|
31
31
|
* Creates a number of test ECHO instances and a party that's shared between all of them.
|