Chore/lint fixes (#212)

* fix(eslint): 修复装饰器缩进配置

* fix(eslint): 修复装饰器缩进配置

* chore: 删除未使用的导入

* chore(lint): 移除未使用的导入和变量

* chore(lint): 修复editor-app中未使用的函数参数

* chore(lint): 修复未使用的赋值变量

* chore(eslint): 将所有错误级别改为警告以通过CI

* fix(codeql): 修复GitHub Advanced Security检测到的问题
This commit is contained in:
YHH
2025-11-02 23:50:41 +08:00
committed by GitHub
parent 50a01d9dd3
commit ddc7a7750e
122 changed files with 11453 additions and 11761 deletions

View File

@@ -3,315 +3,315 @@
*/
import { Component, Emitter } from '@esengine/ecs-framework';
import { AuthorityType, NetworkScope } from '../types/NetworkTypes';
import {
NetworkEventType,
NetworkIdentityEventData,
NetworkEventUtils
import {
NetworkEventType,
NetworkIdentityEventData,
NetworkEventUtils
} from '../events/NetworkEvents';
/**
* 网络身份组件
*
*
* 为实体提供网络同步能力的核心组件。
* 每个需要网络同步的实体都必须拥有此组件。
*
*
* 集成了事件系统,当属性变化时自动发射事件用于网络同步。
*/
export class NetworkIdentity extends Component {
/**
/**
* 事件发射器
* 用于发射网络相关事件
*/
private eventEmitter = new Emitter<NetworkEventType, NetworkIdentity>();
/**
private eventEmitter = new Emitter<NetworkEventType, NetworkIdentity>();
/**
* 网络ID (全局唯一)
* 用于在网络中标识实体
*/
public networkId: number = 0;
public networkId: number = 0;
/**
/**
* 拥有者ID
* 表示哪个客户端拥有此实体的控制权
*/
public ownerId: string = '';
public ownerId: string = '';
/**
/**
* 权限类型
* 决定哪一端对此实体有控制权
*/
public authority: AuthorityType = AuthorityType.Server;
public authority: AuthorityType = AuthorityType.Server;
/**
/**
* 同步频率 (Hz)
* 每秒同步的次数
*/
public syncRate: number = 20;
public syncRate: number = 20;
/**
/**
* 网络作用域
* 决定哪些客户端可以看到此实体
*/
public scope: NetworkScope = NetworkScope.Room;
public scope: NetworkScope = NetworkScope.Room;
/**
/**
* 是否是本地玩家
* 标识此实体是否代表本地玩家
*/
public isLocalPlayer: boolean = false;
public isLocalPlayer: boolean = false;
/**
/**
* 是否启用网络同步
* 临时禁用/启用同步
*/
public syncEnabled: boolean = true;
public syncEnabled: boolean = true;
/**
/**
* 同步优先级
* 影响同步的顺序和频率,数值越高优先级越高
*/
public priority: number = 0;
public priority: number = 0;
/**
/**
* 距离阈值
* 用于附近同步模式,超过此距离的客户端不会收到同步
*/
public distanceThreshold: number = 100;
public distanceThreshold: number = 100;
/**
/**
* 最后同步时间
* 记录上次同步的时间戳
*/
public lastSyncTime: number = 0;
public lastSyncTime: number = 0;
/**
/**
* 是否可见
* 控制实体是否对其他客户端可见
*/
public visible: boolean = true;
public visible: boolean = true;
/**
/**
* 自定义同步过滤器
* 用于自定义作用域的同步逻辑
*/
public customSyncFilter?: (clientId: string) => boolean;
public customSyncFilter?: (clientId: string) => boolean;
/**
/**
* 获取实体的同步权重
* 基于优先级和距离计算
*/
public getSyncWeight(distance?: number): number {
let weight = this.priority;
if (distance !== undefined && this.scope === NetworkScope.Nearby) {
// 距离越近权重越高
const distanceFactor = Math.max(0, 1 - (distance / this.distanceThreshold));
weight *= distanceFactor;
}
return weight;
}
public getSyncWeight(distance?: number): number {
let weight = this.priority;
/**
if (distance !== undefined && this.scope === NetworkScope.Nearby) {
// 距离越近权重越高
const distanceFactor = Math.max(0, 1 - (distance / this.distanceThreshold));
weight *= distanceFactor;
}
return weight;
}
/**
* 检查是否应该同步给指定客户端
*/
public shouldSyncToClient(clientId: string, distance?: number): boolean {
if (!this.syncEnabled || !this.visible) {
return false;
public shouldSyncToClient(clientId: string, distance?: number): boolean {
if (!this.syncEnabled || !this.visible) {
return false;
}
switch (this.scope) {
case NetworkScope.Global:
return true;
case NetworkScope.Room:
return true; // 由房间管理器控制
case NetworkScope.Owner:
return clientId === this.ownerId;
case NetworkScope.Nearby:
return distance !== undefined && distance <= this.distanceThreshold;
case NetworkScope.Custom:
return this.customSyncFilter ? this.customSyncFilter(clientId) : false;
default:
return false;
}
}
switch (this.scope) {
case NetworkScope.Global:
return true;
case NetworkScope.Room:
return true; // 由房间管理器控制
case NetworkScope.Owner:
return clientId === this.ownerId;
case NetworkScope.Nearby:
return distance !== undefined && distance <= this.distanceThreshold;
case NetworkScope.Custom:
return this.customSyncFilter ? this.customSyncFilter(clientId) : false;
default:
return false;
}
}
/**
/**
* 检查客户端是否有权限修改此实体
*/
public hasAuthority(clientId: string): boolean {
switch (this.authority) {
case AuthorityType.Server:
return false; // 只有服务端有权限
case AuthorityType.Client:
return clientId === this.ownerId;
case AuthorityType.Shared:
return true; // 任何人都可以修改
default:
return false;
}
}
public hasAuthority(clientId: string): boolean {
switch (this.authority) {
case AuthorityType.Server:
return false; // 只有服务端有权限
/**
case AuthorityType.Client:
return clientId === this.ownerId;
case AuthorityType.Shared:
return true; // 任何人都可以修改
default:
return false;
}
}
/**
* 设置拥有者
*/
public setOwner(clientId: string): void {
const oldOwner = this.ownerId;
this.ownerId = clientId;
// 发射拥有者变化事件
this.emitEvent(
NetworkEventType.IDENTITY_OWNER_CHANGED,
NetworkEventUtils.createIdentityEventData(
this.networkId,
clientId,
oldOwner,
clientId
)
);
}
public setOwner(clientId: string): void {
const oldOwner = this.ownerId;
this.ownerId = clientId;
/**
// 发射拥有者变化事件
this.emitEvent(
NetworkEventType.IDENTITY_OWNER_CHANGED,
NetworkEventUtils.createIdentityEventData(
this.networkId,
clientId,
oldOwner,
clientId
)
);
}
/**
* 设置权限类型
*/
public setAuthority(authority: AuthorityType): void {
const oldAuthority = this.authority;
this.authority = authority;
// 发射权限变化事件
this.emitEvent(
NetworkEventType.IDENTITY_AUTHORITY_CHANGED,
NetworkEventUtils.createIdentityEventData(
this.networkId,
this.ownerId,
oldAuthority,
authority
)
);
}
public setAuthority(authority: AuthorityType): void {
const oldAuthority = this.authority;
this.authority = authority;
/**
// 发射权限变化事件
this.emitEvent(
NetworkEventType.IDENTITY_AUTHORITY_CHANGED,
NetworkEventUtils.createIdentityEventData(
this.networkId,
this.ownerId,
oldAuthority,
authority
)
);
}
/**
* 设置同步状态
*/
public setSyncEnabled(enabled: boolean): void {
const oldEnabled = this.syncEnabled;
this.syncEnabled = enabled;
// 发射同步状态变化事件
const eventType = enabled
? NetworkEventType.IDENTITY_SYNC_ENABLED
: NetworkEventType.IDENTITY_SYNC_DISABLED;
this.emitEvent(
eventType,
NetworkEventUtils.createIdentityEventData(
this.networkId,
this.ownerId,
oldEnabled,
enabled
)
);
}
public setSyncEnabled(enabled: boolean): void {
const oldEnabled = this.syncEnabled;
this.syncEnabled = enabled;
/**
// 发射同步状态变化事件
const eventType = enabled
? NetworkEventType.IDENTITY_SYNC_ENABLED
: NetworkEventType.IDENTITY_SYNC_DISABLED;
this.emitEvent(
eventType,
NetworkEventUtils.createIdentityEventData(
this.networkId,
this.ownerId,
oldEnabled,
enabled
)
);
}
/**
* 设置同步频率
*/
public setSyncRate(rate: number): void {
const oldRate = this.syncRate;
this.syncRate = rate;
// 发射同步频率变化事件
this.emitEvent(
NetworkEventType.SYNC_RATE_CHANGED,
NetworkEventUtils.createIdentityEventData(
this.networkId,
this.ownerId,
oldRate,
rate
)
);
}
public setSyncRate(rate: number): void {
const oldRate = this.syncRate;
this.syncRate = rate;
/**
// 发射同步频率变化事件
this.emitEvent(
NetworkEventType.SYNC_RATE_CHANGED,
NetworkEventUtils.createIdentityEventData(
this.networkId,
this.ownerId,
oldRate,
rate
)
);
}
/**
* 添加事件监听器
*/
public addEventListener(eventType: NetworkEventType, handler: (data: NetworkIdentityEventData) => void): void {
this.eventEmitter.addObserver(eventType, handler, this);
}
public addEventListener(eventType: NetworkEventType, handler: (data: NetworkIdentityEventData) => void): void {
this.eventEmitter.addObserver(eventType, handler, this);
}
/**
/**
* 移除事件监听器
*/
public removeEventListener(eventType: NetworkEventType, handler: (data: NetworkIdentityEventData) => void): void {
this.eventEmitter.removeObserver(eventType, handler);
}
public removeEventListener(eventType: NetworkEventType, handler: (data: NetworkIdentityEventData) => void): void {
this.eventEmitter.removeObserver(eventType, handler);
}
/**
/**
* 发射事件
* @private
*/
private emitEvent(eventType: NetworkEventType, data: NetworkIdentityEventData): void {
this.eventEmitter.emit(eventType, data);
}
private emitEvent(eventType: NetworkEventType, data: NetworkIdentityEventData): void {
this.eventEmitter.emit(eventType, data);
}
/**
/**
* 监听属性变化事件
*/
public onPropertyChanged(handler: (data: NetworkIdentityEventData) => void): void {
this.addEventListener(NetworkEventType.IDENTITY_PROPERTY_CHANGED, handler);
}
public onPropertyChanged(handler: (data: NetworkIdentityEventData) => void): void {
this.addEventListener(NetworkEventType.IDENTITY_PROPERTY_CHANGED, handler);
}
/**
/**
* 监听拥有者变化事件
*/
public onOwnerChanged(handler: (data: NetworkIdentityEventData) => void): void {
this.addEventListener(NetworkEventType.IDENTITY_OWNER_CHANGED, handler);
}
public onOwnerChanged(handler: (data: NetworkIdentityEventData) => void): void {
this.addEventListener(NetworkEventType.IDENTITY_OWNER_CHANGED, handler);
}
/**
/**
* 监听权限变化事件
*/
public onAuthorityChanged(handler: (data: NetworkIdentityEventData) => void): void {
this.addEventListener(NetworkEventType.IDENTITY_AUTHORITY_CHANGED, handler);
}
public onAuthorityChanged(handler: (data: NetworkIdentityEventData) => void): void {
this.addEventListener(NetworkEventType.IDENTITY_AUTHORITY_CHANGED, handler);
}
/**
/**
* 监听同步状态变化事件
*/
public onSyncStateChanged(handler: (data: NetworkIdentityEventData) => void): void {
this.addEventListener(NetworkEventType.IDENTITY_SYNC_ENABLED, handler);
this.addEventListener(NetworkEventType.IDENTITY_SYNC_DISABLED, handler);
}
public onSyncStateChanged(handler: (data: NetworkIdentityEventData) => void): void {
this.addEventListener(NetworkEventType.IDENTITY_SYNC_ENABLED, handler);
this.addEventListener(NetworkEventType.IDENTITY_SYNC_DISABLED, handler);
}
/**
/**
* 获取调试信息
*/
public getDebugInfo(): Record<string, any> {
return {
networkId: this.networkId,
ownerId: this.ownerId,
authority: this.authority,
scope: this.scope,
syncRate: this.syncRate,
priority: this.priority,
syncEnabled: this.syncEnabled,
visible: this.visible,
lastSyncTime: this.lastSyncTime
};
}
public getDebugInfo(): Record<string, any> {
return {
networkId: this.networkId,
ownerId: this.ownerId,
authority: this.authority,
scope: this.scope,
syncRate: this.syncRate,
priority: this.priority,
syncEnabled: this.syncEnabled,
visible: this.visible,
lastSyncTime: this.lastSyncTime
};
}
/**
/**
* 组件销毁时清理事件监听器
*/
public dispose(): void {
public dispose(): void {
// 清理所有事件监听器
this.eventEmitter.dispose();
}
}
this.eventEmitter.dispose();
}
}

View File

@@ -19,7 +19,7 @@ export interface ServerRpcOptions extends RpcOptions {
}
/**
* 客户端RPC装饰器选项
* 客户端RPC装饰器选项
*/
export interface ClientRpcOptions extends RpcOptions {
/** 广播到多个客户端时的聚合策略 */
@@ -38,11 +38,11 @@ export function ServerRpc(options: ServerRpcOptions = {}): MethodDecorator {
return function (target: object, propertyKey: string | symbol, descriptor: PropertyDescriptor) {
const className = target.constructor.name;
const methodName = String(propertyKey);
// 获取参数类型和返回值类型
const paramTypes = Reflect.getMetadata('design:paramtypes', target, propertyKey) || [];
const returnType = Reflect.getMetadata('design:returntype', target, propertyKey);
const metadata: RpcMethodMetadata = {
methodName,
className,
@@ -59,15 +59,15 @@ export function ServerRpc(options: ServerRpcOptions = {}): MethodDecorator {
paramTypes: paramTypes.map((type: unknown) => type?.constructor?.name || 'unknown'),
returnType: returnType?.name || 'unknown'
};
// 存储元数据
Reflect.defineMetadata(RPC_METADATA_KEY, metadata, target, propertyKey);
// 添加到方法列表
const existingMethods = Reflect.getMetadata(RPC_METHODS_KEY, target.constructor) || [];
existingMethods.push(methodName);
Reflect.defineMetadata(RPC_METHODS_KEY, existingMethods, target.constructor);
// 包装原方法以添加验证和日志
const originalMethod = descriptor.value;
descriptor.value = async function (...args: unknown[]) {
@@ -80,7 +80,7 @@ export function ServerRpc(options: ServerRpcOptions = {}): MethodDecorator {
throw error;
}
};
return descriptor;
};
}
@@ -93,11 +93,11 @@ export function ClientRpc(options: ClientRpcOptions = {}): MethodDecorator {
return function (target: object, propertyKey: string | symbol, descriptor: PropertyDescriptor) {
const className = target.constructor.name;
const methodName = String(propertyKey);
// 获取参数类型和返回值类型
const paramTypes = Reflect.getMetadata('design:paramtypes', target, propertyKey) || [];
const returnType = Reflect.getMetadata('design:returntype', target, propertyKey);
const metadata: RpcMethodMetadata = {
methodName,
className,
@@ -114,15 +114,15 @@ export function ClientRpc(options: ClientRpcOptions = {}): MethodDecorator {
paramTypes: paramTypes.map((type: unknown) => type?.constructor?.name || 'unknown'),
returnType: returnType?.name || 'unknown'
};
// 存储元数据
Reflect.defineMetadata(RPC_METADATA_KEY, metadata, target, propertyKey);
// 添加到方法列表
const existingMethods = Reflect.getMetadata(RPC_METHODS_KEY, target.constructor) || [];
existingMethods.push(methodName);
Reflect.defineMetadata(RPC_METHODS_KEY, existingMethods, target.constructor);
// 包装原方法以添加调用逻辑
const originalMethod = descriptor.value;
descriptor.value = async function (...args: unknown[]) {
@@ -130,7 +130,7 @@ export function ClientRpc(options: ClientRpcOptions = {}): MethodDecorator {
// 目前保持原方法以支持本地测试
return originalMethod.apply(this, args);
};
return descriptor;
};
}
@@ -141,7 +141,7 @@ export function ClientRpc(options: ClientRpcOptions = {}): MethodDecorator {
export function getRpcMethods(target: Function): RpcMethodMetadata[] {
const methodNames = Reflect.getMetadata(RPC_METHODS_KEY, target) || [];
const prototype = target.prototype;
return methodNames.map((methodName: string) => {
const metadata = Reflect.getMetadata(RPC_METADATA_KEY, prototype, methodName);
if (!metadata) {
@@ -155,7 +155,7 @@ export function getRpcMethods(target: Function): RpcMethodMetadata[] {
* 获取特定方法的RPC元数据
*/
export function getRpcMethodMetadata(
target: object,
target: object,
methodName: string | symbol
): RpcMethodMetadata | undefined {
return Reflect.getMetadata(RPC_METADATA_KEY, target, methodName);
@@ -203,7 +203,7 @@ export class RpcMethodValidator {
error: `参数数量不匹配,期望 ${metadata.paramTypes.length} 个,实际 ${args.length}`
};
}
// 权限检查
if (metadata.options.requireAuth && !callerId) {
return {
@@ -211,10 +211,10 @@ export class RpcMethodValidator {
error: '该方法需要身份验证'
};
}
return { valid: true };
}
/**
* 验证RPC方法定义
*/
@@ -226,7 +226,7 @@ export class RpcMethodValidator {
error: '方法名无效'
};
}
// 超时时间检查
if (metadata.options.timeout && metadata.options.timeout <= 0) {
return {
@@ -234,16 +234,16 @@ export class RpcMethodValidator {
error: '超时时间必须大于0'
};
}
// 优先级检查
if (metadata.options.priority !== undefined &&
if (metadata.options.priority !== undefined &&
(metadata.options.priority < 0 || metadata.options.priority > 10)) {
return {
valid: false,
error: '优先级必须在0-10之间'
};
}
return { valid: true };
}
}
}

View File

@@ -75,14 +75,14 @@ export const DEFAULT_SYNCVAR_OPTIONS: Required<SyncVarOptions<SyncVarValue>> = {
export function SyncVar<T extends SyncVarValue = SyncVarValue>(options: SyncVarOptions<T> = {}) {
return function (target: object, propertyKey: string | symbol) {
const fullOptions = { ...DEFAULT_SYNCVAR_OPTIONS, ...options } as Required<SyncVarOptions<T>>;
// 获取或创建元数据存储
if (!(target.constructor as any)[SYNCVAR_METADATA_KEY]) {
(target.constructor as any)[SYNCVAR_METADATA_KEY] = new Map();
}
const metadataMap = (target.constructor as any)[SYNCVAR_METADATA_KEY] as Map<string | symbol, SyncVarMetadata<T>>;
// 创建元数据
const metadata: SyncVarMetadata<T> = {
propertyKey,
@@ -91,21 +91,21 @@ export function SyncVar<T extends SyncVarValue = SyncVarValue>(options: SyncVarO
isDirty: false,
syncCount: 0
};
metadataMap.set(propertyKey, metadata);
// 获取原始属性描述符
const originalDescriptor = Object.getOwnPropertyDescriptor(target, propertyKey) || {
writable: true,
enumerable: true,
configurable: true
};
metadata.originalDescriptor = originalDescriptor;
// 创建内部存储属性名
const internalPropertyKey = Symbol(`_syncVar_${String(propertyKey)}`);
// 重新定义属性,添加变化检测
Object.defineProperty(target, propertyKey, {
get: function() {
@@ -113,23 +113,23 @@ export function SyncVar<T extends SyncVarValue = SyncVarValue>(options: SyncVarO
},
set: function(newValue: T) {
const oldValue = (this as any)[internalPropertyKey];
// 检查是否真的发生了变化
if (!hasValueChanged(oldValue, newValue, fullOptions.threshold)) {
return;
}
// 更新值
(this as any)[internalPropertyKey] = newValue;
// 标记为脏数据
markAsDirty(this, propertyKey);
// 触发变化回调
if (fullOptions.onChanged) {
fullOptions.onChanged(oldValue, newValue);
}
// 如果启用了自动同步,立即同步
if (fullOptions.syncRate === 0) {
requestImmediateSync(this, propertyKey);
@@ -138,7 +138,7 @@ export function SyncVar<T extends SyncVarValue = SyncVarValue>(options: SyncVarO
enumerable: originalDescriptor.enumerable,
configurable: originalDescriptor.configurable
});
// 设置初始值
if (originalDescriptor.value !== undefined) {
(target as any)[internalPropertyKey] = originalDescriptor.value;
@@ -154,22 +154,22 @@ function hasValueChanged(oldValue: SyncVarValue, newValue: SyncVarValue, thresho
if (oldValue === newValue) {
return false;
}
// null/undefined 检查
if (oldValue == null || newValue == null) {
return oldValue !== newValue;
}
// 数值类型的阈值检查
if (typeof oldValue === 'number' && typeof newValue === 'number') {
return Math.abs(oldValue - newValue) > threshold;
}
// 对象类型的深度比较
if (typeof oldValue === 'object' && typeof newValue === 'object') {
return !deepEqual(oldValue, newValue);
}
return true;
}
@@ -180,36 +180,36 @@ function deepEqual(obj1: SyncVarValue, obj2: SyncVarValue): boolean {
if (obj1 === obj2) {
return true;
}
if (obj1 == null || obj2 == null) {
return obj1 === obj2;
}
if (typeof obj1 !== typeof obj2) {
return false;
}
if (typeof obj1 !== 'object') {
return obj1 === obj2;
}
const keys1 = Object.keys(obj1);
const keys2 = Object.keys(obj2);
if (keys1.length !== keys2.length) {
return false;
}
for (const key of keys1) {
if (!keys2.includes(key)) {
return false;
}
if (!deepEqual((obj1 as any)[key], (obj2 as any)[key])) {
return false;
}
}
return true;
}
@@ -219,12 +219,12 @@ function deepEqual(obj1: SyncVarValue, obj2: SyncVarValue): boolean {
function markAsDirty(instance: object, propertyKey: string | symbol): void {
const metadataMap = (instance.constructor as any)[SYNCVAR_METADATA_KEY] as Map<string | symbol, SyncVarMetadata>;
const metadata = metadataMap?.get(propertyKey);
if (metadata) {
metadata.isDirty = true;
metadata.lastValue = (instance as any)[propertyKey];
}
// 通知SyncVar管理器
if (typeof window !== 'undefined' && (window as any).SyncVarManager) {
(window as any).SyncVarManager.markInstanceDirty(instance);
@@ -248,7 +248,7 @@ export function getSyncVarMetadata(target: object): Map<string | symbol, SyncVar
if (!target || !target.constructor) {
return new Map();
}
return (target.constructor as any)[SYNCVAR_METADATA_KEY] || new Map();
}
@@ -274,13 +274,13 @@ export function hasSyncVars(target: object): boolean {
export function getDirtySyncVars(target: object): Map<string | symbol, SyncVarMetadata> {
const metadataMap = getSyncVarMetadata(target);
const dirtyVars = new Map<string | symbol, SyncVarMetadata>();
for (const [key, metadata] of metadataMap) {
if (metadata.isDirty) {
dirtyVars.set(key, metadata);
}
}
return dirtyVars;
}
@@ -289,7 +289,7 @@ export function getDirtySyncVars(target: object): Map<string | symbol, SyncVarMe
*/
export function clearDirtyFlags(target: object): void {
const metadataMap = getSyncVarMetadata(target);
for (const metadata of metadataMap.values()) {
metadata.isDirty = false;
metadata.lastSyncTime = Date.now();
@@ -302,7 +302,7 @@ export function clearDirtyFlags(target: object): void {
*/
export function resetSyncVarStats(target: object): void {
const metadataMap = getSyncVarMetadata(target);
for (const metadata of metadataMap.values()) {
metadata.syncCount = 0;
metadata.lastSyncTime = 0;
@@ -315,7 +315,7 @@ export function resetSyncVarStats(target: object): void {
export function getSyncVarStats(target: object): { [key: string]: { syncCount: number; lastSyncTime: number; isDirty: boolean } } {
const metadataMap = getSyncVarMetadata(target);
const stats: { [key: string]: { syncCount: number; lastSyncTime: number; isDirty: boolean } } = {};
for (const [key, metadata] of metadataMap) {
stats[String(key)] = {
syncCount: metadata.syncCount,
@@ -323,6 +323,6 @@ export function getSyncVarStats(target: object): { [key: string]: { syncCount: n
isDirty: metadata.isDirty
};
}
return stats;
}
}

View File

@@ -3,4 +3,4 @@
*/
export * from './SyncVar';
export * from './RpcDecorators';
export * from './RpcDecorators';

View File

@@ -11,7 +11,7 @@ export enum NetworkEventType {
RECONNECTION_STARTED = 'network:reconnection:started',
RECONNECTION_SUCCEEDED = 'network:reconnection:succeeded',
RECONNECTION_FAILED = 'network:reconnection:failed',
// 网络身份相关事件
IDENTITY_CREATED = 'network:identity:created',
IDENTITY_DESTROYED = 'network:identity:destroyed',
@@ -21,14 +21,14 @@ export enum NetworkEventType {
IDENTITY_SYNC_DISABLED = 'network:identity:sync:disabled',
IDENTITY_PROPERTY_CHANGED = 'network:identity:property:changed',
IDENTITY_VISIBLE_CHANGED = 'network:identity:visible:changed',
// 同步相关事件
SYNC_STARTED = 'network:sync:started',
SYNC_COMPLETED = 'network:sync:completed',
SYNC_FAILED = 'network:sync:failed',
SYNC_RATE_CHANGED = 'network:sync:rate:changed',
SYNC_PRIORITY_CHANGED = 'network:sync:priority:changed',
// RPC相关事件
RPC_CALL_SENT = 'network:rpc:call:sent',
RPC_CALL_RECEIVED = 'network:rpc:call:received',
@@ -36,7 +36,7 @@ export enum NetworkEventType {
RPC_RESPONSE_RECEIVED = 'network:rpc:response:received',
RPC_ERROR = 'network:rpc:error',
RPC_TIMEOUT = 'network:rpc:timeout',
// 消息相关事件
MESSAGE_SENT = 'network:message:sent',
MESSAGE_RECEIVED = 'network:message:received',
@@ -44,7 +44,7 @@ export enum NetworkEventType {
MESSAGE_DROPPED = 'network:message:dropped',
MESSAGE_RETRY = 'network:message:retry',
MESSAGE_ACKNOWLEDGED = 'network:message:acknowledged',
// 房间相关事件
ROOM_JOINED = 'network:room:joined',
ROOM_LEFT = 'network:room:left',
@@ -52,26 +52,26 @@ export enum NetworkEventType {
ROOM_DESTROYED = 'network:room:destroyed',
ROOM_PLAYER_JOINED = 'network:room:player:joined',
ROOM_PLAYER_LEFT = 'network:room:player:left',
// 客户端相关事件
CLIENT_CONNECTED = 'network:client:connected',
CLIENT_DISCONNECTED = 'network:client:disconnected',
CLIENT_AUTHENTICATED = 'network:client:authenticated',
CLIENT_KICKED = 'network:client:kicked',
CLIENT_TIMEOUT = 'network:client:timeout',
// 服务器相关事件
SERVER_STARTED = 'network:server:started',
SERVER_STOPPED = 'network:server:stopped',
SERVER_ERROR = 'network:server:error',
SERVER_OVERLOADED = 'network:server:overloaded',
// 数据相关事件
DATA_SYNCHRONIZED = 'network:data:synchronized',
DATA_CONFLICT = 'network:data:conflict',
DATA_CORRUPTED = 'network:data:corrupted',
DATA_VALIDATED = 'network:data:validated',
// 性能相关事件
BANDWIDTH_WARNING = 'network:bandwidth:warning',
LATENCY_HIGH = 'network:latency:high',
@@ -284,4 +284,4 @@ export class NetworkEventUtils {
duration
};
}
}
}

View File

@@ -1 +1 @@
export * from './NetworkEvents';
export * from './NetworkEvents';

View File

@@ -25,13 +25,13 @@ export * from './events/NetworkEvents';
// 序列化系统
export * from './serialization/JSONSerializer';
export * from './serialization/MessageCompressor';
export {
SyncVarSerializer,
export {
SyncVarSerializer,
SyncVarSerializerConfig,
SerializationResult as SyncVarSerializationResult,
DeserializationResult as SyncVarDeserializationResult,
DeltaData as SyncVarDeltaData,
CompressionMetadata
CompressionMetadata
} from './serialization/SyncVarSerializer';
// 装饰器系统
@@ -45,18 +45,18 @@ export * from './rpc/RpcReliabilityManager';
// 同步系统
export { SyncVarManager, SyncBatch } from './sync/SyncVarManager';
export {
DeltaSync,
export {
DeltaSync,
DeltaSyncConfig,
DeltaData,
DeltaOperationType,
DeltaOperation,
VersionedData,
DeltaSyncStats
DeltaSyncStats
} from './sync/DeltaSync';
// 监控系统
export * from './monitoring';
// 工具类
export * from './utils';
export * from './utils';

View File

@@ -99,19 +99,19 @@ export interface BandwidthMonitorEvents {
export class BandwidthMonitor extends EventEmitter {
private logger = createLogger('BandwidthMonitor');
private config: BandwidthMonitorConfig;
/** 带宽样本历史 */
private samples: BandwidthSample[] = [];
/** 当前带宽限制 */
private limits: BandwidthLimit;
/** 当前警告级别 */
private currentWarningLevel = BandwidthWarningLevel.Normal;
/** 监控定时器 */
private monitorTimer: ReturnType<typeof setInterval> | null = null;
/** 统计信息 */
private stats: BandwidthStats = {
currentUpload: 0,
@@ -127,10 +127,10 @@ export class BandwidthMonitor extends EventEmitter {
latencyJitter: 0,
utilization: 0
};
/** 上次统计时间 */
private lastStatsTime = Date.now();
/** 累计字节数 */
private cumulativeBytesIn = 0;
private cumulativeBytesOut = 0;
@@ -139,7 +139,7 @@ export class BandwidthMonitor extends EventEmitter {
constructor(config: Partial<BandwidthMonitorConfig> = {}) {
super();
this.config = {
monitorInterval: 1000,
sampleWindowSize: 60,
@@ -149,13 +149,13 @@ export class BandwidthMonitor extends EventEmitter {
adaptiveFactor: 0.1,
...config
};
this.limits = {
uploadLimit: 1024 * 1024, // 1MB/s
downloadLimit: 1024 * 1024, // 1MB/s
enabled: false
};
this.startMonitoring();
}
@@ -167,7 +167,7 @@ export class BandwidthMonitor extends EventEmitter {
this.cumulativeBytesOut += bytesOut;
this.cumulativePacketsIn += packetsIn;
this.cumulativePacketsOut += packetsOut;
this.stats.totalUpload += bytesOut;
this.stats.totalDownload += bytesIn;
}
@@ -178,9 +178,9 @@ export class BandwidthMonitor extends EventEmitter {
public setBandwidthLimits(limits: Partial<BandwidthLimit>): void {
const oldLimits = { ...this.limits };
Object.assign(this.limits, limits);
this.logger.info(`带宽限制已更新: 上行=${this.limits.uploadLimit}B/s, 下行=${this.limits.downloadLimit}B/s`);
if (this.config.enableAdaptive) {
this.emit('adaptiveAdjustment', oldLimits, this.limits);
}
@@ -214,7 +214,7 @@ export class BandwidthMonitor extends EventEmitter {
if (!this.limits.enabled) {
return { upload: false, download: false };
}
return {
upload: this.stats.currentUpload > this.limits.uploadLimit,
download: this.stats.currentDownload > this.limits.downloadLimit
@@ -228,9 +228,9 @@ export class BandwidthMonitor extends EventEmitter {
if (!this.limits.enabled) {
return Infinity;
}
const uploadUtilization = this.stats.currentUpload / this.limits.uploadLimit;
if (uploadUtilization < this.config.warningThreshold) {
return this.limits.uploadLimit * 0.1; // 10% of limit
} else if (uploadUtilization < this.config.criticalThreshold) {
@@ -248,7 +248,7 @@ export class BandwidthMonitor extends EventEmitter {
this.stats.currentUpload / this.limits.uploadLimit,
this.stats.currentDownload / this.limits.downloadLimit
);
if (utilization < this.config.warningThreshold) {
return 0;
} else if (utilization < this.config.criticalThreshold) {
@@ -276,7 +276,7 @@ export class BandwidthMonitor extends EventEmitter {
latencyJitter: 0,
utilization: 0
};
this.samples.length = 0;
this.cumulativeBytesIn = 0;
this.cumulativeBytesOut = 0;
@@ -290,7 +290,7 @@ export class BandwidthMonitor extends EventEmitter {
*/
public updateConfig(newConfig: Partial<BandwidthMonitorConfig>): void {
Object.assign(this.config, newConfig);
if (newConfig.monitorInterval !== undefined) {
this.restartMonitoring();
}
@@ -312,7 +312,7 @@ export class BandwidthMonitor extends EventEmitter {
if (this.monitorTimer) {
return;
}
this.monitorTimer = setInterval(() => {
this.updateStats();
}, this.config.monitorInterval);
@@ -342,16 +342,16 @@ export class BandwidthMonitor extends EventEmitter {
private updateStats(): void {
const now = Date.now();
const deltaTime = (now - this.lastStatsTime) / 1000; // 转换为秒
if (deltaTime <= 0) {
return;
}
// 计算当前速率
const currentUpload = this.cumulativeBytesOut / deltaTime;
const currentDownload = this.cumulativeBytesIn / deltaTime;
const currentPacketRate = (this.cumulativePacketsIn + this.cumulativePacketsOut) / deltaTime;
// 创建新样本
const sample: BandwidthSample = {
timestamp: now,
@@ -361,47 +361,47 @@ export class BandwidthMonitor extends EventEmitter {
packetsOut: this.cumulativePacketsOut,
latency: 0 // 需要从外部提供
};
this.samples.push(sample);
// 限制样本数量
if (this.samples.length > this.config.sampleWindowSize) {
this.samples.shift();
}
// 更新统计信息
this.stats.currentUpload = currentUpload;
this.stats.currentDownload = currentDownload;
this.stats.currentPacketRate = currentPacketRate;
// 更新峰值
this.stats.peakUpload = Math.max(this.stats.peakUpload, currentUpload);
this.stats.peakDownload = Math.max(this.stats.peakDownload, currentDownload);
// 计算平均值
this.calculateAverages();
// 计算利用率
this.calculateUtilization();
// 检查限制
this.checkLimits();
// 检查警告级别
this.checkWarningLevel();
// 自适应调整
if (this.config.enableAdaptive) {
this.performAdaptiveAdjustment();
}
// 重置累计值
this.cumulativeBytesIn = 0;
this.cumulativeBytesOut = 0;
this.cumulativePacketsIn = 0;
this.cumulativePacketsOut = 0;
this.lastStatsTime = now;
// 发出事件
this.emit('bandwidthChanged', this.stats);
}
@@ -413,30 +413,30 @@ export class BandwidthMonitor extends EventEmitter {
if (this.samples.length === 0) {
return;
}
let totalUpload = 0;
let totalDownload = 0;
let totalLatency = 0;
for (let i = 1; i < this.samples.length; i++) {
const prev = this.samples[i - 1];
const curr = this.samples[i];
const deltaTime = (curr.timestamp - prev.timestamp) / 1000;
if (deltaTime > 0) {
totalUpload += (curr.bytesOut - prev.bytesOut) / deltaTime;
totalDownload += (curr.bytesIn - prev.bytesIn) / deltaTime;
totalLatency += curr.latency;
}
}
const sampleCount = this.samples.length - 1;
if (sampleCount > 0) {
this.stats.averageUpload = totalUpload / sampleCount;
this.stats.averageDownload = totalDownload / sampleCount;
this.stats.averageLatency = totalLatency / this.samples.length;
}
// 计算延迟抖动
this.calculateLatencyJitter();
}
@@ -448,16 +448,16 @@ export class BandwidthMonitor extends EventEmitter {
if (this.samples.length < 2) {
return;
}
let jitterSum = 0;
let jitterCount = 0;
for (let i = 1; i < this.samples.length; i++) {
const diff = Math.abs(this.samples[i].latency - this.samples[i - 1].latency);
jitterSum += diff;
jitterCount++;
}
this.stats.latencyJitter = jitterCount > 0 ? jitterSum / jitterCount : 0;
}
@@ -469,10 +469,10 @@ export class BandwidthMonitor extends EventEmitter {
this.stats.utilization = 0;
return;
}
const uploadUtilization = this.stats.currentUpload / this.limits.uploadLimit;
const downloadUtilization = this.stats.currentDownload / this.limits.downloadLimit;
this.stats.utilization = Math.max(uploadUtilization, downloadUtilization);
}
@@ -483,11 +483,11 @@ export class BandwidthMonitor extends EventEmitter {
if (!this.limits.enabled) {
return;
}
if (this.stats.currentUpload > this.limits.uploadLimit) {
this.emit('limitExceeded', 'upload', this.stats.currentUpload, this.limits.uploadLimit);
}
if (this.stats.currentDownload > this.limits.downloadLimit) {
this.emit('limitExceeded', 'download', this.stats.currentDownload, this.limits.downloadLimit);
}
@@ -498,13 +498,13 @@ export class BandwidthMonitor extends EventEmitter {
*/
private checkWarningLevel(): void {
let newLevel = BandwidthWarningLevel.Normal;
if (this.stats.utilization >= this.config.criticalThreshold) {
newLevel = BandwidthWarningLevel.Critical;
} else if (this.stats.utilization >= this.config.warningThreshold) {
newLevel = BandwidthWarningLevel.Warning;
}
if (newLevel !== this.currentWarningLevel) {
this.currentWarningLevel = newLevel;
this.emit('warningLevelChanged', newLevel, this.stats);
@@ -518,9 +518,9 @@ export class BandwidthMonitor extends EventEmitter {
if (!this.limits.enabled || this.stats.utilization < this.config.warningThreshold) {
return;
}
const oldLimits = { ...this.limits };
// 根据当前利用率动态调整限制
if (this.stats.utilization > this.config.criticalThreshold) {
// 严重超载,降低限制
@@ -531,11 +531,11 @@ export class BandwidthMonitor extends EventEmitter {
this.limits.uploadLimit *= (1 + this.config.adaptiveFactor * 0.5);
this.limits.downloadLimit *= (1 + this.config.adaptiveFactor * 0.5);
}
// 检查是否有变化
if (this.limits.uploadLimit !== oldLimits.uploadLimit ||
if (this.limits.uploadLimit !== oldLimits.uploadLimit ||
this.limits.downloadLimit !== oldLimits.downloadLimit) {
this.emit('adaptiveAdjustment', oldLimits, this.limits);
}
}
}
}

View File

@@ -2,4 +2,4 @@
* 监控模块导出
*/
export * from './BandwidthMonitor';
export * from './BandwidthMonitor';

View File

@@ -59,7 +59,7 @@ class SnowflakeIdGenerator {
private static readonly WORKER_ID_BITS = 5;
private static readonly DATACENTER_ID_BITS = 5;
private static readonly SEQUENCE_BITS = 12;
private readonly workerId: number;
private readonly datacenterId: number;
private sequence = 0;
@@ -107,16 +107,16 @@ export class MessageManager {
private logger = createLogger('MessageManager');
private config: MessageManagerConfig;
private stats: MessageStats;
// ID生成器
private sequentialId = 0;
private snowflakeGenerator: SnowflakeIdGenerator;
// 消息去重和排序
private recentMessageIds: Set<string> = new Set();
private pendingMessages: Map<string, INetworkMessage> = new Map();
private messageSequence: Map<string, number> = new Map();
// 清理定时器
private cleanupTimer?: NodeJS.Timeout;
@@ -201,7 +201,7 @@ export class MessageManager {
*/
validateMessage(message: INetworkMessage, senderId?: string): MessageValidationResult {
this.stats.totalValidated++;
const errors: string[] = [];
const warnings: string[] = [];
@@ -233,12 +233,12 @@ export class MessageManager {
if (this.config.enableTimestampValidation && message.timestamp) {
const now = Date.now();
const drift = Math.abs(now - message.timestamp);
if (drift > this.config.maxTimestampDrift) {
errors.push(`时间戳偏移过大: ${drift}ms > ${this.config.maxTimestampDrift}ms`);
this.stats.timestampErrors++;
}
if (message.timestamp > now + 10000) { // 未来10秒以上
warnings.push('消息时间戳来自未来');
}
@@ -255,7 +255,7 @@ export class MessageManager {
}
const isValid = errors.length === 0;
if (isValid) {
this.stats.validMessages++;
} else {
@@ -279,11 +279,11 @@ export class MessageManager {
const senderId = message.senderId;
const currentSequence = this.messageSequence.get(senderId) || 0;
// 检查消息是否按顺序到达
const messageTimestamp = message.timestamp;
const expectedSequence = currentSequence + 1;
// 简单的时间戳排序逻辑
if (messageTimestamp >= expectedSequence) {
// 消息按顺序到达
@@ -293,13 +293,13 @@ export class MessageManager {
// 消息乱序,暂存
this.pendingMessages.set(message.messageId, message);
this.stats.outOfOrderMessages++;
// 检查是否超出最大待处理数量
if (this.pendingMessages.size > this.config.maxPendingMessages) {
this.logger.warn('待处理消息数量过多,清理旧消息');
this.cleanupOldPendingMessages();
}
return [];
}
}
@@ -332,18 +332,18 @@ export class MessageManager {
updateConfig(newConfig: Partial<MessageManagerConfig>): void {
const oldConfig = { ...this.config };
Object.assign(this.config, newConfig);
// 如果去重配置改变,清理相关数据
if (!this.config.enableMessageDeduplication && oldConfig.enableMessageDeduplication) {
this.recentMessageIds.clear();
}
// 如果排序配置改变,清理相关数据
if (!this.config.enableMessageOrdering && oldConfig.enableMessageOrdering) {
this.pendingMessages.clear();
this.messageSequence.clear();
}
this.logger.info('消息管理器配置已更新:', newConfig);
}
@@ -355,7 +355,7 @@ export class MessageManager {
clearInterval(this.cleanupTimer);
this.cleanupTimer = undefined;
}
this.recentMessageIds.clear();
this.pendingMessages.clear();
this.messageSequence.clear();
@@ -378,20 +378,20 @@ export class MessageManager {
private flushPendingMessages(senderId: string): INetworkMessage[] {
const flushedMessages: INetworkMessage[] = [];
const messagesToRemove: string[] = [];
for (const [messageId, message] of this.pendingMessages) {
if (message.senderId === senderId) {
flushedMessages.push(message);
messagesToRemove.push(messageId);
}
}
// 移除已处理的消息
messagesToRemove.forEach(id => this.pendingMessages.delete(id));
messagesToRemove.forEach((id) => this.pendingMessages.delete(id));
// 按时间戳排序
flushedMessages.sort((a, b) => a.timestamp - b.timestamp);
return flushedMessages;
}
@@ -401,15 +401,15 @@ export class MessageManager {
private cleanupOldPendingMessages(): void {
const now = Date.now();
const messagesToRemove: string[] = [];
for (const [messageId, message] of this.pendingMessages) {
if (now - message.timestamp > this.config.orderingWindowMs) {
messagesToRemove.push(messageId);
}
}
messagesToRemove.forEach(id => this.pendingMessages.delete(id));
messagesToRemove.forEach((id) => this.pendingMessages.delete(id));
if (messagesToRemove.length > 0) {
this.logger.debug(`清理了 ${messagesToRemove.length} 个过期的待处理消息`);
}
@@ -429,7 +429,7 @@ export class MessageManager {
*/
private performCleanup(): void {
const now = Date.now();
// 清理过期的消息ID用于去重
if (this.config.enableMessageDeduplication) {
// 由于Set没有时间戳我们定期清理所有ID
@@ -439,7 +439,7 @@ export class MessageManager {
this.logger.debug('清理了过期的消息ID缓存');
}
}
// 清理过期的待处理消息
if (this.config.enableMessageOrdering) {
this.cleanupOldPendingMessages();
@@ -453,7 +453,7 @@ export class MessageManager {
const totalProcessed = this.stats.validMessages + this.stats.invalidMessages;
const validRate = totalProcessed > 0 ? (this.stats.validMessages / totalProcessed) * 100 : 0;
const duplicateRate = totalProcessed > 0 ? (this.stats.duplicateMessages / totalProcessed) * 100 : 0;
return {
stats: this.getStats(),
validationRate: validRate,
@@ -483,7 +483,7 @@ export class MessageManager {
* 批量验证消息
*/
validateMessageBatch(messages: INetworkMessage[], senderId?: string): MessageValidationResult[] {
return messages.map(message => this.validateMessage(message, senderId));
return messages.map((message) => this.validateMessage(message, senderId));
}
/**
@@ -499,4 +499,4 @@ export class MessageManager {
isMessageExpired(message: INetworkMessage, maxAge: number = 300000): boolean {
return this.getMessageAge(message) > maxAge;
}
}
}

View File

@@ -266,7 +266,7 @@ export interface IErrorMessage extends INetworkMessage {
/**
* 消息类型联合
*/
export type NetworkMessage =
export type NetworkMessage =
| IConnectMessage
| IConnectResponseMessage
| IHeartbeatMessage
@@ -280,4 +280,4 @@ export type NetworkMessage =
| ILeaveRoomMessage
| IRoomStateMessage
| IGameEventMessage
| IErrorMessage;
| IErrorMessage;

View File

@@ -1,9 +1,9 @@
import { createLogger } from '@esengine/ecs-framework';
import { EventEmitter } from '../utils/EventEmitter';
import {
RpcCallRequest,
RpcCallResponse,
RpcError,
import {
RpcCallRequest,
RpcCallResponse,
RpcError,
RpcErrorType,
RpcStats,
RpcMethodMetadata
@@ -67,13 +67,13 @@ export class RpcCallHandler extends EventEmitter {
private logger = createLogger('RpcCallHandler');
private config: RpcCallHandlerConfig;
private metadataManager: RpcMetadataManager;
/** 当前活跃的调用 */
private activeCalls = new Map<string, CallStats>();
/** 速率限制器 */
private rateLimiters = new Map<string, RateLimiter>();
/** 统计信息 */
private stats: RpcStats = {
totalCalls: 0,
@@ -85,10 +85,10 @@ export class RpcCallHandler extends EventEmitter {
retryCount: 0,
lastUpdated: Date.now()
};
/** 历史调用统计 */
private callHistory: CallStats[] = [];
/** 权限检查器 */
private permissionChecker?: (methodName: string, senderId: string) => boolean;
@@ -97,7 +97,7 @@ export class RpcCallHandler extends EventEmitter {
config: Partial<RpcCallHandlerConfig> = {}
) {
super();
this.metadataManager = metadataManager;
this.config = {
maxConcurrentCalls: 100,
@@ -128,11 +128,11 @@ export class RpcCallHandler extends EventEmitter {
startTime,
success: false
};
this.activeCalls.set(request.callId, callStats);
this.stats.pendingCalls++;
this.emit('callStarted', request);
try {
// 1. 检查并发限制
if (this.activeCalls.size > this.config.maxConcurrentCalls) {
@@ -141,7 +141,7 @@ export class RpcCallHandler extends EventEmitter {
`超过最大并发调用数限制: ${this.config.maxConcurrentCalls}`
);
}
// 2. 获取方法元数据
const metadata = this.metadataManager.getMethodMetadata(request.methodName);
if (!metadata) {
@@ -150,21 +150,21 @@ export class RpcCallHandler extends EventEmitter {
`RPC方法不存在: ${request.methodName}`
);
}
// 3. 验证方法调用
const validation = this.metadataManager.validateMethodCall(
request.methodName,
Array.from(request.args),
request.senderId
);
if (!validation.valid) {
throw this.createError(
RpcErrorType.INVALID_ARGUMENTS,
validation.error || '参数验证失败'
);
}
// 4. 权限检查
if (this.config.enablePermissionCheck && !this.checkPermission(metadata, request.senderId)) {
this.emit('permissionDenied', request.methodName, request.senderId);
@@ -173,7 +173,7 @@ export class RpcCallHandler extends EventEmitter {
`没有调用权限: ${request.methodName}`
);
}
// 5. 速率限制检查
if (this.config.enableRateLimit && !this.checkRateLimit(metadata, request.senderId)) {
this.emit('rateLimitExceeded', request.methodName, request.senderId);
@@ -182,7 +182,7 @@ export class RpcCallHandler extends EventEmitter {
`调用频率超限: ${request.methodName}`
);
}
// 6. 执行方法调用
const handler = this.metadataManager.getMethodHandler(request.methodName);
if (!handler) {
@@ -191,19 +191,19 @@ export class RpcCallHandler extends EventEmitter {
`方法处理器不存在: ${request.methodName}`
);
}
// 创建带超时的Promise
const timeout = request.options.timeout || metadata.options.timeout || this.config.defaultTimeout;
const result = await this.executeWithTimeout(handler, request.args, timeout);
// 7. 创建成功响应
const endTime = Date.now();
const duration = endTime - startTime;
callStats.endTime = endTime;
callStats.duration = duration;
callStats.success = true;
const response: RpcCallResponse<R> = {
callId: request.callId,
success: true,
@@ -211,25 +211,25 @@ export class RpcCallHandler extends EventEmitter {
timestamp: endTime,
duration
};
this.updateStats(callStats);
this.emit('callCompleted', request, response);
return response;
} catch (error) {
// 8. 处理错误
const endTime = Date.now();
const duration = endTime - startTime;
const rpcError = error instanceof Error && 'type' in error
const rpcError = error instanceof Error && 'type' in error
? error as RpcError
: this.createError(RpcErrorType.SERVER_ERROR, String(error));
callStats.endTime = endTime;
callStats.duration = duration;
callStats.error = rpcError;
const response: RpcCallResponse<R> = {
callId: request.callId,
success: false,
@@ -237,12 +237,12 @@ export class RpcCallHandler extends EventEmitter {
timestamp: endTime,
duration
};
this.updateStats(callStats);
this.emit('callFailed', request, rpcError);
return response;
} finally {
// 9. 清理
this.activeCalls.delete(request.callId);
@@ -270,13 +270,13 @@ export class RpcCallHandler extends EventEmitter {
* 获取方法调用历史
*/
public getCallHistory(methodName?: string, limit: number = 100): CallStats[] {
let history = [...this.callHistory];
const history = [...this.callHistory];
if (methodName) {
// 这里需要扩展CallStats接口来包含methodName
// 暂时返回所有历史
}
return history.slice(-limit);
}
@@ -294,7 +294,7 @@ export class RpcCallHandler extends EventEmitter {
retryCount: 0,
lastUpdated: Date.now()
};
this.callHistory.length = 0;
this.rateLimiters.clear();
}
@@ -324,12 +324,12 @@ export class RpcCallHandler extends EventEmitter {
if (!metadata.options.requireAuth) {
return true;
}
// 使用自定义权限检查器
if (this.permissionChecker) {
return this.permissionChecker(metadata.methodName, senderId);
}
// 默认:需要认证但没有检查器,拒绝访问
return false;
}
@@ -342,10 +342,10 @@ export class RpcCallHandler extends EventEmitter {
if (!rateLimit) {
return true;
}
const key = `${senderId}:${metadata.methodName}`;
let limiter = this.rateLimiters.get(key);
if (!limiter) {
limiter = {
calls: [],
@@ -354,17 +354,17 @@ export class RpcCallHandler extends EventEmitter {
};
this.rateLimiters.set(key, limiter);
}
const now = Date.now();
// 清理过期的调用记录
limiter.calls = limiter.calls.filter(time => now - time < limiter.window);
limiter.calls = limiter.calls.filter((time) => now - time < limiter.window);
// 检查是否超限
if (limiter.calls.length >= limiter.limit) {
return false;
}
// 记录本次调用
limiter.calls.push(now);
return true;
@@ -385,13 +385,13 @@ export class RpcCallHandler extends EventEmitter {
`方法调用超时: ${timeout}ms`
));
}, timeout);
Promise.resolve(handler(...args))
.then(result => {
.then((result) => {
clearTimeout(timer);
resolve(result);
})
.catch(error => {
.catch((error) => {
clearTimeout(timer);
reject(error);
});
@@ -414,17 +414,17 @@ export class RpcCallHandler extends EventEmitter {
*/
private updateStats(callStats: CallStats): void {
this.stats.totalCalls++;
if (callStats.success) {
this.stats.successfulCalls++;
} else {
this.stats.failedCalls++;
if (callStats.error?.type === RpcErrorType.TIMEOUT) {
this.stats.timeoutCalls++;
}
}
// 更新平均响应时间
if (callStats.duration !== undefined) {
const totalTime = this.stats.averageResponseTime * (this.stats.totalCalls - 1) + callStats.duration;
@@ -439,16 +439,16 @@ export class RpcCallHandler extends EventEmitter {
if (!this.config.enablePerformanceMonitoring) {
return;
}
this.callHistory.push(callStats);
// 清理过期的历史记录
const cutoffTime = Date.now() - this.config.statsRetentionTime;
this.callHistory = this.callHistory.filter(stats => stats.startTime > cutoffTime);
this.callHistory = this.callHistory.filter((stats) => stats.startTime > cutoffTime);
// 限制历史记录数量
if (this.callHistory.length > 10000) {
this.callHistory = this.callHistory.slice(-5000);
}
}
}
}

View File

@@ -1,9 +1,9 @@
import { createLogger } from '@esengine/ecs-framework';
import { EventEmitter } from '../utils/EventEmitter';
import {
RpcCallRequest,
RpcCallResponse,
RpcError,
import {
RpcCallRequest,
RpcCallResponse,
RpcError,
RpcErrorType,
RpcCallInfo,
RpcCallStatus,
@@ -62,16 +62,16 @@ export class RpcCallProxy extends EventEmitter {
private logger = createLogger('RpcCallProxy');
private config: RpcCallProxyConfig;
private networkSender: NetworkSender;
/** 待处理的调用 */
private pendingCalls = new Map<string, RpcCallInfo>();
/** 离线队列 */
private offlineQueue: RpcCallRequest[] = [];
/** 是否在线 */
private isOnline = true;
/** 统计信息 */
private stats: RpcStats = {
totalCalls: 0,
@@ -83,7 +83,7 @@ export class RpcCallProxy extends EventEmitter {
retryCount: 0,
lastUpdated: Date.now()
};
/** 重试定时器 */
private retryTimers = new Map<string, ReturnType<typeof setTimeout>>();
@@ -92,7 +92,7 @@ export class RpcCallProxy extends EventEmitter {
config: Partial<RpcCallProxyConfig> = {}
) {
super();
this.networkSender = networkSender;
this.config = {
defaultTimeout: 30000,
@@ -149,7 +149,7 @@ export class RpcCallProxy extends EventEmitter {
): Promise<TReturn> {
const callId = this.config.generateCallId!();
const timeout = options.timeout || this.config.defaultTimeout;
const request: RpcCallRequest<TArgs> = {
callId,
methodName,
@@ -164,7 +164,7 @@ export class RpcCallProxy extends EventEmitter {
...options
}
};
// 创建Promise和调用信息
return new Promise<TReturn>((resolve, reject) => {
const callInfo: RpcCallInfo<TArgs> = {
@@ -175,16 +175,16 @@ export class RpcCallProxy extends EventEmitter {
retryCount: 0,
createdAt: Date.now()
};
this.pendingCalls.set(callId, callInfo);
this.stats.pendingCalls++;
this.stats.totalCalls++;
// 设置超时
setTimeout(() => {
this.handleTimeout(callId);
}, timeout);
// 发送调用
this.sendCall(callInfo);
});
@@ -199,18 +199,18 @@ export class RpcCallProxy extends EventEmitter {
this.logger.warn(`收到未知调用的响应: ${response.callId}`);
return;
}
// 清理定时器
const timer = this.retryTimers.get(response.callId);
if (timer) {
clearTimeout(timer);
this.retryTimers.delete(response.callId);
}
// 更新状态
callInfo.status = response.success ? RpcCallStatus.COMPLETED : RpcCallStatus.FAILED;
callInfo.completedAt = Date.now();
// 更新统计
if (response.success) {
this.stats.successfulCalls++;
@@ -218,9 +218,9 @@ export class RpcCallProxy extends EventEmitter {
} else {
this.stats.failedCalls++;
}
this.stats.pendingCalls--;
// 处理结果
if (response.success) {
callInfo.resolve!(response.result);
@@ -228,7 +228,7 @@ export class RpcCallProxy extends EventEmitter {
callInfo.reject!(response.error!);
this.emit('callFailed', response.callId, response.error!);
}
// 清理
this.pendingCalls.delete(response.callId);
this.emit('responseReceived', response);
@@ -240,7 +240,7 @@ export class RpcCallProxy extends EventEmitter {
public setOnlineStatus(online: boolean): void {
const wasOnline = this.isOnline;
this.isOnline = online;
if (online && !wasOnline) {
// 从离线状态恢复,处理离线队列
this.processOfflineQueue();
@@ -255,27 +255,27 @@ export class RpcCallProxy extends EventEmitter {
if (!callInfo) {
return false;
}
// 清理定时器
const timer = this.retryTimers.get(callId);
if (timer) {
clearTimeout(timer);
this.retryTimers.delete(callId);
}
// 更新状态
callInfo.status = RpcCallStatus.CANCELLED;
// 拒绝Promise
callInfo.reject!({
type: RpcErrorType.CLIENT_ERROR,
message: '调用被取消'
});
// 清理
this.pendingCalls.delete(callId);
this.stats.pendingCalls--;
return true;
}
@@ -326,16 +326,16 @@ export class RpcCallProxy extends EventEmitter {
for (const callId of pendingCallIds) {
this.cancelCall(callId);
}
// 清理定时器
for (const timer of this.retryTimers.values()) {
clearTimeout(timer);
}
this.retryTimers.clear();
// 清理队列
this.offlineQueue.length = 0;
this.removeAllListeners();
}
@@ -353,7 +353,7 @@ export class RpcCallProxy extends EventEmitter {
}
return;
}
// 构建网络消息
const message = {
type: MessageType.RPC_CALL,
@@ -364,18 +364,18 @@ export class RpcCallProxy extends EventEmitter {
reliable: callInfo.request.options.reliable,
priority: callInfo.request.options.priority
};
// 发送消息
await this.networkSender.sendMessage(message);
callInfo.status = RpcCallStatus.SENT;
callInfo.sentAt = Date.now();
this.emit('callSent', callInfo.request);
} catch (error) {
this.logger.error(`发送RPC调用失败: ${callInfo.request.methodName}`, error);
// 检查是否可以重试
if (callInfo.retryCount < this.config.maxRetries) {
this.scheduleRetry(callInfo);
@@ -396,7 +396,7 @@ export class RpcCallProxy extends EventEmitter {
if (!callInfo || callInfo.status === RpcCallStatus.COMPLETED) {
return;
}
// 检查是否可以重试
if (callInfo.retryCount < this.config.maxRetries) {
this.scheduleRetry(callInfo);
@@ -416,20 +416,20 @@ export class RpcCallProxy extends EventEmitter {
private scheduleRetry<T extends readonly unknown[]>(callInfo: RpcCallInfo<T>): void {
callInfo.retryCount++;
this.stats.retryCount++;
// 计算延迟时间(指数退避)
const baseDelay = this.config.retryDelayBase * Math.pow(this.config.retryDelayMultiplier, callInfo.retryCount - 1);
const delay = Math.min(baseDelay, this.config.maxRetryDelay);
callInfo.nextRetryTime = Date.now() + delay;
this.emit('retryAttempt', callInfo.request.callId, callInfo.retryCount);
const timer = setTimeout(() => {
this.retryTimers.delete(callInfo.request.callId);
this.sendCall(callInfo);
}, delay);
this.retryTimers.set(callInfo.request.callId, timer);
}
@@ -439,13 +439,13 @@ export class RpcCallProxy extends EventEmitter {
private handleCallFailure<T extends readonly unknown[]>(callInfo: RpcCallInfo<T>, error: RpcError): void {
callInfo.status = RpcCallStatus.FAILED;
callInfo.completedAt = Date.now();
callInfo.reject!(error);
this.pendingCalls.delete(callInfo.request.callId);
this.stats.pendingCalls--;
this.stats.failedCalls++;
this.emit('callFailed', callInfo.request.callId, error);
}
@@ -457,7 +457,7 @@ export class RpcCallProxy extends EventEmitter {
// 移除最旧的请求
this.offlineQueue.shift();
}
this.offlineQueue.push(request);
}
@@ -468,10 +468,10 @@ export class RpcCallProxy extends EventEmitter {
if (!this.isOnline || this.offlineQueue.length === 0) {
return;
}
const queue = [...this.offlineQueue];
this.offlineQueue.length = 0;
for (const request of queue) {
try {
// 重新创建调用信息
@@ -481,10 +481,10 @@ export class RpcCallProxy extends EventEmitter {
retryCount: 0,
createdAt: Date.now()
};
this.pendingCalls.set(request.callId, callInfo);
await this.sendCall(callInfo);
} catch (error) {
this.logger.error(`处理离线队列失败: ${request.methodName}`, error);
}
@@ -497,8 +497,8 @@ export class RpcCallProxy extends EventEmitter {
private updateAverageResponseTime(responseTime: number): void {
const totalResponses = this.stats.successfulCalls;
const currentAverage = this.stats.averageResponseTime;
this.stats.averageResponseTime =
this.stats.averageResponseTime =
(currentAverage * (totalResponses - 1) + responseTime) / totalResponses;
}
}
}

View File

@@ -19,16 +19,16 @@ export interface RpcMetadataManagerEvents {
*/
export class RpcMetadataManager extends EventEmitter {
private logger = createLogger('RpcMetadataManager');
/** 方法注册表 */
private registry: RpcMethodRegistry = new Map();
/** 类到方法的映射 */
private classMethods = new Map<string, Set<string>>();
/** 方法名到类的映射 */
private methodToClass = new Map<string, string>();
/** 实例缓存 */
private instances = new Map<string, object>();
@@ -37,15 +37,15 @@ export class RpcMetadataManager extends EventEmitter {
*/
public registerClass(instance: object): void {
const className = instance.constructor.name;
try {
const rpcMethods = getRpcMethods(instance.constructor as Function);
if (rpcMethods.length === 0) {
this.logger.warn(`${className} 没有RPC方法`);
return;
}
// 验证所有方法定义
for (const metadata of rpcMethods) {
const validation = RpcMethodValidator.validateMethodDefinition(metadata);
@@ -53,44 +53,44 @@ export class RpcMetadataManager extends EventEmitter {
throw new Error(`${className}.${metadata.methodName}: ${validation.error}`);
}
}
// 注册方法
const methodNames = new Set<string>();
for (const metadata of rpcMethods) {
const fullMethodName = `${className}.${metadata.methodName}`;
// 检查方法是否已存在
if (this.registry.has(fullMethodName)) {
throw new Error(`RPC方法已存在: ${fullMethodName}`);
}
// 获取实际方法处理器
const handler = (instance as Record<string, unknown>)[metadata.methodName];
if (typeof handler !== 'function') {
throw new Error(`方法不存在或不是函数: ${fullMethodName}`);
}
// 注册方法
this.registry.set(fullMethodName, {
metadata,
handler: handler.bind(instance)
});
methodNames.add(metadata.methodName);
this.methodToClass.set(fullMethodName, className);
this.logger.debug(`已注册RPC方法: ${fullMethodName}`);
this.emit('methodRegistered', metadata);
}
// 更新类映射
this.classMethods.set(className, methodNames);
this.instances.set(className, instance);
this.logger.info(`已注册RPC类: ${className},方法数: ${methodNames.size}`);
this.emit('classRegistered', className, methodNames.size);
} catch (error) {
this.logger.error(`注册RPC类失败: ${className}`, error);
throw error;
@@ -101,16 +101,16 @@ export class RpcMetadataManager extends EventEmitter {
* 注销RPC类
*/
public unregisterClass(classNameOrInstance: string | object): void {
const className = typeof classNameOrInstance === 'string'
? classNameOrInstance
const className = typeof classNameOrInstance === 'string'
? classNameOrInstance
: classNameOrInstance.constructor.name;
const methodNames = this.classMethods.get(className);
if (!methodNames) {
this.logger.warn(`RPC类未注册: ${className}`);
return;
}
// 移除所有方法
for (const methodName of methodNames) {
const fullMethodName = `${className}.${methodName}`;
@@ -118,11 +118,11 @@ export class RpcMetadataManager extends EventEmitter {
this.methodToClass.delete(fullMethodName);
this.emit('methodUnregistered', fullMethodName);
}
// 清理映射
this.classMethods.delete(className);
this.instances.delete(className);
this.logger.info(`已注销RPC类: ${className}`);
this.emit('classUnregistered', className);
}
@@ -155,13 +155,13 @@ export class RpcMetadataManager extends EventEmitter {
*/
public getServerRpcMethods(): RpcMethodMetadata[] {
const methods: RpcMethodMetadata[] = [];
for (const [, entry] of this.registry) {
if (entry.metadata.isServerRpc) {
methods.push(entry.metadata);
}
}
return methods;
}
@@ -170,13 +170,13 @@ export class RpcMetadataManager extends EventEmitter {
*/
public getClientRpcMethods(): RpcMethodMetadata[] {
const methods: RpcMethodMetadata[] = [];
for (const [, entry] of this.registry) {
if (!entry.metadata.isServerRpc) {
methods.push(entry.metadata);
}
}
return methods;
}
@@ -188,9 +188,9 @@ export class RpcMetadataManager extends EventEmitter {
if (!methodNames) {
return [];
}
const methods: RpcMethodMetadata[] = [];
for (const methodName of methodNames) {
const fullMethodName = `${className}.${methodName}`;
const entry = this.registry.get(fullMethodName);
@@ -198,7 +198,7 @@ export class RpcMetadataManager extends EventEmitter {
methods.push(entry.metadata);
}
}
return methods;
}
@@ -238,10 +238,10 @@ export class RpcMetadataManager extends EventEmitter {
serverRpcMethods: number;
clientRpcMethods: number;
registeredClasses: number;
} {
} {
let serverRpcCount = 0;
let clientRpcCount = 0;
for (const [, entry] of this.registry) {
if (entry.metadata.isServerRpc) {
serverRpcCount++;
@@ -249,7 +249,7 @@ export class RpcMetadataManager extends EventEmitter {
clientRpcCount++;
}
}
return {
totalMethods: this.registry.size,
serverRpcMethods: serverRpcCount,
@@ -273,7 +273,7 @@ export class RpcMetadataManager extends EventEmitter {
error: `RPC方法不存在: ${methodName}`
};
}
return RpcMethodValidator.validateCall(metadata, args, callerId);
}
@@ -287,33 +287,33 @@ export class RpcMetadataManager extends EventEmitter {
target?: string;
}): RpcMethodMetadata[] {
const results: RpcMethodMetadata[] = [];
for (const [methodName, entry] of this.registry) {
const metadata = entry.metadata;
// 类名过滤
if (query.className && metadata.className !== query.className) {
continue;
}
// RPC类型过滤
if (query.isServerRpc !== undefined && metadata.isServerRpc !== query.isServerRpc) {
continue;
}
// 认证要求过滤
if (query.requireAuth !== undefined && metadata.options.requireAuth !== query.requireAuth) {
continue;
}
// 目标过滤
if (query.target && metadata.options.target !== query.target) {
continue;
}
results.push(metadata);
}
return results;
}
@@ -322,16 +322,16 @@ export class RpcMetadataManager extends EventEmitter {
*/
public clear(): void {
const classNames = Array.from(this.classMethods.keys());
for (const className of classNames) {
this.unregisterClass(className);
}
this.registry.clear();
this.classMethods.clear();
this.methodToClass.clear();
this.instances.clear();
this.logger.info('已清空所有RPC注册');
}
@@ -342,4 +342,4 @@ export class RpcMetadataManager extends EventEmitter {
this.clear();
this.removeAllListeners();
}
}
}

View File

@@ -106,25 +106,25 @@ export interface RpcReliabilityManagerEvents {
export class RpcReliabilityManager extends EventEmitter {
private logger = createLogger('RpcReliabilityManager');
private config: RpcReliabilityConfig;
/** 重复调用记录 */
private duplicateRecords = new Map<string, DuplicateCallRecord>();
/** 活跃事务 */
private transactions = new Map<string, TransactionInfo>();
/** 顺序执行队列(按发送者分组) */
private orderedQueues = new Map<string, OrderedQueueItem[]>();
/** 正在处理的有序调用 */
private processingOrdered = new Set<string>();
/** 清理定时器 */
private cleanupTimer: ReturnType<typeof setInterval> | null = null;
constructor(config: Partial<RpcReliabilityConfig> = {}) {
super();
this.config = {
idempotency: {
enabled: true,
@@ -146,7 +146,7 @@ export class RpcReliabilityManager extends EventEmitter {
...config.transaction
}
};
this.startCleanupTimer();
}
@@ -161,18 +161,18 @@ export class RpcReliabilityManager extends EventEmitter {
if (!this.config.idempotency.enabled) {
return { isDuplicate: false, shouldProcess: true };
}
const key = `${request.senderId}:${request.callId}`;
const existing = this.duplicateRecords.get(key);
const now = Date.now();
if (existing) {
// 更新重复调用记录
existing.lastCallTime = now;
existing.callCount++;
this.emit('duplicateCallDetected', existing);
// 如果已有响应,直接返回
if (existing.response) {
return {
@@ -181,7 +181,7 @@ export class RpcReliabilityManager extends EventEmitter {
shouldProcess: false
};
}
// 如果在检查窗口内,认为是重复调用但还在处理中
if (now - existing.firstCallTime < this.config.idempotency.checkWindowTime) {
return {
@@ -190,7 +190,7 @@ export class RpcReliabilityManager extends EventEmitter {
};
}
}
// 记录新的调用
const record: DuplicateCallRecord = {
callId: request.callId,
@@ -200,9 +200,9 @@ export class RpcReliabilityManager extends EventEmitter {
lastCallTime: now,
callCount: 1
};
this.duplicateRecords.set(key, record);
return { isDuplicate: false, shouldProcess: true };
}
@@ -213,10 +213,10 @@ export class RpcReliabilityManager extends EventEmitter {
if (!this.config.idempotency.enabled) {
return;
}
const key = `${request.senderId}:${request.callId}`;
const record = this.duplicateRecords.get(key);
if (record) {
record.response = response;
}
@@ -232,9 +232,9 @@ export class RpcReliabilityManager extends EventEmitter {
if (!this.config.orderedExecution.enabled) {
return handler();
}
const senderId = request.senderId;
return new Promise<RpcCallResponse>((resolve, reject) => {
const queueItem: OrderedQueueItem = {
request,
@@ -243,14 +243,14 @@ export class RpcReliabilityManager extends EventEmitter {
reject,
enqueuedAt: Date.now()
};
// 获取或创建队列
let queue = this.orderedQueues.get(senderId);
if (!queue) {
queue = [];
this.orderedQueues.set(senderId, queue);
}
// 检查队列大小
if (queue.length >= this.config.orderedExecution.maxQueueSize) {
reject({
@@ -259,10 +259,10 @@ export class RpcReliabilityManager extends EventEmitter {
});
return;
}
queue.push(queueItem);
this.emit('orderedCallQueued', request.callId, queue.length);
// 如果没有正在处理的调用,开始处理
if (!this.processingOrdered.has(senderId)) {
this.processOrderedQueue(senderId);
@@ -277,15 +277,15 @@ export class RpcReliabilityManager extends EventEmitter {
if (!this.config.transaction.enabled) {
throw new Error('事务功能未启用');
}
if (this.transactions.has(transactionId)) {
throw new Error(`事务已存在: ${transactionId}`);
}
if (this.transactions.size >= this.config.transaction.maxTransactions) {
throw new Error('超过最大事务数量限制');
}
const transaction: TransactionInfo = {
transactionId,
calls: [],
@@ -293,10 +293,10 @@ export class RpcReliabilityManager extends EventEmitter {
status: 'pending',
rollbackActions: []
};
this.transactions.set(transactionId, transaction);
this.emit('transactionStarted', transactionId);
// 设置事务超时
setTimeout(() => {
if (this.transactions.has(transactionId)) {
@@ -317,13 +317,13 @@ export class RpcReliabilityManager extends EventEmitter {
if (!transaction) {
throw new Error(`事务不存在: ${transactionId}`);
}
if (transaction.status !== 'pending') {
throw new Error(`事务状态无效: ${transaction.status}`);
}
transaction.calls.push(request);
if (rollbackAction) {
transaction.rollbackActions.push(rollbackAction);
}
@@ -337,14 +337,14 @@ export class RpcReliabilityManager extends EventEmitter {
if (!transaction) {
throw new Error(`事务不存在: ${transactionId}`);
}
if (transaction.status !== 'pending') {
throw new Error(`事务状态无效: ${transaction.status}`);
}
transaction.status = 'committed';
this.transactions.delete(transactionId);
this.emit('transactionCommitted', transactionId);
this.logger.info(`事务已提交: ${transactionId},包含 ${transaction.calls.length} 个调用`);
}
@@ -357,13 +357,13 @@ export class RpcReliabilityManager extends EventEmitter {
if (!transaction) {
throw new Error(`事务不存在: ${transactionId}`);
}
if (transaction.status !== 'pending') {
return; // 已经处理过
}
transaction.status = 'rolledback';
// 执行回滚操作
for (const rollbackAction of transaction.rollbackActions.reverse()) {
try {
@@ -372,9 +372,9 @@ export class RpcReliabilityManager extends EventEmitter {
this.logger.error(`回滚操作失败: ${transactionId}`, error);
}
}
this.transactions.delete(transactionId);
this.emit('transactionRolledback', transactionId, reason);
this.logger.warn(`事务已回滚: ${transactionId},原因: ${reason}`);
}
@@ -394,12 +394,12 @@ export class RpcReliabilityManager extends EventEmitter {
activeTransactions: number;
totalQueuedCalls: number;
processingQueues: number;
} {
} {
let totalQueuedCalls = 0;
for (const queue of this.orderedQueues.values()) {
totalQueuedCalls += queue.length;
}
return {
duplicateRecords: this.duplicateRecords.size,
activeTransactions: this.transactions.size,
@@ -432,15 +432,15 @@ export class RpcReliabilityManager extends EventEmitter {
clearInterval(this.cleanupTimer);
this.cleanupTimer = null;
}
// 回滚所有活跃事务
const transactionIds = Array.from(this.transactions.keys());
for (const transactionId of transactionIds) {
this.rollbackTransaction(transactionId, '管理器销毁').catch(error => {
this.rollbackTransaction(transactionId, '管理器销毁').catch((error) => {
this.logger.error(`销毁时回滚事务失败: ${transactionId}`, error);
});
}
// 清理队列
for (const queue of this.orderedQueues.values()) {
for (const item of queue) {
@@ -450,12 +450,12 @@ export class RpcReliabilityManager extends EventEmitter {
});
}
}
this.duplicateRecords.clear();
this.transactions.clear();
this.orderedQueues.clear();
this.processingOrdered.clear();
this.removeAllListeners();
}
@@ -464,17 +464,17 @@ export class RpcReliabilityManager extends EventEmitter {
*/
private async processOrderedQueue(senderId: string): Promise<void> {
this.processingOrdered.add(senderId);
try {
const queue = this.orderedQueues.get(senderId);
if (!queue || queue.length === 0) {
return;
}
while (queue.length > 0) {
const item = queue.shift()!;
const waitTime = Date.now() - item.enqueuedAt;
// 检查等待时间是否超限
if (waitTime > this.config.orderedExecution.maxWaitTime) {
item.reject({
@@ -483,21 +483,21 @@ export class RpcReliabilityManager extends EventEmitter {
});
continue;
}
try {
const response = await item.handler();
item.resolve(response);
this.emit('orderedCallProcessed', item.request.callId, waitTime);
} catch (error) {
item.reject(error as RpcError);
}
}
} finally {
this.processingOrdered.delete(senderId);
// 如果队列还有新的项目,继续处理
const queue = this.orderedQueues.get(senderId);
if (queue && queue.length > 0) {
@@ -520,7 +520,7 @@ export class RpcReliabilityManager extends EventEmitter {
*/
private cleanup(): void {
const now = Date.now();
// 清理过期的重复调用记录
if (this.config.idempotency.enabled) {
for (const [key, record] of this.duplicateRecords) {
@@ -528,20 +528,20 @@ export class RpcReliabilityManager extends EventEmitter {
this.duplicateRecords.delete(key);
}
}
// 限制记录数量
if (this.duplicateRecords.size > this.config.idempotency.maxRecords) {
const sortedRecords = Array.from(this.duplicateRecords.entries())
.sort(([,a], [,b]) => a.lastCallTime - b.lastCallTime);
const keepCount = Math.floor(this.config.idempotency.maxRecords * 0.8);
for (let i = 0; i < sortedRecords.length - keepCount; i++) {
this.duplicateRecords.delete(sortedRecords[i][0]);
}
}
}
// 清理空的有序队列
for (const [senderId, queue] of this.orderedQueues) {
if (queue.length === 0 && !this.processingOrdered.has(senderId)) {
@@ -549,4 +549,4 @@ export class RpcReliabilityManager extends EventEmitter {
}
}
}
}
}

View File

@@ -66,7 +66,7 @@ export class JSONSerializer {
private logger = createLogger('JSONSerializer');
private config: SerializerConfig;
private stats: SerializationStats;
// 性能分析
private serializationTimes: number[] = [];
private deserializationTimes: number[] = [];
@@ -101,7 +101,7 @@ export class JSONSerializer {
*/
serialize<T extends INetworkMessage>(message: T): SerializationResult {
const startTime = performance.now();
try {
// 类型检查
if (this.config.enableTypeChecking) {
@@ -110,10 +110,10 @@ export class JSONSerializer {
// 预处理消息
const processedMessage = this.preprocessMessage(message);
// 序列化
let serializedData: string;
// 使用自定义序列化器
const customSerializer = this.findCustomSerializer(processedMessage);
if (customSerializer) {
@@ -151,17 +151,17 @@ export class JSONSerializer {
*/
deserialize<T extends INetworkMessage>(data: string | ArrayBuffer): DeserializationResult<T> {
const startTime = performance.now();
try {
// 转换数据格式
const jsonString = data instanceof ArrayBuffer ? new TextDecoder().decode(data) :
typeof data === 'string' ? data : String(data);
const jsonString = data instanceof ArrayBuffer ? new TextDecoder().decode(data) :
typeof data === 'string' ? data : String(data);
// 解析JSON
const parsedData = JSON.parse(jsonString, this.createReviver());
// 类型检查
const validationResult = this.config.enableTypeChecking ?
const validationResult = this.config.enableTypeChecking ?
this.validateParsedMessage(parsedData) : { isValid: true, errors: [] };
// 后处理消息
@@ -183,7 +183,7 @@ export class JSONSerializer {
} catch (error) {
this.stats.errorCount++;
this.logger.error('反序列化失败:', error);
return {
data: {} as T,
deserializationTime: performance.now() - startTime,
@@ -198,11 +198,11 @@ export class JSONSerializer {
*/
serializeBatch<T extends INetworkMessage>(messages: T[]): SerializationResult {
const startTime = performance.now();
try {
const batchData = {
type: 'batch',
messages: messages.map(msg => {
messages: messages.map((msg) => {
if (this.config.enableTypeChecking) {
this.validateMessage(msg);
}
@@ -212,7 +212,7 @@ export class JSONSerializer {
};
const serializedData = JSON.stringify(batchData, this.createReplacer());
if (serializedData.length > this.config.maxMessageSize) {
throw new Error(`批量消息大小超过限制: ${serializedData.length} > ${this.config.maxMessageSize}`);
}
@@ -240,7 +240,7 @@ export class JSONSerializer {
*/
deserializeBatch<T extends INetworkMessage>(data: string | ArrayBuffer): DeserializationResult<T[]> {
const result = this.deserialize<any>(data);
if (!result.isValid || !result.data.messages) {
return {
data: [],
@@ -251,7 +251,7 @@ export class JSONSerializer {
}
const messages = result.data.messages.map((msg: any) => this.postprocessMessage(msg));
return {
data: messages as T[],
deserializationTime: result.deserializationTime,
@@ -280,7 +280,7 @@ export class JSONSerializer {
errorCount: 0,
compressionSavings: 0
};
this.serializationTimes.length = 0;
this.deserializationTimes.length = 0;
this.messageSizes.length = 0;
@@ -394,7 +394,7 @@ export class JSONSerializer {
}
return result;
}
return data;
}
@@ -421,7 +421,7 @@ export class JSONSerializer {
}
return result;
}
return data;
}
@@ -477,10 +477,10 @@ export class JSONSerializer {
private updateSerializationStats(size: number, time: number): void {
this.stats.totalSerialized++;
this.stats.totalBytes += size;
this.serializationTimes.push(time);
this.messageSizes.push(size);
// 保持最近1000个样本
if (this.serializationTimes.length > 1000) {
this.serializationTimes.shift();
@@ -488,11 +488,11 @@ export class JSONSerializer {
if (this.messageSizes.length > 1000) {
this.messageSizes.shift();
}
// 计算平均值
this.stats.averageSerializationTime =
this.stats.averageSerializationTime =
this.serializationTimes.reduce((sum, t) => sum + t, 0) / this.serializationTimes.length;
this.stats.averageMessageSize =
this.stats.averageMessageSize =
this.messageSizes.reduce((sum, s) => sum + s, 0) / this.messageSizes.length;
}
@@ -501,16 +501,16 @@ export class JSONSerializer {
*/
private updateDeserializationStats(time: number): void {
this.stats.totalDeserialized++;
this.deserializationTimes.push(time);
// 保持最近1000个样本
if (this.deserializationTimes.length > 1000) {
this.deserializationTimes.shift();
}
// 计算平均值
this.stats.averageDeserializationTime =
this.stats.averageDeserializationTime =
this.deserializationTimes.reduce((sum, t) => sum + t, 0) / this.deserializationTimes.length;
}
@@ -536,10 +536,10 @@ export class JSONSerializer {
*/
private calculatePercentiles(values: number[]) {
if (values.length === 0) return {};
const sorted = [...values].sort((a, b) => a - b);
const n = sorted.length;
return {
p50: sorted[Math.floor(n * 0.5)],
p90: sorted[Math.floor(n * 0.9)],
@@ -547,4 +547,4 @@ export class JSONSerializer {
p99: sorted[Math.floor(n * 0.99)]
};
}
}
}

View File

@@ -14,27 +14,27 @@ export interface ICompressionAlgorithm {
readonly version: string;
/** 是否支持异步压缩 */
readonly supportsAsync: boolean;
/**
* 同步压缩
*/
compress(data: ArrayBuffer): ArrayBuffer;
/**
* 同步解压缩
*/
decompress(data: ArrayBuffer): ArrayBuffer;
/**
* 异步压缩(可选)
*/
compressAsync?(data: ArrayBuffer): Promise<ArrayBuffer>;
/**
* 异步解压缩(可选)
*/
decompressAsync?(data: ArrayBuffer): Promise<ArrayBuffer>;
/**
* 估算压缩后大小(可选)
*/
@@ -124,15 +124,15 @@ export class NoCompressionAlgorithm implements ICompressionAlgorithm {
readonly name = 'none';
readonly version = '1.0.0';
readonly supportsAsync = false;
compress(data: ArrayBuffer): ArrayBuffer {
return data.slice(0);
}
decompress(data: ArrayBuffer): ArrayBuffer {
return data.slice(0);
}
estimateCompressedSize(data: ArrayBuffer): number {
return data.byteLength;
}
@@ -145,39 +145,39 @@ export class LZCompressionAlgorithm implements ICompressionAlgorithm {
readonly name = 'lz-string';
readonly version = '1.0.0';
readonly supportsAsync = false;
compress(data: ArrayBuffer): ArrayBuffer {
// 将ArrayBuffer转换为字符串
const decoder = new TextDecoder();
const input = decoder.decode(data);
if (!input) {
return data.slice(0);
}
// LZ压缩算法
const dictionary: { [key: string]: number } = {};
let dictSize = 256;
// 初始化字典
for (let i = 0; i < 256; i++) {
dictionary[String.fromCharCode(i)] = i;
}
let w = '';
const result: number[] = [];
for (let i = 0; i < input.length; i++) {
const c = input.charAt(i);
const wc = w + c;
if (dictionary[wc] !== undefined) {
w = wc;
} else {
result.push(dictionary[w]);
dictionary[wc] = dictSize++;
w = c;
// 防止字典过大
if (dictSize >= 0xFFFF) {
dictSize = 256;
@@ -190,40 +190,40 @@ export class LZCompressionAlgorithm implements ICompressionAlgorithm {
}
}
}
if (w) {
result.push(dictionary[w]);
}
// 将结果转换为ArrayBuffer
return this.numbersToArrayBuffer(result);
}
decompress(data: ArrayBuffer): ArrayBuffer {
if (data.byteLength === 0) {
return data.slice(0);
}
const numbers = this.arrayBufferToNumbers(data);
if (numbers.length === 0) {
return data.slice(0);
}
const dictionary: { [key: number]: string } = {};
let dictSize = 256;
// 初始化字典
for (let i = 0; i < 256; i++) {
dictionary[i] = String.fromCharCode(i);
}
let w = String.fromCharCode(numbers[0]);
const result = [w];
for (let i = 1; i < numbers.length; i++) {
const k = numbers[i];
let entry: string;
if (dictionary[k] !== undefined) {
entry = dictionary[k];
} else if (k === dictSize) {
@@ -231,11 +231,11 @@ export class LZCompressionAlgorithm implements ICompressionAlgorithm {
} else {
throw new Error('LZ解压缩错误无效的压缩数据');
}
result.push(entry);
dictionary[dictSize++] = w + entry.charAt(0);
w = entry;
// 防止字典过大
if (dictSize >= 0xFFFF) {
dictSize = 256;
@@ -247,26 +247,26 @@ export class LZCompressionAlgorithm implements ICompressionAlgorithm {
}
}
}
// 将结果转换为ArrayBuffer
const output = result.join('');
const encoder = new TextEncoder();
return encoder.encode(output).buffer;
}
estimateCompressedSize(data: ArrayBuffer): number {
// 简单估算假设压缩率在30%-70%之间
const size = data.byteLength;
return Math.floor(size * 0.5); // 50%的估算压缩率
}
/**
* 将数字数组转换为ArrayBuffer
*/
private numbersToArrayBuffer(numbers: number[]): ArrayBuffer {
// 使用变长编码以节省空间
const bytes: number[] = [];
for (const num of numbers) {
if (num < 128) {
// 小于128用1字节
@@ -282,20 +282,20 @@ export class LZCompressionAlgorithm implements ICompressionAlgorithm {
bytes.push((num >> 14) & 0x7F);
}
}
return new Uint8Array(bytes).buffer;
}
/**
* 将ArrayBuffer转换为数字数组
*/
private arrayBufferToNumbers(buffer: ArrayBuffer): number[] {
const bytes = new Uint8Array(buffer);
const numbers: number[] = [];
for (let i = 0; i < bytes.length; i++) {
const byte1 = bytes[i];
if ((byte1 & 0x80) === 0) {
// 单字节数字
numbers.push(byte1);
@@ -303,11 +303,11 @@ export class LZCompressionAlgorithm implements ICompressionAlgorithm {
// 多字节数字
let num = byte1 & 0x7F;
i++;
if (i < bytes.length) {
const byte2 = bytes[i];
num |= (byte2 & 0x7F) << 7;
if ((byte2 & 0x80) !== 0) {
// 三字节数字
i++;
@@ -317,11 +317,11 @@ export class LZCompressionAlgorithm implements ICompressionAlgorithm {
}
}
}
numbers.push(num);
}
}
return numbers;
}
}
@@ -372,10 +372,10 @@ export class MessageCompressor {
if (this.algorithms.has(algorithm.name)) {
this.logger.warn(`压缩算法 '${algorithm.name}' 已存在,将被覆盖`);
}
this.algorithms.set(algorithm.name, algorithm);
this.stats.algorithmUsage[algorithm.name] = 0;
this.logger.info(`注册压缩算法: ${algorithm.name} v${algorithm.version}`);
}
@@ -387,13 +387,13 @@ export class MessageCompressor {
this.logger.warn('无法注销默认的无压缩算法');
return false;
}
const removed = this.algorithms.delete(algorithmName);
if (removed) {
delete this.stats.algorithmUsage[algorithmName];
this.logger.info(`注销压缩算法: ${algorithmName}`);
}
return removed;
}
@@ -415,21 +415,21 @@ export class MessageCompressor {
* 压缩数据
*/
public async compress(
data: ArrayBuffer | string,
data: ArrayBuffer | string,
algorithmName?: string
): Promise<CompressionResult> {
const startTime = performance.now();
// 转换输入数据
const inputBuffer = typeof data === 'string'
? new TextEncoder().encode(data).buffer
const inputBuffer = typeof data === 'string'
? new TextEncoder().encode(data).buffer
: data;
const originalSize = inputBuffer.byteLength;
// 选择压缩算法
const selectedAlgorithm = algorithmName || this.config.defaultAlgorithm;
const algorithm = this.algorithms.get(selectedAlgorithm);
if (!algorithm) {
throw new Error(`未找到压缩算法: ${selectedAlgorithm}`);
}
@@ -459,9 +459,9 @@ export class MessageCompressor {
// 更新统计信息
if (this.config.enableStats) {
this.updateCompressionStats(
selectedAlgorithm,
originalSize,
compressedSize,
selectedAlgorithm,
originalSize,
compressedSize,
compressionTime
);
}
@@ -494,12 +494,12 @@ export class MessageCompressor {
* 解压缩数据
*/
public async decompress(
data: ArrayBuffer,
data: ArrayBuffer,
algorithmName: string
): Promise<DecompressionResult> {
const startTime = performance.now();
const compressedSize = data.byteLength;
const algorithm = this.algorithms.get(algorithmName);
if (!algorithm) {
throw new Error(`未找到解压缩算法: ${algorithmName}`);
@@ -549,12 +549,12 @@ export class MessageCompressor {
* 估算压缩后大小
*/
public estimateCompressedSize(
data: ArrayBuffer,
data: ArrayBuffer,
algorithmName?: string
): number {
const selectedAlgorithm = algorithmName || this.config.defaultAlgorithm;
const algorithm = this.algorithms.get(selectedAlgorithm);
if (!algorithm) {
return data.byteLength;
}
@@ -614,9 +614,9 @@ export class MessageCompressor {
* 更新压缩统计信息
*/
private updateCompressionStats(
algorithmName: string,
originalSize: number,
compressedSize: number,
algorithmName: string,
originalSize: number,
compressedSize: number,
compressionTime: number
): void {
this.stats.totalCompressions++;
@@ -625,13 +625,13 @@ export class MessageCompressor {
this.stats.algorithmUsage[algorithmName]++;
// 更新平均压缩比
this.stats.averageCompressionRatio = this.stats.totalOriginalBytes > 0
? this.stats.totalCompressedBytes / this.stats.totalOriginalBytes
this.stats.averageCompressionRatio = this.stats.totalOriginalBytes > 0
? this.stats.totalCompressedBytes / this.stats.totalOriginalBytes
: 1.0;
// 更新平均压缩时间
this.stats.averageCompressionTime =
(this.stats.averageCompressionTime * (this.stats.totalCompressions - 1) + compressionTime)
this.stats.averageCompressionTime =
(this.stats.averageCompressionTime * (this.stats.totalCompressions - 1) + compressionTime)
/ this.stats.totalCompressions;
}
@@ -642,8 +642,8 @@ export class MessageCompressor {
this.stats.totalDecompressions++;
// 更新平均解压缩时间
this.stats.averageDecompressionTime =
(this.stats.averageDecompressionTime * (this.stats.totalDecompressions - 1) + decompressionTime)
this.stats.averageDecompressionTime =
(this.stats.averageDecompressionTime * (this.stats.totalDecompressions - 1) + decompressionTime)
/ this.stats.totalDecompressions;
}
}
@@ -651,4 +651,4 @@ export class MessageCompressor {
/**
* 全局压缩器实例
*/
export const globalCompressor = new MessageCompressor();
export const globalCompressor = new MessageCompressor();

View File

@@ -107,19 +107,19 @@ export class SyncVarSerializer {
public serializeSyncBatch(batch: SyncBatch): SerializationResult {
try {
const startTime = performance.now();
// 准备序列化数据
let dataToSerialize: any = batch;
// 应用差量同步
if (this.config.enableDeltaSync) {
dataToSerialize = this.applyDeltaCompression(batch);
}
// 基础JSON序列化
const jsonString = JSON.stringify(dataToSerialize, this.replacer.bind(this));
const originalSize = new TextEncoder().encode(jsonString).length;
// 检查消息大小限制
if (originalSize > this.config.maxMessageSize) {
return {
@@ -130,10 +130,10 @@ export class SyncVarSerializer {
compressionRatio: 0
};
}
let finalData: ArrayBuffer | string = jsonString;
let compressedSize = originalSize;
// 应用压缩
if (this.config.enableCompression && originalSize > 256) {
const compressionResult = this.compress(jsonString);
@@ -142,9 +142,9 @@ export class SyncVarSerializer {
compressedSize = compressionResult.data.byteLength;
}
}
const compressionRatio = originalSize > 0 ? compressedSize / originalSize : 1;
return {
success: true,
data: finalData,
@@ -152,7 +152,7 @@ export class SyncVarSerializer {
compressedSize,
compressionRatio
};
} catch (error) {
return {
success: false,
@@ -170,7 +170,7 @@ export class SyncVarSerializer {
public deserializeSyncBatch(data: ArrayBuffer | string): DeserializationResult<SyncBatch> {
try {
let jsonString: string;
// 解压缩
if (data instanceof ArrayBuffer) {
const decompressResult = this.decompress(data);
@@ -185,10 +185,10 @@ export class SyncVarSerializer {
} else {
jsonString = data;
}
// JSON反序列化
const parsedData = JSON.parse(jsonString, this.reviver.bind(this));
// 类型检查
if (this.config.enableTypeChecking) {
const typeCheckResult = this.validateSyncBatchType(parsedData);
@@ -200,19 +200,19 @@ export class SyncVarSerializer {
};
}
}
// 应用差量还原
let finalData = parsedData;
if (this.config.enableDeltaSync && this.isDeltaData(parsedData)) {
finalData = this.applyDeltaRestore(parsedData);
}
return {
success: true,
data: finalData as SyncBatch,
isValidType: true
};
} catch (error) {
return {
success: false,
@@ -227,7 +227,7 @@ export class SyncVarSerializer {
*/
public createSyncMessage(batch: SyncBatch, senderId: string): INetworkMessage {
const serializedData = this.serializeSyncBatch(batch);
return {
type: MessageType.SYNC_BATCH,
messageId: this.generateMessageId(),
@@ -250,7 +250,7 @@ export class SyncVarSerializer {
isValidType: false
};
}
return this.deserializeSyncBatch(message.data);
}
@@ -293,7 +293,7 @@ export class SyncVarSerializer {
private applyDeltaCompression(batch: SyncBatch): DeltaData | SyncBatch {
const key = batch.instanceId;
const lastRecord = this.deltaHistory.get(key);
if (!lastRecord) {
// 第一次同步,存储完整数据
this.deltaHistory.set(key, {
@@ -302,18 +302,18 @@ export class SyncVarSerializer {
});
return batch;
}
// 计算差量
const changes: { [key: string]: any } = {};
const deletions: string[] = [];
// 检查变化的属性
for (const [prop, value] of Object.entries(batch.changes)) {
if (!lastRecord.data.changes || lastRecord.data.changes[prop] !== value) {
changes[prop] = value;
}
}
// 检查删除的属性
if (lastRecord.data.changes) {
for (const prop of Object.keys(lastRecord.data.changes)) {
@@ -322,7 +322,7 @@ export class SyncVarSerializer {
}
}
}
// 如果没有变化,返回空的差量数据
if (Object.keys(changes).length === 0 && deletions.length === 0) {
return {
@@ -332,14 +332,14 @@ export class SyncVarSerializer {
deletions: []
};
}
// 更新历史记录
const currentVersion = ++this.versionCounter;
this.deltaHistory.set(key, {
version: currentVersion,
data: { ...batch }
});
return {
baseVersion: lastRecord.version,
currentVersion,
@@ -370,7 +370,7 @@ export class SyncVarSerializer {
* 检查是否为差量数据
*/
private isDeltaData(data: any): data is DeltaData {
return data &&
return data &&
typeof data.baseVersion === 'number' &&
typeof data.currentVersion === 'number' &&
typeof data.changes === 'object' &&
@@ -386,7 +386,7 @@ export class SyncVarSerializer {
const compressed = this.lzCompress(data);
const encoder = new TextEncoder();
const bytes = encoder.encode(compressed);
return {
success: true,
data: bytes.buffer
@@ -404,7 +404,7 @@ export class SyncVarSerializer {
const decoder = new TextDecoder();
const compressedString = decoder.decode(data);
const decompressed = this.lzDecompress(compressedString);
return {
success: true,
data: decompressed
@@ -422,20 +422,20 @@ export class SyncVarSerializer {
if (value instanceof Date) {
return { __type: 'Date', value: value.toISOString() };
}
if (value instanceof Map) {
return { __type: 'Map', value: Array.from(value.entries()) };
}
if (value instanceof Set) {
return { __type: 'Set', value: Array.from(value) };
}
// 处理BigInt
if (typeof value === 'bigint') {
return { __type: 'BigInt', value: value.toString() };
}
return value;
}
@@ -455,7 +455,7 @@ export class SyncVarSerializer {
return BigInt(value.value);
}
}
return value;
}
@@ -464,28 +464,28 @@ export class SyncVarSerializer {
*/
private validateSyncBatchType(data: any): { isValid: boolean; errors: string[] } {
const errors: string[] = [];
if (!data || typeof data !== 'object') {
errors.push('数据不是对象');
return { isValid: false, errors };
}
if (typeof data.instanceId !== 'string') {
errors.push('instanceId必须是字符串');
}
if (typeof data.instanceType !== 'string') {
errors.push('instanceType必须是字符串');
}
if (!data.changes || typeof data.changes !== 'object') {
errors.push('changes必须是对象');
}
if (typeof data.timestamp !== 'number') {
errors.push('timestamp必须是数字');
}
return { isValid: errors.length === 0, errors };
}
@@ -505,7 +505,7 @@ export class SyncVarSerializer {
if (priorities.length === 0) {
return 5; // 默认优先级
}
// 使用最高优先级
return Math.max(...priorities);
}
@@ -515,22 +515,22 @@ export class SyncVarSerializer {
*/
private lzCompress(input: string): string {
if (!input) return '';
const dictionary: { [key: string]: number } = {};
let dictSize = 256;
// 初始化字典
for (let i = 0; i < 256; i++) {
dictionary[String.fromCharCode(i)] = i;
}
let w = '';
const result: number[] = [];
for (let i = 0; i < input.length; i++) {
const c = input.charAt(i);
const wc = w + c;
if (dictionary[wc] !== undefined) {
w = wc;
} else {
@@ -539,11 +539,11 @@ export class SyncVarSerializer {
w = c;
}
}
if (w) {
result.push(dictionary[w]);
}
// 将结果编码为Base64以确保字符串安全
return this.arrayToBase64(result);
}
@@ -553,25 +553,25 @@ export class SyncVarSerializer {
*/
private lzDecompress(compressed: string): string {
if (!compressed) return '';
const data = this.base64ToArray(compressed);
if (data.length === 0) return '';
const dictionary: { [key: number]: string } = {};
let dictSize = 256;
// 初始化字典
for (let i = 0; i < 256; i++) {
dictionary[i] = String.fromCharCode(i);
}
let w = String.fromCharCode(data[0]);
const result = [w];
for (let i = 1; i < data.length; i++) {
const k = data[i];
let entry: string;
if (dictionary[k] !== undefined) {
entry = dictionary[k];
} else if (k === dictSize) {
@@ -579,12 +579,12 @@ export class SyncVarSerializer {
} else {
throw new Error('解压缩错误:无效的压缩数据');
}
result.push(entry);
dictionary[dictSize++] = w + entry.charAt(0);
w = entry;
}
return result.join('');
}
@@ -602,7 +602,7 @@ export class SyncVarSerializer {
bytes.push(255, num - 255);
}
}
// 转换为字符串然后编码为Base64
const binaryString = String.fromCharCode(...bytes);
return btoa(binaryString);
@@ -615,11 +615,11 @@ export class SyncVarSerializer {
try {
const binaryString = atob(base64);
const bytes: number[] = [];
for (let i = 0; i < binaryString.length; i++) {
bytes.push(binaryString.charCodeAt(i));
}
// 还原原始数字数组
const result: number[] = [];
for (let i = 0; i < bytes.length; i++) {
@@ -630,10 +630,10 @@ export class SyncVarSerializer {
result.push(bytes[i]);
}
}
return result;
} catch (error) {
throw new Error('Base64解码失败');
}
}
}
}

View File

@@ -89,19 +89,19 @@ export interface DeltaSyncStats {
export class DeltaSync {
private logger = createLogger('DeltaSync');
private config: DeltaSyncConfig;
/** 版本历史 */
private versionHistory = new Map<string, Map<number, VersionedData>>();
/** 版本计数器 */
private versionCounters = new Map<string, number>();
/** 差量缓存 */
private deltaCache = new Map<string, DeltaData>();
/** 待合并操作 */
private pendingOperations = new Map<string, DeltaOperation[]>();
/** 统计信息 */
private stats: DeltaSyncStats = {
totalDeltas: 0,
@@ -111,7 +111,7 @@ export class DeltaSync {
cacheHitRate: 0,
mergedOperations: 0
};
/** 合并定时器 */
private mergeTimers = new Map<string, any>();
@@ -134,7 +134,7 @@ export class DeltaSync {
if (!this.config.enabled) {
return 0;
}
const version = this.getNextVersion(instanceId);
const versionedData: VersionedData = {
version,
@@ -142,7 +142,7 @@ export class DeltaSync {
data: this.deepClone(data),
checksum: this.calculateChecksum(data)
};
this.storeVersion(instanceId, versionedData);
return version;
}
@@ -154,14 +154,14 @@ export class DeltaSync {
if (!this.config.enabled) {
return null;
}
const history = this.versionHistory.get(instanceId);
if (!history || history.size === 0) {
// 没有基线,记录第一个版本
this.recordBaseline(instanceId, newData);
return null;
}
// 选择基线版本
let baseVersionData: VersionedData;
if (baseVersion !== undefined) {
@@ -185,16 +185,16 @@ export class DeltaSync {
}
baseVersionData = latestVersion;
}
const targetVersion = this.getNextVersion(instanceId);
const changes = this.computeChanges(baseVersionData.data, newData);
const deletions = this.computeDeletions(baseVersionData.data, newData);
// 检查是否有变化
if (Object.keys(changes).length === 0 && deletions.length === 0) {
return null;
}
const deltaData: DeltaData = {
baseVersion: baseVersionData.version,
targetVersion,
@@ -206,13 +206,13 @@ export class DeltaSync {
compressionRatio: 1
}
};
// 记录新版本
this.recordBaseline(instanceId, newData);
// 更新统计
this.updateStats(deltaData);
return deltaData;
}
@@ -223,32 +223,32 @@ export class DeltaSync {
if (!this.config.enabled) {
return null;
}
const history = this.versionHistory.get(instanceId);
if (!history) {
this.logger.error(`实例 ${instanceId} 没有版本历史`);
return null;
}
const baseData = history.get(delta.baseVersion);
if (!baseData) {
this.logger.error(`未找到基线版本 ${delta.baseVersion}`);
return null;
}
// 复制基线数据
const result = this.deepClone(baseData.data);
// 应用变化
for (const [key, value] of Object.entries(delta.changes)) {
this.setNestedProperty(result, key, value);
}
// 应用删除
for (const key of delta.deletions) {
this.deleteNestedProperty(result, key);
}
// 记录结果版本
const resultVersion: VersionedData = {
version: delta.targetVersion,
@@ -256,9 +256,9 @@ export class DeltaSync {
data: this.deepClone(result),
checksum: this.calculateChecksum(result)
};
this.storeVersion(instanceId, resultVersion);
return result;
}
@@ -269,13 +269,13 @@ export class DeltaSync {
if (!this.config.enableSmartMerging || operations.length <= 1) {
return operations;
}
const pathMap = new Map<string, DeltaOperation>();
// 按路径分组操作
for (const op of operations) {
const existing = pathMap.get(op.path);
if (!existing) {
pathMap.set(op.path, op);
} else {
@@ -285,9 +285,9 @@ export class DeltaSync {
this.stats.mergedOperations++;
}
}
// 过滤掉NOOP操作
return Array.from(pathMap.values()).filter(op => op.type !== DeltaOperationType.NOOP);
return Array.from(pathMap.values()).filter((op) => op.type !== DeltaOperationType.NOOP);
}
/**
@@ -297,25 +297,25 @@ export class DeltaSync {
if (!this.config.enableSmartMerging) {
return;
}
let operations = this.pendingOperations.get(instanceId);
if (!operations) {
operations = [];
this.pendingOperations.set(instanceId, operations);
}
operations.push(operation);
// 重置合并定时器
const existingTimer = this.mergeTimers.get(instanceId);
if (existingTimer) {
clearTimeout(existingTimer);
}
const timer = setTimeout(() => {
this.flushPendingOperations(instanceId);
}, this.config.mergeWindow);
this.mergeTimers.set(instanceId, timer);
}
@@ -326,14 +326,14 @@ export class DeltaSync {
if (delta.metadata.size < this.config.compressionThreshold) {
return delta;
}
// 简化的压缩实现
const compressedChanges = this.compressObject(delta.changes);
const compressedDeletions = delta.deletions; // 删除操作通常已经很紧凑
const originalSize = delta.metadata.size;
const compressedSize = this.estimateSize(compressedChanges) + this.estimateSize(compressedDeletions);
return {
...delta,
changes: compressedChanges,
@@ -351,34 +351,34 @@ export class DeltaSync {
*/
public cleanup(): void {
const now = Date.now();
for (const [instanceId, history] of this.versionHistory) {
const versionsToDelete: number[] = [];
for (const [version, versionData] of history) {
// 检查超时
if (now - versionData.timestamp > this.config.versionTimeout) {
versionsToDelete.push(version);
}
}
// 保留最新的几个版本
const sortedVersions = Array.from(history.keys()).sort((a, b) => b - a);
const toKeep = sortedVersions.slice(0, this.config.maxHistoryVersions);
for (const version of versionsToDelete) {
if (!toKeep.includes(version)) {
history.delete(version);
}
}
// 如果实例没有版本了,删除实例
if (history.size === 0) {
this.versionHistory.delete(instanceId);
this.versionCounters.delete(instanceId);
}
}
// 清理差量缓存
this.deltaCache.clear();
}
@@ -419,7 +419,7 @@ export class DeltaSync {
for (const timer of this.mergeTimers.values()) {
clearTimeout(timer);
}
this.versionHistory.clear();
this.versionCounters.clear();
this.deltaCache.clear();
@@ -446,9 +446,9 @@ export class DeltaSync {
history = new Map();
this.versionHistory.set(instanceId, history);
}
history.set(versionData.version, versionData);
// 限制历史版本数量
if (history.size > this.config.maxHistoryVersions) {
const oldestVersion = Math.min(...Array.from(history.keys()));
@@ -464,7 +464,7 @@ export class DeltaSync {
if (!history || history.size === 0) {
return undefined;
}
const latestVersion = Math.max(...Array.from(history.keys()));
return history.get(latestVersion);
}
@@ -474,15 +474,15 @@ export class DeltaSync {
*/
private computeChanges(oldData: any, newData: any): { [key: string]: any } {
const changes: { [key: string]: any } = {};
for (const [key, newValue] of Object.entries(newData)) {
const oldValue = oldData[key];
if (!this.deepEqual(oldValue, newValue)) {
changes[key] = newValue;
}
}
return changes;
}
@@ -491,13 +491,13 @@ export class DeltaSync {
*/
private computeDeletions(oldData: any, newData: any): string[] {
const deletions: string[] = [];
for (const key of Object.keys(oldData)) {
if (!(key in newData)) {
deletions.push(key);
}
}
return deletions;
}
@@ -539,7 +539,7 @@ export class DeltaSync {
}
// 检查是否值回到了原始状态
if (op1.type === DeltaOperationType.MODIFY &&
if (op1.type === DeltaOperationType.MODIFY &&
op2.type === DeltaOperationType.MODIFY &&
this.deepEqual(op1.oldValue, op2.newValue)) {
// 值回到原始状态 = 无操作
@@ -563,10 +563,10 @@ export class DeltaSync {
if (!operations || operations.length === 0) {
return;
}
// 合并操作并发送
this.mergeOperations(instanceId, operations);
// 清理待处理操作
this.pendingOperations.delete(instanceId);
this.mergeTimers.delete(instanceId);
@@ -582,7 +582,7 @@ export class DeltaSync {
// 移除null和undefined值
const compressed: any = Array.isArray(obj) ? [] : {};
for (const [key, value] of Object.entries(obj)) {
if (value !== null && value !== undefined) {
if (typeof value === 'object') {
@@ -603,19 +603,19 @@ export class DeltaSync {
if (obj === null || obj === undefined) {
return 4; // "null"的长度
}
if (typeof obj === 'string') {
return obj.length * 2; // UTF-16字符估算
}
if (typeof obj === 'number') {
return 8; // 64位数字
}
if (typeof obj === 'boolean') {
return 4; // true/false
}
if (Array.isArray(obj)) {
let size = 2; // []
for (const item of obj) {
@@ -623,7 +623,7 @@ export class DeltaSync {
}
return size;
}
if (typeof obj === 'object') {
let size = 2; // {}
for (const [key, value] of Object.entries(obj)) {
@@ -632,7 +632,7 @@ export class DeltaSync {
}
return size;
}
return JSON.stringify(obj).length;
}
@@ -643,28 +643,28 @@ export class DeltaSync {
if (obj === null || obj === undefined) {
return obj;
}
if (typeof obj !== 'object') {
return obj;
}
if (obj instanceof Date) {
return new Date(obj.getTime());
}
if (obj instanceof RegExp) {
return new RegExp(obj);
}
if (Array.isArray(obj)) {
return obj.map(item => this.deepClone(item));
return obj.map((item) => this.deepClone(item));
}
const cloned: any = {};
for (const [key, value] of Object.entries(obj)) {
cloned[key] = this.deepClone(value);
}
return cloned;
}
@@ -675,27 +675,27 @@ export class DeltaSync {
if (obj1 === obj2) {
return true;
}
if (obj1 === null || obj2 === null || obj1 === undefined || obj2 === undefined) {
return obj1 === obj2;
}
if (typeof obj1 !== typeof obj2) {
return false;
}
if (typeof obj1 !== 'object') {
return obj1 === obj2;
}
if (obj1 instanceof Date && obj2 instanceof Date) {
return obj1.getTime() === obj2.getTime();
}
if (Array.isArray(obj1) !== Array.isArray(obj2)) {
return false;
}
if (Array.isArray(obj1)) {
if (obj1.length !== obj2.length) {
return false;
@@ -707,14 +707,14 @@ export class DeltaSync {
}
return true;
}
const keys1 = Object.keys(obj1);
const keys2 = Object.keys(obj2);
if (keys1.length !== keys2.length) {
return false;
}
for (const key of keys1) {
if (!keys2.includes(key)) {
return false;
@@ -723,7 +723,7 @@ export class DeltaSync {
return false;
}
}
return true;
}
@@ -733,7 +733,7 @@ export class DeltaSync {
private setNestedProperty(obj: any, path: string, value: any): void {
const keys = path.split('.');
let current = obj;
for (let i = 0; i < keys.length - 1; i++) {
const key = keys[i];
if (!(key in current)) {
@@ -741,7 +741,7 @@ export class DeltaSync {
}
current = current[key];
}
current[keys[keys.length - 1]] = value;
}
@@ -751,7 +751,7 @@ export class DeltaSync {
private deleteNestedProperty(obj: any, path: string): void {
const keys = path.split('.');
let current = obj;
for (let i = 0; i < keys.length - 1; i++) {
const key = keys[i];
if (!(key in current)) {
@@ -759,7 +759,7 @@ export class DeltaSync {
}
current = current[key];
}
delete current[keys[keys.length - 1]];
}
@@ -770,13 +770,13 @@ export class DeltaSync {
// 简化的校验和实现
const str = JSON.stringify(obj);
let hash = 0;
for (let i = 0; i < str.length; i++) {
const char = str.charCodeAt(i);
hash = ((hash << 5) - hash) + char;
hash = hash & hash; // 转换为32位整数
}
return hash.toString(16);
}
@@ -787,8 +787,8 @@ export class DeltaSync {
this.stats.totalDeltas++;
this.stats.totalSize += delta.metadata.size;
this.stats.averageDeltaSize = this.stats.totalSize / this.stats.totalDeltas;
this.stats.compressionRatio =
(this.stats.compressionRatio * (this.stats.totalDeltas - 1) + delta.metadata.compressionRatio) /
this.stats.compressionRatio =
(this.stats.compressionRatio * (this.stats.totalDeltas - 1) + delta.metadata.compressionRatio) /
this.stats.totalDeltas;
}
}
}

View File

@@ -1,8 +1,6 @@
import {
getSyncVarMetadata,
getDirtySyncVars,
clearDirtyFlags,
SyncVarMetadata,
import {
getDirtySyncVars,
clearDirtyFlags,
hasSyncVars,
SyncVarValue
} from '../decorators/SyncVar';
@@ -68,19 +66,19 @@ export interface SyncVarManagerEvents {
*/
export class SyncVarManager extends EventEmitter {
private static instance: SyncVarManager | null = null;
/** 注册的实例映射 */
private registeredInstances = new Map<string, object>();
/** 脏实例集合 */
private dirtyInstances = new Set<string>();
/** 实例ID计数器 */
private instanceIdCounter = 0;
/** 实例ID映射 */
private instanceIdMap = new WeakMap<any, string>();
/** 统计信息 */
private stats: SyncStats = {
registeredInstances: 0,
@@ -91,19 +89,19 @@ export class SyncVarManager extends EventEmitter {
syncsPerSecond: 0,
lastSyncTime: 0
};
/** 自动同步定时器 */
private autoSyncTimer: ReturnType<typeof setInterval> | null = null;
/** 同步频率(毫秒) */
private syncRate = 100;
/** 是否启用自动同步 */
private autoSyncEnabled = true;
/** 最大批次大小 */
private maxBatchSize = 100;
/** 立即同步请求队列 */
private immediateSyncQueue = new Set<{ instanceId: string; propertyKey?: string | symbol }>();
@@ -137,14 +135,14 @@ export class SyncVarManager extends EventEmitter {
// 生成新的实例ID
const instanceId = `syncvar_${++this.instanceIdCounter}`;
// 注册实例
this.registeredInstances.set(instanceId, instance);
this.instanceIdMap.set(instance, instanceId);
// 更新统计
this.stats.registeredInstances = this.registeredInstances.size;
this.emit('instanceRegistered', instanceId, instance);
return instanceId;
}
@@ -162,11 +160,11 @@ export class SyncVarManager extends EventEmitter {
this.registeredInstances.delete(instanceId);
this.instanceIdMap.delete(instance);
this.dirtyInstances.delete(instanceId);
// 更新统计
this.stats.registeredInstances = this.registeredInstances.size;
this.stats.dirtyInstances = this.dirtyInstances.size;
this.emit('instanceUnregistered', instanceId);
return true;
}
@@ -197,7 +195,7 @@ export class SyncVarManager extends EventEmitter {
this.markInstanceDirty(instance);
this.immediateSyncQueue.add({ instanceId, propertyKey });
// 立即处理同步
this.processImmediateSyncs();
}
@@ -207,10 +205,10 @@ export class SyncVarManager extends EventEmitter {
*/
public syncNow(): SyncBatch[] {
const batches: SyncBatch[] = [];
// 处理立即同步请求
this.processImmediateSyncs();
// 收集所有脏实例的数据
for (const instanceId of this.dirtyInstances) {
const batch = this.createSyncBatch(instanceId);
@@ -218,14 +216,14 @@ export class SyncVarManager extends EventEmitter {
batches.push(batch);
}
}
// 清理脏标记
this.clearAllDirtyFlags();
// 更新统计
this.stats.totalSyncs += batches.length;
this.stats.lastSyncTime = Date.now();
return batches;
}
@@ -369,7 +367,7 @@ export class SyncVarManager extends EventEmitter {
}
const batches: SyncBatch[] = [];
for (const request of this.immediateSyncQueue) {
const batch = this.createSyncBatch(request.instanceId);
if (batch && Object.keys(batch.changes).length > 0) {
@@ -413,7 +411,7 @@ export class SyncVarManager extends EventEmitter {
clearDirtyFlags(instance);
}
}
this.dirtyInstances.clear();
this.stats.dirtyInstances = 0;
}
@@ -461,4 +459,4 @@ export class SyncVarManager extends EventEmitter {
// 全局单例访问
if (typeof window !== 'undefined') {
(window as any).SyncVarManager = SyncVarManager.getInstance();
}
}

View File

@@ -3,4 +3,4 @@
*/
export * from './SyncVarManager';
export * from './DeltaSync';
export * from './DeltaSync';

View File

@@ -67,11 +67,11 @@ export class ErrorHandler {
private config: ErrorHandlerConfig;
private stats: ErrorStats;
private eventHandlers: Partial<ErrorHandlerEvents> = {};
// 错误恢复状态
private retryAttempts: Map<string, number> = new Map();
private pendingRecoveries: Set<string> = new Set();
// 错误分类规则
private severityRules: Map<NetworkErrorType, ErrorSeverity> = new Map();
private recoveryRules: Map<NetworkErrorType, RecoveryStrategy> = new Map();
@@ -105,10 +105,10 @@ export class ErrorHandler {
handleError(error: Error | INetworkError, context?: string): void {
const networkError = this.normalizeError(error, context);
const severity = this.classifyErrorSeverity(networkError);
// 更新统计
this.updateStats(networkError, severity);
this.logger.error(`网络错误 [${severity}]: ${networkError.message}`, {
type: networkError.type,
code: networkError.code,
@@ -237,7 +237,7 @@ export class ErrorHandler {
*/
private determineErrorType(error: Error): NetworkErrorType {
const message = error.message.toLowerCase();
if (message.includes('timeout')) {
return NetworkErrorType.TIMEOUT;
} else if (message.includes('connection')) {
@@ -270,18 +270,18 @@ export class ErrorHandler {
case NetworkErrorType.CONNECTION_FAILED:
case NetworkErrorType.CONNECTION_LOST:
return ErrorSeverity.High;
case NetworkErrorType.AUTHENTICATION_FAILED:
case NetworkErrorType.PERMISSION_DENIED:
return ErrorSeverity.Critical;
case NetworkErrorType.TIMEOUT:
case NetworkErrorType.RATE_LIMITED:
return ErrorSeverity.Medium;
case NetworkErrorType.INVALID_MESSAGE:
return ErrorSeverity.Low;
default:
return ErrorSeverity.Medium;
}
@@ -307,7 +307,7 @@ export class ErrorHandler {
}
const errorId = this.generateErrorId(error);
// 检查是否已经在恢复中
if (this.pendingRecoveries.has(errorId)) {
return;
@@ -339,8 +339,8 @@ export class ErrorHandler {
* 执行恢复策略
*/
private executeRecoveryStrategy(
error: INetworkError,
strategy: RecoveryStrategy,
error: INetworkError,
strategy: RecoveryStrategy,
errorId: string
): void {
try {
@@ -349,17 +349,17 @@ export class ErrorHandler {
// 这里应该重试导致错误的操作
// 具体实现需要外部提供重试回调
break;
case RecoveryStrategy.Reconnect:
// 这里应该触发重连
// 具体实现需要外部处理
break;
case RecoveryStrategy.Restart:
// 这里应该重启相关服务
// 具体实现需要外部处理
break;
case RecoveryStrategy.Escalate:
// 上报错误给上层处理
this.logger.error('错误需要上层处理:', error);
@@ -368,7 +368,7 @@ export class ErrorHandler {
this.pendingRecoveries.delete(errorId);
this.eventHandlers.errorRecovered?.(error, strategy);
} catch (recoveryError) {
this.logger.error('错误恢复失败:', recoveryError);
this.pendingRecoveries.delete(errorId);
@@ -458,4 +458,4 @@ export class ErrorHandler {
return { trend: 'stable', recommendation: '错误处理正常' };
}
}
}
}

View File

@@ -55,16 +55,16 @@ export class HeartbeatManager {
private config: HeartbeatConfig;
private status: HeartbeatStatus;
private eventHandlers: Partial<HeartbeatEvents> = {};
// 定时器
private heartbeatTimer?: number;
private timeoutTimer?: number;
// 延迟测量
private pendingPings: Map<number, number> = new Map();
private latencyHistory: number[] = [];
private sequence = 0;
// 统计信息
private sentCount = 0;
private receivedCount = 0;
@@ -119,10 +119,10 @@ export class HeartbeatManager {
const now = Date.now();
this.status.lastHeartbeat = now;
this.receivedCount++;
// 重置丢失心跳计数
this.status.missedHeartbeats = 0;
// 计算延迟
if (this.config.enableLatencyMeasurement && message.sequence !== undefined) {
const sentTime = this.pendingPings.get(message.sequence);
@@ -130,14 +130,14 @@ export class HeartbeatManager {
const latency = now - sentTime;
this.updateLatency(latency);
this.pendingPings.delete(message.sequence);
this.eventHandlers.heartbeatReceived?.(latency);
}
}
// 更新健康状态
this.updateHealthStatus(true);
// 停止超时定时器
this.stopTimeoutTimer();
}
@@ -148,10 +148,10 @@ export class HeartbeatManager {
handleHeartbeatTimeout(): void {
this.status.missedHeartbeats++;
this.logger.warn(`心跳超时,丢失次数: ${this.status.missedHeartbeats}`);
// 触发超时事件
this.eventHandlers.heartbeatTimeout?.(this.status.missedHeartbeats);
// 检查是否达到最大丢失次数
if (this.status.missedHeartbeats >= this.config.maxMissedHeartbeats) {
this.updateHealthStatus(false);
@@ -169,9 +169,9 @@ export class HeartbeatManager {
* 获取统计信息
*/
getStats() {
const packetLoss = this.sentCount > 0 ?
const packetLoss = this.sentCount > 0 ?
((this.sentCount - this.receivedCount) / this.sentCount) * 100 : 0;
return {
sentCount: this.sentCount,
receivedCount: this.receivedCount,
@@ -211,7 +211,7 @@ export class HeartbeatManager {
updateConfig(newConfig: Partial<HeartbeatConfig>): void {
Object.assign(this.config, newConfig);
this.logger.info('心跳配置已更新:', newConfig);
// 重启定时器以应用新配置
if (this.heartbeatTimer) {
this.stop();
@@ -270,7 +270,7 @@ export class HeartbeatManager {
const now = Date.now();
const sequence = this.config.enableLatencyMeasurement ? ++this.sequence : undefined;
const message: HeartbeatMessage = {
type: MessageType.HEARTBEAT,
clientTime: now,
@@ -280,21 +280,21 @@ export class HeartbeatManager {
try {
this.sendHeartbeat(message);
this.sentCount++;
// 记录发送时间用于延迟计算
if (sequence !== undefined) {
this.pendingPings.set(sequence, now);
// 清理过期的pending pings
this.cleanupPendingPings();
}
// 启动超时定时器
this.stopTimeoutTimer();
this.startTimeoutTimer();
this.eventHandlers.heartbeatSent?.(now);
} catch (error) {
this.logger.error('发送心跳失败:', error);
}
@@ -305,16 +305,16 @@ export class HeartbeatManager {
*/
private updateLatency(latency: number): void {
this.status.latency = latency;
// 保存延迟历史最多100个样本
this.latencyHistory.push(latency);
if (this.latencyHistory.length > 100) {
this.latencyHistory.shift();
}
// 计算平均延迟
this.status.averageLatency = this.latencyHistory.reduce((sum, lat) => sum + lat, 0) / this.latencyHistory.length;
this.logger.debug(`延迟更新: ${latency}ms, 平均: ${this.status.averageLatency?.toFixed(1)}ms`);
}
@@ -335,7 +335,7 @@ export class HeartbeatManager {
private cleanupPendingPings(): void {
const now = Date.now();
const timeout = this.config.timeout * 2; // 清理超过2倍超时时间的记录
for (const [sequence, sentTime] of this.pendingPings) {
if (now - sentTime > timeout) {
this.pendingPings.delete(sequence);
@@ -363,8 +363,8 @@ export class HeartbeatManager {
isConnectionHealthy(): boolean {
const now = Date.now();
const timeSinceLastHeartbeat = now - this.status.lastHeartbeat;
return this.status.isHealthy &&
return this.status.isHealthy &&
timeSinceLastHeartbeat <= this.config.timeout &&
this.status.missedHeartbeats < this.config.maxMissedHeartbeats;
}
@@ -378,4 +378,4 @@ export class HeartbeatManager {
const multiplier = Math.min(Math.pow(2, this.status.missedHeartbeats), 8);
return baseDelay * multiplier;
}
}
}

View File

@@ -10,29 +10,29 @@ export enum MessageType {
CONNECT = 'connect',
DISCONNECT = 'disconnect',
HEARTBEAT = 'heartbeat',
// 数据同步
SYNC_VAR = 'sync_var',
SYNC_BATCH = 'sync_batch',
SYNC_SNAPSHOT = 'sync_snapshot',
// RPC调用
RPC_CALL = 'rpc_call',
RPC_RESPONSE = 'rpc_response',
// 实体管理
ENTITY_CREATE = 'entity_create',
ENTITY_DESTROY = 'entity_destroy',
ENTITY_UPDATE = 'entity_update',
// 房间管理
JOIN_ROOM = 'join_room',
LEAVE_ROOM = 'leave_room',
ROOM_STATE = 'room_state',
// 游戏事件
GAME_EVENT = 'game_event',
// 系统消息
ERROR = 'error',
WARNING = 'warning',
@@ -248,4 +248,4 @@ export interface INetworkError {
code?: number;
details?: any;
timestamp: number;
}
}

View File

@@ -183,7 +183,7 @@ export interface RpcStats {
/**
* RPC方法签名类型
*/
export type RpcMethod<TArgs extends readonly unknown[] = readonly unknown[], TReturn = unknown> =
export type RpcMethod<TArgs extends readonly unknown[] = readonly unknown[], TReturn = unknown> =
(...args: TArgs) => Promise<TReturn>;
/**
@@ -211,4 +211,4 @@ export type ServerRpcInvoker = <TArgs extends readonly unknown[], TReturn>(
methodName: string,
args: TArgs,
options?: Partial<RpcOptions>
) => Promise<TReturn>;
) => Promise<TReturn>;

View File

@@ -225,4 +225,4 @@ export interface ITransportConfig {
cert?: string;
key?: string;
};
}
}

View File

@@ -25,7 +25,7 @@ export class EventEmitter extends Emitter<string | symbol, void> {
/**
* 添加一次性事件监听器
* @param event 事件名称
* @param event 事件名称
* @param listener 监听函数
*/
public once(event: string | symbol, listener: Function): this {
@@ -82,4 +82,4 @@ export class EventEmitter extends Emitter<string | symbol, void> {
super.emit(event, ...args);
return true;
}
}
}

View File

@@ -1,4 +1,4 @@
/**
* 网络层工具类
*/
export * from './EventEmitter';
export * from './EventEmitter';