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'); +});