web-dc-api 0.0.46 → 0.0.48

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.
@@ -52,7 +52,7 @@ export class ChainUtil {
52
52
  // 获取用户钱包信息
53
53
  async getUserInfoWithAccount(account: string): Promise<User> {
54
54
  const walletAccountStorage =
55
- await this.dcchainapi?.query.dcNode.walletAccountStorage(account);
55
+ await (this.dcchainapi?.query as any).dcNode.walletAccountStorage(account);
56
56
  if (!walletAccountStorage) {
57
57
  throw new Error("walletAccountStorage is null");
58
58
  }
@@ -67,7 +67,7 @@ export class ChainUtil {
67
67
  }
68
68
  if (userInfo?.parentAccount !== account) {
69
69
  const parentWalletAccountStorage =
70
- await this.dcchainapi?.query.dcNode.walletAccountStorage(
70
+ await (this.dcchainapi?.query as any).dcNode.walletAccountStorage(
71
71
  userInfo?.parentAccount
72
72
  );
73
73
  if (!parentWalletAccountStorage) {
@@ -131,7 +131,7 @@ export class ChainUtil {
131
131
  // 获取用户钱包信息
132
132
  async getUserInfoWithNftHex(nftHexAccount: string): Promise<User> {
133
133
  const walletAccount =
134
- await this.dcchainapi?.query.dcNode.nftToWalletAccount(nftHexAccount);
134
+ await (this.dcchainapi?.query as any).dcNode.nftToWalletAccount(nftHexAccount);
135
135
  if (!walletAccount || !walletAccount.toString()) {
136
136
  throw new Error("walletAccount is null");
137
137
  }
@@ -191,7 +191,7 @@ export class ChainUtil {
191
191
  const accountHash = await sha256(accountBytes);
192
192
  const nftHexAccount = "0x" + Buffer.from(accountHash).toString("hex");
193
193
  const walletAccount =
194
- await this.dcchainapi?.query.dcNode.nftToWalletAccount(nftHexAccount);
194
+ await (this.dcchainapi?.query as any).dcNode.nftToWalletAccount(nftHexAccount);
195
195
  if (!walletAccount || !walletAccount.toString()) {
196
196
  throw new Error("walletAccount is null");
197
197
  }
@@ -200,7 +200,7 @@ export class ChainUtil {
200
200
 
201
201
  // 获取所有文件存储节点
202
202
  getObjNodes = async (cid: string): Promise<string[] | undefined> => {
203
- const fileInfo = (await this.dcchainapi?.query.dcNode.files(cid)) || null;
203
+ const fileInfo = (await (this.dcchainapi?.query as any).dcNode.files(cid)) || null;
204
204
  const fileInfoJSON = fileInfo?.toJSON();
205
205
  if (
206
206
  !fileInfoJSON ||
@@ -226,7 +226,7 @@ export class ChainUtil {
226
226
 
227
227
  // 链上查询节点信息
228
228
  // getDcNodeAddr = async (peerid: string) => {
229
- // const peerInfo = await this.dcchainapi?.query.dcNode.peers(peerid);
229
+ // const peerInfo = await (this.dcchainapi?.query as any).dcNode.peers(peerid);
230
230
  // const peerInfoJson = peerInfo?.toJSON();
231
231
  // if (
232
232
  // !peerInfoJson ||
@@ -264,7 +264,7 @@ export class ChainUtil {
264
264
  // peerid: 节点的peerid
265
265
  // 直接连接节点的地址
266
266
  getDcNodeWebrtcDirectAddr = async (peerid: string): Promise<Multiaddr | null> => {
267
- const peerInfo = await this.dcchainapi?.query.dcNode.peers(peerid);
267
+ const peerInfo = await (this.dcchainapi?.query as any).dcNode.peers(peerid);
268
268
  const peerInfoJson = peerInfo?.toJSON();
269
269
  if (
270
270
  !peerInfoJson ||
@@ -288,7 +288,7 @@ export class ChainUtil {
288
288
 
289
289
  // 链上查询节点列表
290
290
  getDcNodeList = async (): Promise<string[]> => {
291
- const peerList = await this.dcchainapi?.query.dcNode.onlineNodesAddress();
291
+ const peerList = await (this.dcchainapi?.query as any).dcNode.onlineNodesAddress();
292
292
  const peerListJson = peerList?.toJSON();
293
293
  console.log(
294
294
  "peerListJson================================================",
@@ -319,7 +319,7 @@ export class ChainUtil {
319
319
  return [null, new Error("dcchainapi is not initialized")];
320
320
  }
321
321
 
322
- const fileInfo = await this.dcchainapi.query.dcNode.files(cid);
322
+ const fileInfo = await (this.dcchainapi.query as any).dcNode.files(cid);
323
323
 
324
324
  if (!fileInfo || fileInfo.isEmpty) {
325
325
  return [null, new Error(`File with CID ${cid} not found`)];
@@ -426,7 +426,7 @@ export class ChainUtil {
426
426
  }
427
427
  const appIdBytes = new TextEncoder().encode(appId);
428
428
  const appIdHex = "0x" + Buffer.from(appIdBytes).toString("hex");
429
- const appInfoStr = await this.dcchainapi?.query.dcNode.appsInfo(appIdHex);
429
+ const appInfoStr = await (this.dcchainapi?.query as any).dcNode.appsInfo(appIdHex);
430
430
  if (!appInfoStr || appInfoStr.isEmpty) {
431
431
  throw new Error(`App info for ${appId} not found`);
432
432
  }
@@ -21,7 +21,7 @@ const walletOpenVersion =
21
21
 
22
22
  let _baseUrl = "";
23
23
  let _walletOrigin = "";
24
- if (isProd) {
24
+ if (true) {
25
25
  _baseUrl = "/v0_0_10";
26
26
  _walletOrigin = "https://wallet.dcnetio.com";
27
27
  if(walletOpenType === "iframe") {
@@ -28,13 +28,30 @@ export async function registerServiceWorker(fileOps?: IFileOperations, swUrl: st
28
28
  : '/sw.js';
29
29
 
30
30
  const registration = await navigator.serviceWorker.register(swPath);
31
-
31
+ // 让等待中的 SW 立即成为激活态
32
+ if (registration.waiting) {
33
+ registration.waiting.postMessage({ type: 'SKIP_WAITING' });
34
+ }
35
+ // 有新 SW 安装后自动接管
36
+ registration.addEventListener('updatefound', () => {
37
+ const nw = registration.installing;
38
+ if (!nw) return;
39
+ nw.addEventListener('statechange', () => {
40
+ if (nw.state === 'installed' && navigator.serviceWorker.controller) {
41
+ nw.postMessage({ type: 'SKIP_WAITING' });
42
+ }
43
+ });
44
+ });
32
45
  // 设置消息监听器处理IPFS资源请求
33
46
  navigator.serviceWorker.addEventListener('message', async (event) => {
34
47
  if (event.data && event.data.type === 'ipfs-fetch') {
35
48
  await handleIpfsRequest(event.data, event.ports[0]!, fileOps);
36
49
  }
37
50
  });
51
+ // 控制器变化(新 SW 接管)
52
+ navigator.serviceWorker.addEventListener('controllerchange', () => {
53
+ location.reload();
54
+ });
38
55
 
39
56
  return registration;
40
57
  } catch (error) {
@@ -51,7 +68,7 @@ export async function registerServiceWorker(fileOps?: IFileOperations, swUrl: st
51
68
  * @param port 消息端口
52
69
  * @param fileOps 文件操作对象
53
70
  */
54
- async function handleIpfsRequest(
71
+ export async function handleIpfsRequest(
55
72
  data: { id: string, pathname: string, range?: string },
56
73
  port: MessagePort,
57
74
  fileOps?: IFileOperations
package/lib/dc.ts CHANGED
@@ -82,7 +82,7 @@ export class DC implements DCContext {
82
82
  this.dcChain = new ChainUtil();
83
83
  this.dcutil = new DcUtil(this.dcChain);
84
84
  // //todo 发布注释 remove
85
- // this.dcutil.defaultPeerId= "12D3KooWEGzh4AcbJrfZMfQb63wncBUpscMEEyiMemSWzEnjVCPf";
85
+ // this.dcutil.defaultPeerId= "12D3KooWEGzh4AcbJrfZMfQb63wncBUpscMEEyiMemSWzEnjVCPf";
86
86
  // //todo remove end
87
87
  this.appInfo = options.appInfo || ({} as APPInfo);
88
88
  this.accountInfo = {} as AccountInfo;
@@ -413,7 +413,7 @@ export class AccountManager {
413
413
  const accountHash = await sha256(accountBytes);
414
414
  const nftHexAccount = "0x" + Buffer.from(accountHash).toString("hex");
415
415
  const walletAccount =
416
- await this.chainUtil.dcchainapi?.query.dcNode.nftToWalletAccount(
416
+ await (this.chainUtil.dcchainapi?.query as any).dcNode.nftToWalletAccount(
417
417
  nftHexAccount
418
418
  );
419
419
  // 比较公钥
@@ -441,7 +441,7 @@ export class AccountManager {
441
441
  const accountHash = await sha256(accountBytes);
442
442
  const nftHexAccount = "0x" + Buffer.from(accountHash).toString("hex");
443
443
  const walletAccount =
444
- await this.chainUtil.dcchainapi?.query.dcNode.nftToWalletAccount(
444
+ await (this.chainUtil.dcchainapi?.query as any).dcNode.nftToWalletAccount(
445
445
  nftHexAccount
446
446
  );
447
447
  if (!walletAccount.toString()) {
@@ -94,7 +94,59 @@ export class CommentClient {
94
94
  }
95
95
 
96
96
 
97
-
97
+ async getUserOffChainUsedInfo(
98
+ vaccount: string = ""
99
+ ): Promise<dcnet.pb.GetUserOffChainUsedInfoReply> {
100
+ const message = new dcnet.pb.GetUserOffChainUsedInfoRequest({});
101
+ message.vaccount = new TextEncoder().encode(vaccount);
102
+ const messageBytes =
103
+ dcnet.pb.GetUserOffChainUsedInfoRequest.encode(message).finish();
104
+ try {
105
+ const grpcClient = new Libp2pGrpcClient(
106
+ this.client.p2pNode,
107
+ this.client.peerAddr,
108
+ this.client.token,
109
+ this.client.protocol
110
+ );
111
+ const reply = await grpcClient.unaryCall(
112
+ "/dcnet.pb.Service/GetUserOffChainUsedInfo",
113
+ messageBytes,
114
+ 30000
115
+ );
116
+ const decoded = dcnet.pb.GetUserOffChainUsedInfoReply.decode(reply);
117
+ return decoded;
118
+ } catch (error: any) {
119
+ if (error.message.indexOf(Errors.INVALID_TOKEN.message) != -1) {
120
+ // try to get token
121
+ const token = await this.client.GetToken(
122
+ this.context.appInfo.appId || "",
123
+ this.context.getPublicKey().string(),
124
+ (payload: Uint8Array): Promise<Uint8Array> => {
125
+ return this.context.sign(payload);
126
+ }
127
+ );
128
+ if (!token) {
129
+ throw new Error(Errors.INVALID_TOKEN.message);
130
+ }
131
+ const grpcClient = new Libp2pGrpcClient(
132
+ this.client.p2pNode,
133
+ this.client.peerAddr,
134
+ this.client.token,
135
+ this.client.protocol
136
+ );
137
+ const reply = await grpcClient.unaryCall(
138
+ "/dcnet.pb.Service/GetUserOffChainUsedInfo",
139
+ messageBytes,
140
+ 30000
141
+ );
142
+ const decoded = dcnet.pb.GetUserOffChainUsedInfoReply.decode(reply);
143
+ console.log("GetUserOffChainUsedInfo decoded", decoded);
144
+ return decoded;
145
+ }
146
+ throw error;
147
+ }
148
+
149
+ }
98
150
 
99
151
  async addUserOffChainOpTimes(
100
152
  pubkey: string,
@@ -310,7 +310,25 @@ export class CommentManager {
310
310
  }
311
311
  }
312
312
 
313
-
313
+ async getUserOffChainUsedInfo(vaccount: string = ""): Promise<[dcnet.pb.GetUserOffChainUsedInfoReply | null, Error | null]> {
314
+ try {
315
+ if (!this.accountBackupDc?.client) {
316
+ return [null, Errors.ErrNoDcPeerConnected];
317
+ }
318
+ if(!this.accountBackupDc?.nodeAddr){
319
+ return [null, Errors.ErrNoDcPeerConnected];
320
+ }
321
+ const commentClient = new CommentClient(
322
+ this.accountBackupDc.client,
323
+ this.dcNodeClient,
324
+ this.context
325
+ );
326
+ const res = await commentClient.getUserOffChainUsedInfo(vaccount);
327
+ return [res, null];
328
+ } catch (err) {
329
+ return [null, err as Error];
330
+ }
331
+ }
314
332
 
315
333
  async addUserOffChainOpTimes(
316
334
  times: number,
@@ -1516,7 +1516,21 @@ async create(threadId: string, collectionName: string, jsonInstance: string): P
1516
1516
  // if (jsonInstance.length > 100 * 1024) { // 100 KB
1517
1517
  // throw new Error("instance too big");
1518
1518
  // }
1519
+
1520
+ // 判断instance里面是否有_mod字段,存在则删除
1521
+ try {
1522
+ const instanceObj = JSON.parse(jsonInstance);
1523
+ if (instanceObj && typeof instanceObj === 'object' && '_mod' in instanceObj) {
1524
+ delete instanceObj._mod;
1525
+ jsonInstance = JSON.stringify(instanceObj);
1526
+ }
1527
+ } catch (err) {
1528
+ // JSON解析失败,保持原字符串不变
1529
+ console.warn('Failed to parse instance JSON, keeping original:', err);
1530
+ throw new Error("Invalid instance JSON format");
1531
+ }
1519
1532
  try {
1533
+
1520
1534
  // 解码threaddbID
1521
1535
  const tID = ThreadID.fromString(threadId);
1522
1536
 
@@ -1587,7 +1601,20 @@ async save(threadId: string, collectionName: string, instance: string): Promise<
1587
1601
  // 解码线程ID
1588
1602
  const tID = ThreadID.fromString(threadId);
1589
1603
 
1590
-
1604
+ // 判断instance里面是否有_mod字段,存在则删除
1605
+ try {
1606
+ const instanceObj = JSON.parse(instance);
1607
+ if (instanceObj && typeof instanceObj === 'object' && '_mod' in instanceObj) {
1608
+ delete instanceObj._mod;
1609
+ instance = JSON.stringify(instanceObj);
1610
+ }
1611
+ } catch (err) {
1612
+ // JSON解析失败,保持原字符串不变
1613
+ console.warn('Failed to parse instance JSON, keeping original:', err);
1614
+ throw new Error("Invalid instance JSON format");
1615
+ }
1616
+
1617
+
1591
1618
 
1592
1619
  // 获取线程数据库
1593
1620
  const threadDB = await this.getDB(tID);
@@ -484,10 +484,14 @@ async ensureUniqueLog(id: ThreadID, key?: Ed25519PrivKey | Ed25519PubKey, identi
484
484
  */
485
485
  async pullThread(id: ThreadID): Promise<void> {
486
486
  try {
487
+ let recs: Record<string, PeerRecords> = {};
487
488
  const mutex = this.getMutexForThread(id.toString());
488
489
  await mutex.acquire();
489
- const recs = await this.pullThreadDeal(id);
490
- mutex.release();
490
+ try {
491
+ recs = await this.pullThreadDeal(id);
492
+ } finally {
493
+ mutex.release();
494
+ }
491
495
 
492
496
  const [connector, appConnected] = this.getConnector(id);
493
497
 
@@ -1148,66 +1152,113 @@ async getRecord( id: ThreadID, rid: CID): Promise<IRecord> {
1148
1152
 
1149
1153
  // 确定需要获取的对等点数量
1150
1154
  const needFetched = Math.min(2, peers.length);
1151
- let fetchedPeers = 0;
1155
+ let resolved = false; // 防止重复调用 resolve
1156
+ // 使用对象来保证引用一致性
1157
+ const fetchState = {
1158
+ fetchedPeers: 0
1159
+ };
1160
+ let timeoutId: NodeJS.Timeout | undefined;
1161
+ // 设置超时
1162
+ const timeoutPromise = new Promise<void>((resolve) => {
1163
+ timeoutId = setTimeout(() => {
1164
+ resolve(); // 超时时总是resolve,在外部判断是否有足够的数据
1165
+ }, 30000);
1166
+ });
1152
1167
 
1153
1168
  // 创建一个 Promise 在足够的对等点响应时解析
1154
1169
  const fetchPromise = new Promise<void>((resolve) => {
1155
- // 当所有查询完成时,解析 Promise
1170
+ // 立即检查是否满足条件
1156
1171
  const checkComplete = () => {
1157
- if (fetchedPeers >= needFetched) {
1172
+ if (!resolved && fetchState.fetchedPeers >= needFetched) {
1173
+ resolved = true;
1158
1174
  resolve();
1159
1175
  }
1160
1176
  };
1161
1177
 
1162
1178
  // 从每个对等点查询记录
1163
1179
  const fetchPromises = peers.map(async (peerId) => {
1180
+ let timeoutId: NodeJS.Timeout | undefined;
1181
+ // 为每个peer设置独立的超时
1182
+ const peerTimeout = new Promise<never>((_, reject) => {
1183
+ timeoutId = setTimeout(() => reject(new Error(`Peer ${peerId} timeout after 30s`)), 30000);
1184
+ });
1185
+
1164
1186
  try {
1165
- //连接到指定peerId,返回一个Client
1166
- const client = await this.getClient(peerId);
1167
- if (!client) {
1168
- return;
1169
- }
1170
- const dbClient = new DBClient(client,this.dc,this,this.logstore);
1171
-
1172
- // 这里使用一个队列来控制并发,类似于 Go 代码中的 queueGetRecords
1173
- const records = await dbClient.getRecordsFromPeer( req, serviceKey);
1174
-
1175
- // 更新收集器
1176
- Object.entries(records).forEach(([logId, rs]) => {
1177
- recordCollector.updateHeadCounter(logId, rs.counter);
1178
- rs.records.forEach(record => {
1179
- recordCollector.store(logId, record);
1180
- });
1181
- });
1182
-
1183
- fetchedPeers++;
1184
-
1185
- // 如果获取了记录并且达到了所需的对等点数量,则解析 Promise
1186
- if (Object.keys(records).length > 0 && fetchedPeers >= needFetched) {
1187
- resolve();
1188
- }
1187
+ // 使用 Promise.race 为每个peer设置超时
1188
+ await Promise.race([
1189
+ (async () => {
1190
+ //连接到指定peerId,返回一个Client
1191
+ const client = await this.getClient(peerId);
1192
+ if (!client) {
1193
+ return;
1194
+ }
1195
+ const dbClient = new DBClient(client,this.dc,this,this.logstore);
1189
1196
 
1190
- // 暂停一秒钟避免过多并发请求
1191
- await new Promise(r => setTimeout(r, 1000));
1197
+ // 这里使用一个队列来控制并发,类似于 Go 代码中的 queueGetRecords
1198
+ const records = await dbClient.getRecordsFromPeer( req, serviceKey);
1199
+
1200
+ // 更新收集器
1201
+ Object.entries(records).forEach(([logId, rs]) => {
1202
+ recordCollector.updateHeadCounter(logId, rs.counter);
1203
+ rs.records.forEach(record => {
1204
+ recordCollector.store(logId, record);
1205
+ });
1206
+ });
1207
+
1208
+ fetchState.fetchedPeers++;
1209
+
1210
+ // 每次成功获取记录后立即检查是否满足条件
1211
+ checkComplete();
1212
+ })(),
1213
+ peerTimeout
1214
+ ]);
1192
1215
  } catch (err) {
1193
1216
  console.error(`Error getting records from peer ${peerId}:`, err);
1217
+ // 错误不影响其他peer的执行
1218
+ } finally {
1219
+ // 清除定时器,防止内存泄漏
1220
+ if (timeoutId) {
1221
+ clearTimeout(timeoutId);
1222
+ }
1223
+ }
1224
+ });
1225
+
1226
+ // 使用 Promise.allSettled 替代 Promise.all,避免被单个失败阻塞
1227
+ // 同时设置额外的兜底检查机制
1228
+ Promise.allSettled(fetchPromises).then(() => {
1229
+ if (!resolved) {
1230
+ checkComplete();
1194
1231
  }
1195
1232
  });
1196
1233
 
1197
- // 当所有查询完成或失败时,检查是否需要解析 Promise
1198
- Promise.all(fetchPromises.map(p => p.catch(e => e)))
1199
- .then(() => checkComplete());
1234
+ // 添加定期检查机制,防止被某些未知问题阻塞
1235
+ const checkInterval = setInterval(() => {
1236
+ if (resolved) {
1237
+ clearInterval(checkInterval);
1238
+ } else {
1239
+ checkComplete();
1240
+ }
1241
+ }, 5000); // 每5秒检查一次
1242
+
1243
+ // 确保interval最终被清理
1244
+ setTimeout(() => clearInterval(checkInterval), 35000);
1200
1245
  });
1201
1246
 
1202
- // 设置超时
1203
- const timeoutPromise = new Promise<void>((_, reject) => {
1204
- setTimeout(() => reject(new Error("Fetch records timeout")), 30000);
1205
- });
1247
+
1206
1248
 
1207
1249
  // 等待获取足够的记录或超时
1208
1250
  await Promise.race([fetchPromise, timeoutPromise]);
1251
+ // 清除超时定时器
1252
+ if (timeoutId) {
1253
+ clearTimeout(timeoutId);
1254
+ }
1255
+ // 检查是否获取到足够的数据
1256
+ if (fetchState.fetchedPeers === 0) {
1257
+ throw new Error("Fetch records timeout: no peers responded");
1258
+ }
1209
1259
 
1210
- // 返回收集到的记录
1260
+ // 如果有数据就返回(不管是1个还是2个节点)
1261
+ console.log(`获取记录完成: ${fetchState.fetchedPeers}/${needFetched} 个节点响应`);
1211
1262
  return recordCollector.list();
1212
1263
  } catch (err) {
1213
1264
  console.error("getRecords error:", err);
@@ -1,5 +1,6 @@
1
1
  import { IAppInfo } from '../../lib/common/types/types';
2
2
  import { SymmetricKey, Key as ThreadKey } from '../implements/threaddb/common/key';
3
+ import { IFileOperations } from './file-interface';
3
4
 
4
5
 
5
6
  export interface IUtilOperations {
@@ -8,11 +9,23 @@ export interface IUtilOperations {
8
9
  /**
9
10
  * 设置应用信息,发布应用时调用
10
11
  * @param appId string 应用ID
11
- * @param domain
12
12
  * @param fid
13
+ * @param domain
13
14
  * @param owner
14
15
  * @param rewarder
15
16
  */
16
- setAppInfo(appId: string,domain:string,fid:string,owner?: string,rewarder?: string): Promise<[boolean|null, Error | null]>;
17
+ setAppInfo(appId: string,fid:string,domain:string,owner?: string,rewarder?: string): Promise<[boolean|null, Error | null]>;
17
18
  getAppInfo(appId: string): Promise<[IAppInfo|null, Error | null]>;
19
+
20
+ /**
21
+ * 处理IPFS请求
22
+ * @param data 请求数据
23
+ * @param port 消息端口
24
+ * @param fileOps 文件操作对象
25
+ */
26
+ handleIpfsRequest(
27
+ data: { id: string, pathname: string, range?: string },
28
+ port: MessagePort,
29
+ fileOps?: IFileOperations
30
+ ): Promise<void>
18
31
  }
@@ -115,21 +115,26 @@ export class AuthModule implements DCModule, IAuthOperations {
115
115
  if (userInfo == null) {
116
116
  throw Errors.USER_NOT_BIND_TO_PEER;
117
117
  }
118
- if (
119
- userInfo.offchainSpace < OffChainSpaceLimit ||
120
- userInfo.offchainOptimes < OffChainOpTimesLimit
121
- ) {
122
- const commentManager = new CommentManager(this.context);
123
- if (userInfo.offchainSpace < OffChainSpaceLimit) {
124
- const [addOffChainBool, addOffChainError] =
125
- await commentManager.addUserOffChainSpace();
118
+ //获取用户已经使用的评论空间和操作次数
119
+ const commentManager = new CommentManager(this.context);
120
+ const [offchainUsedInfo,resErr] = await commentManager.getUserOffChainUsedInfo()
121
+ if (resErr) {
122
+ throw resErr;
123
+ }
124
+ const leftSpace = offchainUsedInfo?userInfo.offchainSpace - Number(offchainUsedInfo.usedspace) :userInfo.offchainSpace;
125
+ const leftOptimes = offchainUsedInfo?userInfo.offchainOptimes - Number(offchainUsedInfo.usedtimes):userInfo.offchainOptimes;
126
+ logger.info(
127
+ `用户线下评论空间剩余: ${leftSpace} / ${userInfo.offchainSpace}, 线下操作次数剩余: ${leftOptimes} / ${userInfo.offchainOptimes}`
128
+ );
129
+ if (leftSpace < OffChainSpaceLimit || leftOptimes < OffChainOpTimesLimit) {
130
+ if (leftSpace < OffChainSpaceLimit) {
131
+ const [addOffChainBool, addOffChainError] = await commentManager.addUserOffChainSpace();
126
132
  if (addOffChainError || !addOffChainBool) {
127
133
  throw addOffChainError || new Error("addUserOffChainSpace error");
128
134
  }
129
135
  }
130
- if (userInfo.offchainOptimes < OffChainOpTimesLimit) {
131
- const [addOffChainOpTimesBool, addOffChainOpTimesError] =
132
- await commentManager.addUserOffChainOpTimes(OffChainOpTimes);
136
+ if (leftOptimes < OffChainOpTimesLimit) {
137
+ const [addOffChainOpTimesBool, addOffChainOpTimesError] =await commentManager.addUserOffChainOpTimes(OffChainOpTimes);
133
138
  if (addOffChainOpTimesError || !addOffChainOpTimesBool) {
134
139
  throw (
135
140
  addOffChainOpTimesError || new Error("addUserOffChainSpace error")
@@ -2,11 +2,12 @@
2
2
  import { IUtilOperations } from '../interfaces/util-interface';
3
3
  import { SymmetricKey,Key as ThreadKey } from '../implements/threaddb/common/key';
4
4
  import { CoreModuleName } from '../common/module-system';
5
- import { DCContext } from '../interfaces';
5
+ import { DCContext, IFileOperations } from '../interfaces';
6
6
  import { createLogger } from '../util/logger';
7
7
  import { UtilManager } from '../../lib/implements/util/manager';
8
8
  import { IAppInfo } from '../../lib/common/types/types';
9
9
  import { Errors } from '../../lib/common/error';
10
+ import { handleIpfsRequest } from '../common/service-worker';
10
11
  const logger = createLogger("UtilModule");
11
12
  export class UtilModule implements IUtilOperations {
12
13
  readonly moduleName = CoreModuleName.UTIL;
@@ -121,5 +122,27 @@ export class UtilModule implements IUtilOperations {
121
122
  async shutdown(): Promise<void> {
122
123
  this.initialized = false;
123
124
  }
125
+
126
+
127
+ /**
128
+ * 处理IPFS请求
129
+ * @param data 请求数据
130
+ * @param port 消息端口
131
+ * @param fileOps 文件操作对象
132
+ */
133
+ async handleIpfsRequest(
134
+ data: { id: string, pathname: string, range?: string },
135
+ port: MessagePort,
136
+ fileOps?: IFileOperations
137
+ ): Promise<void>{
138
+ if (!this.initialized) {
139
+ return;
140
+ }
141
+ try {
142
+ await handleIpfsRequest(data, port, fileOps);
143
+ } catch (error) {
144
+ logger.error("页面处理IPFS请求失败:", error);
145
+ }
146
+ }
124
147
 
125
148
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "web-dc-api",
3
- "version": "0.0.46",
3
+ "version": "0.0.48",
4
4
  "description": "web相关的dcapi",
5
5
  "type": "module",
6
6
  "browser": "dist/dc.min.js",