diff --git a/cocoscreator_projects/YouleNexus/assets/framework/net/net-client.ts b/cocoscreator_projects/YouleNexus/assets/framework/net/net-client.ts index 8187073..cb70cbb 100644 --- a/cocoscreator_projects/YouleNexus/assets/framework/net/net-client.ts +++ b/cocoscreator_projects/YouleNexus/assets/framework/net/net-client.ts @@ -23,6 +23,8 @@ export interface NetClientOptions { transportFactory: () => Transport; clock?: Clock; bus?: EventBus; + 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(); @@ -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 diff --git a/cocoscreator_projects/framework-tests/net/net-client.test.ts b/cocoscreator_projects/framework-tests/net/net-client.test.ts index ef68e0b..d7bdd87 100644 --- a/cocoscreator_projects/framework-tests/net/net-client.test.ts +++ b/cocoscreator_projects/framework-tests/net/net-client.test.ts @@ -123,3 +123,41 @@ test('TcpID 去重:旧连接的残留包被丢弃', async () => { await t1.flush(); assert.equal(messages.length, 0); }); + +test('debug=true 记录 send 与 recv(注入 logger)', async () => { + const t = new FakeTransport(); + const { clock } = fakeClock(); + const logs: unknown[][] = []; + const client = new NetClient({ + servers: 'ws://a', + transportFactory: () => t, + clock, + debug: true, + logger: (...a: unknown[]) => logs.push(a), + }); + client.setIdentity(IDENTITY); + client.start(); + await t.flush(); + assert.ok(logs.some((l) => l[0] === '[net] →')); // 发出 player_login 被记录 + t.serverPush(JSON.stringify({ data: JSON.stringify({ route: 'agent', rpc: 'player_login', data: { state: 0, playerid: 9 } }) })); + await t.flush(); + assert.ok(logs.some((l) => l[0] === '[net] ←')); // 收包被记录 +}); + +test('debug 默认关闭:logger 不被调用', async () => { + const t = new FakeTransport(); + const { clock } = fakeClock(); + const logs: unknown[][] = []; + const client = new NetClient({ + servers: 'ws://a', + transportFactory: () => t, + clock, + logger: (...a: unknown[]) => logs.push(a), + }); + client.setIdentity(IDENTITY); + client.start(); + await t.flush(); + t.serverPush(JSON.stringify({ data: JSON.stringify({ route: 'agent', rpc: 'player_login', data: { state: 0, playerid: 9 } }) })); + await t.flush(); + assert.equal(logs.length, 0); +});