62 lines
1.7 KiB
TypeScript
62 lines
1.7 KiB
TypeScript
import type { SessionState } from "../types";
|
|
|
|
/** 合法状态迁移表 */
|
|
const TRANSITIONS: Record<SessionState, SessionState[]> = {
|
|
idle: ["connecting", "disconnected"],
|
|
connecting: ["auth_pending", "error", "disconnected"],
|
|
auth_pending: ["connected", "error", "disconnected"],
|
|
connected: ["reconnecting", "disconnected", "error"],
|
|
reconnecting: ["connected", "error", "disconnected"],
|
|
disconnected: ["connecting", "idle"],
|
|
error: ["connecting", "disconnected"],
|
|
};
|
|
|
|
export function canTransition(from: SessionState, to: SessionState): boolean {
|
|
return (TRANSITIONS[from] ?? []).includes(to);
|
|
}
|
|
|
|
export function assertTransition(from: SessionState, to: SessionState): void {
|
|
if (!canTransition(from, to)) {
|
|
throw new Error(`非法状态跳转: ${from} → ${to}`);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* SessionMachine — 会话生命周期状态机。
|
|
* 纯状态逻辑,无任何副作用,零 DOM 依赖。
|
|
*/
|
|
export class SessionMachine {
|
|
private _state: SessionState = "idle";
|
|
private listeners = new Set<(state: SessionState) => void>();
|
|
|
|
get state(): SessionState {
|
|
return this._state;
|
|
}
|
|
|
|
transition(to: SessionState): void {
|
|
assertTransition(this._state, to);
|
|
this._state = to;
|
|
for (const fn of this.listeners) {
|
|
fn(this._state);
|
|
}
|
|
}
|
|
|
|
tryTransition(to: SessionState): boolean {
|
|
if (!canTransition(this._state, to)) return false;
|
|
this.transition(to);
|
|
return true;
|
|
}
|
|
|
|
onChange(fn: (state: SessionState) => void): () => void {
|
|
this.listeners.add(fn);
|
|
return () => this.listeners.delete(fn);
|
|
}
|
|
|
|
reset(): void {
|
|
this._state = "idle";
|
|
for (const fn of this.listeners) {
|
|
fn(this._state);
|
|
}
|
|
}
|
|
}
|