oicq-icalingua-plus-plus 1.26.5 → 1.26.6

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.
@@ -391,6 +391,18 @@ const map = {
391
391
  468: "/失眠",
392
392
  469: "/坚毅",
393
393
  470: "/马到成功",
394
+ 472: "/心动",
395
+ 474: "/给你一拳",
396
+ 475: "/干饭",
397
+ 476: "/不是吧",
398
+ 477: "/你懂的",
399
+ 478: "/对的对的",
400
+ 479: "/不对不对",
401
+ 480: "/散味儿",
402
+ 481: "/学习",
403
+ 482: "/热化了",
404
+ 483: "/略",
405
+ 484: "/比爱心",
394
406
  };
395
407
 
396
408
  const FACE_OLD_BUF = Buffer.from([0x00, 0x01, 0x00, 0x04, 0x52, 0xCC, 0xF5, 0xD0]);
package/lib/service.js CHANGED
@@ -176,117 +176,138 @@ function highwayUploadStream(readable, obj, ip, port) {
176
176
  }
177
177
 
178
178
  const __ = Buffer.from([41])
179
- // TODO: 优化内存占用
180
179
  function highwayHttpUpload(readable, obj) {
181
- const agent = new http.Agent({ maxSockets: 10 })
180
+ const agent = new http.Agent({ maxSockets: 1 })
182
181
  const ip = this.storage.ip
183
182
  const port = this.storage.port
184
183
  if (!port) throw new Error("没有上传通道,如果你刚刚登录,请等待几秒")
185
184
 
186
185
  console.log(`highway(http) ip:${ip} port:${port}`)
187
186
  const url = "http://" + ip + ":" + port + "/cgi-bin/httpconn?htcmd=0x6FF0087&uin=" + this.uin
188
- let seq = 1
189
- let offset = 0, limit = 524288
187
+ const limit = 524288
190
188
  obj.ticket = this.storage.sig_session
191
189
 
192
- const bufs = new Set()
193
- const controller = new AbortController();
194
- require("events").setMaxListeners(233, controller.signal);
195
- let finished = 0
190
+ let seq = 1
191
+ let offset = 0
192
+ let totalChunks = 0
193
+ let readEnded = false
194
+
195
+ // 顺序队列:每读到一个完整分块就推入,drain 循环逐个串行上传
196
+ const queue = []
197
+ let notify = null // 用于队列非空时唤醒 drain
198
+ let errFlag = null // 记录首个错误,终止后续上传
199
+ let quickDone = false
196
200
 
201
+ const buildBuf = (chunk, chunkOffset) => {
202
+ const head = pb.encode({
203
+ 1: {
204
+ 1: 1,
205
+ 2: String(this.uin),
206
+ 3: "PicUp.DataUp",
207
+ 4: seq++,
208
+ 5: 0,
209
+ 6: this.apk.subid,
210
+ 8: obj.cmdid,
211
+ },
212
+ 2: {
213
+ 1: 0,
214
+ 2: obj.size,
215
+ 3: chunkOffset,
216
+ 4: chunk.length,
217
+ 6: obj.ticket,
218
+ 8: md5(chunk),
219
+ 9: obj.md5,
220
+ 10: 0,
221
+ 13: 0,
222
+ },
223
+ 3: obj.ext,
224
+ 4: Date.now()
225
+ })
226
+ const header = Buffer.allocUnsafe(9)
227
+ header.writeUInt8(40)
228
+ header.writeUInt32BE(head.length, 1)
229
+ header.writeUInt32BE(chunk.length, 5)
230
+ return Buffer.concat([header, head, chunk, __])
231
+ }
232
+
233
+ // 读取流 → 分块 → 入队
197
234
  readable.on("data", data => {
235
+ if (errFlag || quickDone) return
198
236
  let _offset = 0
199
237
  while (_offset < data.length) {
200
238
  const chunk = data.slice(_offset, limit + _offset)
201
- const head = pb.encode({
202
- 1: {
203
- 1: 1,
204
- 2: String(this.uin),
205
- 3: "PicUp.DataUp",
206
- 4: seq++,
207
- 5: 0,
208
- 6: this.apk.subid,
209
- 8: obj.cmdid,
210
- },
211
- 2: {
212
- 1: 0,
213
- 2: obj.size,
214
- 3: offset + _offset,
215
- 4: chunk.length,
216
- 6: obj.ticket,
217
- 8: md5(chunk),
218
- 9: obj.md5,
219
- 10: 0,
220
- 13: 0,
221
- },
222
- 3: obj.ext,
223
- 4: Date.now()
224
- })
225
239
  _offset += chunk.length
226
- const _ = Buffer.allocUnsafe(9)
227
- _.writeUInt8(40)
228
- _.writeUInt32BE(head.length, 1)
229
- _.writeUInt32BE(chunk.length, 5)
230
- const buf = Buffer.concat([_, head, chunk, __])
231
- bufs.add(buf)
240
+ ++totalChunks
241
+ const buf = buildBuf(chunk, offset + _offset - chunk.length)
242
+ queue.push(buf)
243
+ if (notify) { notify(); notify = null }
232
244
  }
233
245
  offset += data.length
234
246
  })
235
247
 
248
+ readable.on("err", err => { errFlag = err })
249
+
250
+ // 串行 drain 循环:逐个从队列取分块上传
251
+ const drain = async () => {
252
+ let finished = 0
253
+ while (true) {
254
+ while (queue.length === 0) {
255
+ if (errFlag) return
256
+ if (readEnded) {
257
+ // 流已结束且队列为空,检查是否全部完成
258
+ if (finished >= totalChunks) return
259
+ }
260
+ // 等待新分块入队
261
+ await new Promise(r => { notify = r })
262
+ }
263
+ const buf = queue.shift()
264
+ const r = await axios.post(url, buf, {
265
+ responseType: "arraybuffer",
266
+ httpAgent: agent,
267
+ headers: {
268
+ "Content-Length": String(buf.length),
269
+ "Content-Type": "application/octet-stream"
270
+ }
271
+ })
272
+ let rsp
273
+ try {
274
+ const respBuf = Buffer.from(r?.data)
275
+ const header = respBuf.slice(9, respBuf.length - 1)
276
+ rsp = pb.decode(header)
277
+ } catch (err) {
278
+ throw err
279
+ }
280
+ if (rsp?.[3] !== 0) {
281
+ throw new Error(`${rsp[3]}, unknown highway error`)
282
+ }
283
+ ++finished
284
+ const percentage = (finished / totalChunks * 100).toFixed(2)
285
+ this.logger.debug(`highway(http) chunk uploaded (${percentage}%)`)
286
+ if (typeof obj.callback === "function")
287
+ obj.callback(percentage)
288
+ // 快传:服务端已持有全部数据,跳过后续分块
289
+ if (rsp[7]?.toBuffer().length > 0) {
290
+ quickDone = true
291
+ this.logger.debug(`highway(http) can quick upload`)
292
+ this.logger.debug(`highway(http) chunk uploaded (100.00%)`)
293
+ if (typeof obj.callback === "function")
294
+ obj.callback("100.00")
295
+ return
296
+ }
297
+ }
298
+ }
299
+
236
300
  return new Promise((resolve, reject) => {
237
301
  readable.on("err", reject)
238
- .on("end", async() => {
239
- let flag = false
240
- for (const buf of bufs) {
241
- if (flag) break
242
- await axios.post(url, buf, {
243
- responseType: "arraybuffer",
244
- httpAgent: agent,
245
- signal: controller.signal,
246
- headers: {
247
- "Content-Length": String(buf.length),
248
- "Content-Type": "application/octet-stream"
249
- }
250
- }).then(r => {
251
- let percentage, rsp
252
- try {
253
- const buf = Buffer.from(r?.data)
254
- const header = buf.slice(9, buf.length - 1)
255
- rsp = pb.decode(header)
256
- } catch (err) {
257
- this.logger.error(err)
258
- reject(err)
259
- return
260
- }
261
- if (rsp?.[3] !== 0) {
262
- controller.abort()
263
- reject(new Error(`${rsp[3]}, unknown highway error"`))
264
- return
265
- }
266
- ++finished
267
- percentage = (finished / bufs.size * 100).toFixed(2)
268
- this.logger.debug(`highway(http) chunk uploaded (${percentage}%)`)
269
- if (typeof obj.callback === "function" && percentage)
270
- obj.callback(percentage)
271
- if (finished < bufs.size && rsp[7]?.toBuffer().length > 0) {
272
- controller.abort()
273
- flag = true
274
- this.logger.debug(`highway(http) can quick upload`)
275
- this.logger.debug(`highway(http) chunk uploaded (100.00%)`)
276
- if (typeof obj.callback === "function")
277
- obj.callback("100.00")
278
- }
279
- if (finished >= bufs.size && !rsp[7]?.toBuffer().length)
280
- reject("文件校验未通过,上传失败")
281
- }).catch(err => {
282
- if (err instanceof axios.Cancel === false) {
283
- reject(err)
284
- }
285
- flag = true
286
- })
287
- }
288
- resolve(undefined)
302
+ readable.on("end", () => {
303
+ readEnded = true
304
+ // 流结束时唤醒 drain(如果它正在等待)
305
+ if (notify) { notify(); notify = null }
289
306
  })
307
+ drain().then(() => {
308
+ if (errFlag) reject(errFlag)
309
+ else resolve(undefined)
310
+ }).catch(reject)
290
311
  })
291
312
  }
292
313
 
package/package.json CHANGED
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "name": "oicq-icalingua-plus-plus",
3
3
  "app_name": "oicq-icalingua-plus-plus",
4
- "version": "1.26.5",
5
- "app_version": "1.26.5",
6
- "upday": "2026/06/30",
4
+ "version": "1.26.6",
5
+ "app_version": "1.26.6",
6
+ "upday": "2026/07/18",
7
7
  "protocol_version": "v11",
8
8
  "description": "oicq(https://github.com/takayama-lily/oicq) v1 for Icalingua++",
9
9
  "main": "index.js",