mytglib 2.0.4 → 2.0.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/README.md CHANGED
@@ -185,6 +185,8 @@ reCAPTCHA 由客户端的全局 network middleware 处理,不限于 `auth.send
185
185
 
186
186
  Rust `grammers_core` 对初始 `auth.sendCode` 及其自动生成的 `invokeWithReCaptcha(auth.sendCode)` 额外设置完整 frame 写出后的 20 秒响应期限。连接类失败会先关闭当前 DC sender,再用同一序列化请求和同一 reCAPTCHA token 在新代理隧道上重放一次;明确的 Telegram RPC 错误、取消和第二次连接失败不会重放。该规则不改变 Node.js `@mtcute/node` 实现,也不适用于 `signIn`、`signUp` 或其他 RPC。
187
187
 
188
+ Rust `verify_phone_code()` / `register()`(包括对应 `CoreOperation`)的每个授权步骤共用 60 秒期限,包含开始/结束日志回调、重连、DC 迁移、核验、退避和授权元数据处理;日志回调也响应取消和期限。未派发业务请求的结构化连接初始化超时最多额外重试 3 次;仅 `auth.signUp` 的 `500 REG_ID_GENERATE_FAILED` 最多额外重试 3 次,退避均为 2、5、5 秒。注册重放前直接调用 `users.getUsers(InputUserSelf)`:已授权则保存成功,只有明确 `401 AUTH_KEY_UNREGISTERED` 才允许重放该 500。发送结果未知时只核验、不重放。恢复次数或期限耗尽、核验失败时返回 `CoreError::AuthorizationRecoveryRequired`,保留原始错误和重试记录,超时丢弃在途调用时也不会丢失这些记录;`signUp` 返回非成功授权响应同样归为授权未知;取消保持 `CoreError::Aborted`。恢复复用原 Session 和参数,禁止额外 reCAPTCHA 求解,不重新取号或发码。调用方应将最终未知结果隔离,不在外层另开自动重试循环。Node.js 行为不变。
189
+
188
190
  `auth.sentCodePaymentRequired` 不是 RPC 错误,而是 `auth.sendCode` 的合法返回。它表示由于所在国家或运营商的短信验证成本较高,官方客户端必须先完成 Telegram Premium 购买流程才能继续登录或注册。原始响应中的 `storeProduct`、`premiumDays`、`currency` 和 `amount` 描述商品与价格,`phoneCodeHash` 保留后续授权上下文,`supportEmailAddress` 和 `supportEmailSubject` 用于联系支持。
189
191
 
190
192
  `sendCode()` 或 `verifyEmailCode()` 收到该响应时,会像保存 `phoneCodeHash` 一样把三个必需字段原子地挂载到 `core.inputStore`:`{ premiumDays, currency, amount }`。普通 `auth.sentCode`、`auth.sentCodeSuccess`、授权成功及成功销毁客户端时会清空该状态。
@@ -236,6 +238,7 @@ const pool = await createPhoneStatusPool({
236
238
  databasePath: resolve(".data/phone-status-pool/pool.sqlite"),
237
239
  minWarmSlots: 10,
238
240
  retryWarmSlots: 200,
241
+ maxConcurrentChecks: 256,
239
242
  });
240
243
 
241
244
  const account = await pool.importAccount({
@@ -288,8 +291,21 @@ Pool 的 PRIMARY 策略硬上限固定为 `minWarmSlots * 5`,加上 `retryWarm
288
291
  事件循环压力评估限制。忙碌槽位超过当前连接数一半时,Pool 会在资源允许的情况下异步提高目标槽位;
289
292
  高峰过后,弹性槽位连续空闲 10 分钟才进入回收,并且每 30 秒最多回收一个,避免连接数瞬间震荡。
290
293
  进入 `PRESSURED` 时,Pool 会先回收 PRIMARY 弹性槽,并保留当前资源上限能够承载的基础 PRIMARY
291
- 和独立 RETRY 槽;若上限不足,则优先保证 PRIMARY,按剩余容量降低 RETRY 数。只有进入
292
- `CRITICAL` 时才暂停建连并回收全部 RETRY 和 PRIMARY 弹性槽。
294
+ 和独立 RETRY 槽;若上限不足,则优先保证 PRIMARY,按剩余容量降低 RETRY 数。
295
+ 单次事件循环尖峰只触发 `PRESSURED`,连续 3 次成功采集的严重样本才进入软 `CRITICAL`,连续 2 次健康样本恢复;采样失败会打断连续计数。
296
+ `resource.hardCritical` 区分内存/堆硬危险与事件循环软压力:软 `CRITICAL` 暂停建连、保留就绪主备槽并
297
+ 以 10% 检测预算继续服务,不因 PRIMARY 未达到配置目标而回收已有 RETRY;暂停预热期间有效目标按实际存量显示。
298
+ 硬危险立即拒绝新检测并逐步释放空闲连接,可低于配置的最小暖槽数。
299
+ 压力回收每秒最多启动一个,不中断正在使用的槽。`resource.pressureReasons` 报告具体压力原因,
300
+ `resource.capacityLimitingFactor` 单独报告连接容量瓶颈,避免把“目标未预热满”当成“资源未承压”。
301
+ 监控采样失败时停止新建连接、缩小检测预算,连续 3 次失败后拒绝新检测;运行期单次采样最多等待 3 秒,
302
+ 未完成的采样不会重复启动。`lastSuccessfulSampleAt` 用于识别陈旧数据。
303
+
304
+ `maxConcurrentChecks` 默认 `256`,限制未完成的不同手机号共享检测任务(包含等待 READY 的任务)。
305
+ `PRESSURED` 下预算为 50%,软 `CRITICAL` 为 10%,硬危险为 0;达到上限立即返回 `POOL_QUEUE_FULL`。
306
+ 缓存命中和相同手机号的跟随者不新增共享检测名额。HTTP 层仍需独立限制总请求数与每用户并发,
307
+ 防止大量跟随者占满 Web 进程。预热只排入最多两倍握手并发的连接任务,分别计算 PRIMARY/RETRY 缺口,主槽富余不会抵消重试槽缺口。
308
+ READY 槽按风险/最近使用时间由索引优先队列选择,不再逐请求排序全部连接。
293
309
  当总连接上限高于 `minWarmSlots` 时,Pool 会在这个上限内部为导入和待机账号自检保留 1 个临时
294
310
  管理连接位;该预留不会突破 PRIMARY 策略上限与 `retryWarmSlots` 之和。若资源上限已经低到不高于
295
311
  最小暖槽数,管理建连会返回 `POOL_BUSY`,优先保护正在提供服务的暖槽。
@@ -300,6 +316,7 @@ Pool 的 PRIMARY 策略硬上限固定为 `minWarmSlots * 5`,加上 `retryWarm
300
316
  const response = await pool.checkPhoneStatus({
301
317
  phone: "+12025550123",
302
318
  abortSignal: new AbortController().signal,
319
+ deadlineAt: Date.now() + 13_000, // 可选:调用方等待的绝对期限
303
320
  });
304
321
 
305
322
  console.log(response.status, response.waitTime, response.error);
@@ -338,13 +355,21 @@ console.log(response.status, response.waitTime, response.error);
338
355
  返回的等待秒数退出暖槽并进入冷却,Pool 随即从库存异步补入其他账号。
339
356
  若暖槽返回冻结账号错误,Pool 会将该账号永久隔离并换用其他 `READY` 槽位;当前检测返回的错误仍保留
340
357
  Telegram 原始 `code = 420` 和错误文本。
341
- `PHONE_NUMBER_FLOOD` 是目标手机号级错误,不换槽重试,只保护目标手机号 5 分钟且不处罚账号。
342
- 明确检测结果缓存 5 分钟,最多保存 10,000 条;同一手机号的并发请求会合并为一次检测,
343
- 基础设施错误不缓存,也不提供强制刷新。
358
+ `PHONE_NUMBER_FLOOD` 是目标手机号级错误,当前请求不换槽重试、不处罚账号,也不缓存错误;后续同号请求可重新检测。
359
+ 仅 `PHONE_NUMBER_OCCUPIED`、`PHONE_NUMBER_NO_OCCUPIED`、`PHONE_NUMBER_INVALID` 和
360
+ `PHONE_NUMBER_BANNED` 的确定结果缓存 60 秒,最多保存 10,000 条;有效期从写入时计算,命中不续期。
361
+ 本地格式校验失败仍即时返回 `PHONE_NUMBER_INVALID`,不发起 RPC,也不占用结果缓存。
362
+ 同一手机号的并发请求会合并为一次检测;`FLOOD_WAIT`、`OTHER_ERROR` 等其他结果不缓存,
363
+ 共享检测结束后后续请求可重新检测,也不提供强制刷新。
344
364
 
345
365
  `abortSignal` 只取消当前调用方等待,并以 `OTHER_ERROR` 返回取消原因;它不会中断已经启动的
346
366
  single-flight RPC。即使当前只有一个等待者,后台检测仍可完成并写入明确结果缓存。调用开始前已经
347
367
  取消的 signal 会在读取缓存前返回,不会命中旧结果或启动新 RPC。
368
+ `deadlineAt` 同样只限制当前调用方等待,不会缩短同号码其他调用者共享任务的 14 秒内部预算。
369
+ 调用方离开后,内部任务仍占用 `maxConcurrentChecks` 名额直至完成。
370
+ 普通检测的统计增量每秒合并写入 SQLite,并在候选选择和关闭时刷新;异常退出可能丢失最后
371
+ 约一秒统计,账号冷却/隔离等调度状态仍立即持久化。统计写失败保留待写增量并报告后台错误。
372
+ 管理查询直接叠加待写统计、不强制刷新;仓储新增不会因无关统计刷新失败出现“已落库却抛错”,删除和冷却/隔离状态落盘也不受统计刷新阻断。候选选择仍要求统计刷新成功以保持排序;完整导入流程中的必要写入失败时仍会回滚导入。
348
373
 
349
374
  按照当前业务规则,`403 RECAPTCHA_CHECK_signup`(含 site key 后缀)直接判定为
350
375
  `PHONE_NUMBER_NO_OCCUPIED`。Pool 不求解、不重放 challenge;它会回收触发 challenge 的槽位并从库存
@@ -352,6 +377,15 @@ single-flight RPC。即使当前只有一个等待者,后台检测仍可完成
352
377
 
353
378
  ### 管理与运行状态
354
379
 
380
+ 大库存管理列表可调用 `await pool.listAccountsPage({ page: 1, pageSize: 20, phone: "", runtimeStatus: "READY" })`,
381
+ 返回 `{ accounts, total, page, pageSize }`。`pageSize` 为 1–100,页码越界时回到最后一页,筛选后的账号投影不读取
382
+ auth key 或 session metadata。原 `listAccounts()` 继续兼容。`getStatus()` 从轻量状态索引汇总,包含
383
+ `resource`、`roles`、`queues` 和 `admission`,不读取全量会话。
384
+
385
+ 本机 mock Telegram + 真实 SQLite 的容量测量见 [基准说明](docs/phone-status-pool-benchmark.md)。
386
+ 该基准只能验证调度开销与预算上限,真实吞吐还需在目标硬件、真实网络延迟和账号限流条件下测量。
387
+
388
+
355
389
  ```js
356
390
  const accounts = await pool.listAccounts();
357
391
  const detail = await pool.getAccount(account.accountId);
@@ -460,6 +494,10 @@ Telegram 客户端、定时器、缓存、SQLite 连接和 owner lock。关闭
460
494
 
461
495
  ### Rust API
462
496
 
497
+ 同一个 Pool 还支持通过 `userId` 查询大约注册年月,Node.js 使用 `getRegistrationDate()`,Rust 使用
498
+ `get_registration_date()`;暖槽授权、DeviceCheck 材料配置、并发与返回契约见
499
+ [注册年月查询](docs/registration-date.md)。
500
+
463
501
  Rust 实现从 `grammers_core` 根模块导出 `create_phone_status_pool()`、`PhoneStatusPool` 及相关
464
502
  输入、响应和状态类型。调度、持久化格式和暖槽策略与 Node.js 实现一致。手机号检测统一返回
465
503
  扁平的 `PhoneStatusCheckResponse`,字段为 `wait_time`、`phone`、`started_at`、`ended_at`、