web-dc-api 0.1.5 → 0.1.7
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/cjs/index.js +1 -1
- package/dist/dc.min.js +1 -1
- package/dist/esm/index.js +1 -1
- package/dist/index.d.ts +934 -878
- package/package.json +4 -8
- package/dist/cjs/helia-core-B1Xqha7a.js +0 -1
- package/dist/cjs/helia-core-D8Uv1KjQ.js +0 -1
- package/dist/cjs/polkadot-api-7PhQf3ws.js +0 -1
- package/dist/cjs/polkadot-api-CtrJVWuZ.js +0 -1
- package/dist/esm/chunks/helia-core-BxMqyK2Y.js +0 -1
- package/dist/esm/chunks/helia-core-DMXRpcO-.js +0 -1
- package/dist/esm/chunks/polkadot-api-5Y9Bw8VT.js +0 -1
- package/dist/esm/chunks/polkadot-api-D69Ioun_.js +0 -1
- package/lib/common/blowfish/block.ts +0 -259
- package/lib/common/blowfish/cipher.ts +0 -144
- package/lib/common/blowfish/const.ts +0 -195
- package/lib/common/chain.ts +0 -469
- package/lib/common/commonclient.ts +0 -202
- package/lib/common/constants.ts +0 -55
- package/lib/common/dc-key/ed25519.ts +0 -343
- package/lib/common/dc-key/keyManager.ts +0 -424
- package/lib/common/dcapi.ts +0 -98
- package/lib/common/dcutil.ts +0 -627
- package/lib/common/define.ts +0 -70
- package/lib/common/error.ts +0 -67
- package/lib/common/grpc-dc.ts +0 -104
- package/lib/common/module-system.ts +0 -184
- package/lib/common/service-worker.ts +0 -234
- package/lib/common/types/types.ts +0 -344
- package/lib/dc.ts +0 -701
- package/lib/implements/account/client.ts +0 -185
- package/lib/implements/account/manager.ts +0 -683
- package/lib/implements/aiproxy/client.ts +0 -357
- package/lib/implements/aiproxy/manager.ts +0 -670
- package/lib/implements/cache/client.ts +0 -105
- package/lib/implements/cache/manager.ts +0 -127
- package/lib/implements/comment/client.ts +0 -982
- package/lib/implements/comment/manager.ts +0 -1151
- package/lib/implements/dc/client.ts +0 -51
- package/lib/implements/dc/manager.ts +0 -33
- package/lib/implements/file/client.ts +0 -253
- package/lib/implements/file/file-cache-manager.ts +0 -142
- package/lib/implements/file/manager.ts +0 -1240
- package/lib/implements/file/seekableFileStream.ts +0 -344
- package/lib/implements/file/streamwriter.ts +0 -322
- package/lib/implements/keyvalue/client.ts +0 -376
- package/lib/implements/keyvalue/manager.ts +0 -759
- package/lib/implements/message/client.ts +0 -250
- package/lib/implements/message/manager.ts +0 -215
- package/lib/implements/threaddb/cbor/coding.ts +0 -62
- package/lib/implements/threaddb/cbor/event.ts +0 -336
- package/lib/implements/threaddb/cbor/node.ts +0 -542
- package/lib/implements/threaddb/cbor/record.ts +0 -398
- package/lib/implements/threaddb/common/AsyncMutex.ts +0 -24
- package/lib/implements/threaddb/common/addrinfo.ts +0 -135
- package/lib/implements/threaddb/common/dispatcher.ts +0 -81
- package/lib/implements/threaddb/common/idbstore-adapter.ts +0 -260
- package/lib/implements/threaddb/common/json-patcher.ts +0 -204
- package/lib/implements/threaddb/common/key.ts +0 -290
- package/lib/implements/threaddb/common/level-adapter.ts +0 -235
- package/lib/implements/threaddb/common/lineReader.ts +0 -79
- package/lib/implements/threaddb/common/logstore.ts +0 -215
- package/lib/implements/threaddb/common/transformed-datastore.ts +0 -308
- package/lib/implements/threaddb/core/app.ts +0 -206
- package/lib/implements/threaddb/core/core.ts +0 -230
- package/lib/implements/threaddb/core/db.ts +0 -249
- package/lib/implements/threaddb/core/event.ts +0 -54
- package/lib/implements/threaddb/core/head.ts +0 -89
- package/lib/implements/threaddb/core/identity.ts +0 -171
- package/lib/implements/threaddb/core/logstore.ts +0 -137
- package/lib/implements/threaddb/core/options.ts +0 -14
- package/lib/implements/threaddb/core/record.ts +0 -54
- package/lib/implements/threaddb/db/collection.ts +0 -1910
- package/lib/implements/threaddb/db/db.ts +0 -698
- package/lib/implements/threaddb/db/json2Query.ts +0 -192
- package/lib/implements/threaddb/db/query.ts +0 -524
- package/lib/implements/threaddb/dbclient.ts +0 -543
- package/lib/implements/threaddb/dbmanager.ts +0 -1906
- package/lib/implements/threaddb/lsstoreds/addr_book.ts +0 -549
- package/lib/implements/threaddb/lsstoreds/cache.ts +0 -36
- package/lib/implements/threaddb/lsstoreds/cyclic_batch.ts +0 -87
- package/lib/implements/threaddb/lsstoreds/global.ts +0 -151
- package/lib/implements/threaddb/lsstoreds/headbook.ts +0 -373
- package/lib/implements/threaddb/lsstoreds/keybook.ts +0 -297
- package/lib/implements/threaddb/lsstoreds/logstore.ts +0 -29
- package/lib/implements/threaddb/lsstoreds/metadata.ts +0 -223
- package/lib/implements/threaddb/net/define.ts +0 -149
- package/lib/implements/threaddb/net/grpcClient.ts +0 -589
- package/lib/implements/threaddb/net/grpcserver.ts +0 -146
- package/lib/implements/threaddb/net/net.ts +0 -2047
- package/lib/implements/threaddb/pb/lstore.proto +0 -38
- package/lib/implements/threaddb/pb/lstore.ts +0 -393
- package/lib/implements/threaddb/pb/lstore_pb.d.ts +0 -433
- package/lib/implements/threaddb/pb/lstore_pb.js +0 -1085
- package/lib/implements/threaddb/pb/net.proto +0 -194
- package/lib/implements/threaddb/pb/net_pb.d.ts +0 -2349
- package/lib/implements/threaddb/pb/net_pb.js +0 -5525
- package/lib/implements/threaddb/pb/proto-custom-types.ts +0 -212
- package/lib/implements/util/client.ts +0 -72
- package/lib/implements/util/manager.ts +0 -146
- package/lib/implements/wallet/manager.ts +0 -671
- package/lib/index.ts +0 -57
- package/lib/interfaces/DCContext.ts +0 -51
- package/lib/interfaces/aiproxy-interface.ts +0 -145
- package/lib/interfaces/auth-interface.ts +0 -118
- package/lib/interfaces/cache-interface.ts +0 -22
- package/lib/interfaces/client-interface.ts +0 -11
- package/lib/interfaces/comment-interface.ts +0 -167
- package/lib/interfaces/components/news-component.ts +0 -0
- package/lib/interfaces/database-interface.ts +0 -169
- package/lib/interfaces/file-interface.ts +0 -120
- package/lib/interfaces/index.ts +0 -10
- package/lib/interfaces/keyvalue-interface.ts +0 -156
- package/lib/interfaces/message-interface.ts +0 -22
- package/lib/interfaces/util-interface.ts +0 -31
- package/lib/modules/aiproxy-module.ts +0 -246
- package/lib/modules/auth-module.ts +0 -753
- package/lib/modules/cache-module.ts +0 -99
- package/lib/modules/client-module.ts +0 -71
- package/lib/modules/comment-module.ts +0 -429
- package/lib/modules/components/news-components.ts +0 -390
- package/lib/modules/database-module.ts +0 -598
- package/lib/modules/file-module.ts +0 -291
- package/lib/modules/index.ts +0 -13
- package/lib/modules/keyvalue-module.ts +0 -379
- package/lib/modules/message-module.ts +0 -107
- package/lib/modules/util-module.ts +0 -148
- package/lib/polyfills/process-env-browser.ts +0 -1
- package/lib/proto/datasource.ts +0 -93
- package/lib/proto/dcnet.proto +0 -1601
- package/lib/proto/dcnet_proto.d.ts +0 -22857
- package/lib/proto/dcnet_proto.js +0 -55204
- package/lib/proto/dcnet_proto_sparse.js +0 -55166
- package/lib/proto/oidfetch.proto +0 -25
- package/lib/proto/oidfetch_proto.d.ts +0 -585
- package/lib/proto/oidfetch_proto.js +0 -1247
- package/lib/serverless/babel-browser.ts +0 -39
- package/lib/serverless/base_entity.ts +0 -78
- package/lib/serverless/base_repository.ts +0 -414
- package/lib/serverless/browser_schema_extractor.ts +0 -283
- package/lib/serverless/decorator_factory.ts +0 -322
- package/lib/util/BrowserLineReader.ts +0 -73
- package/lib/util/base64.ts +0 -105
- package/lib/util/bcrypt.ts +0 -206
- package/lib/util/curve25519Encryption.ts +0 -418
- package/lib/util/dccrypt.ts +0 -73
- package/lib/util/logger.ts +0 -104
- package/lib/util/utils.ts +0 -289
|
@@ -1,698 +0,0 @@
|
|
|
1
|
-
// db.ts - Complete TypeScript Implementation (Simplified Core)
|
|
2
|
-
import { EventEmitter } from "events";
|
|
3
|
-
import {} from "../common/transformed-datastore";
|
|
4
|
-
import { Key, Query } from "interface-datastore";
|
|
5
|
-
import { Key as ThreadKey } from "../common/key";
|
|
6
|
-
import { Connector } from "../core/app";
|
|
7
|
-
import {
|
|
8
|
-
Context,
|
|
9
|
-
IDBInfo,
|
|
10
|
-
ManagedOptions,
|
|
11
|
-
ThreadInfo,
|
|
12
|
-
ThreadMuliaddr,
|
|
13
|
-
} from "../core/core";
|
|
14
|
-
import {
|
|
15
|
-
EventCodec,
|
|
16
|
-
Errors,
|
|
17
|
-
pullThreadBackgroundTimeout,
|
|
18
|
-
PullTimeout,
|
|
19
|
-
} from "../core/db";
|
|
20
|
-
import { IThreadRecord } from "../core/record";
|
|
21
|
-
import { Ed25519PubKey } from "../../../common/dc-key/ed25519";
|
|
22
|
-
import { JSONSchemaType } from "ajv";
|
|
23
|
-
import { IThreadEvent } from "../core/event";
|
|
24
|
-
import { Collection, Txn } from "./collection";
|
|
25
|
-
import { ThreadToken } from "../core/identity";
|
|
26
|
-
import { NewOptions, Index, ICollectionConfig } from "../core/core";
|
|
27
|
-
import {
|
|
28
|
-
Event,
|
|
29
|
-
InstanceID,
|
|
30
|
-
ReduceAction,
|
|
31
|
-
Action,
|
|
32
|
-
CoreActionType,
|
|
33
|
-
TxnDatastoreExtended,
|
|
34
|
-
Transaction,
|
|
35
|
-
IndexFunc,
|
|
36
|
-
DBPrefix,
|
|
37
|
-
IDB,
|
|
38
|
-
ITxn,
|
|
39
|
-
} from "../core/db";
|
|
40
|
-
|
|
41
|
-
import { ulid } from "ulid";
|
|
42
|
-
import { JsonPatcher } from "../common/json-patcher";
|
|
43
|
-
import { multiaddr, Multiaddr } from "@multiformats/multiaddr";
|
|
44
|
-
import { ThreadID } from "@textile/threads-id";
|
|
45
|
-
import { PeerId } from "@libp2p/interface";
|
|
46
|
-
import { Net } from "../core/app";
|
|
47
|
-
import { Dispatcher } from "../common/dispatcher";
|
|
48
|
-
import { LocalEventsBus, App } from "../core/app";
|
|
49
|
-
import * as dagPB from "@ipld/dag-pb";
|
|
50
|
-
import * as threadEvent from "../cbor/event";
|
|
51
|
-
import { IRecord } from "../core/record";
|
|
52
|
-
import { IPLDNode } from "../core/core";
|
|
53
|
-
import { jsonStringify } from "../../../util/utils";
|
|
54
|
-
|
|
55
|
-
const baseKey = DBPrefix.dsPrefix.child(new Key("collection"));
|
|
56
|
-
const getBlockInitialTimeout = 500;
|
|
57
|
-
const getBlockRetries = 3;
|
|
58
|
-
|
|
59
|
-
export class CollectionEvent<T = any> implements Event<T> {
|
|
60
|
-
readonly timestamp: BigInt;
|
|
61
|
-
|
|
62
|
-
constructor(
|
|
63
|
-
readonly instanceID: InstanceID,
|
|
64
|
-
readonly collection: string,
|
|
65
|
-
readonly payload: T
|
|
66
|
-
) {
|
|
67
|
-
this.timestamp = BigInt(
|
|
68
|
-
Date.now() * 1000000 + Math.floor(Math.random() * 1000000)
|
|
69
|
-
);
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
async marshal(): Promise<Uint8Array> {
|
|
73
|
-
return new TextEncoder().encode(
|
|
74
|
-
jsonStringify({
|
|
75
|
-
t: this.timestamp,
|
|
76
|
-
i: this.instanceID,
|
|
77
|
-
c: this.collection,
|
|
78
|
-
p: this.payload,
|
|
79
|
-
})
|
|
80
|
-
);
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
class CollectionExistsError extends Error {
|
|
85
|
-
name: string;
|
|
86
|
-
constructor(name: string) {
|
|
87
|
-
super(`Collection ${name} already exists`);
|
|
88
|
-
this.name = "CollectionExistsError";
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
export class DB implements App, IDB {
|
|
93
|
-
private name: string;
|
|
94
|
-
public connector: Connector | null = null; //
|
|
95
|
-
public datastore: TxnDatastoreExtended;
|
|
96
|
-
public dispatcher: Dispatcher | null = null;
|
|
97
|
-
public eventcodec: EventCodec;
|
|
98
|
-
public collections: Map<string, Collection> = new Map();
|
|
99
|
-
public localEventsBus: LocalEventsBus | null = null;
|
|
100
|
-
private webLock: string;
|
|
101
|
-
|
|
102
|
-
constructor(
|
|
103
|
-
datastore: TxnDatastoreExtended,
|
|
104
|
-
net: Net,
|
|
105
|
-
id: string,
|
|
106
|
-
opts: NewOptions
|
|
107
|
-
) {
|
|
108
|
-
this.datastore = datastore;
|
|
109
|
-
this.name = opts.name || "unnamed";
|
|
110
|
-
this.eventcodec = opts.eventCodec || new JsonPatcher();
|
|
111
|
-
this.webLock = "webLock_db_" + id;
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
// 新建 DB 实例
|
|
115
|
-
static async newDB(
|
|
116
|
-
store: TxnDatastoreExtended,
|
|
117
|
-
n: Net,
|
|
118
|
-
id: ThreadID,
|
|
119
|
-
opts?: NewOptions
|
|
120
|
-
): Promise<DB> {
|
|
121
|
-
const args = opts || new NewOptions();
|
|
122
|
-
if (!args.eventCodec) {
|
|
123
|
-
args.eventCodec = new JsonPatcher(); //DefaultEventCodec()
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
const dbInstance = new DB(store, n, id.toString(), args);
|
|
127
|
-
dbInstance.name = "";
|
|
128
|
-
dbInstance.dispatcher = new Dispatcher(store);
|
|
129
|
-
dbInstance.localEventsBus = new LocalEventsBus();
|
|
130
|
-
|
|
131
|
-
try {
|
|
132
|
-
await dbInstance.loadName();
|
|
133
|
-
} catch (error) {
|
|
134
|
-
throw new Error("Failed to load DB name");
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
const prevName = dbInstance.name;
|
|
138
|
-
if (args.name) {
|
|
139
|
-
dbInstance.name = args.name;
|
|
140
|
-
} else if (prevName === "") {
|
|
141
|
-
dbInstance.name = "unnamed";
|
|
142
|
-
}
|
|
143
|
-
await dbInstance.saveName(prevName);
|
|
144
|
-
await dbInstance.reCreateCollections();
|
|
145
|
-
dbInstance.dispatcher.register(dbInstance);
|
|
146
|
-
|
|
147
|
-
try {
|
|
148
|
-
const connector = await n.connectApp(dbInstance, id);
|
|
149
|
-
dbInstance.connector = connector;
|
|
150
|
-
} catch (err) {
|
|
151
|
-
throw new Error(
|
|
152
|
-
`Failed to connect app: ${
|
|
153
|
-
err instanceof Error ? err.message : String(err)
|
|
154
|
-
}`
|
|
155
|
-
);
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
// 处理集合配置
|
|
159
|
-
if (args.collections && args.collections.length > 0) {
|
|
160
|
-
for (const collectionConfig of args.collections) {
|
|
161
|
-
try {
|
|
162
|
-
await dbInstance.newCollection(collectionConfig);
|
|
163
|
-
} catch (err) {
|
|
164
|
-
throw new Error(
|
|
165
|
-
`Failed to create collection: ${
|
|
166
|
-
err instanceof Error ? err.message : String(err)
|
|
167
|
-
}`
|
|
168
|
-
);
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
return dbInstance;
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
/**
|
|
176
|
-
* GetDBInfo returns the addresses and key that can be used to join the DB thread.
|
|
177
|
-
* @param options Optional settings for the operation
|
|
178
|
-
* @returns Promise resolving to thread info
|
|
179
|
-
*/
|
|
180
|
-
async getDBInfo(options?: ManagedOptions): Promise<IDBInfo> {
|
|
181
|
-
console.debug(`getting db info in ${this.name}`);
|
|
182
|
-
|
|
183
|
-
try {
|
|
184
|
-
const threadInfo = await this.connector?.net.getThread(
|
|
185
|
-
this.connector?.threadId,
|
|
186
|
-
{ token: options?.token }
|
|
187
|
-
);
|
|
188
|
-
const dbInfo: IDBInfo = {
|
|
189
|
-
id: this.connector ? this.connector.threadId.toString() : "",
|
|
190
|
-
name: this.name,
|
|
191
|
-
addrs: threadInfo
|
|
192
|
-
? threadInfo.addrs.map((addr: ThreadMuliaddr) => addr.toString())
|
|
193
|
-
: [],
|
|
194
|
-
key: threadInfo ? threadInfo.key?.toString() : "",
|
|
195
|
-
};
|
|
196
|
-
return dbInfo;
|
|
197
|
-
} catch (err) {
|
|
198
|
-
throw new Error(
|
|
199
|
-
`Failed to get DB info: ${
|
|
200
|
-
err instanceof Error ? err.message : String(err)
|
|
201
|
-
}`
|
|
202
|
-
);
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
async saveName(prevName: string): Promise<void> {
|
|
207
|
-
if (this.name === prevName) return;
|
|
208
|
-
if (!this.name.match(/^[a-zA-Z0-9_-]+$/)) {
|
|
209
|
-
// 根据需求定义规则
|
|
210
|
-
throw new Error("Invalid name");
|
|
211
|
-
}
|
|
212
|
-
await this.datastore.put(
|
|
213
|
-
DBPrefix.dsName,
|
|
214
|
-
new TextEncoder().encode(this.name)
|
|
215
|
-
);
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
async loadName(): Promise<void> {
|
|
219
|
-
try {
|
|
220
|
-
const nameBuffer = await this.datastore.get(DBPrefix.dsName);
|
|
221
|
-
if (nameBuffer) {
|
|
222
|
-
this.name = new TextDecoder().decode(nameBuffer);
|
|
223
|
-
}
|
|
224
|
-
} catch (error) {}
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
async saveVerno(verno: number): Promise<void> {
|
|
228
|
-
await this.datastore.put(
|
|
229
|
-
DBPrefix.dsVerno,
|
|
230
|
-
new TextEncoder().encode(verno.toString())
|
|
231
|
-
);
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
async loadVerno(): Promise<number> {
|
|
235
|
-
try {
|
|
236
|
-
const vernoBuffer = await this.datastore.get(DBPrefix.dsVerno);
|
|
237
|
-
if (vernoBuffer) {
|
|
238
|
-
return parseInt(new TextDecoder().decode(vernoBuffer));
|
|
239
|
-
}
|
|
240
|
-
} catch (error) {}
|
|
241
|
-
return 0;
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
private async initCollections(configs: ICollectionConfig[]): Promise<void> {
|
|
246
|
-
for (const config of configs) {
|
|
247
|
-
await this.newCollection(config);
|
|
248
|
-
}
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
async upgradeCollections(configs: ICollectionConfig[]): Promise<void> {
|
|
252
|
-
for (const config of configs) {
|
|
253
|
-
await this.newCollection(config,true);
|
|
254
|
-
}
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
async newCollection(config: ICollectionConfig,forceUpdate:boolean=false): Promise<Collection> {
|
|
258
|
-
if (this.collections.has(config.name) && !forceUpdate) {
|
|
259
|
-
throw new CollectionExistsError(config.name);
|
|
260
|
-
}
|
|
261
|
-
const collection = new Collection(config.name, config.schema, this);
|
|
262
|
-
|
|
263
|
-
// Add default _id index
|
|
264
|
-
await collection.addIndex({ path: "_id", unique: true });
|
|
265
|
-
|
|
266
|
-
// Add custom indexes
|
|
267
|
-
for (const index of config.indexes || []) {
|
|
268
|
-
await collection.addIndex(index);
|
|
269
|
-
}
|
|
270
|
-
//保存集合配置到数据存储
|
|
271
|
-
this.saveCollection(collection);
|
|
272
|
-
return collection;
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
async saveCollection(c: Collection): Promise<void> {
|
|
276
|
-
console.debug(`saving collection ${c.name} in ${this.name}`);
|
|
277
|
-
|
|
278
|
-
try {
|
|
279
|
-
// Save schema
|
|
280
|
-
await this.datastore.put(
|
|
281
|
-
DBPrefix.dsSchemas.child(new Key(c.name)),
|
|
282
|
-
c.getSchema()
|
|
283
|
-
);
|
|
284
|
-
|
|
285
|
-
// Save write validator if exists
|
|
286
|
-
if (c.rawWriteValidator) {
|
|
287
|
-
await this.datastore.put(
|
|
288
|
-
DBPrefix.dsValidators.child(new Key(c.name)),
|
|
289
|
-
new TextEncoder().encode(c.rawWriteValidator)
|
|
290
|
-
);
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
// Save read filter if exists
|
|
294
|
-
if (c.rawReadFilter) {
|
|
295
|
-
await this.datastore.put(
|
|
296
|
-
DBPrefix.dsFilters.child(new Key(c.name)),
|
|
297
|
-
new TextEncoder().encode(c.rawReadFilter)
|
|
298
|
-
);
|
|
299
|
-
}
|
|
300
|
-
// Add collection to local map
|
|
301
|
-
this.collections.set(c.name, c);
|
|
302
|
-
} catch (err) {
|
|
303
|
-
throw new Error(
|
|
304
|
-
`Failed to save collection ${c.name}: ${
|
|
305
|
-
err instanceof Error ? err.message : String(err)
|
|
306
|
-
}`
|
|
307
|
-
);
|
|
308
|
-
}
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
async reCreateCollections(): Promise<void> {
|
|
312
|
-
try {
|
|
313
|
-
const results = this.datastore.query({
|
|
314
|
-
prefix: DBPrefix.dsSchemas.toString(),
|
|
315
|
-
}) as AsyncIterable<{ key: Key; value: Uint8Array }>;
|
|
316
|
-
|
|
317
|
-
try {
|
|
318
|
-
for await (const res of results) {
|
|
319
|
-
const name = res.key.name();
|
|
320
|
-
const schema = JSON.parse(new TextDecoder().decode(res.value));
|
|
321
|
-
|
|
322
|
-
let wv: string | undefined;
|
|
323
|
-
try {
|
|
324
|
-
const wvBuffer = await this.datastore.get(
|
|
325
|
-
DBPrefix.dsValidators.child(new Key(name))
|
|
326
|
-
);
|
|
327
|
-
wv = new TextDecoder().decode(wvBuffer);
|
|
328
|
-
} catch (err: any) {
|
|
329
|
-
if (err.code !== "ERR_NOT_FOUND") throw err;
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
let rf: string | undefined;
|
|
333
|
-
try {
|
|
334
|
-
const rfBuffer = await this.datastore.get(
|
|
335
|
-
DBPrefix.dsFilters.child(new Key(name))
|
|
336
|
-
);
|
|
337
|
-
rf = new TextDecoder().decode(rfBuffer);
|
|
338
|
-
} catch (err: any) {
|
|
339
|
-
if (err.code !== "ERR_NOT_FOUND") throw err;
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
const c = new Collection(name, schema, this);
|
|
343
|
-
|
|
344
|
-
// 修复索引对象
|
|
345
|
-
try {
|
|
346
|
-
const indexBuffer = await this.datastore.get(
|
|
347
|
-
DBPrefix.dsIndexes.child(new Key(name))
|
|
348
|
-
);
|
|
349
|
-
const indexData = JSON.parse(new TextDecoder().decode(indexBuffer));
|
|
350
|
-
|
|
351
|
-
// 修复索引映射 - 使用 Map 而不是对象
|
|
352
|
-
for (const [path, index] of Object.entries(indexData)) {
|
|
353
|
-
if (path) {
|
|
354
|
-
c.indexes.set(path, index as Index);
|
|
355
|
-
}
|
|
356
|
-
}
|
|
357
|
-
} catch (err: any) {
|
|
358
|
-
if (err.code !== "ERR_NOT_FOUND") throw err;
|
|
359
|
-
}
|
|
360
|
-
|
|
361
|
-
// 添加到集合映射
|
|
362
|
-
this.collections.set(c.name, c);
|
|
363
|
-
}
|
|
364
|
-
} catch (err) {
|
|
365
|
-
throw new Error(
|
|
366
|
-
`Error re-creating collections: ${
|
|
367
|
-
err instanceof Error ? err.message : String(err)
|
|
368
|
-
}`
|
|
369
|
-
);
|
|
370
|
-
}
|
|
371
|
-
} catch (err) {
|
|
372
|
-
throw new Error(
|
|
373
|
-
`Error re-creating collections: ${
|
|
374
|
-
err instanceof Error ? err.message : String(err)
|
|
375
|
-
}`
|
|
376
|
-
);
|
|
377
|
-
}
|
|
378
|
-
}
|
|
379
|
-
|
|
380
|
-
getCollection(name: string): Collection {
|
|
381
|
-
const collection = this.collections.get(name);
|
|
382
|
-
if (!collection) throw new Error(`Collection ${name} not found`);
|
|
383
|
-
return collection;
|
|
384
|
-
}
|
|
385
|
-
|
|
386
|
-
async close(): Promise<void> {}
|
|
387
|
-
|
|
388
|
-
async reduce(events: Event[]): Promise<void> {
|
|
389
|
-
try {
|
|
390
|
-
// 调用事件编解码器的 reduce 方法获取处理结果
|
|
391
|
-
const codecActions = await this.eventcodec.reduce(
|
|
392
|
-
events,
|
|
393
|
-
this.datastore,
|
|
394
|
-
baseKey,
|
|
395
|
-
this.defaultIndexFunc()
|
|
396
|
-
);
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
// 创建 actions 数组并映射处理结果
|
|
400
|
-
const actions: Action[] = codecActions.map((ca) => {
|
|
401
|
-
// 返回转换后的 Action 对象
|
|
402
|
-
return {
|
|
403
|
-
collectionName: ca.collection,
|
|
404
|
-
type: ca.type,
|
|
405
|
-
instanceID: ca.instanceID,
|
|
406
|
-
};
|
|
407
|
-
});
|
|
408
|
-
|
|
409
|
-
// 通知状态变更
|
|
410
|
-
this.notifyStateChanged(actions);
|
|
411
|
-
} catch (err) {
|
|
412
|
-
throw new Error(
|
|
413
|
-
`Error reducing events: ${
|
|
414
|
-
err instanceof Error ? err.message : String(err)
|
|
415
|
-
}`
|
|
416
|
-
);
|
|
417
|
-
}
|
|
418
|
-
}
|
|
419
|
-
|
|
420
|
-
/**
|
|
421
|
-
* 默认索引函数
|
|
422
|
-
* 创建一个处理集合索引更新的函数
|
|
423
|
-
*/
|
|
424
|
-
defaultIndexFunc(): (
|
|
425
|
-
collection: string,
|
|
426
|
-
key: Key,
|
|
427
|
-
txn: any,
|
|
428
|
-
oldData?: Uint8Array,
|
|
429
|
-
newData?: Uint8Array
|
|
430
|
-
) => Promise<void> {
|
|
431
|
-
return async (
|
|
432
|
-
collection: string,
|
|
433
|
-
key: Key,
|
|
434
|
-
txn: any,
|
|
435
|
-
oldData?: Uint8Array,
|
|
436
|
-
newData?: Uint8Array
|
|
437
|
-
): Promise<void> => {
|
|
438
|
-
const c = this.collections.get(collection);
|
|
439
|
-
if (!c) {
|
|
440
|
-
throw new Error(`collection (${collection}) not found`);
|
|
441
|
-
}
|
|
442
|
-
if (oldData) {
|
|
443
|
-
await c.indexDelete(txn, key, oldData);
|
|
444
|
-
}
|
|
445
|
-
if (!newData) {
|
|
446
|
-
return;
|
|
447
|
-
}
|
|
448
|
-
await c.indexAdd(txn, key, newData);
|
|
449
|
-
};
|
|
450
|
-
}
|
|
451
|
-
|
|
452
|
-
// 添加通知状态变更的方法
|
|
453
|
-
private notifyStateChanged(actions: Action[]): void {
|
|
454
|
-
// 发送状态变更事件
|
|
455
|
-
if (this.localEventsBus) {
|
|
456
|
-
//浏览器侧暂不实现
|
|
457
|
-
}
|
|
458
|
-
}
|
|
459
|
-
/**
|
|
460
|
-
* 通知事务事件
|
|
461
|
-
* 将事务相关的节点和令牌发送到本地事件总线
|
|
462
|
-
*/
|
|
463
|
-
async notifyTxnEvents(node: IPLDNode, token: ThreadToken): Promise<void> {
|
|
464
|
-
try {
|
|
465
|
-
await this.localEventsBus?.send({
|
|
466
|
-
node: node,
|
|
467
|
-
token: token,
|
|
468
|
-
});
|
|
469
|
-
} catch (err) {
|
|
470
|
-
throw new Error(
|
|
471
|
-
`Failed to notify transaction events: ${
|
|
472
|
-
err instanceof Error ? err.message : String(err)
|
|
473
|
-
}`
|
|
474
|
-
);
|
|
475
|
-
}
|
|
476
|
-
}
|
|
477
|
-
|
|
478
|
-
async dispatch(events: Event[]): Promise<void> {
|
|
479
|
-
// 实现事件分发逻辑
|
|
480
|
-
for (const event of events) {
|
|
481
|
-
await this.reduce([event]);
|
|
482
|
-
}
|
|
483
|
-
}
|
|
484
|
-
|
|
485
|
-
async validateNetRecordBody(
|
|
486
|
-
body: IPLDNode,
|
|
487
|
-
identity: Ed25519PubKey
|
|
488
|
-
): Promise<Error | undefined> {
|
|
489
|
-
try {
|
|
490
|
-
const events: Event[] = await this.eventcodec.eventsFromBytes(
|
|
491
|
-
body.data()
|
|
492
|
-
);
|
|
493
|
-
if (events.length === 0) {
|
|
494
|
-
return;
|
|
495
|
-
}
|
|
496
|
-
|
|
497
|
-
for (const e of events) {
|
|
498
|
-
const collection = this.collections.get(e.collection);
|
|
499
|
-
if (!collection) {
|
|
500
|
-
return Errors.ErrCollectionNotFound;
|
|
501
|
-
}
|
|
502
|
-
}
|
|
503
|
-
return;
|
|
504
|
-
} catch (error) {
|
|
505
|
-
return error as Error;
|
|
506
|
-
}
|
|
507
|
-
}
|
|
508
|
-
|
|
509
|
-
async handleNetRecord(
|
|
510
|
-
rec: IThreadRecord,
|
|
511
|
-
key: ThreadKey
|
|
512
|
-
): Promise<Error | undefined> {
|
|
513
|
-
let event: any;
|
|
514
|
-
try {
|
|
515
|
-
if (!this.connector) {
|
|
516
|
-
return new Error("no connector");
|
|
517
|
-
}
|
|
518
|
-
// 从记录中解码事件
|
|
519
|
-
event = await threadEvent.EventFromRecord(
|
|
520
|
-
this.connector?.net.bstore,
|
|
521
|
-
rec.value()
|
|
522
|
-
);
|
|
523
|
-
} catch (err) {
|
|
524
|
-
// 如果解码失败,尝试从块中获取事件
|
|
525
|
-
try {
|
|
526
|
-
const block = await this.getBlockWithRetry(rec.value());
|
|
527
|
-
event = await threadEvent.EventFromNode(block);
|
|
528
|
-
} catch (blockErr) {
|
|
529
|
-
return blockErr as Error;
|
|
530
|
-
}
|
|
531
|
-
}
|
|
532
|
-
try {
|
|
533
|
-
// 获取事件的主体
|
|
534
|
-
const body = await event.getBody(this.connector?.net, key.read());
|
|
535
|
-
|
|
536
|
-
// 从字节数据中解码事件
|
|
537
|
-
const events = await this.eventcodec.eventsFromBytes(body.rawData());
|
|
538
|
-
|
|
539
|
-
// 分发事件
|
|
540
|
-
await this.dispatch(events);
|
|
541
|
-
} catch (err) {
|
|
542
|
-
return new Error(
|
|
543
|
-
`error when processing event: ${
|
|
544
|
-
err instanceof Error ? err.message : String(err)
|
|
545
|
-
}`
|
|
546
|
-
);
|
|
547
|
-
}
|
|
548
|
-
return;
|
|
549
|
-
}
|
|
550
|
-
|
|
551
|
-
async getNetRecordCreateTime(
|
|
552
|
-
rec: IThreadRecord,
|
|
553
|
-
key: ThreadKey
|
|
554
|
-
): Promise<BigInt> {
|
|
555
|
-
let event: IThreadEvent;
|
|
556
|
-
if (!this.connector) {
|
|
557
|
-
throw new Error("no connector");
|
|
558
|
-
}
|
|
559
|
-
try {
|
|
560
|
-
// 从记录中解码事件
|
|
561
|
-
event = await threadEvent.EventFromRecord(
|
|
562
|
-
this.connector?.net.bstore,
|
|
563
|
-
rec.value()
|
|
564
|
-
);
|
|
565
|
-
} catch (err) {
|
|
566
|
-
// 如果解码失败,尝试从块中获取事件
|
|
567
|
-
try {
|
|
568
|
-
const block = await this.getBlockWithRetry(rec.value());
|
|
569
|
-
event = await threadEvent.EventFromNode(block);
|
|
570
|
-
} catch (decodeErr) {
|
|
571
|
-
throw new Error(
|
|
572
|
-
`Error when decoding block to event: ${
|
|
573
|
-
decodeErr instanceof Error ? decodeErr.message : String(decodeErr)
|
|
574
|
-
}`
|
|
575
|
-
);
|
|
576
|
-
}
|
|
577
|
-
}
|
|
578
|
-
|
|
579
|
-
let body: IPLDNode;
|
|
580
|
-
try {
|
|
581
|
-
// 获取事件的主体
|
|
582
|
-
body = await event.getBody(this.connector?.net.bstore, key.read());
|
|
583
|
-
} catch (err) {
|
|
584
|
-
throw new Error(
|
|
585
|
-
`Error when getting body of event on thread ${
|
|
586
|
-
this.connector?.threadId
|
|
587
|
-
}/${rec.logID()}: ${err instanceof Error ? err.message : String(err)}`
|
|
588
|
-
);
|
|
589
|
-
}
|
|
590
|
-
|
|
591
|
-
let events: Event<any>[];
|
|
592
|
-
try {
|
|
593
|
-
// 从字节数据中解码事件
|
|
594
|
-
events = await this.eventcodec.eventsFromBytes(body.data());
|
|
595
|
-
} catch (err) {
|
|
596
|
-
throw new Error(
|
|
597
|
-
`Error when unmarshaling event from bytes: ${
|
|
598
|
-
err instanceof Error ? err.message : String(err)
|
|
599
|
-
}`
|
|
600
|
-
);
|
|
601
|
-
}
|
|
602
|
-
|
|
603
|
-
if (events.length === 0) {
|
|
604
|
-
throw new Error("No events found in record");
|
|
605
|
-
}
|
|
606
|
-
return events[0]!.timestamp;
|
|
607
|
-
}
|
|
608
|
-
|
|
609
|
-
private async getBlockWithRetry(rec: IRecord): Promise<any> {
|
|
610
|
-
let backoff = getBlockInitialTimeout;
|
|
611
|
-
let lastError: Error | null = null;
|
|
612
|
-
if (!this.connector) {
|
|
613
|
-
throw new Error("no connector");
|
|
614
|
-
}
|
|
615
|
-
// 重试循环
|
|
616
|
-
for (let i = 1; i <= getBlockRetries; i++) {
|
|
617
|
-
try {
|
|
618
|
-
// 尝试获取块
|
|
619
|
-
const block = await rec.getBlock(this.connector?.net.bstore);
|
|
620
|
-
return block; // 成功则立即返回
|
|
621
|
-
} catch (err) {
|
|
622
|
-
lastError = err as Error;
|
|
623
|
-
console.warn(`错误: 在第 ${i} 次重试中获取块 ${rec.cid()} 失败`);
|
|
624
|
-
await new Promise((resolve) => setTimeout(resolve, backoff));
|
|
625
|
-
backoff *= 2;
|
|
626
|
-
}
|
|
627
|
-
}
|
|
628
|
-
}
|
|
629
|
-
|
|
630
|
-
async readTxn(
|
|
631
|
-
collection: Collection,
|
|
632
|
-
fn: (txn: ITxn) => Promise<void>,
|
|
633
|
-
token?: ThreadToken
|
|
634
|
-
): Promise<void> {
|
|
635
|
-
// 创建事务选项
|
|
636
|
-
const args = { token: undefined } as any;
|
|
637
|
-
|
|
638
|
-
// 创建只读事务
|
|
639
|
-
const txn = new Txn(collection, token, true);
|
|
640
|
-
|
|
641
|
-
try {
|
|
642
|
-
// 执行事务函数
|
|
643
|
-
await fn(txn);
|
|
644
|
-
} finally {
|
|
645
|
-
// 确保事务被丢弃
|
|
646
|
-
txn.discard();
|
|
647
|
-
}
|
|
648
|
-
}
|
|
649
|
-
|
|
650
|
-
// 使用队列确保写入操作按顺序执行
|
|
651
|
-
private writeQueue = Promise.resolve();
|
|
652
|
-
|
|
653
|
-
async writeTxn(
|
|
654
|
-
collection: Collection,
|
|
655
|
-
fn: (txn: ITxn) => Promise<void>,
|
|
656
|
-
token?: ThreadToken
|
|
657
|
-
): Promise<void> {
|
|
658
|
-
// Save the current promise chain
|
|
659
|
-
const previousOperation = this.writeQueue;
|
|
660
|
-
|
|
661
|
-
// Create a new promise for this operation
|
|
662
|
-
const currentOperation = new Promise<void>((resolve, reject) => {
|
|
663
|
-
// Wait for previous operations to complete (or fail)
|
|
664
|
-
previousOperation
|
|
665
|
-
.catch(() => {
|
|
666
|
-
// Ignore previous errors - just ensure we wait for previous operations
|
|
667
|
-
})
|
|
668
|
-
.finally(async () => {
|
|
669
|
-
// After previous operations are done (success or failure), run this operation
|
|
670
|
-
const txn = new Txn(collection, token, false);
|
|
671
|
-
try {
|
|
672
|
-
// Execute transaction function
|
|
673
|
-
await fn(txn);
|
|
674
|
-
|
|
675
|
-
// Commit transaction
|
|
676
|
-
await txn.commit();
|
|
677
|
-
resolve();
|
|
678
|
-
} catch (err) {
|
|
679
|
-
// Properly propagate the error
|
|
680
|
-
reject(err);
|
|
681
|
-
} finally {
|
|
682
|
-
// Always discard the transaction
|
|
683
|
-
txn.discard();
|
|
684
|
-
}
|
|
685
|
-
});
|
|
686
|
-
});
|
|
687
|
-
|
|
688
|
-
// Update the queue with our operation
|
|
689
|
-
this.writeQueue = currentOperation.catch(() => {
|
|
690
|
-
// Swallow errors in the queue chain but log them
|
|
691
|
-
// This ensures future operations will still execute
|
|
692
|
-
return Promise.resolve();
|
|
693
|
-
});
|
|
694
|
-
|
|
695
|
-
// Return the current operation, allowing errors to propagate to the caller
|
|
696
|
-
return currentOperation;
|
|
697
|
-
}
|
|
698
|
-
}
|