From 79d0071645c44eff5b957b19183e52ff6907dd67 Mon Sep 17 00:00:00 2001 From: Joywayer Date: Sun, 28 Jun 2026 14:23:41 +0800 Subject: [PATCH] =?UTF-8?q?feat(framework):=20net=20=E5=80=99=E9=80=89?= =?UTF-8?q?=E6=9C=8D=E5=8A=A1=E5=99=A8=E8=BD=AE=E8=AF=A2=E7=AD=96=E7=95=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.8 (1M context) --- .../assets/framework/net/reconnect.ts | 21 ++++++++++++ .../framework-tests/net/reconnect.test.ts | 32 +++++++++++++++++++ 2 files changed, 53 insertions(+) create mode 100644 cocoscreator_projects/YouleNexus/assets/framework/net/reconnect.ts create mode 100644 cocoscreator_projects/framework-tests/net/reconnect.test.ts diff --git a/cocoscreator_projects/YouleNexus/assets/framework/net/reconnect.ts b/cocoscreator_projects/YouleNexus/assets/framework/net/reconnect.ts new file mode 100644 index 0000000..c2c89c6 --- /dev/null +++ b/cocoscreator_projects/YouleNexus/assets/framework/net/reconnect.ts @@ -0,0 +1,21 @@ +/** 候选服务器轮询。docs/protocol/01 §7.3。 */ +export class ReconnectPolicy { + private servers: string[]; + private index = 0; + private failCount = 0; + constructor(servers: string | string[], private rotateEvery: number) { + this.servers = Array.isArray(servers) ? servers.slice() : [servers]; + } + current(): string { return this.servers[this.index]; } + /** 记一次连接失败,按 rotateEvery 轮换候选,返回新的 current。 */ + onFailure(): string { + this.failCount++; + if (this.servers.length > 1 && this.failCount % this.rotateEvery === 0) { + this.index = (this.index + 1) % this.servers.length; + } + return this.current(); + } + reset(): void { this.failCount = 0; } + /** 服务器切换指令:改用指定地址。docs/protocol/01 §7.4。 */ + setCurrent(server: string): void { this.servers = [server]; this.index = 0; this.failCount = 0; } +} diff --git a/cocoscreator_projects/framework-tests/net/reconnect.test.ts b/cocoscreator_projects/framework-tests/net/reconnect.test.ts new file mode 100644 index 0000000..e520c77 --- /dev/null +++ b/cocoscreator_projects/framework-tests/net/reconnect.test.ts @@ -0,0 +1,32 @@ +import { test } from 'node:test'; +import assert from 'node:assert/strict'; +import { ReconnectPolicy } from '../../YouleNexus/assets/framework/net/reconnect.ts'; + +test('单服务器:失败永不轮换', () => { + const p = new ReconnectPolicy('ws://a', 3); + assert.equal(p.current(), 'ws://a'); + for (let i = 0; i < 10; i++) assert.equal(p.onFailure(), 'ws://a'); +}); + +test('多服务器:每 3 次失败轮换下一个', () => { + const p = new ReconnectPolicy(['ws://a', 'ws://b', 'ws://c'], 3); + assert.equal(p.onFailure(), 'ws://a'); // 1 + assert.equal(p.onFailure(), 'ws://a'); // 2 + assert.equal(p.onFailure(), 'ws://b'); // 3 → 轮换 + assert.equal(p.onFailure(), 'ws://b'); // 4 + assert.equal(p.onFailure(), 'ws://b'); // 5 + assert.equal(p.onFailure(), 'ws://c'); // 6 → 轮换 +}); + +test('reset 清零失败计数', () => { + const p = new ReconnectPolicy(['ws://a', 'ws://b'], 3); + p.onFailure(); p.onFailure(); + p.reset(); + assert.equal(p.onFailure(), 'ws://a'); // 计数从 1 起,未到 3,不轮换 +}); + +test('setCurrent 切换到指定服务器(服务器切换指令)', () => { + const p = new ReconnectPolicy(['ws://a', 'ws://b'], 3); + p.setCurrent('ws://room1'); + assert.equal(p.current(), 'ws://room1'); +});