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,291 +0,0 @@
|
|
|
1
|
-
// modules/file-module.ts
|
|
2
|
-
// 文件功能模块
|
|
3
|
-
|
|
4
|
-
import { IFileOperations } from "../interfaces/file-interface";
|
|
5
|
-
import { DCContext } from "../../lib/interfaces/DCContext";
|
|
6
|
-
import { DCModule, CoreModuleName } from "../common/module-system";
|
|
7
|
-
import { FileManager } from "../implements/file/manager";
|
|
8
|
-
import { FileCacheManager } from "../implements/file/file-cache-manager";
|
|
9
|
-
import { SeekableFileStream } from "../implements/file/seekableFileStream";
|
|
10
|
-
import { createLogger } from "../util/logger";
|
|
11
|
-
import { registerServiceWorker } from "../common/service-worker";
|
|
12
|
-
|
|
13
|
-
const logger = createLogger('FileModule');
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* 文件模块
|
|
17
|
-
* 提供文件上传、下载、缓存等功能
|
|
18
|
-
*/
|
|
19
|
-
export class FileModule implements DCModule, IFileOperations {
|
|
20
|
-
readonly moduleName = CoreModuleName.FILE;
|
|
21
|
-
private fileManager!: FileManager;
|
|
22
|
-
private fileCacheManager!: FileCacheManager;
|
|
23
|
-
private initialized: boolean = false;
|
|
24
|
-
private swUrl: string;
|
|
25
|
-
|
|
26
|
-
constructor(url: string) {
|
|
27
|
-
this.swUrl = url;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* 初始化文件模块
|
|
32
|
-
* @param context DC上下文
|
|
33
|
-
* @returns 是否初始化成功
|
|
34
|
-
*/
|
|
35
|
-
async initialize(context: DCContext): Promise<boolean> {
|
|
36
|
-
try {
|
|
37
|
-
this.fileManager = new FileManager(
|
|
38
|
-
context.dcutil,
|
|
39
|
-
context.connectedDc,
|
|
40
|
-
context.dcChain,
|
|
41
|
-
context.dcNodeClient,
|
|
42
|
-
context
|
|
43
|
-
);
|
|
44
|
-
|
|
45
|
-
this.fileCacheManager = new FileCacheManager();
|
|
46
|
-
|
|
47
|
-
// 注册 Service Worker
|
|
48
|
-
try {
|
|
49
|
-
logger.info('Service Worker 已开始注册');
|
|
50
|
-
const registration = await registerServiceWorker(this, this.swUrl || '');
|
|
51
|
-
if(registration) {
|
|
52
|
-
logger.info('Service Worker 注册成功');
|
|
53
|
-
context.swInited = true;
|
|
54
|
-
}else {
|
|
55
|
-
logger.warn('Service Worker 注册失败');
|
|
56
|
-
context.swInited = false;
|
|
57
|
-
}
|
|
58
|
-
} catch (err) {
|
|
59
|
-
logger.warn('Service Worker 注册失败:', err);
|
|
60
|
-
context.swInited = false;
|
|
61
|
-
// 服务工作者注册失败不阻断模块初始化
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
this.initialized = true;
|
|
65
|
-
return true;
|
|
66
|
-
} catch (error) {
|
|
67
|
-
logger.error("文件模块初始化失败:", error);
|
|
68
|
-
return false;
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
/**
|
|
73
|
-
* 关闭文件模块
|
|
74
|
-
*/
|
|
75
|
-
async shutdown(): Promise<void> {
|
|
76
|
-
// 清理所有缓存
|
|
77
|
-
if (this.fileCacheManager) {
|
|
78
|
-
this.clearFileCache();
|
|
79
|
-
this.fileCacheManager.stopCacheCleanupTask();
|
|
80
|
-
}
|
|
81
|
-
this.initialized = false;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
/**
|
|
85
|
-
* 获取可寻址文件流
|
|
86
|
-
*/
|
|
87
|
-
async getSeekableFileStream(ipfsPath: string, decryptKey: string): Promise<SeekableFileStream> {
|
|
88
|
-
|
|
89
|
-
try {
|
|
90
|
-
this.assertInitialized();
|
|
91
|
-
// 先查看缓存
|
|
92
|
-
const cachedStream = this.fileCacheManager.getCachedFileStream(ipfsPath, decryptKey);
|
|
93
|
-
if (cachedStream) {
|
|
94
|
-
return cachedStream;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
// 没有缓存,创建新的流
|
|
98
|
-
const fileStream = await this.fileManager.createSeekableFileStream(ipfsPath, decryptKey);
|
|
99
|
-
if(!fileStream) {
|
|
100
|
-
throw new Error(`获取文件流失败: ${ipfsPath}`);
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
// 将新创建的流保存到缓存
|
|
104
|
-
this.fileCacheManager.cacheFileStream(ipfsPath, decryptKey, fileStream);
|
|
105
|
-
|
|
106
|
-
return fileStream;
|
|
107
|
-
} catch (error) {
|
|
108
|
-
logger.error(`获取文件流失败: ${ipfsPath}`, error);
|
|
109
|
-
throw new Error(`获取文件流失败: ${error instanceof Error ? error.message : String(error)}`);
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
/**
|
|
114
|
-
* 清理文件缓存
|
|
115
|
-
*/
|
|
116
|
-
clearFileCache(pathname?: string): void {
|
|
117
|
-
try {
|
|
118
|
-
this.assertInitialized();
|
|
119
|
-
this.fileCacheManager.clearFileCache(pathname);
|
|
120
|
-
} catch (error) {
|
|
121
|
-
logger.error(`清理文件缓存失败`, error);
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
/**
|
|
126
|
-
* 获取缓存统计信息
|
|
127
|
-
*/
|
|
128
|
-
getCacheStats(): [{ total: number, keys: string[] } | null, Error | null] {
|
|
129
|
-
try {
|
|
130
|
-
this.assertInitialized();
|
|
131
|
-
const stats = this.fileCacheManager.getCacheStats();
|
|
132
|
-
return [stats, null];
|
|
133
|
-
} catch (error) {
|
|
134
|
-
return [null, error as Error];
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
/**
|
|
139
|
-
* 获取文件内容
|
|
140
|
-
*/
|
|
141
|
-
async getFile(cid: string, decryptKey: string): Promise<[Uint8Array | null, Error | null]> {
|
|
142
|
-
try {
|
|
143
|
-
this.assertInitialized();
|
|
144
|
-
const fileContent = await this.fileManager.getFileFromDc(cid, decryptKey);
|
|
145
|
-
return [fileContent, null];
|
|
146
|
-
} catch (error) {
|
|
147
|
-
logger.error(`获取文件失败: ${cid}`, error);
|
|
148
|
-
throw [null, new Error(`获取文件失败: ${error instanceof Error ? error.message : String(error)}`)];
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
/**
|
|
153
|
-
* 创建文件流
|
|
154
|
-
*/
|
|
155
|
-
async createFileStream(
|
|
156
|
-
cid: string,
|
|
157
|
-
decryptKey: string
|
|
158
|
-
): Promise<ReadableStream<Uint8Array> | null> {
|
|
159
|
-
try {
|
|
160
|
-
this.assertInitialized();
|
|
161
|
-
const fileStream = await this.fileManager.createSeekableFileStream(
|
|
162
|
-
cid,
|
|
163
|
-
decryptKey
|
|
164
|
-
);
|
|
165
|
-
if(!fileStream) {
|
|
166
|
-
return null;
|
|
167
|
-
}
|
|
168
|
-
return fileStream.createReadableStream();
|
|
169
|
-
} catch (error) {
|
|
170
|
-
logger.error(`创建文件流失败: ${cid}`, error);
|
|
171
|
-
return null;
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
/**
|
|
176
|
-
* 添加文件
|
|
177
|
-
*/
|
|
178
|
-
async addFile(
|
|
179
|
-
file: File,
|
|
180
|
-
enkey: string,
|
|
181
|
-
onUpdateTransmitSize: (status: number, size: number) => void
|
|
182
|
-
): Promise<[string | null, Error | null]> {
|
|
183
|
-
|
|
184
|
-
try {
|
|
185
|
-
this.assertInitialized();
|
|
186
|
-
if (!file) {
|
|
187
|
-
throw new Error("文件不能为空");
|
|
188
|
-
}
|
|
189
|
-
const res = await this.fileManager.addFile(file, enkey, onUpdateTransmitSize);
|
|
190
|
-
return res;
|
|
191
|
-
} catch (error) {
|
|
192
|
-
logger.error(`添加文件失败: ${file?.name}`, error);
|
|
193
|
-
return [null, new Error(`添加文件失败: ${error instanceof Error ? error.message : String(error)}`)];
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
/**
|
|
198
|
-
* 添加文件夹
|
|
199
|
-
*/
|
|
200
|
-
async addFolder(
|
|
201
|
-
files: FileList,
|
|
202
|
-
enkey: string,
|
|
203
|
-
onUpdateTransmitCount: (status: number, total: number, process: number) => void
|
|
204
|
-
): Promise<[string | null, Error | null]> {
|
|
205
|
-
|
|
206
|
-
try {
|
|
207
|
-
this.assertInitialized();
|
|
208
|
-
if (!files || files.length === 0) {
|
|
209
|
-
throw new Error("文件夹不能为空");
|
|
210
|
-
}
|
|
211
|
-
const res = await this.fileManager.addFolder(files, enkey, onUpdateTransmitCount);
|
|
212
|
-
return res;
|
|
213
|
-
} catch (error) {
|
|
214
|
-
logger.error(`添加文件夹失败`, error);
|
|
215
|
-
return [null, new Error(`添加文件夹失败: ${error instanceof Error ? error.message : String(error)}`)];
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
/**
|
|
221
|
-
* 获取文件夹下的所有文件,包括内容(支持多级目录递归)
|
|
222
|
-
* @param cid 根目录的CID
|
|
223
|
-
* @param decryptKey 解密密钥
|
|
224
|
-
* @param recursive 是否递归获取子目录,默认false(保持向后兼容)
|
|
225
|
-
* @returns 文件列表:[{Name:文件或目录名,Type:0-文件 1-目录,Size:大小,Hash:文件或目录cid,Path:完整路径}]
|
|
226
|
-
*/
|
|
227
|
-
async getFolderFileListWithContent(
|
|
228
|
-
cid: string,
|
|
229
|
-
decryptKey: string,
|
|
230
|
-
recursive: boolean = true
|
|
231
|
-
): Promise<[Array<{Name: string; Type: number; Size: number; Hash: string; Path: string, Content?: Uint8Array}> | null, Error | null]> {
|
|
232
|
-
const [fileList, err] = await this.fileManager.getFolderFileListWithContent(cid, decryptKey, recursive);
|
|
233
|
-
return [fileList, err];
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
/**
|
|
237
|
-
* 获取文件夹下的文件列表(支持多级目录递归)
|
|
238
|
-
* @param cid 根目录的CID
|
|
239
|
-
* @param flag 是否需要连接节点
|
|
240
|
-
* @param recursive 是否递归获取子目录,默认false(保持向后兼容)
|
|
241
|
-
* @returns 返回JSON格式的文件列表:[{Name:文件或目录名,Type:0-文件 1-目录,Size:大小,Hash:文件或目录cid,Path:完整路径}]
|
|
242
|
-
*/
|
|
243
|
-
async getFolderFileList(
|
|
244
|
-
cid: string,
|
|
245
|
-
flag?: number,
|
|
246
|
-
recursive: boolean = true
|
|
247
|
-
): Promise<[Array<{Name: string; Type: number; Size: number; Hash: string; Path: string, Content?: Uint8Array}> | null, Error | null]> {
|
|
248
|
-
const [fileList, err] = await this.fileManager.getFolderFileList(cid, flag, recursive);
|
|
249
|
-
return [fileList, err];
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
/**
|
|
256
|
-
* Creates a custom FileList object from file paths and contents
|
|
257
|
-
* @param filesMap - Map of file paths to content (string or Uint8Array)
|
|
258
|
-
* @param rootFolderName - Optional root folder name (defaults to "upload")
|
|
259
|
-
* @returns A FileList-like object that can be used with addFolder
|
|
260
|
-
*/
|
|
261
|
-
createCustomFileList(
|
|
262
|
-
filesMap:
|
|
263
|
-
| Map<string, string | Uint8Array | ArrayBuffer>
|
|
264
|
-
| Record<string, string | Uint8Array | ArrayBuffer>,
|
|
265
|
-
rootFolderName: string = "upload"
|
|
266
|
-
): [FileList | null, Error | null] {
|
|
267
|
-
try {
|
|
268
|
-
this.assertInitialized();
|
|
269
|
-
// filesMap 判断
|
|
270
|
-
if (!filesMap || filesMap.size === 0) {
|
|
271
|
-
return [null, new Error("文件夹不能为空")];
|
|
272
|
-
}
|
|
273
|
-
const fileList = this.fileManager.createCustomFileList(filesMap, rootFolderName);
|
|
274
|
-
return [fileList, null];
|
|
275
|
-
} catch (error) {
|
|
276
|
-
logger.error("创建自定义文件列表失败:", error);
|
|
277
|
-
return [null, new Error("文件模块未初始化")];
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
/**
|
|
284
|
-
* 断言模块已初始化
|
|
285
|
-
*/
|
|
286
|
-
private assertInitialized(): void {
|
|
287
|
-
if (!this.initialized) {
|
|
288
|
-
throw new Error("文件模块未初始化");
|
|
289
|
-
}
|
|
290
|
-
}
|
|
291
|
-
}
|
package/lib/modules/index.ts
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
// modules/index.ts
|
|
2
|
-
// 导出所有模块供注册使用
|
|
3
|
-
|
|
4
|
-
export { FileModule } from './file-module';
|
|
5
|
-
export { AuthModule } from './auth-module';
|
|
6
|
-
export { CommentModule } from './comment-module';
|
|
7
|
-
export { DatabaseModule } from './database-module';
|
|
8
|
-
export { MessageModule } from './message-module';
|
|
9
|
-
export { KeyValueModule } from './keyvalue-module';
|
|
10
|
-
export { ClientModule } from './client-module';
|
|
11
|
-
export { CacheModule } from './cache-module';
|
|
12
|
-
export { AIProxyModule } from './aiproxy-module';
|
|
13
|
-
export { UtilModule } from './util-module';
|
|
@@ -1,379 +0,0 @@
|
|
|
1
|
-
// modules/keyvalue-module.ts
|
|
2
|
-
// 键值存储功能模块
|
|
3
|
-
|
|
4
|
-
import { IKeyValueOperations } from "../interfaces/keyvalue-interface";
|
|
5
|
-
import { DCContext } from "../../lib/interfaces/DCContext";
|
|
6
|
-
import { DCModule, CoreModuleName } from "../common/module-system";
|
|
7
|
-
import { KeyValueManager, KeyValueStoreType, KeyValueDB } from "../implements/keyvalue/manager";
|
|
8
|
-
import { createLogger } from "../util/logger";
|
|
9
|
-
import { ThemeAuthInfo, ThemeComment } from "../common/types/types";
|
|
10
|
-
import { Direction } from "../common/define";
|
|
11
|
-
import { ThemePermission } from "../common/constants";
|
|
12
|
-
import {padPositiveInt20} from "../util/utils";
|
|
13
|
-
const logger = createLogger('KeyValueModule');
|
|
14
|
-
const indexkey_dckv = "indexkey_dckv"; //索引键名,keyvalue设置过程中key本身的索引键
|
|
15
|
-
/**
|
|
16
|
-
* 键值存储模块
|
|
17
|
-
* 提供键值存储功能
|
|
18
|
-
*/
|
|
19
|
-
export class KeyValueModule implements DCModule, IKeyValueOperations {
|
|
20
|
-
readonly moduleName = CoreModuleName.KEYVALUE;
|
|
21
|
-
private keyValueManager!: KeyValueManager;
|
|
22
|
-
private initialized: boolean = false;
|
|
23
|
-
private context: DCContext = {} as DCContext;
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* 初始化键值存储模块
|
|
27
|
-
* @param context DC上下文
|
|
28
|
-
* @returns 是否初始化成功
|
|
29
|
-
*/
|
|
30
|
-
async initialize(context: DCContext): Promise<boolean> {
|
|
31
|
-
try {
|
|
32
|
-
this.context = context;
|
|
33
|
-
this.keyValueManager = new KeyValueManager(
|
|
34
|
-
context.dcutil,
|
|
35
|
-
context.dcChain,
|
|
36
|
-
context
|
|
37
|
-
);
|
|
38
|
-
|
|
39
|
-
this.initialized = true;
|
|
40
|
-
return true;
|
|
41
|
-
} catch (error) {
|
|
42
|
-
logger.error("键值存储模块初始化失败:", error);
|
|
43
|
-
return false;
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
/**
|
|
48
|
-
* 关闭键值存储模块
|
|
49
|
-
*/
|
|
50
|
-
async shutdown(): Promise<void> {
|
|
51
|
-
this.initialized = false;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
/**
|
|
55
|
-
* 创建存储主题
|
|
56
|
-
* @param appId 应用ID
|
|
57
|
-
* @param themeAuthor 主题作者
|
|
58
|
-
* @param theme 主题名称
|
|
59
|
-
* @param space 空间大小
|
|
60
|
-
* @param type 主题类型
|
|
61
|
-
* @returns 创建结果
|
|
62
|
-
*/
|
|
63
|
-
async createStore(
|
|
64
|
-
appId: string,
|
|
65
|
-
theme: string,
|
|
66
|
-
space: number,
|
|
67
|
-
type: KeyValueStoreType
|
|
68
|
-
): Promise<[KeyValueDB|null, Error | null]> {
|
|
69
|
-
const err = this.assertInitialized();
|
|
70
|
-
if (err) {
|
|
71
|
-
return [null, err];
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
try {
|
|
75
|
-
const [kvdb,err] = await this.keyValueManager.createStore(
|
|
76
|
-
appId,
|
|
77
|
-
theme,
|
|
78
|
-
space,
|
|
79
|
-
type
|
|
80
|
-
);
|
|
81
|
-
return [kvdb,err];
|
|
82
|
-
} catch (error) {
|
|
83
|
-
return [null, error instanceof Error ? error : new Error(String(error))];
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
async getStore(
|
|
89
|
-
appId: string,
|
|
90
|
-
theme: string,
|
|
91
|
-
themeAuthor: string
|
|
92
|
-
): Promise<[KeyValueDB|null, Error | null]> {
|
|
93
|
-
const err = this.assertInitialized();
|
|
94
|
-
if (err) {
|
|
95
|
-
return [null, err];
|
|
96
|
-
}
|
|
97
|
-
try {
|
|
98
|
-
const [kvdb,err] = await this.keyValueManager.getKeyValueDB(
|
|
99
|
-
appId,
|
|
100
|
-
theme,
|
|
101
|
-
themeAuthor
|
|
102
|
-
);
|
|
103
|
-
return [kvdb,err];
|
|
104
|
-
} catch (error) {
|
|
105
|
-
return [null, error instanceof Error ? error : new Error(String(error))];
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
async configAuth(
|
|
112
|
-
kvdb: KeyValueDB,
|
|
113
|
-
authPubkey: string,
|
|
114
|
-
permission: ThemePermission,
|
|
115
|
-
remark: string,
|
|
116
|
-
vaccount?: string
|
|
117
|
-
): Promise<[number | null, Error | null]> {
|
|
118
|
-
const err = this.assertInitialized();
|
|
119
|
-
if (err) {
|
|
120
|
-
return [null, err];
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
try {
|
|
124
|
-
const res = await kvdb.configAuth(authPubkey, permission, remark, vaccount);
|
|
125
|
-
return res;
|
|
126
|
-
} catch (error) {
|
|
127
|
-
return [null, error instanceof Error ? error : new Error(String(error))];
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
async getAuthList(
|
|
131
|
-
kvdb: KeyValueDB,
|
|
132
|
-
vaccount?: string
|
|
133
|
-
): Promise<[ThemeAuthInfo[]|null,ThemeComment[] | null, Error | null]> {
|
|
134
|
-
const err = this.assertInitialized();
|
|
135
|
-
if (err) {
|
|
136
|
-
return [null, null,err];
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
try {
|
|
140
|
-
const res = await kvdb.getAuthList(vaccount);
|
|
141
|
-
return res;
|
|
142
|
-
} catch (error) {
|
|
143
|
-
return [null, null, error instanceof Error ? error : new Error(String(error))];
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
async set(
|
|
150
|
-
kvdb: KeyValueDB,
|
|
151
|
-
key: string,
|
|
152
|
-
value: string,
|
|
153
|
-
indexs: string, //索引列表,格式为json字符串:[{key:"indexkey1",type:"string",value:"value"},{key:"indexkey2",type:"number", value:12}],这里统一转换格式为key1:value1$$$key2:value2
|
|
154
|
-
vaccount?: string
|
|
155
|
-
): Promise<[boolean | null, number | null, Error | null]> {
|
|
156
|
-
const err = this.assertInitialized();
|
|
157
|
-
if (err) {
|
|
158
|
-
return [null, null, err];
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
try {
|
|
162
|
-
//进行格式转换
|
|
163
|
-
let strIndexs = "";
|
|
164
|
-
try {
|
|
165
|
-
if (indexs && indexs != "") {
|
|
166
|
-
const indexArray = JSON.parse(indexs);
|
|
167
|
-
for (const index of indexArray) {
|
|
168
|
-
let indexValue = "";
|
|
169
|
-
if( index.type === "number" ){ //
|
|
170
|
-
indexValue = padPositiveInt20(index.value);
|
|
171
|
-
}else{
|
|
172
|
-
indexValue = index.value;
|
|
173
|
-
}
|
|
174
|
-
strIndexs += `${index.key}:${indexValue}$$$`;
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
}
|
|
179
|
-
} catch (error) {
|
|
180
|
-
logger.error(`设置索引,解析失败:`, error);
|
|
181
|
-
}
|
|
182
|
-
const res = await kvdb.set(key, value, strIndexs, vaccount);
|
|
183
|
-
return res;
|
|
184
|
-
} catch (error) {
|
|
185
|
-
return [null,null, error instanceof Error ? error : new Error(String(error))];
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
/**
|
|
191
|
-
* 获取当前用户设置的指定键的元数据
|
|
192
|
-
* @param kvdb
|
|
193
|
-
* @param key
|
|
194
|
-
* @param vaccount
|
|
195
|
-
* @returns [值, 错误信息],值的格式: value$$$dckv_extra$$${'dc_timestamp':'%d','dc_opuser':'%s'}
|
|
196
|
-
*/
|
|
197
|
-
async getValueSetByCurrentUser(kvdb: KeyValueDB, key: string,vaccount?: string): Promise<[string | null, Error | null]> {
|
|
198
|
-
if(!this.context.publicKey){
|
|
199
|
-
return [null, new Error("当前用户公钥未设置")];
|
|
200
|
-
}
|
|
201
|
-
return this.get(kvdb,key, this.context.publicKey.string(), vaccount);
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
/**
|
|
206
|
-
* 获取指定键的元数据
|
|
207
|
-
* @param kvdb
|
|
208
|
-
* @param key
|
|
209
|
-
* @param writerPubkey
|
|
210
|
-
* @param vaccount
|
|
211
|
-
* @returns [值, 错误信息],值的格式: value$$$dckv_extra$$${'dc_timestamp':'%d','dc_opuser':'%s'}
|
|
212
|
-
*/
|
|
213
|
-
async get(
|
|
214
|
-
kvdb: KeyValueDB,
|
|
215
|
-
key: string,
|
|
216
|
-
writerPubkey?: string,
|
|
217
|
-
vaccount?: string
|
|
218
|
-
): Promise<[string | null, Error | null]> {
|
|
219
|
-
const err = this.assertInitialized();
|
|
220
|
-
if (err) {
|
|
221
|
-
return [null, err];
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
try {
|
|
225
|
-
const res = await kvdb.get(key, writerPubkey, vaccount);
|
|
226
|
-
return res;
|
|
227
|
-
} catch (error) {
|
|
228
|
-
return [null, error instanceof Error ? error : new Error(String(error))];
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
/**
|
|
234
|
-
* 获取指定键的值列表
|
|
235
|
-
* @param kvdb: KeyValueDB,
|
|
236
|
-
* @param key 键名
|
|
237
|
-
* @param limit 返回结果数量限制
|
|
238
|
-
* @param seekKey 查询起始键,用于分页查询
|
|
239
|
-
* @param offset 结果偏移量
|
|
240
|
-
* @param vaccount 可选的虚拟账户
|
|
241
|
-
* @returns [值列表数组生成的json字符串, 错误信息] 数组的每个元素的格式: key:value$$$dckv_extra$$${'dc_timestamp':'%d','dc_opuser':'%s'}
|
|
242
|
-
*/
|
|
243
|
-
async getValues(
|
|
244
|
-
kvdb: KeyValueDB,
|
|
245
|
-
key: string,
|
|
246
|
-
options: { limit?: number; seekKey?: string; direction?: Direction; offset?: number } ,
|
|
247
|
-
vaccount?: string
|
|
248
|
-
): Promise<[string | null, Error | null]> {
|
|
249
|
-
const err = this.assertInitialized();
|
|
250
|
-
if (err) {
|
|
251
|
-
return [null, err];
|
|
252
|
-
}
|
|
253
|
-
const limit = options.limit? options.limit: 10;
|
|
254
|
-
const seekKey = options.seekKey? options.seekKey: "";
|
|
255
|
-
const direction = options.direction? options.direction: Direction.Forward;
|
|
256
|
-
const offset = options.offset? options.offset: 0;
|
|
257
|
-
try {
|
|
258
|
-
const res = await kvdb.getWithIndex(indexkey_dckv, key, limit, seekKey, direction, offset, vaccount);
|
|
259
|
-
return res;
|
|
260
|
-
} catch (error) {
|
|
261
|
-
return [null, error instanceof Error ? error : new Error(String(error))];
|
|
262
|
-
}
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
/**
|
|
266
|
-
* 批量获取指定键的值
|
|
267
|
-
* @param kvdb KeyValueDB实例
|
|
268
|
-
* @param keys 逗号分隔的键列表
|
|
269
|
-
* @param writerPubkey 可选,指定写入者公钥
|
|
270
|
-
* @param vaccount 可选的虚拟账户
|
|
271
|
-
* @returns [值的数组的JSON字符串, 错误信息] 数组的每个元素的格式: key:value$$$dckv_extra$$${'dc_timestamp':'%d','dc_opuser':'%s'}
|
|
272
|
-
*/
|
|
273
|
-
async getBatch(
|
|
274
|
-
kvdb: KeyValueDB,
|
|
275
|
-
keys: string,
|
|
276
|
-
writerPubkey: string = "",
|
|
277
|
-
vaccount: string = ""
|
|
278
|
-
): Promise<[string | null, Error | null]> {
|
|
279
|
-
const err = this.assertInitialized();
|
|
280
|
-
if (err) {
|
|
281
|
-
return [null, err];
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
try {
|
|
285
|
-
const res = await kvdb.getBatch(keys, writerPubkey, vaccount);
|
|
286
|
-
return res;
|
|
287
|
-
} catch (error) {
|
|
288
|
-
return [null, error instanceof Error ? error : new Error(String(error))];
|
|
289
|
-
}
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
/**
|
|
293
|
-
* 获取指定索引的值
|
|
294
|
-
* @param kvdb KeyValueDB实例
|
|
295
|
-
* @param indexKey 索引键名
|
|
296
|
-
* @param indexValue 索引值
|
|
297
|
-
* @param type 索引值类型
|
|
298
|
-
* @param seekKey 查询起始键,用于分页查询
|
|
299
|
-
* @param direction 查询方向
|
|
300
|
-
* @param offset 结果偏移量
|
|
301
|
-
* @param vaccount 可选的虚拟账户
|
|
302
|
-
* @returns [值的数组形式的JSON字符串, 错误信息] 数组的每个元素的格式: key:value$$$dckv_extra$$${'dc_timestamp':'%d','dc_opuser':'%s'}
|
|
303
|
-
*/
|
|
304
|
-
async getWithIndex(
|
|
305
|
-
kvdb: KeyValueDB,
|
|
306
|
-
indexKey:string,
|
|
307
|
-
indexValue:string,
|
|
308
|
-
options: {type?:string; limit?: number; seekKey?: string; direction?: Direction; offset?: number } ,
|
|
309
|
-
vaccount?: string
|
|
310
|
-
): Promise<[string | null, Error | null]> {
|
|
311
|
-
const err = this.assertInitialized();
|
|
312
|
-
if (err) {
|
|
313
|
-
return [null, err];
|
|
314
|
-
}
|
|
315
|
-
const limit = options.limit? options.limit: 10;
|
|
316
|
-
const seekKey = options.seekKey? options.seekKey: "";
|
|
317
|
-
const direction = options.direction? options.direction: Direction.Forward;
|
|
318
|
-
const offset = options.offset? options.offset: 0;
|
|
319
|
-
let indexValueStr = "";
|
|
320
|
-
if( options.type === "number" ){ //
|
|
321
|
-
indexValueStr = padPositiveInt20(indexValue);
|
|
322
|
-
}
|
|
323
|
-
try {
|
|
324
|
-
const res = await kvdb.getWithIndex(indexKey, indexValueStr, limit,seekKey, direction,offset, vaccount);
|
|
325
|
-
return res;
|
|
326
|
-
} catch (error) {
|
|
327
|
-
return [null, error instanceof Error ? error : new Error(String(error))];
|
|
328
|
-
}
|
|
329
|
-
}
|
|
330
|
-
|
|
331
|
-
/**
|
|
332
|
-
* 按设置时间顺序获取主题的的键值对列表
|
|
333
|
-
* @param kvdb KeyValueDB实例
|
|
334
|
-
* @param limit 返回结果数量限制
|
|
335
|
-
* @param seekKey 查询起始键,用于分页查询
|
|
336
|
-
* @param direction 查询方向
|
|
337
|
-
* @param offset 结果偏移量
|
|
338
|
-
* @param vaccount 可选的虚拟账户
|
|
339
|
-
* @returns [值列表数组生成的json字符串, 错误信息] 数组的每个元素的格式: key:value$$$dckv_extra$$${'dc_timestamp':'%d','dc_opuser':'%s'}
|
|
340
|
-
*/
|
|
341
|
-
async getWithTimeOrder(
|
|
342
|
-
kvdb: KeyValueDB,
|
|
343
|
-
timestamp: number,//毫秒时间戳
|
|
344
|
-
options: { limit?: number; seekKey?: string; direction?: Direction; offset?: number },
|
|
345
|
-
vaccount?: string
|
|
346
|
-
): Promise<[string | null, Error | null]> {
|
|
347
|
-
const err = this.assertInitialized();
|
|
348
|
-
if (err) {
|
|
349
|
-
return [null, err];
|
|
350
|
-
}
|
|
351
|
-
let timestampStr = "";
|
|
352
|
-
if( timestamp > 0 ){
|
|
353
|
-
//把毫秒时间转为微妙时间戳字符串,与DC节点存储的时间戳格式一致
|
|
354
|
-
timestampStr = padPositiveInt20(timestamp * 1000);
|
|
355
|
-
//前面补0,保证长度为20位
|
|
356
|
-
timestampStr = timestampStr.padStart(20, "0");
|
|
357
|
-
}
|
|
358
|
-
const limit = options.limit ? options.limit : 10;
|
|
359
|
-
const seekKey = options.seekKey ? options.seekKey : "";
|
|
360
|
-
const direction = options.direction ? options.direction : Direction.Forward;
|
|
361
|
-
const offset = options.offset ? options.offset : 0;
|
|
362
|
-
try {
|
|
363
|
-
const res = await kvdb.getWithIndex("indexkey_timestamp", timestampStr, limit, seekKey, direction, offset, vaccount);
|
|
364
|
-
return res;
|
|
365
|
-
} catch (error) {
|
|
366
|
-
return [null, error instanceof Error ? error : new Error(String(error))];
|
|
367
|
-
}
|
|
368
|
-
}
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
/**
|
|
372
|
-
* 断言模块已初始化
|
|
373
|
-
*/
|
|
374
|
-
private assertInitialized(): Error | void {
|
|
375
|
-
if (!this.initialized) {
|
|
376
|
-
return Error("键值存储模块未初始化");
|
|
377
|
-
}
|
|
378
|
-
}
|
|
379
|
-
}
|