@yyyu-star/arcade-kit 0.19.1 → 0.20.1

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.
Files changed (57) hide show
  1. package/CHANGELOG.md +31 -0
  2. package/README.md +48 -2
  3. package/dist/client.d.ts +44 -1
  4. package/dist/client.d.ts.map +1 -1
  5. package/dist/client.js +103 -0
  6. package/dist/client.js.map +1 -1
  7. package/dist/fun-logic.d.ts +8 -0
  8. package/dist/fun-logic.d.ts.map +1 -1
  9. package/dist/fun-logic.js +12 -1
  10. package/dist/fun-logic.js.map +1 -1
  11. package/dist/game.d.ts +7 -0
  12. package/dist/game.d.ts.map +1 -1
  13. package/dist/game.js +38 -0
  14. package/dist/game.js.map +1 -1
  15. package/dist/internal.d.ts +4 -0
  16. package/dist/internal.d.ts.map +1 -1
  17. package/dist/internal.js +6 -0
  18. package/dist/internal.js.map +1 -1
  19. package/dist/match.d.ts +85 -0
  20. package/dist/match.d.ts.map +1 -0
  21. package/dist/match.js +361 -0
  22. package/dist/match.js.map +1 -0
  23. package/dist/meter.d.ts +38 -0
  24. package/dist/meter.d.ts.map +1 -1
  25. package/dist/meter.js +56 -14
  26. package/dist/meter.js.map +1 -1
  27. package/dist/protocol.d.ts +35 -0
  28. package/dist/protocol.d.ts.map +1 -1
  29. package/dist/protocol.js.map +1 -1
  30. package/dist/room.d.ts +48 -1
  31. package/dist/room.d.ts.map +1 -1
  32. package/dist/room.js +157 -17
  33. package/dist/room.js.map +1 -1
  34. package/dist/table-chat.d.ts +5 -1
  35. package/dist/table-chat.d.ts.map +1 -1
  36. package/dist/table-chat.js +25 -2
  37. package/dist/table-chat.js.map +1 -1
  38. package/dist/table-fun.d.ts +31 -7
  39. package/dist/table-fun.d.ts.map +1 -1
  40. package/dist/table-fun.js +31 -14
  41. package/dist/table-fun.js.map +1 -1
  42. package/dist/worker.d.ts +12 -0
  43. package/dist/worker.d.ts.map +1 -1
  44. package/dist/worker.js +44 -1
  45. package/dist/worker.js.map +1 -1
  46. package/package.json +5 -1
  47. package/src/client.ts +118 -1
  48. package/src/fun-logic.ts +14 -1
  49. package/src/game.ts +40 -0
  50. package/src/internal.ts +8 -0
  51. package/src/match.ts +371 -0
  52. package/src/meter.ts +68 -12
  53. package/src/protocol.ts +41 -0
  54. package/src/room.ts +171 -18
  55. package/src/table-chat.ts +26 -3
  56. package/src/table-fun.ts +53 -14
  57. package/src/worker.ts +44 -2
package/dist/game.d.ts CHANGED
@@ -164,4 +164,11 @@ export interface RoomGame<S, A, V, O = unknown, E extends RoomEffect = RoomEffec
164
164
  * 座位信息按最坏情况算:全是真人、昵称都是 16 个汉字。
165
165
  */
166
166
  export declare function snapshotBytes<S, A, V, O, E extends RoomEffect>(game: RoomGame<S, A, V, O, E>, state: S): number;
167
+ /**
168
+ * 快速匹配的配置对不对得上房间(0.20.0,安全审阅):每个开放的档位,排队那边的 tableSize(一桌几个真人)和 roomOptions(开桌带的选项)
169
+ * 要过得了这张桌的 RoomGame。对不上的话房间每桌都回 bad / bad_options、排到的人都转单机,线上只看得到日志。
170
+ * 游戏在自己的测试里调:`expect(matchConfigErrors(game, tiers, (t) => queue.tableSize(t), (t) => queue.roomOptions(t))).toEqual([])`。
171
+ * 返回每个问题一句话,没问题是空数组。纯函数,不碰运行时(普通 Node 测试能用)
172
+ */
173
+ export declare function matchConfigErrors<S, A, V, O, E extends RoomEffect>(game: RoomGame<S, A, V, O, E>, tiers: readonly string[], tableSize: (tier: string) => number, roomOptions?: (tier: string) => unknown): string[];
167
174
  //# sourceMappingURL=game.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"game.d.ts","sourceRoot":"","sources":["../src/game.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"game.d.ts","sourceRoot":"","sources":["../src/game.ts"],"names":[],"mappings":"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"}
package/dist/game.js CHANGED
@@ -39,4 +39,42 @@ export function snapshotBytes(game, state) {
39
39
  }
40
40
  return max;
41
41
  }
42
+ /**
43
+ * 快速匹配的配置对不对得上房间(0.20.0,安全审阅):每个开放的档位,排队那边的 tableSize(一桌几个真人)和 roomOptions(开桌带的选项)
44
+ * 要过得了这张桌的 RoomGame。对不上的话房间每桌都回 bad / bad_options、排到的人都转单机,线上只看得到日志。
45
+ * 游戏在自己的测试里调:`expect(matchConfigErrors(game, tiers, (t) => queue.tableSize(t), (t) => queue.roomOptions(t))).toEqual([])`。
46
+ * 返回每个问题一句话,没问题是空数组。纯函数,不碰运行时(普通 Node 测试能用)
47
+ */
48
+ export function matchConfigErrors(game, tiers, tableSize, roomOptions = () => undefined) {
49
+ const out = [];
50
+ for (const tier of tiers) {
51
+ const raw = roomOptions(tier);
52
+ let opts;
53
+ if (raw !== undefined) {
54
+ if (!game.options) {
55
+ out.push(`${tier}: roomOptions given but the game has no options()`);
56
+ continue;
57
+ }
58
+ const o = game.options(raw);
59
+ if (o === null) {
60
+ out.push(`${tier}: roomOptions rejected by game.options()`);
61
+ continue;
62
+ }
63
+ opts = o;
64
+ }
65
+ else if (game.options && game.options(undefined) === null) {
66
+ out.push(`${tier}: game.options() needs roomOptions for this tier`);
67
+ continue;
68
+ }
69
+ const count = game.seatCount ? game.seatCount(opts) : game.seats;
70
+ const size = tableSize(tier);
71
+ if (!Number.isInteger(size) || size < 2)
72
+ out.push(`${tier}: tableSize ${size} must be an integer ≥ 2`);
73
+ else if (size > count)
74
+ out.push(`${tier}: tableSize ${size} is more than the ${count} seats this table plays`);
75
+ else if (size > 9)
76
+ out.push(`${tier}: tableSize ${size} is more than 9 (blockedAmong limit)`);
77
+ }
78
+ return out;
79
+ }
42
80
  //# sourceMappingURL=game.js.map
package/dist/game.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"game.js","sourceRoot":"","sources":["../src/game.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,gBAAgB,EAAiD,MAAM,eAAe,CAAC;AA2KhG;;;;GAIG;AACH,MAAM,UAAU,aAAa,CAAmC,IAA6B,EAAE,KAAQ;IACrG,MAAM,IAAI,GAAa;QACrB,IAAI,EAAE,QAAQ;QACd,MAAM,EAAE,SAAS;QACjB,KAAK,EAAE,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,KAAK,EAAE,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;QAClI,IAAI,EAAE;YACJ,IAAI,EAAE,CAAC;YACP,QAAQ,EAAE,iBAAiB;YAC3B,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SACnF;QACD,qCAAqC;QACrC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,KAAK,EAAE,iBAAiB,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAC/D,CAAC;IACF,IAAI,GAAG,GAAG,CAAC,CAAC;IACZ,KAAK,MAAM,IAAI,IAAI,CAAC,IAAI,EAAE,GAAG,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QAC9E,MAAM,GAAG,GAAkB;YACzB,CAAC,EAAE,SAAS;YACZ,CAAC,EAAE,gBAAgB;YACnB,gBAAgB,EAAE,CAAC;YACnB,GAAG,EAAE,OAAO;YACZ,GAAG,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,IAAI,CAAC,EAAE;YAC/B,IAAI;YACJ,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC;YAC5B,sBAAsB;YACtB,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAC7D,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,EAAE,EAAE,GAAG,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SACrE,CAAC;QACF,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC;IAChF,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC"}
1
+ {"version":3,"file":"game.js","sourceRoot":"","sources":["../src/game.ts"],"names":[],"mappings":"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"}
@@ -36,4 +36,8 @@ export declare const MISS_HEADER = "x-kit-miss";
36
36
  export declare const LIMITED_HEADER = "x-kit-limited";
37
37
  /** 计量的 stub:和房间一样放在亚太,开房、报数少绕路。 */
38
38
  export declare function meterStub(ns: DurableObjectNamespace): DurableObjectStub;
39
+ /** 快速匹配的排队(0.20.0):每个档位一个实例,和房间一样放在亚太 */
40
+ export declare function matchStub(ns: DurableObjectNamespace, tier: string): DurableObjectStub;
41
+ /** 档位 key 的格式:游戏给的短字符串(如 real-2、fun-normal) */
42
+ export declare const TIER_RE: RegExp;
39
43
  //# sourceMappingURL=internal.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"internal.d.ts","sourceRoot":"","sources":["../src/internal.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;;GAGG;AACH,eAAO,MAAM,cAAc,eAAe,CAAC;AAE3C,sCAAsC;AACtC,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAM/D;AAED,+CAA+C;AAC/C,MAAM,WAAW,QAAQ;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;;GAGG;AACH,eAAO,MAAM,QAAQ,wBAAwB,CAAC;AAE9C,qEAAqE;AACrE,wBAAgB,cAAc,CAAC,EAAE,EAAE,QAAQ,GAAG,MAAM,CAEnD;AAED,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,GAAG,QAAQ,GAAG,IAAI,CAQjE;AAED,yBAAyB;AACzB,wBAAgB,WAAW,IAAI,MAAM,CAEpC;AAED,kCAAkC;AAClC,wBAAgB,QAAQ,CAAC,EAAE,EAAE,sBAAsB,EAAE,IAAI,EAAE,MAAM,GAAG,iBAAiB,CAEpF;AAED,2CAA2C;AAC3C,eAAO,MAAM,UAAU,cAAc,CAAC;AAEtC,gFAAgF;AAChF,wBAAgB,QAAQ,CAAC,EAAE,EAAE,sBAAsB,EAAE,GAAG,EAAE,MAAM,GAAG,iBAAiB,CAEnF;AAED,mEAAmE;AACnE,eAAO,MAAM,WAAW,eAAe,CAAC;AAExC,uEAAuE;AACvE,eAAO,MAAM,cAAc,kBAAkB,CAAC;AAE9C,mCAAmC;AACnC,wBAAgB,SAAS,CAAC,EAAE,EAAE,sBAAsB,GAAG,iBAAiB,CAEvE"}
1
+ {"version":3,"file":"internal.d.ts","sourceRoot":"","sources":["../src/internal.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;;GAGG;AACH,eAAO,MAAM,cAAc,eAAe,CAAC;AAE3C,sCAAsC;AACtC,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAM/D;AAED,+CAA+C;AAC/C,MAAM,WAAW,QAAQ;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;;GAGG;AACH,eAAO,MAAM,QAAQ,wBAAwB,CAAC;AAE9C,qEAAqE;AACrE,wBAAgB,cAAc,CAAC,EAAE,EAAE,QAAQ,GAAG,MAAM,CAEnD;AAED,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,GAAG,QAAQ,GAAG,IAAI,CAQjE;AAED,yBAAyB;AACzB,wBAAgB,WAAW,IAAI,MAAM,CAEpC;AAED,kCAAkC;AAClC,wBAAgB,QAAQ,CAAC,EAAE,EAAE,sBAAsB,EAAE,IAAI,EAAE,MAAM,GAAG,iBAAiB,CAEpF;AAED,2CAA2C;AAC3C,eAAO,MAAM,UAAU,cAAc,CAAC;AAEtC,gFAAgF;AAChF,wBAAgB,QAAQ,CAAC,EAAE,EAAE,sBAAsB,EAAE,GAAG,EAAE,MAAM,GAAG,iBAAiB,CAEnF;AAED,mEAAmE;AACnE,eAAO,MAAM,WAAW,eAAe,CAAC;AAExC,uEAAuE;AACvE,eAAO,MAAM,cAAc,kBAAkB,CAAC;AAE9C,mCAAmC;AACnC,wBAAgB,SAAS,CAAC,EAAE,EAAE,sBAAsB,GAAG,iBAAiB,CAEvE;AAED,yCAAyC;AACzC,wBAAgB,SAAS,CAAC,EAAE,EAAE,sBAAsB,EAAE,IAAI,EAAE,MAAM,GAAG,iBAAiB,CAErF;AAED,+CAA+C;AAC/C,eAAO,MAAM,OAAO,QAA8B,CAAC"}
package/dist/internal.js CHANGED
@@ -58,4 +58,10 @@ export const LIMITED_HEADER = 'x-kit-limited';
58
58
  export function meterStub(ns) {
59
59
  return ns.get(ns.idFromName(METER_NAME), { locationHint: 'apac' });
60
60
  }
61
+ /** 快速匹配的排队(0.20.0):每个档位一个实例,和房间一样放在亚太 */
62
+ export function matchStub(ns, tier) {
63
+ return ns.get(ns.idFromName(`kit-match:${tier}`), { locationHint: 'apac' });
64
+ }
65
+ /** 档位 key 的格式:游戏给的短字符串(如 real-2、fun-normal) */
66
+ export const TIER_RE = /^[a-z0-9][a-z0-9-]{0,31}$/;
61
67
  //# sourceMappingURL=internal.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"internal.js","sourceRoot":"","sources":["../src/internal.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;;GAGG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,YAAY,CAAC;AAE3C,sCAAsC;AACtC,MAAM,UAAU,gBAAgB,CAAC,MAAqB;IACpD,IAAI,CAAC,MAAM;QAAE,OAAO,KAAK,CAAC;IAC1B,OAAO,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE;QACrC,MAAM,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QAC5B,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,KAAK,cAAc,IAAI,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC;IAChG,CAAC,CAAC,CAAC;AACL,CAAC;AAQD;;;GAGG;AACH,MAAM,CAAC,MAAM,QAAQ,GAAG,qBAAqB,CAAC;AAE9C,qEAAqE;AACrE,MAAM,UAAU,cAAc,CAAC,EAAY;IACzC,OAAO,kBAAkB,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,EAAE,CAAC,MAAM,EAAE,IAAI,EAAE,EAAE,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;AAClF,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,GAAkB;IAC9C,IAAI,CAAC,GAAG;QAAE,OAAO,IAAI,CAAC;IACtB,IAAI,CAAC;QACH,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,kBAAkB,CAAC,GAAG,CAAC,CAAsB,CAAC;QACnE,OAAO,OAAO,CAAC,CAAC,MAAM,KAAK,QAAQ,IAAI,CAAC,CAAC,MAAM,IAAI,OAAO,CAAC,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;IAC5H,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,yBAAyB;AACzB,MAAM,UAAU,WAAW;IACzB,OAAO,MAAM,CAAC,MAAM,CAAC,eAAe,CAAC,IAAI,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAE,GAAG,SAAS,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;AAC7F,CAAC;AAED,kCAAkC;AAClC,MAAM,UAAU,QAAQ,CAAC,EAA0B,EAAE,IAAY;IAC/D,OAAO,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,EAAE,YAAY,EAAE,MAAM,EAAE,CAAC,CAAC;AAC/D,CAAC;AAED,2CAA2C;AAC3C,MAAM,CAAC,MAAM,UAAU,GAAG,WAAW,CAAC;AAEtC,gFAAgF;AAChF,MAAM,UAAU,QAAQ,CAAC,EAA0B,EAAE,GAAW;IAC9D,OAAO,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,UAAU,CAAC,YAAY,GAAG,EAAE,CAAC,EAAE,EAAE,YAAY,EAAE,MAAM,EAAE,CAAC,CAAC;AAC5E,CAAC;AAED,mEAAmE;AACnE,MAAM,CAAC,MAAM,WAAW,GAAG,YAAY,CAAC;AAExC,uEAAuE;AACvE,MAAM,CAAC,MAAM,cAAc,GAAG,eAAe,CAAC;AAE9C,mCAAmC;AACnC,MAAM,UAAU,SAAS,CAAC,EAA0B;IAClD,OAAO,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,EAAE,YAAY,EAAE,MAAM,EAAE,CAAC,CAAC;AACrE,CAAC"}
1
+ {"version":3,"file":"internal.js","sourceRoot":"","sources":["../src/internal.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,85 @@
1
+ /**
2
+ * 快速匹配的排队(0.20.0,设计 docs/match.md):游戏 Worker 里的 Durable Object 继承它,填上一桌几个真人,就能按档位排队凑桌。
3
+ * 每个档位一个实例(matchStub 按档位取),浏览器经 worker.ts 的 acceptMatch 连进来,连接本身就是"排着"。
4
+ *
5
+ * 守的规矩(和房间同一套,docs/platform-backend.md 第 4 节):
6
+ * - 0 行存储:排着的人就是 ctx.getWebSockets(),附件里只放 userId、昵称、开始排的时间;被驱逐后名单还在;
7
+ * - 只用一个闹钟:最早那个人等满 waitMs 的时刻,只往早了调(setAlarm 也算一行写入);
8
+ * - 只用 ctx.acceptWebSocket,不用 setTimeout / setInterval;排队连接只收不发,浏览器发什么都 1008 断开;
9
+ * - 不碰牌局:不 import 规则、不读房间状态。电脑补位、公平底线全在房间里,和好友房一样;
10
+ * - 名额由房间开桌时向计量一次占齐(kitCreateMatch),排队本身不占。
11
+ */
12
+ import { DurableObject } from 'cloudflare:workers';
13
+ import { type Identity } from './internal.js';
14
+ import type { MatchOutcome } from './room.js';
15
+ export type { MatchDownMsg, MatchSoloWhy } from './protocol.js';
16
+ /** 排队对象要的绑定:房间 ROOM(开桌),平台 ARCADE(可选,屏蔽名单;单独部署没有) */
17
+ export interface MatchEnv {
18
+ ROOM: DurableObjectNamespace;
19
+ ARCADE?: Fetcher;
20
+ }
21
+ /**
22
+ * 凑桌时找平台、找房间最多等多久(毫秒,安全审阅 0.20.0):凑桌持着"正在凑"的锁,平台或房间卡住时整个档位都会一直"等待中"。
23
+ * 超时的屏蔽名单按空的算,建房按 unavailable(这一桌的人转单机)
24
+ */
25
+ export declare const MATCH_CALL_MS = 3000;
26
+ export declare abstract class MatchQueue<Env extends MatchEnv = MatchEnv> extends DurableObject<Env> {
27
+ /** 一桌最多几个真人(凑满就开)。按档位不同的游戏覆盖 tableSize */
28
+ protected abstract readonly seats: number;
29
+ /** 最多等多久(毫秒):到点 ≥ 2 人就开,只剩自己就转单机 */
30
+ protected readonly waitMs: number;
31
+ /** 一个档位最多排几个人,满了 1013(挡刷连接) */
32
+ protected readonly maxQueue: number;
33
+ /** 每人每小时最多排几次,超了 4029(内存里记,被驱逐就清零,接受) */
34
+ protected readonly perHour: number;
35
+ /** 凑桌时找平台、找房间最多等多久(毫秒,见 MATCH_CALL_MS) */
36
+ protected readonly callMs: number;
37
+ /** 这个档位一桌最多几个真人;默认 seats */
38
+ protected tableSize(_tier: string): number;
39
+ /** 这个档位开桌带的开局选项(交给房间的 RoomGame.options 校验);默认不带 */
40
+ protected roomOptions(_tier: string): unknown;
41
+ /**
42
+ * 这几个人之间谁屏蔽了谁(平台 0.25.0 的 ARCADE.blockedAmong,最多 9 人,只读)。没有平台(单独部署)、出错都当没有,回 []。
43
+ * 测试覆盖它换成假名单
44
+ */
45
+ protected blockedAmong(userIds: string[]): Promise<[string, string][]>;
46
+ /** 开一张匹配桌(房间的 kitCreateMatch)。游戏不用覆盖;kit 的测试用它模拟房间卡住 */
47
+ protected createMatchRoom(code: string, players: Identity[], opts: unknown): Promise<MatchOutcome>;
48
+ /** 现在设着的闹钟;undefined 是还不知道,用前 getAlarm() 读 */
49
+ private alarmAt;
50
+ /** 正在凑桌(中间 await 了平台和房间):这时进来的人、到点的闹钟只记一笔,凑完再来一轮 */
51
+ private forming;
52
+ private again;
53
+ /** 凑桌途中已经选中的人:别的一轮不再选他们 */
54
+ private readonly taken;
55
+ /** 每人这一小时排了几次 */
56
+ private readonly hourly;
57
+ constructor(ctx: DurableObjectState, env: Env);
58
+ /** 入队:只认 kit 自己拼的内部地址(worker.ts 的 acceptMatch),身份在 x-kit-user 头里。 */
59
+ fetch(request: Request): Promise<Response>;
60
+ /** 排队连接只收不发:发什么都断开(不让它变成能刷的入口) */
61
+ webSocketMessage(ws: WebSocket): Promise<void>;
62
+ webSocketClose(ws: WebSocket, code: number): Promise<void>;
63
+ webSocketError(ws: WebSocket): Promise<void>;
64
+ alarm(): Promise<void>;
65
+ /**
66
+ * 凑一轮:凑满一桌立刻开;最早的人等够了:≥ 2 人就开,只剩自己转单机。凑完还有人就把闹钟对到下一个人。
67
+ * 凑桌中间要 await(平台、房间),这时别的入口进来只记 again,凑完再来一轮
68
+ */
69
+ private form;
70
+ /** 凑一桌;凑出了(或者有人被请出去了)回 true,接着凑下一桌 */
71
+ private formOnce;
72
+ /** 只往早了调闹钟:最早那个人等够的时刻 */
73
+ private planAlarm;
74
+ private sockets;
75
+ private waiting;
76
+ /** 排着的人,按开始排的先后;同一个人只算最新的那条 */
77
+ private queue;
78
+ /** 人数变了就推一次(不每秒推,页面自己倒计时) */
79
+ private pushWaiting;
80
+ private solo;
81
+ /** 发最后一条,出队、关掉 */
82
+ private finish;
83
+ private drop;
84
+ }
85
+ //# sourceMappingURL=match.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"match.d.ts","sourceRoot":"","sources":["../src/match.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,KAAK,QAAQ,EAAkD,MAAM,eAAe,CAAC;AAE9F,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAE9C,YAAY,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAEhE,qDAAqD;AACrD,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,sBAAsB,CAAC;IAC7B,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAiBD;;;GAGG;AACH,eAAO,MAAM,aAAa,OAAQ,CAAC;AAEnC,8BAAsB,UAAU,CAAC,GAAG,SAAS,QAAQ,GAAG,QAAQ,CAAE,SAAQ,aAAa,CAAC,GAAG,CAAC;IAC1F,0CAA0C;IAC1C,SAAS,CAAC,QAAQ,CAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IAC1C,oCAAoC;IACpC,SAAS,CAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAU;IAC3C,+BAA+B;IAC/B,SAAS,CAAC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAO;IAC1C,yCAAyC;IACzC,SAAS,CAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAM;IACxC,0CAA0C;IAC1C,SAAS,CAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAiB;IAElD,4BAA4B;IAC5B,SAAS,CAAC,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEzC;IAED,mDAAmD;IACnD,SAAS,CAAC,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAE5C;IAED;;;OAGG;IACH,UAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC,CAU3E;IAED,wDAAwD;IACxD,SAAS,CAAC,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,EAAE,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC,YAAY,CAAC,CAGjG;IAED,8CAA8C;IAC9C,OAAO,CAAC,OAAO,CAA4B;IAC3C,oDAAoD;IACpD,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,KAAK,CAAS;IACtB,2BAA2B;IAC3B,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAqB;IAC3C,iBAAiB;IACjB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA+B;IAEtD,YAAY,GAAG,EAAE,kBAAkB,EAAE,GAAG,EAAE,GAAG,EAG5C;IAED,qEAAqE;IACtD,KAAK,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,QAAQ,CAAC,CAoCxD;IAED,kCAAkC;IACnB,gBAAgB,CAAC,EAAE,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CAG5D;IAEc,cAAc,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAQxE;IAEc,cAAc,CAAC,EAAE,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CAG1D;IAEc,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAQpC;IAID;;;OAGG;YACW,IAAI;IAoBlB,sCAAsC;YACxB,QAAQ;IA8EtB,yBAAyB;YACX,SAAS;IAiBvB,OAAO,CAAC,OAAO;IAIf,OAAO,CAAC,OAAO;IAIf,+BAA+B;IAC/B,OAAO,CAAC,KAAK;IAUb,6BAA6B;IAC7B,OAAO,CAAC,WAAW;IASnB,OAAO,CAAC,IAAI;IAIZ,kBAAkB;IAClB,OAAO,CAAC,MAAM;IAKd,OAAO,CAAC,IAAI;CAQb"}
package/dist/match.js ADDED
@@ -0,0 +1,361 @@
1
+ /**
2
+ * 快速匹配的排队(0.20.0,设计 docs/match.md):游戏 Worker 里的 Durable Object 继承它,填上一桌几个真人,就能按档位排队凑桌。
3
+ * 每个档位一个实例(matchStub 按档位取),浏览器经 worker.ts 的 acceptMatch 连进来,连接本身就是"排着"。
4
+ *
5
+ * 守的规矩(和房间同一套,docs/platform-backend.md 第 4 节):
6
+ * - 0 行存储:排着的人就是 ctx.getWebSockets(),附件里只放 userId、昵称、开始排的时间;被驱逐后名单还在;
7
+ * - 只用一个闹钟:最早那个人等满 waitMs 的时刻,只往早了调(setAlarm 也算一行写入);
8
+ * - 只用 ctx.acceptWebSocket,不用 setTimeout / setInterval;排队连接只收不发,浏览器发什么都 1008 断开;
9
+ * - 不碰牌局:不 import 规则、不读房间状态。电脑补位、公平底线全在房间里,和好友房一样;
10
+ * - 名额由房间开桌时向计量一次占齐(kitCreateMatch),排队本身不占。
11
+ */
12
+ import { DurableObject } from 'cloudflare:workers';
13
+ import { KIT_HOST, newRoomCode, parseIdentity, roomStub } from './internal.js';
14
+ import { CLOSE } from './protocol.js';
15
+ /** 开桌时房间码撞了最多再换几次 */
16
+ const CODE_TRIES = 5;
17
+ /** 一次凑桌最多重来几轮(有人被计量挡掉、请出去以后接着凑) */
18
+ const FORM_ROUNDS = 8;
19
+ /** 平台屏蔽名单一次最多问几个人(平台 blockedAmong 的上限,德州 9 人桌) */
20
+ const BLOCK_MAX = 9;
21
+ /**
22
+ * 凑桌时找平台、找房间最多等多久(毫秒,安全审阅 0.20.0):凑桌持着"正在凑"的锁,平台或房间卡住时整个档位都会一直"等待中"。
23
+ * 超时的屏蔽名单按空的算,建房按 unavailable(这一桌的人转单机)
24
+ */
25
+ export const MATCH_CALL_MS = 3_000;
26
+ export class MatchQueue extends DurableObject {
27
+ /** 最多等多久(毫秒):到点 ≥ 2 人就开,只剩自己就转单机 */
28
+ waitMs = 15_000;
29
+ /** 一个档位最多排几个人,满了 1013(挡刷连接) */
30
+ maxQueue = 200;
31
+ /** 每人每小时最多排几次,超了 4029(内存里记,被驱逐就清零,接受) */
32
+ perHour = 30;
33
+ /** 凑桌时找平台、找房间最多等多久(毫秒,见 MATCH_CALL_MS) */
34
+ callMs = MATCH_CALL_MS;
35
+ /** 这个档位一桌最多几个真人;默认 seats */
36
+ tableSize(_tier) {
37
+ return this.seats;
38
+ }
39
+ /** 这个档位开桌带的开局选项(交给房间的 RoomGame.options 校验);默认不带 */
40
+ roomOptions(_tier) {
41
+ return undefined;
42
+ }
43
+ /**
44
+ * 这几个人之间谁屏蔽了谁(平台 0.25.0 的 ARCADE.blockedAmong,最多 9 人,只读)。没有平台(单独部署)、出错都当没有,回 []。
45
+ * 测试覆盖它换成假名单
46
+ */
47
+ async blockedAmong(userIds) {
48
+ const arcade = this.env.ARCADE;
49
+ if (!arcade || userIds.length < 2)
50
+ return [];
51
+ try {
52
+ const out = await arcade.blockedAmong(userIds.slice(0, BLOCK_MAX));
53
+ return Array.isArray(out) ? out.filter((p) => Array.isArray(p) && typeof p[0] === 'string' && typeof p[1] === 'string') : [];
54
+ }
55
+ catch (e) {
56
+ console.error('blockedAmong failed, matching without it', e instanceof Error ? e.message : e);
57
+ return [];
58
+ }
59
+ }
60
+ /** 开一张匹配桌(房间的 kitCreateMatch)。游戏不用覆盖;kit 的测试用它模拟房间卡住 */
61
+ createMatchRoom(code, players, opts) {
62
+ const stub = roomStub(this.env.ROOM, code);
63
+ return stub.kitCreateMatch(code, players, opts);
64
+ }
65
+ /** 现在设着的闹钟;undefined 是还不知道,用前 getAlarm() 读 */
66
+ alarmAt;
67
+ /** 正在凑桌(中间 await 了平台和房间):这时进来的人、到点的闹钟只记一笔,凑完再来一轮 */
68
+ forming = false;
69
+ again = false;
70
+ /** 凑桌途中已经选中的人:别的一轮不再选他们 */
71
+ taken = new Set();
72
+ /** 每人这一小时排了几次 */
73
+ hourly = new Map();
74
+ constructor(ctx, env) {
75
+ super(ctx, env);
76
+ ctx.setWebSocketAutoResponse(new WebSocketRequestResponsePair('ping', 'pong'));
77
+ }
78
+ /** 入队:只认 kit 自己拼的内部地址(worker.ts 的 acceptMatch),身份在 x-kit-user 头里。 */
79
+ async fetch(request) {
80
+ const url = new URL(request.url);
81
+ if (url.hostname !== KIT_HOST || url.pathname !== '/match' || request.headers.get('upgrade')?.toLowerCase() !== 'websocket') {
82
+ return new Response('not a kit request', { status: 400 });
83
+ }
84
+ const me = parseIdentity(request.headers.get('x-kit-user'));
85
+ const tier = url.searchParams.get('tier');
86
+ if (!me || !tier)
87
+ return new Response('no identity', { status: 401 });
88
+ const pair = new WebSocketPair();
89
+ const [client, server] = [pair[0], pair[1]];
90
+ this.ctx.acceptWebSocket(server);
91
+ const done = new Response(null, { status: 101, webSocket: client });
92
+ const now = Date.now();
93
+ // 只数还排着的(附件还在):已经出队、正在关的连接不占队长
94
+ const others = this.waiting().filter((o) => o !== server);
95
+ const mine = others.filter((o) => waiterOf(o)?.userId === me.userId);
96
+ if (others.length - mine.length >= this.maxQueue) {
97
+ server.close(CLOSE.tryLater, 'queue full');
98
+ return done;
99
+ }
100
+ // 一小时前的旧条目顺手清掉(排过一次就走的人不能让这张表一直涨)
101
+ for (const [u, ts] of this.hourly)
102
+ if (now - ts[ts.length - 1] >= 3_600_000)
103
+ this.hourly.delete(u);
104
+ const times = (this.hourly.get(me.userId) ?? []).filter((t) => now - t < 3_600_000);
105
+ if (times.length >= this.perHour) {
106
+ this.hourly.set(me.userId, times);
107
+ server.close(CLOSE.tooManyJoins, 'too often');
108
+ return done;
109
+ }
110
+ times.push(now);
111
+ this.hourly.set(me.userId, times);
112
+ // 同一个人只排一次:旧的那条让位
113
+ for (const o of mine)
114
+ this.drop(o, CLOSE.replaced, 'replaced');
115
+ server.serializeAttachment({ userId: me.userId, name: me.name, since: now, tier });
116
+ // 先回 101 再凑桌:凑桌要找平台、房间,不能让新来的人连连接都拿不到
117
+ this.ctx.waitUntil(this.form());
118
+ return done;
119
+ }
120
+ /** 排队连接只收不发:发什么都断开(不让它变成能刷的入口) */
121
+ async webSocketMessage(ws) {
122
+ this.drop(ws, CLOSE.policy, 'queue is receive-only');
123
+ this.pushWaiting();
124
+ }
125
+ async webSocketClose(ws, code) {
126
+ try {
127
+ ws.close(code === 1005 || code === 1006 ? 1000 : code, 'bye');
128
+ }
129
+ catch {
130
+ // 已经关了
131
+ }
132
+ ws.serializeAttachment(null);
133
+ this.pushWaiting();
134
+ }
135
+ async webSocketError(ws) {
136
+ ws.serializeAttachment(null);
137
+ this.pushWaiting();
138
+ }
139
+ async alarm() {
140
+ this.alarmAt = null;
141
+ try {
142
+ await this.form();
143
+ }
144
+ catch (e) {
145
+ // 闹钟里不往外抛(会自动重试、每次计费)
146
+ console.error('match alarm failed', e instanceof Error ? e.message : e);
147
+ }
148
+ }
149
+ // ---------- 凑桌 ----------
150
+ /**
151
+ * 凑一轮:凑满一桌立刻开;最早的人等够了:≥ 2 人就开,只剩自己转单机。凑完还有人就把闹钟对到下一个人。
152
+ * 凑桌中间要 await(平台、房间),这时别的入口进来只记 again,凑完再来一轮
153
+ */
154
+ async form() {
155
+ if (this.forming) {
156
+ this.again = true;
157
+ return;
158
+ }
159
+ this.forming = true;
160
+ try {
161
+ let rounds = 0;
162
+ do {
163
+ this.again = false;
164
+ while (rounds++ < FORM_ROUNDS && (await this.formOnce()))
165
+ ;
166
+ } while (this.again && rounds < FORM_ROUNDS);
167
+ }
168
+ finally {
169
+ this.forming = false;
170
+ this.taken.clear();
171
+ }
172
+ this.pushWaiting();
173
+ await this.planAlarm();
174
+ }
175
+ /** 凑一桌;凑出了(或者有人被请出去了)回 true,接着凑下一桌 */
176
+ async formOnce() {
177
+ const list = this.queue().filter((w) => !this.taken.has(w.me.userId));
178
+ if (!list.length)
179
+ return false;
180
+ const tier = list[0].me.tier;
181
+ const size = Math.max(1, Math.min(this.tableSize(tier), BLOCK_MAX));
182
+ const due = Date.now() >= list[0].me.since + this.waitMs;
183
+ if (list.length < size && !due)
184
+ return false;
185
+ const blocks = await withTimeout(this.blockedAmong(list.slice(0, BLOCK_MAX).map((w) => w.me.userId)), this.callMs).catch((e) => {
186
+ console.error('blockedAmong timed out, matching without it', e instanceof Error ? e.message : e);
187
+ return [];
188
+ });
189
+ const chosen = [];
190
+ for (const w of list.slice(0, BLOCK_MAX)) {
191
+ if (chosen.length >= size)
192
+ break;
193
+ if (chosen.some((c) => blocks.some(([a, b]) => (a === c.me.userId && b === w.me.userId) || (a === w.me.userId && b === c.me.userId))))
194
+ continue;
195
+ chosen.push(w);
196
+ }
197
+ if (chosen.length < size && !due)
198
+ return false;
199
+ if (chosen.length < 2) {
200
+ // 等够了却只有自己(或者在的人都和他互相屏蔽):转单机
201
+ this.solo(chosen[0].ws, 'alone');
202
+ return true;
203
+ }
204
+ for (const c of chosen)
205
+ this.taken.add(c.me.userId);
206
+ const players = chosen.map((c) => ({ userId: c.me.userId, name: c.me.name }));
207
+ let out = { r: 'unavailable' };
208
+ let code = '';
209
+ for (let i = 0; i < CODE_TRIES; i++) {
210
+ code = newRoomCode();
211
+ try {
212
+ out = await withTimeout(this.createMatchRoom(code, players, this.roomOptions(tier)), this.callMs);
213
+ }
214
+ catch (e) {
215
+ console.error('kitCreateMatch failed', e instanceof Error ? e.message : e);
216
+ out = { r: 'unavailable' };
217
+ }
218
+ if (out.r !== 'exists')
219
+ break;
220
+ }
221
+ for (const c of chosen)
222
+ this.taken.delete(c.me.userId);
223
+ // 等的这一会儿可能有人走了、换了页面:按 userId 找他现在的连接
224
+ const sockOf = (userId) => this.waiting().find((ws) => waiterOf(ws)?.userId === userId);
225
+ if (out.r === 'created') {
226
+ for (const c of chosen) {
227
+ const ws = sockOf(c.me.userId);
228
+ if (ws)
229
+ this.finish(ws, { t: 'matched', code });
230
+ }
231
+ return true;
232
+ }
233
+ if (out.r === 'refused') {
234
+ if (out.userId === null) {
235
+ // 全站忙:这一轮的人都转单机,其他人留着(到点还会被同样挡掉)
236
+ for (const c of chosen) {
237
+ const ws = sockOf(c.me.userId);
238
+ if (ws)
239
+ this.solo(ws, 'busy');
240
+ }
241
+ return true;
242
+ }
243
+ const ws = sockOf(out.userId);
244
+ if (ws) {
245
+ if (out.why === 'has_room')
246
+ this.finish(ws, { t: 'has_room', code: out.code });
247
+ else
248
+ this.solo(ws, 'daily_limit');
249
+ return true;
250
+ }
251
+ return true;
252
+ }
253
+ // 房间那边出错、超时、选项不对:这一轮的人转单机,不让他们一直等。
254
+ // bad / bad_options 是游戏配错了(tableSize 比这一局的座位多、roomOptions 过不了 RoomGame.options),每桌都会这样:
255
+ // 大声记日志;游戏在自己的测试里用 game.ts 的 matchConfigErrors 先查
256
+ if (out.r === 'bad' || out.r === 'bad_options')
257
+ console.error(`MatchQueue misconfigured for tier ${tier}: room said ${out.r} (check tableSize / roomOptions with matchConfigErrors)`);
258
+ else
259
+ console.error('match room not created', out.r);
260
+ for (const c of chosen) {
261
+ const ws = sockOf(c.me.userId);
262
+ if (ws)
263
+ this.solo(ws, 'unavailable');
264
+ }
265
+ // 房间那边不好(超时、出错):这一次不接着凑,剩下的人等下一次闹钟,不让锁一直被连着的超时占着
266
+ this.again = false;
267
+ return false;
268
+ }
269
+ /** 只往早了调闹钟:最早那个人等够的时刻 */
270
+ async planAlarm() {
271
+ const list = this.queue();
272
+ if (!list.length)
273
+ return;
274
+ const next = list[0].me.since + this.waitMs;
275
+ if (this.alarmAt === undefined)
276
+ this.alarmAt = await this.ctx.storage.getAlarm();
277
+ if (this.alarmAt !== null && this.alarmAt <= next && this.alarmAt > Date.now() - 1_000)
278
+ return;
279
+ this.alarmAt = next;
280
+ try {
281
+ await this.ctx.storage.setAlarm(next);
282
+ }
283
+ catch (e) {
284
+ console.error('match setAlarm failed', e instanceof Error ? e.message : e);
285
+ this.alarmAt = undefined;
286
+ }
287
+ }
288
+ // ---------- 连接 ----------
289
+ sockets() {
290
+ return this.ctx.getWebSockets();
291
+ }
292
+ waiting() {
293
+ return this.sockets().filter((ws) => waiterOf(ws) !== null);
294
+ }
295
+ /** 排着的人,按开始排的先后;同一个人只算最新的那条 */
296
+ queue() {
297
+ const by = new Map();
298
+ for (const ws of this.waiting()) {
299
+ const me = waiterOf(ws);
300
+ const had = by.get(me.userId);
301
+ if (!had || had.me.since <= me.since)
302
+ by.set(me.userId, { ws, me });
303
+ }
304
+ return [...by.values()].sort((a, b) => a.me.since - b.me.since);
305
+ }
306
+ /** 人数变了就推一次(不每秒推,页面自己倒计时) */
307
+ pushWaiting() {
308
+ const list = this.queue();
309
+ if (!list.length)
310
+ return;
311
+ // 倒计时按最早的那个人算:他到点时大家一起凑,后来的人等不满 waitMs
312
+ const left = Math.max(0, list[0].me.since + this.waitMs - Date.now());
313
+ const msg = { t: 'waiting', n: list.length, seats: this.tableSize(list[0].me.tier), left };
314
+ for (const { ws } of list)
315
+ send(ws, msg);
316
+ }
317
+ solo(ws, why) {
318
+ this.finish(ws, { t: 'solo', why });
319
+ }
320
+ /** 发最后一条,出队、关掉 */
321
+ finish(ws, msg) {
322
+ send(ws, msg);
323
+ this.drop(ws, 1000, msg.t);
324
+ }
325
+ drop(ws, code, reason) {
326
+ ws.serializeAttachment(null);
327
+ try {
328
+ ws.close(code, reason);
329
+ }
330
+ catch {
331
+ // 已经关了
332
+ }
333
+ }
334
+ }
335
+ function waiterOf(ws) {
336
+ const a = ws.deserializeAttachment();
337
+ return a && typeof a.userId === 'string' ? a : null;
338
+ }
339
+ function send(ws, msg) {
340
+ try {
341
+ ws.send(JSON.stringify(msg));
342
+ }
343
+ catch {
344
+ // 连接正在关
345
+ }
346
+ }
347
+ /**
348
+ * 等一个外部调用最多 ms 毫秒,超时抛错(调用方按失败处理)。只在凑桌这一次请求里等,不是房间的状态计时,
349
+ * 所以用运行时的 scheduler.wait(不是 setTimeout、也不占那一个闹钟)
350
+ */
351
+ async function withTimeout(p, ms) {
352
+ // 超时以后原来的调用照样可能失败:先接住它的错,免得变成没人处理的 rejection
353
+ const settled = p.then((v) => ({ ok: true, v }), (e) => ({ ok: false, e }));
354
+ const out = await Promise.race([settled, scheduler.wait(ms).then(() => null)]);
355
+ if (out === null)
356
+ throw new Error(`timed out after ${ms} ms`);
357
+ if (!out.ok)
358
+ throw out.e;
359
+ return out.v;
360
+ }
361
+ //# sourceMappingURL=match.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"match.js","sourceRoot":"","sources":["../src/match.ts"],"names":[],"mappings":"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"}