feat(framework): net NetClient 可选 debug 收发包日志

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-28 18:16:36 +08:00
co-authored by Claude Opus 4.8
parent 2c2e487d8f
commit 5ab4a0a4b6
2 changed files with 53 additions and 2 deletions
@@ -23,6 +23,8 @@ export interface NetClientOptions {
transportFactory: () => Transport;
clock?: Clock;
bus?: EventBus<NetClientEvents>;
debug?: boolean; // 为真时打印每帧 send/recv
logger?: (...args: unknown[]) => void; // 日志函数,默认 console.log(便于测试注入)
}
/** 网络客户端:编排 transport/codec/heartbeat/reconnect,事件驱动,忠实 docs/protocol/01。 */
@@ -41,6 +43,8 @@ export class NetClient {
private loginGuard: unknown = null;
private reconnectTimer: unknown = null;
private stopped = false;
private debug: boolean;
private logger: (...args: unknown[]) => void;
constructor(opts: NetClientOptions) {
this.bus = opts.bus ?? new EventBus<NetClientEvents>();
@@ -48,6 +52,8 @@ export class NetClient {
this.clock = opts.clock ?? realClock;
this.policy = new ReconnectPolicy(opts.servers, SERVER_ROTATE_EVERY);
this.watchdog = new HeartbeatWatchdog(RECV_TIMEOUT_MS, () => this.onRecvTimeout(), this.clock);
this.debug = opts.debug ?? false;
this.logger = opts.logger ?? console.log;
}
setIdentity(identity: LoginRequestData): void { this.identity = identity; }
@@ -66,7 +72,13 @@ export class NetClient {
/** 发业务包(单层信封)。 */
send(route: string, rpc: string, data: unknown): void {
this.transport?.send(encodeOutbound(route, rpc, data));
this.sendFrame(encodeOutbound(route, rpc, data));
}
/** 统一发送切面:debug 时打印出站帧。 */
private sendFrame(frame: string): void {
if (this.debug) this.logger('[net] →', frame);
this.transport?.send(frame);
}
private connect(url: string): void {
@@ -87,12 +99,13 @@ export class NetClient {
private sendLogin(): void {
if (!this.identity) return; // 无身份不发(docs §6.1:首登需身份)
this.isSendLoginState = true;
this.transport?.send(encodeOutbound(Route.agent, 'player_login', this.identity));
this.sendFrame(encodeOutbound(Route.agent, 'player_login', this.identity));
if (this.loginGuard != null) this.clock.clearTimeout(this.loginGuard);
this.loginGuard = this.clock.setTimeout(() => { this.loginGuard = null; this.onLoginGuardTimeout(); }, LOGIN_GUARD_MS); // docs §6.2
}
private onMessage(frame: string): void {
if (this.debug) this.logger('[net] ←', frame);
const r = decodeFrame(frame);
if (r.kind === 'ignore') return;
this.watchdog.feed(); // 收任意有效帧重置看门狗 docs §4.1