/// import { CamelCasedPropertiesDeep } from 'type-fest'; import { UnionOf } from 'unionize'; export interface KaiheilaEncryptPacket { encrypt: string; } export declare type KaiheilaWebhookRequest = KaiheilaEncryptPacket | KPacket; export declare enum KOpcode { EVENT = 0, HELLO = 1, PING = 2, PONG = 3, RECONNECT = 5, RESUME_ACK = 6 } export interface KPacket { s: KOpcode; d: any; sn?: number; } export interface KMessageEventRaw { channel_type: 'GROUP' | 'PERSON' | 'BROADCAST'; type: number; target_id: string; author_id: string; content: string; msg_id: string; msg_timestamp: number; nonce: string; verify_token?: string; extra: T; [key: string]: any; } export declare type KMessageEvent = CamelCasedPropertiesDeep>; /** * 信令[1] HELLO * * **方向:** server->client * * **说明:** 当我们成功连接websocket后,客户端应该在6s内收到该包,否则认为连接超时。 * * | 状态码 | 含义 | 备注 | * | - | - | - | * | 0 | 成功 | * | 40100 | 缺少参数 | | * | 40101 | 无效的token | | * | 40102 | token验证失败 | | * | 40103 | token过期 | 需要重新连接 | */ export interface KHelloPacket { s: KOpcode; d: { code: 0 | 40100 | 40101 | 40102 | 40103; session_id?: string; }; } /** * 信令[0] EVENT * * **方向:** server->client * * **说明:** 在正常连接状态下,收到的消息事件等。 * * **参数列表:** * * 具体参见[Event](https://developer.kaiheila.cn/doc/event) * * **注意:** 该消息会有 `sn`, 代表消息序号, 针对当前 `session` 的消息的序号, 客户端需记录该数字,并按顺序接收消息, **resume** 时需传入该参数才能完成 * * **注意事项:** * * 1. 收到消息时需要按照 `sn` 顺序处理, 服务端会尽可能保证 `sn` 的顺序性 * 2. 假设收到消息的 `sn` 出现乱序, 需要先存入暂存区 (`buffer`) 等待正确的 `sn` 消息处理后再从暂存区顺序处理 * 3. 假设收到了一条已处理过的 `sn` 的消息, 则直接抛弃不处理 * 4. 客户端需要存储当前已处理成功的最大的 `sn`, 待心跳ping时回传服务端, 如果服务端发现当前客户端最新处理成功的消息 `sn` 落后于最新消息 (丢包等异常情况), 服务端将会按照客户端指定的 `sn` 将之后所有最新的消息重传给客户端. * 5. 消息内容与webhook保持一致 */ export interface KEventPacket { s: KOpcode; d: T; sn: number; } /** * 信令[2] PING * * **方向:** client -> server * * **说明:** 每隔30s(随机-5,+5),将当前的最大 `sn` 传给服务端,客户端应该在6s内收到PONG, 否则心跳超时。 * * **参数列表:** * * | 参数 | 描述 | 类型 | 必传 | * | ---- | --------------------------------- | ---- | ---- | * | sn | 客户端目前收到的最新的消息 **sn** | number | Y | */ export interface KPingPacket { s: KOpcode; /** * | 参数 | 描述 | 类型 | 必传 | * | ---- | --------------------------------- | ---- | ---- | * | sn | 客户端目前收到的最新的消息 **sn** | number | Y | */ sn: number; } /** * 信令[3] PONG * * **方向:** server -> client * * **说明:** 回应客户端发出的ping */ export interface KPongPacket { s: KOpcode; } /** * 信令[5] RECONNECT * **方向:** server->client * * **说明:** 服务端通知客户端, 代表该连接已失效, 请重新连接。客户端收到后应该主动断开当前连接。 * * **注意:** 客户端收到该信令代表因为某些原因导致当前连接已失效, 需要进行以下操作以避免消息丢失. * 1. 重新获取 gateway; * 2. 清空本地的 sn 计数; * 3. 清空本地消息队列. * * | 状态码 | 描述 | * | ------------ | --------------------------------------- | * | 40106 | resume 失败, 缺少参数 | * | 40107 | 当前 `session` 已过期 (resume 失败, PING的sn无效) | * | 40108 | 无效的 `sn` , 或 `sn` 已经不存在 (resume 失败, PING的 `sn` 无效) | */ export interface KReconnectPacket { s: KOpcode; d: { /** * | 状态码 | 描述 | * | ------------ | --------------------------------------- | * | 40106 | resume 失败, 缺少参数 | * | 40107 | 当前 `session` 已过期 (resume 失败, PING的sn无效) | * | 40108 | 无效的 `sn` , 或 `sn` 已经不存在 (resume 失败, PING的 `sn` 无效) | */ code: 40106 | 40107 | 40108; }; } declare type WsContext = { compress: boolean; sessionId?: string; retryCount: number; helloTimeoutMillis: number; heartbeatIntervalMillis: number; heartbeatTimeoutMillis: number; }; declare const States: import("unionize").Unionized<{ INITIAL: WsContext; PULLING_GATEWAY: WsContext; CONNECTING: WsContext; OPEN: WsContext; CLOSED: WsContext; RECONNECTING: WsContext; }, import("unionize").MultiValueVariants<{ INITIAL: WsContext; PULLING_GATEWAY: WsContext; CONNECTING: WsContext; OPEN: WsContext; CLOSED: WsContext; RECONNECTING: WsContext; }, "tag">, "tag">; declare type State = UnionOf; declare const Actions: import("unionize").Unionized<{ PULL_GATEWAY: {}; CONNECT_GATEWAY: {}; OPEN: {}; CLOSE: {}; HELLO_TIMEOUT: {}; PING_TIMEOUT: {}; PONG_TIMEOUT: {}; HEARTBEAT: {}; RECONNECT: {}; }, import("unionize").MultiValueVariants<{ PULL_GATEWAY: {}; CONNECT_GATEWAY: {}; OPEN: {}; CLOSE: {}; HELLO_TIMEOUT: {}; PING_TIMEOUT: {}; PONG_TIMEOUT: {}; HEARTBEAT: {}; RECONNECT: {}; }, "tag">, "tag">; declare type Action = UnionOf; declare const TimeoutKeys: readonly ["hello", "gateway", "ping", "pong", "connect"]; declare type TimeoutKey = typeof TimeoutKeys[number]; declare const Effects: import("unionize").Unionized<{ PULL_GATEWAY: { compress: boolean; }; CONNECT_WS: { compress: boolean; onOpen: Action; onClose: Action; onPongMessage: Action; }; SCHEDULE_TIMEOUT: { key: TimeoutKey; timeoutMillis: number; onTimeout: Action; }; SEND_PING: {}; CLEAR_TIMEOUT: { key: TimeoutKey; }; TRIGGER_ACTION: { action: Action; }; }, import("unionize").MultiValueVariants<{ PULL_GATEWAY: { compress: boolean; }; CONNECT_WS: { compress: boolean; onOpen: Action; onClose: Action; onPongMessage: Action; }; SCHEDULE_TIMEOUT: { key: TimeoutKey; timeoutMillis: number; onTimeout: Action; }; SEND_PING: {}; CLEAR_TIMEOUT: { key: TimeoutKey; }; TRIGGER_ACTION: { action: Action; }; }, "tag">, "tag">; declare type Effect = UnionOf; declare type StateTransfer = (state: State) => [State, Effect[]]; declare type TTimeout = ReturnType; export { States, State, Actions, Action, Effects, Effect, StateTransfer, TimeoutKey, TimeoutKeys, TTimeout, };