@peerbit/shared-log 1.0.2

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.
@@ -0,0 +1,109 @@
1
+ import { variant, option, field, vec, fixedArray } from "@dao-xyz/borsh";
2
+ import { Entry } from "@peerbit/log";
3
+ import { Log } from "@peerbit/log";
4
+ import { logger as loggerFn } from "@peerbit/logger";
5
+ import { TransportMessage } from "./message.js";
6
+
7
+ const logger = loggerFn({ module: "exchange-heads" });
8
+
9
+ export class MinReplicas {
10
+ get value(): number {
11
+ throw new Error("Not implemented");
12
+ }
13
+ }
14
+
15
+ @variant(0)
16
+ export class AbsolutMinReplicas extends MinReplicas {
17
+ _value: number;
18
+ constructor(value: number) {
19
+ super();
20
+ this._value = value;
21
+ }
22
+ get value() {
23
+ return this._value;
24
+ }
25
+ }
26
+
27
+ /**
28
+ * This thing allows use to faster sync since we can provide
29
+ * references that can be read concurrently to
30
+ * the entry when doing Log.fromEntry or Log.fromEntryHash
31
+ */
32
+ @variant(0)
33
+ export class EntryWithRefs<T> {
34
+ @field({ type: Entry })
35
+ entry: Entry<T>;
36
+
37
+ @field({ type: vec(Entry) })
38
+ references: Entry<T>[]; // are some parents to the entry
39
+
40
+ constructor(properties: { entry: Entry<T>; references: Entry<T>[] }) {
41
+ this.entry = properties.entry;
42
+ this.references = properties.references;
43
+ }
44
+ }
45
+
46
+ @variant([0, 0])
47
+ export class ExchangeHeadsMessage<T> extends TransportMessage {
48
+ @field({ type: vec(EntryWithRefs) })
49
+ heads: EntryWithRefs<T>[];
50
+
51
+ @field({ type: option(MinReplicas) })
52
+ minReplicas?: MinReplicas;
53
+
54
+ @field({ type: fixedArray("u8", 4) })
55
+ reserved: Uint8Array = new Uint8Array(4);
56
+
57
+ constructor(props: {
58
+ logId: Uint8Array;
59
+ heads: EntryWithRefs<T>[];
60
+ minReplicas?: MinReplicas;
61
+ }) {
62
+ super();
63
+ this.heads = props.heads;
64
+ this.minReplicas = props.minReplicas;
65
+ }
66
+ }
67
+
68
+ @variant([0, 1])
69
+ export class RequestHeadsMessage extends TransportMessage {
70
+ @field({ type: "string" })
71
+ address: string;
72
+
73
+ constructor(props: { topic: string; address: string }) {
74
+ super();
75
+ if (props) {
76
+ this.address = props.address;
77
+ }
78
+ }
79
+ }
80
+
81
+ export const createExchangeHeadsMessage = async (
82
+ log: Log<any>,
83
+ heads: Entry<any>[],
84
+ includeReferences: boolean
85
+ ) => {
86
+ const headsSet = new Set(heads);
87
+ const headsWithRefs = await Promise.all(
88
+ heads.map(async (head) => {
89
+ const refs = !includeReferences
90
+ ? []
91
+ : (
92
+ await log.getReferenceSamples(head, {
93
+ pointerCount: 8,
94
+ memoryLimit: 1e6 / heads.length,
95
+ })
96
+ ) // 1mb total limit split on all heads
97
+ .filter((r) => !headsSet.has(r)); // pick a proportional amount of refs so we can efficiently load the log. TODO should be equidistant for good performance?
98
+ return new EntryWithRefs({
99
+ entry: head,
100
+ references: refs,
101
+ });
102
+ })
103
+ );
104
+ logger.debug(`Send latest heads of '${log.id}'`);
105
+ return new ExchangeHeadsMessage({
106
+ logId: log.id!,
107
+ heads: headsWithRefs,
108
+ });
109
+ };
@@ -0,0 +1,206 @@
1
+ import { variant, field, option, vec } from "@dao-xyz/borsh";
2
+ import { TransportMessage } from "./message.js";
3
+
4
+ export const WAIT_FOR_PEERS_TIME = 5000;
5
+
6
+ @variant([2, 0])
7
+ export class ReplicatorInfo extends TransportMessage {
8
+ @field({ type: option("string") })
9
+ fromId?: string;
10
+
11
+ @field({ type: "string" })
12
+ topic: string;
13
+
14
+ @field({ type: "u32" })
15
+ store: number; // address
16
+
17
+ @field({ type: vec("string") })
18
+ heads?: string[]; // address
19
+
20
+ constructor(props?: {
21
+ fromId?: string;
22
+ topic: string;
23
+ store: number;
24
+ heads?: string[];
25
+ }) {
26
+ super();
27
+ if (props) {
28
+ this.fromId = props.fromId;
29
+ this.topic = props.topic;
30
+ this.store = props.store;
31
+ this.heads = props.heads;
32
+ /* this.allowForks = props.allowForks; */
33
+ }
34
+ }
35
+ }
36
+
37
+ /* @variant([2, 1])
38
+ export class RequestReplicatorInfo extends ProtocolMessage {
39
+ @field({ type: "string" })
40
+ id: string;
41
+
42
+ @field({ type: "string" })
43
+ topic: string;
44
+
45
+ @field({ type: "string" })
46
+ address: string; // address
47
+
48
+ @field({ type: vec("string") })
49
+ heads: string[];
50
+
51
+ constructor(props?: {
52
+ topic: string;
53
+ address: Address | string;
54
+ heads: string[];
55
+ }) {
56
+ super();
57
+ if (props) {
58
+ this.id = uuid();
59
+ this.topic = props.topic;
60
+ this.address =
61
+ typeof props.address === "string"
62
+ ? props.address
63
+ : props.address.toString();
64
+ this.heads = props.heads;
65
+ }
66
+ }
67
+ }
68
+ */
69
+ /* export interface PeerInfoWithMeta {
70
+ peerInfo: ReplicatorInfo;
71
+ publicKey: PublicSignKey;
72
+ } */
73
+ /* return new PeerInfo({
74
+ key: this._shard.peer.orbitDB.identity,
75
+ addresses: (await this._shard.peer.node.id()).addresses.map(x => x.toString()),
76
+ memoryLeft: v8.getHeapStatistics().total_available_size//v8
77
+ }) */
78
+
79
+ /* export const createEmitHealthCheckJob = (properties: { stores: () => string[] | undefined, subscribingForReplication: (topic: string) => boolean }, replicationTopic: string, publish: (topic: string, message: Uint8Array) => Promise<void>, isOnline: () => boolean, controller: AbortController, sign: (bytes: Uint8Array) => Promise<{ signature: Uint8Array, publicKey: PublicKey }>, encryption: PublicKeyEncryption) => {
80
+
81
+ const emitHealthcheck = async (): Promise<void> => {
82
+ const s = properties.stores();
83
+ if (!s || s.length === 0) {
84
+ return;
85
+ }
86
+ const signedMessage = await new MaybeSigned({
87
+ data: serialize(new PeerInfo({
88
+ replicationTopic,
89
+ stores: s,
90
+ subscribingForReplication: properties.subscribingForReplication(replicationTopic),
91
+ memoryLeft: v8.getHeapStatistics().total_available_size//v8
92
+
93
+ }))
94
+ }).sign(sign)
95
+ const decryptedMessage = new DecryptedThing({
96
+ data: serialize(signedMessage)
97
+ })// TODO add encryption .init(encryption).encrypt(lala)
98
+
99
+ return publish(replicationTopic, serialize(decryptedMessage))
100
+ }
101
+
102
+ const task = async () => {
103
+ await emitHealthcheck();
104
+ }
105
+
106
+ const cron = async () => {
107
+ let stop = false;
108
+ let promise: Promise<any> = undefined;
109
+ let delayStopper: () => void | undefined = undefined;
110
+ controller.signal.addEventListener("abort", async () => {
111
+ stop = true;
112
+ if (delayStopper)
113
+ delayStopper();
114
+ await promise;
115
+ });
116
+ while (isOnline() && !stop) { //
117
+ promise = task();
118
+ await promise;
119
+ await delay(EMIT_HEALTHCHECK_INTERVAL, { stopperCallback: (stopper) => { delayStopper = stopper } }); // some delay
120
+ }
121
+ }
122
+ return cron;
123
+ }
124
+ */
125
+
126
+ /* export const requestPeerInfo = async (
127
+ serializedRequest: Uint8Array,
128
+ replicationTopic: string,
129
+ publish: (topic: string, message: Uint8Array) => Promise<void>,
130
+ identity: Identity
131
+ ) => {
132
+ const signedMessage = await new MaybeSigned({
133
+ data: serializedRequest,
134
+ }).sign(async (data) => {
135
+ return {
136
+ publicKey: identity.publicKey,
137
+ signature: await identity.sign(data),
138
+ };
139
+ });
140
+ const decryptedMessage = new DecryptedThing({
141
+ data: serialize(signedMessage),
142
+ }); // TODO add encryption .init(encryption).encrypt(lala)
143
+
144
+ return publish(replicationTopic, serialize(decryptedMessage));
145
+ }; */
146
+
147
+ /* export const exchangePeerInfo = async (
148
+ fromId: string,
149
+ replicationTopic: string,
150
+ store: Store<any>,
151
+ heads: string[] | undefined,
152
+ publish: (message: Uint8Array) => Promise<void>,
153
+ sign: (
154
+ bytes: Uint8Array
155
+ ) => Promise<{ signature: Uint8Array; publicKey: PublicSignKey }>
156
+ ) => {
157
+ const signedMessage = await new MaybeSigned({
158
+ data: serialize(
159
+ new ReplicatorInfo({
160
+ fromId,
161
+ replicationTopic,
162
+ store: store._storeIndex,
163
+ heads,
164
+ })
165
+ ),
166
+ }).sign(sign);
167
+
168
+ const decryptedMessage = new DecryptedThing({
169
+ data: serialize(signedMessage),
170
+ }); // TODO add encryption .init(encryption).encrypt(lala)
171
+
172
+ return publish(serialize(decryptedMessage));
173
+ };
174
+
175
+ export class ResourceRequirement {
176
+ async ok(_orbitdb: Peerbit): Promise<boolean> {
177
+ throw new Error("Not implemented");
178
+ }
179
+ }
180
+
181
+ @variant(0)
182
+ export class NoResourceRequirement extends ResourceRequirement {} */
183
+
184
+ /* @variant(1)
185
+ export class HeapSizeRequirement extends ResourceRequirement {
186
+
187
+ @field({ type: 'u64' })
188
+ heapSize: bigint
189
+
190
+ constructor(properties?: { heapSize: bigint }) {
191
+ super();
192
+ if (properties) {
193
+ this.heapSize = properties.heapSize;
194
+ }
195
+ }
196
+
197
+ async ok(orbitdb: OrbitDB): Promise<boolean> {
198
+ if (!v8 || typeof orbitdb.heapsizeLimitForForks !== 'number') {
199
+ return true;
200
+ }
201
+ const usedHeap: number = v8.getHeapStatistics().used_heap_size;
202
+ return BigInt(usedHeap) + this.heapSize < orbitdb.heapsizeLimitForForks;
203
+ }
204
+
205
+
206
+ } */