@optimystic/db-p2p 0.1.1 → 0.1.3
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/{readme.md → README.md} +7 -0
- package/dist/index.min.js +31 -30
- package/dist/index.min.js.map +4 -4
- package/dist/src/cluster/cluster-repo.d.ts +27 -0
- package/dist/src/cluster/cluster-repo.d.ts.map +1 -1
- package/dist/src/cluster/cluster-repo.js +139 -18
- package/dist/src/cluster/cluster-repo.js.map +1 -1
- package/dist/src/cluster/service.d.ts +13 -2
- package/dist/src/cluster/service.d.ts.map +1 -1
- package/dist/src/cluster/service.js +17 -7
- package/dist/src/cluster/service.js.map +1 -1
- package/dist/src/index.d.ts +1 -1
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +1 -1
- package/dist/src/index.js.map +1 -1
- package/dist/src/libp2p-node.d.ts +13 -2
- package/dist/src/libp2p-node.d.ts.map +1 -1
- package/dist/src/libp2p-node.js +35 -16
- package/dist/src/libp2p-node.js.map +1 -1
- package/dist/src/protocol-client.d.ts.map +1 -1
- package/dist/src/protocol-client.js +8 -7
- package/dist/src/protocol-client.js.map +1 -1
- package/dist/src/repo/cluster-coordinator.d.ts +7 -2
- package/dist/src/repo/cluster-coordinator.d.ts.map +1 -1
- package/dist/src/repo/cluster-coordinator.js +18 -3
- package/dist/src/repo/cluster-coordinator.js.map +1 -1
- package/dist/src/repo/coordinator-repo.d.ts +26 -3
- package/dist/src/repo/coordinator-repo.d.ts.map +1 -1
- package/dist/src/repo/coordinator-repo.js +117 -22
- package/dist/src/repo/coordinator-repo.js.map +1 -1
- package/dist/src/repo/service.d.ts +13 -2
- package/dist/src/repo/service.d.ts.map +1 -1
- package/dist/src/repo/service.js +25 -12
- package/dist/src/repo/service.js.map +1 -1
- package/dist/src/storage/memory-storage.d.ts +15 -0
- package/dist/src/storage/memory-storage.d.ts.map +1 -1
- package/dist/src/storage/memory-storage.js +23 -4
- package/dist/src/storage/memory-storage.js.map +1 -1
- package/dist/src/storage/storage-repo.d.ts.map +1 -1
- package/dist/src/storage/storage-repo.js.map +1 -1
- package/dist/src/sync/service.d.ts.map +1 -1
- package/dist/src/sync/service.js +7 -2
- package/dist/src/sync/service.js.map +1 -1
- package/package.json +27 -21
- package/src/cluster/cluster-repo.ts +836 -711
- package/src/cluster/service.ts +44 -31
- package/src/index.ts +1 -1
- package/src/libp2p-key-network.ts +334 -334
- package/src/libp2p-node.ts +371 -339
- package/src/network/network-manager-service.ts +334 -334
- package/src/protocol-client.ts +53 -54
- package/src/repo/client.ts +112 -112
- package/src/repo/cluster-coordinator.ts +613 -592
- package/src/repo/coordinator-repo.ts +269 -137
- package/src/repo/service.ts +237 -219
- package/src/storage/block-storage.ts +182 -182
- package/src/storage/memory-storage.ts +24 -5
- package/src/storage/storage-repo.ts +321 -320
- package/src/sync/service.ts +7 -6
- package/dist/src/storage/file-storage.d.ts +0 -30
- package/dist/src/storage/file-storage.d.ts.map +0 -1
- package/dist/src/storage/file-storage.js +0 -127
- package/dist/src/storage/file-storage.js.map +0 -1
- package/src/storage/file-storage.ts +0 -163
package/src/sync/service.ts
CHANGED
|
@@ -132,8 +132,9 @@ export class SyncService implements Startable {
|
|
|
132
132
|
private async readRequest(stream: Stream): Promise<SyncRequest> {
|
|
133
133
|
const messages: Uint8Array[] = [];
|
|
134
134
|
|
|
135
|
+
// Stream is now directly AsyncIterable in libp2p v3
|
|
135
136
|
await pipe(
|
|
136
|
-
stream
|
|
137
|
+
stream,
|
|
137
138
|
lp.decode,
|
|
138
139
|
async (source) => {
|
|
139
140
|
for await (const msg of source) {
|
|
@@ -157,11 +158,11 @@ export class SyncService implements Startable {
|
|
|
157
158
|
const json = JSON.stringify(response);
|
|
158
159
|
const bytes = u8FromString(json, 'utf8');
|
|
159
160
|
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
stream.
|
|
164
|
-
|
|
161
|
+
// Use stream.send() instead of piping to stream.sink in libp2p v3
|
|
162
|
+
const encoded = pipe([bytes], lp.encode);
|
|
163
|
+
for await (const chunk of encoded) {
|
|
164
|
+
stream.send(chunk);
|
|
165
|
+
}
|
|
165
166
|
}
|
|
166
167
|
|
|
167
168
|
/**
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
import type { BlockId, IBlock, Transform, ActionId, ActionRev } from "@optimystic/db-core";
|
|
2
|
-
import type { BlockMetadata } from "./struct.js";
|
|
3
|
-
import type { IRawStorage } from "./i-raw-storage.js";
|
|
4
|
-
export declare class FileRawStorage implements IRawStorage {
|
|
5
|
-
private readonly basePath;
|
|
6
|
-
constructor(basePath: string);
|
|
7
|
-
getMetadata(blockId: BlockId): Promise<BlockMetadata | undefined>;
|
|
8
|
-
saveMetadata(blockId: BlockId, metadata: BlockMetadata): Promise<void>;
|
|
9
|
-
getRevision(blockId: BlockId, rev: number): Promise<ActionId | undefined>;
|
|
10
|
-
saveRevision(blockId: BlockId, rev: number, actionId: ActionId): Promise<void>;
|
|
11
|
-
getPendingTransaction(blockId: BlockId, actionId: ActionId): Promise<Transform | undefined>;
|
|
12
|
-
savePendingTransaction(blockId: BlockId, actionId: ActionId, transform: Transform): Promise<void>;
|
|
13
|
-
deletePendingTransaction(blockId: BlockId, actionId: ActionId): Promise<void>;
|
|
14
|
-
listPendingTransactions(blockId: BlockId): AsyncIterable<ActionId>;
|
|
15
|
-
getTransaction(blockId: BlockId, actionId: ActionId): Promise<Transform | undefined>;
|
|
16
|
-
listRevisions(blockId: BlockId, startRev: number, endRev: number): AsyncIterable<ActionRev>;
|
|
17
|
-
saveTransaction(blockId: BlockId, actionId: ActionId, transform: Transform): Promise<void>;
|
|
18
|
-
getMaterializedBlock(blockId: BlockId, actionId: ActionId): Promise<IBlock | undefined>;
|
|
19
|
-
saveMaterializedBlock(blockId: BlockId, actionId: ActionId, block?: IBlock): Promise<void>;
|
|
20
|
-
promotePendingTransaction(blockId: BlockId, actionId: ActionId): Promise<void>;
|
|
21
|
-
private getBlockPath;
|
|
22
|
-
private getMetadataPath;
|
|
23
|
-
private getRevisionPath;
|
|
24
|
-
private getPendingActionPath;
|
|
25
|
-
private getActionPath;
|
|
26
|
-
private getMaterializedPath;
|
|
27
|
-
private readIfExists;
|
|
28
|
-
private ensureAndWriteFile;
|
|
29
|
-
}
|
|
30
|
-
//# sourceMappingURL=file-storage.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"file-storage.d.ts","sourceRoot":"","sources":["../../../src/storage/file-storage.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAC3F,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAKtD,qBAAa,cAAe,YAAW,WAAW;IACrC,OAAO,CAAC,QAAQ,CAAC,QAAQ;gBAAR,QAAQ,EAAE,MAAM;IAIvC,WAAW,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,aAAa,GAAG,SAAS,CAAC;IAIjE,YAAY,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC;IAOtE,WAAW,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,GAAG,SAAS,CAAC;IAIzE,YAAY,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;IAO9E,qBAAqB,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,SAAS,GAAG,SAAS,CAAC;IAI3F,sBAAsB,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,SAAS,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC;IAOjG,wBAAwB,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;IAS5E,uBAAuB,CAAC,OAAO,EAAE,OAAO,GAAG,aAAa,CAAC,QAAQ,CAAC;IAYnE,cAAc,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,SAAS,GAAG,SAAS,CAAC;IAInF,aAAa,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,aAAa,CAAC,SAAS,CAAC;IAU5F,eAAe,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,SAAS,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC;IAO1F,oBAAoB,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC;IAIvF,qBAAqB,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAe1F,yBAAyB,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;IAiBpF,OAAO,CAAC,YAAY;IAIpB,OAAO,CAAC,eAAe;IAIvB,OAAO,CAAC,eAAe;IAIvB,OAAO,CAAC,oBAAoB;IAI5B,OAAO,CAAC,aAAa;IAIrB,OAAO,CAAC,mBAAmB;YAIb,YAAY;YASZ,kBAAkB;CAIhC"}
|
|
@@ -1,127 +0,0 @@
|
|
|
1
|
-
import { promises as fs } from 'fs';
|
|
2
|
-
import * as path from 'path';
|
|
3
|
-
import { createLogger } from '../logger.js';
|
|
4
|
-
const log = createLogger('storage:file');
|
|
5
|
-
export class FileRawStorage {
|
|
6
|
-
basePath;
|
|
7
|
-
constructor(basePath) {
|
|
8
|
-
this.basePath = basePath;
|
|
9
|
-
// TODO: use https://www.npmjs.com/package/proper-lockfile to take a lock on the basePath, also introduce explicit dispose pattern
|
|
10
|
-
}
|
|
11
|
-
async getMetadata(blockId) {
|
|
12
|
-
return this.readIfExists(this.getMetadataPath(blockId));
|
|
13
|
-
}
|
|
14
|
-
async saveMetadata(blockId, metadata) {
|
|
15
|
-
await this.ensureAndWriteFile(this.getMetadataPath(blockId), JSON.stringify(metadata));
|
|
16
|
-
}
|
|
17
|
-
async getRevision(blockId, rev) {
|
|
18
|
-
return this.readIfExists(this.getRevisionPath(blockId, rev));
|
|
19
|
-
}
|
|
20
|
-
async saveRevision(blockId, rev, actionId) {
|
|
21
|
-
await this.ensureAndWriteFile(this.getRevisionPath(blockId, rev), actionId);
|
|
22
|
-
}
|
|
23
|
-
async getPendingTransaction(blockId, actionId) {
|
|
24
|
-
return this.readIfExists(this.getPendingActionPath(blockId, actionId));
|
|
25
|
-
}
|
|
26
|
-
async savePendingTransaction(blockId, actionId, transform) {
|
|
27
|
-
await this.ensureAndWriteFile(this.getPendingActionPath(blockId, actionId), JSON.stringify(transform));
|
|
28
|
-
}
|
|
29
|
-
async deletePendingTransaction(blockId, actionId) {
|
|
30
|
-
const pendingPath = this.getPendingActionPath(blockId, actionId);
|
|
31
|
-
await fs.unlink(pendingPath)
|
|
32
|
-
.catch((err) => {
|
|
33
|
-
// Ignore if file doesn't exist
|
|
34
|
-
if (err?.code !== 'ENOENT')
|
|
35
|
-
log('deletePendingTransaction unlink failed for %s/%s - %o', blockId, actionId, err);
|
|
36
|
-
});
|
|
37
|
-
}
|
|
38
|
-
async *listPendingTransactions(blockId) {
|
|
39
|
-
const pendingPath = path.join(this.getBlockPath(blockId), 'pend');
|
|
40
|
-
const files = await fs.readdir(pendingPath).catch((err) => { log('listPendingTransactions readdir failed for %s - %o', blockId, err); return []; });
|
|
41
|
-
for (const file of files) {
|
|
42
|
-
if (!file.endsWith('.json'))
|
|
43
|
-
continue;
|
|
44
|
-
const rawActionId = file.slice(0, -5);
|
|
45
|
-
if (!/^[\w\d]+-[\w\d]+-[\w\d]+-[\w\d]+-[\w\d]+$/.test(rawActionId))
|
|
46
|
-
continue;
|
|
47
|
-
yield rawActionId;
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
async getTransaction(blockId, actionId) {
|
|
51
|
-
return this.readIfExists(this.getActionPath(blockId, actionId));
|
|
52
|
-
}
|
|
53
|
-
async *listRevisions(blockId, startRev, endRev) {
|
|
54
|
-
// TODO: Optimize this for sparse revs
|
|
55
|
-
for (let rev = startRev; startRev <= endRev ? rev <= endRev : rev >= endRev; startRev <= endRev ? ++rev : --rev) {
|
|
56
|
-
const actionId = await this.getRevision(blockId, rev);
|
|
57
|
-
if (actionId) {
|
|
58
|
-
yield { actionId, rev };
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
async saveTransaction(blockId, actionId, transform) {
|
|
63
|
-
await this.ensureAndWriteFile(this.getActionPath(blockId, actionId), JSON.stringify(transform));
|
|
64
|
-
}
|
|
65
|
-
async getMaterializedBlock(blockId, actionId) {
|
|
66
|
-
return this.readIfExists(this.getMaterializedPath(blockId, actionId));
|
|
67
|
-
}
|
|
68
|
-
async saveMaterializedBlock(blockId, actionId, block) {
|
|
69
|
-
if (block) {
|
|
70
|
-
await this.ensureAndWriteFile(this.getMaterializedPath(blockId, actionId), JSON.stringify(block));
|
|
71
|
-
}
|
|
72
|
-
else {
|
|
73
|
-
await fs.unlink(this.getMaterializedPath(blockId, actionId))
|
|
74
|
-
.catch((err) => {
|
|
75
|
-
// Ignore if file doesn't exist
|
|
76
|
-
if (err?.code !== 'ENOENT')
|
|
77
|
-
log('saveMaterializedBlock unlink failed for %s/%s - %o', blockId, actionId, err);
|
|
78
|
-
});
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
async promotePendingTransaction(blockId, actionId) {
|
|
82
|
-
const pendingPath = this.getPendingActionPath(blockId, actionId);
|
|
83
|
-
const actionPath = this.getActionPath(blockId, actionId);
|
|
84
|
-
// Ensure target directory exists
|
|
85
|
-
await fs.mkdir(path.dirname(actionPath), { recursive: true });
|
|
86
|
-
return fs.rename(pendingPath, actionPath)
|
|
87
|
-
.catch(err => {
|
|
88
|
-
if (err.code === 'ENOENT') {
|
|
89
|
-
throw new Error(`Pending action ${actionId} not found for block ${blockId}`);
|
|
90
|
-
}
|
|
91
|
-
log('promotePendingTransaction rename failed for %s/%s - %o', blockId, actionId, err);
|
|
92
|
-
throw err;
|
|
93
|
-
});
|
|
94
|
-
}
|
|
95
|
-
getBlockPath(blockId) {
|
|
96
|
-
return path.join(this.basePath, blockId);
|
|
97
|
-
}
|
|
98
|
-
getMetadataPath(blockId) {
|
|
99
|
-
return path.join(this.getBlockPath(blockId), 'meta.json');
|
|
100
|
-
}
|
|
101
|
-
getRevisionPath(blockId, rev) {
|
|
102
|
-
return path.join(this.getBlockPath(blockId), 'revs', `${rev}.json`);
|
|
103
|
-
}
|
|
104
|
-
getPendingActionPath(blockId, actionId) {
|
|
105
|
-
return path.join(this.getBlockPath(blockId), 'pend', `${actionId}.json`);
|
|
106
|
-
}
|
|
107
|
-
getActionPath(blockId, actionId) {
|
|
108
|
-
return path.join(this.getBlockPath(blockId), 'actions', `${actionId}.json`);
|
|
109
|
-
}
|
|
110
|
-
getMaterializedPath(blockId, actionId) {
|
|
111
|
-
return path.join(this.getBlockPath(blockId), 'blocks', `${actionId}.json`);
|
|
112
|
-
}
|
|
113
|
-
async readIfExists(filePath) {
|
|
114
|
-
return fs.readFile(filePath, 'utf-8')
|
|
115
|
-
.then(content => JSON.parse(content))
|
|
116
|
-
.catch(err => {
|
|
117
|
-
if (err.code === 'ENOENT')
|
|
118
|
-
return undefined;
|
|
119
|
-
throw err;
|
|
120
|
-
});
|
|
121
|
-
}
|
|
122
|
-
async ensureAndWriteFile(filePath, content) {
|
|
123
|
-
await fs.mkdir(path.dirname(filePath), { recursive: true });
|
|
124
|
-
await fs.writeFile(filePath, content);
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
//# sourceMappingURL=file-storage.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"file-storage.js","sourceRoot":"","sources":["../../../src/storage/file-storage.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,163 +0,0 @@
|
|
|
1
|
-
import { promises as fs } from 'fs';
|
|
2
|
-
import * as path from 'path';
|
|
3
|
-
import type { BlockId, IBlock, Transform, ActionId, ActionRev } from "@optimystic/db-core";
|
|
4
|
-
import type { BlockMetadata } from "./struct.js";
|
|
5
|
-
import type { IRawStorage } from "./i-raw-storage.js";
|
|
6
|
-
import { createLogger } from '../logger.js'
|
|
7
|
-
|
|
8
|
-
const log = createLogger('storage:file')
|
|
9
|
-
|
|
10
|
-
export class FileRawStorage implements IRawStorage {
|
|
11
|
-
constructor(private readonly basePath: string) {
|
|
12
|
-
// TODO: use https://www.npmjs.com/package/proper-lockfile to take a lock on the basePath, also introduce explicit dispose pattern
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
async getMetadata(blockId: BlockId): Promise<BlockMetadata | undefined> {
|
|
16
|
-
return this.readIfExists<BlockMetadata>(this.getMetadataPath(blockId));
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
async saveMetadata(blockId: BlockId, metadata: BlockMetadata): Promise<void> {
|
|
20
|
-
await this.ensureAndWriteFile(
|
|
21
|
-
this.getMetadataPath(blockId),
|
|
22
|
-
JSON.stringify(metadata)
|
|
23
|
-
);
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
async getRevision(blockId: BlockId, rev: number): Promise<ActionId | undefined> {
|
|
27
|
-
return this.readIfExists<ActionId>(this.getRevisionPath(blockId, rev));
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
async saveRevision(blockId: BlockId, rev: number, actionId: ActionId): Promise<void> {
|
|
31
|
-
await this.ensureAndWriteFile(
|
|
32
|
-
this.getRevisionPath(blockId, rev),
|
|
33
|
-
actionId
|
|
34
|
-
);
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
async getPendingTransaction(blockId: BlockId, actionId: ActionId): Promise<Transform | undefined> {
|
|
38
|
-
return this.readIfExists<Transform>(this.getPendingActionPath(blockId, actionId));
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
async savePendingTransaction(blockId: BlockId, actionId: ActionId, transform: Transform): Promise<void> {
|
|
42
|
-
await this.ensureAndWriteFile(
|
|
43
|
-
this.getPendingActionPath(blockId, actionId),
|
|
44
|
-
JSON.stringify(transform)
|
|
45
|
-
);
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
async deletePendingTransaction(blockId: BlockId, actionId: ActionId): Promise<void> {
|
|
49
|
-
const pendingPath = this.getPendingActionPath(blockId, actionId);
|
|
50
|
-
await fs.unlink(pendingPath)
|
|
51
|
-
.catch((err) => {
|
|
52
|
-
// Ignore if file doesn't exist
|
|
53
|
-
if ((err as NodeJS.ErrnoException)?.code !== 'ENOENT') log('deletePendingTransaction unlink failed for %s/%s - %o', blockId, actionId, err)
|
|
54
|
-
});
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
async *listPendingTransactions(blockId: BlockId): AsyncIterable<ActionId> {
|
|
58
|
-
const pendingPath = path.join(this.getBlockPath(blockId), 'pend');
|
|
59
|
-
|
|
60
|
-
const files = await fs.readdir(pendingPath).catch((err) => { log('listPendingTransactions readdir failed for %s - %o', blockId, err); return [] as string[] });
|
|
61
|
-
for (const file of files) {
|
|
62
|
-
if (!file.endsWith('.json')) continue;
|
|
63
|
-
const rawActionId = file.slice(0, -5);
|
|
64
|
-
if (!/^[\w\d]+-[\w\d]+-[\w\d]+-[\w\d]+-[\w\d]+$/.test(rawActionId)) continue;
|
|
65
|
-
yield rawActionId as ActionId;
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
async getTransaction(blockId: BlockId, actionId: ActionId): Promise<Transform | undefined> {
|
|
70
|
-
return this.readIfExists<Transform>(this.getActionPath(blockId, actionId));
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
async *listRevisions(blockId: BlockId, startRev: number, endRev: number): AsyncIterable<ActionRev> {
|
|
74
|
-
// TODO: Optimize this for sparse revs
|
|
75
|
-
for (let rev = startRev; startRev <= endRev ? rev <= endRev : rev >= endRev; startRev <= endRev ? ++rev : --rev) {
|
|
76
|
-
const actionId = await this.getRevision(blockId, rev);
|
|
77
|
-
if (actionId) {
|
|
78
|
-
yield { actionId, rev };
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
async saveTransaction(blockId: BlockId, actionId: ActionId, transform: Transform): Promise<void> {
|
|
84
|
-
await this.ensureAndWriteFile(
|
|
85
|
-
this.getActionPath(blockId, actionId),
|
|
86
|
-
JSON.stringify(transform)
|
|
87
|
-
);
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
async getMaterializedBlock(blockId: BlockId, actionId: ActionId): Promise<IBlock | undefined> {
|
|
91
|
-
return this.readIfExists<IBlock>(this.getMaterializedPath(blockId, actionId));
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
async saveMaterializedBlock(blockId: BlockId, actionId: ActionId, block?: IBlock): Promise<void> {
|
|
95
|
-
if (block) {
|
|
96
|
-
await this.ensureAndWriteFile(
|
|
97
|
-
this.getMaterializedPath(blockId, actionId),
|
|
98
|
-
JSON.stringify(block)
|
|
99
|
-
);
|
|
100
|
-
} else {
|
|
101
|
-
await fs.unlink(this.getMaterializedPath(blockId, actionId))
|
|
102
|
-
.catch((err) => {
|
|
103
|
-
// Ignore if file doesn't exist
|
|
104
|
-
if ((err as NodeJS.ErrnoException)?.code !== 'ENOENT') log('saveMaterializedBlock unlink failed for %s/%s - %o', blockId, actionId, err)
|
|
105
|
-
});
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
async promotePendingTransaction(blockId: BlockId, actionId: ActionId): Promise<void> {
|
|
110
|
-
const pendingPath = this.getPendingActionPath(blockId, actionId);
|
|
111
|
-
const actionPath = this.getActionPath(blockId, actionId);
|
|
112
|
-
|
|
113
|
-
// Ensure target directory exists
|
|
114
|
-
await fs.mkdir(path.dirname(actionPath), { recursive: true });
|
|
115
|
-
|
|
116
|
-
return fs.rename(pendingPath, actionPath)
|
|
117
|
-
.catch(err => {
|
|
118
|
-
if (err.code === 'ENOENT') {
|
|
119
|
-
throw new Error(`Pending action ${actionId} not found for block ${blockId}`);
|
|
120
|
-
}
|
|
121
|
-
log('promotePendingTransaction rename failed for %s/%s - %o', blockId, actionId, err)
|
|
122
|
-
throw err;
|
|
123
|
-
});
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
private getBlockPath(blockId: BlockId): string {
|
|
127
|
-
return path.join(this.basePath, blockId);
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
private getMetadataPath(blockId: BlockId): string {
|
|
131
|
-
return path.join(this.getBlockPath(blockId), 'meta.json');
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
private getRevisionPath(blockId: BlockId, rev: number): string {
|
|
135
|
-
return path.join(this.getBlockPath(blockId), 'revs', `${rev}.json`);
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
private getPendingActionPath(blockId: BlockId, actionId: ActionId): string {
|
|
139
|
-
return path.join(this.getBlockPath(blockId), 'pend', `${actionId}.json`);
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
private getActionPath(blockId: BlockId, actionId: ActionId): string {
|
|
143
|
-
return path.join(this.getBlockPath(blockId), 'actions', `${actionId}.json`);
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
private getMaterializedPath(blockId: BlockId, actionId: ActionId): string {
|
|
147
|
-
return path.join(this.getBlockPath(blockId), 'blocks', `${actionId}.json`);
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
private async readIfExists<T>(filePath: string): Promise<T | undefined> {
|
|
151
|
-
return fs.readFile(filePath, 'utf-8')
|
|
152
|
-
.then(content => JSON.parse(content) as T)
|
|
153
|
-
.catch(err => {
|
|
154
|
-
if (err.code === 'ENOENT') return undefined;
|
|
155
|
-
throw err;
|
|
156
|
-
});
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
private async ensureAndWriteFile(filePath: string, content: string): Promise<void> {
|
|
160
|
-
await fs.mkdir(path.dirname(filePath), { recursive: true });
|
|
161
|
-
await fs.writeFile(filePath, content);
|
|
162
|
-
}
|
|
163
|
-
}
|