实现ServerRpc和ClientRpc装饰器
This commit is contained in:
345
packages/network-shared/src/rpc/RpcMetadataManager.ts
Normal file
345
packages/network-shared/src/rpc/RpcMetadataManager.ts
Normal file
@@ -0,0 +1,345 @@
|
||||
import { createLogger } from '@esengine/ecs-framework';
|
||||
import { EventEmitter } from '../utils/EventEmitter';
|
||||
import { RpcMethodMetadata, RpcMethodRegistry } from '../types/RpcTypes';
|
||||
import { getRpcMethods, RpcMethodValidator } from '../decorators/RpcDecorators';
|
||||
|
||||
/**
|
||||
* RPC元数据管理器事件
|
||||
*/
|
||||
export interface RpcMetadataManagerEvents {
|
||||
methodRegistered: (metadata: RpcMethodMetadata) => void;
|
||||
methodUnregistered: (methodName: string) => void;
|
||||
classRegistered: (className: string, methodCount: number) => void;
|
||||
classUnregistered: (className: string) => void;
|
||||
}
|
||||
|
||||
/**
|
||||
* RPC元数据管理器
|
||||
* 负责管理所有RPC方法的元数据和注册信息
|
||||
*/
|
||||
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>();
|
||||
|
||||
/**
|
||||
* 注册RPC类
|
||||
*/
|
||||
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);
|
||||
if (!validation.valid) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 注销RPC类
|
||||
*/
|
||||
public unregisterClass(classNameOrInstance: string | object): void {
|
||||
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}`;
|
||||
this.registry.delete(fullMethodName);
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取RPC方法元数据
|
||||
*/
|
||||
public getMethodMetadata(methodName: string): RpcMethodMetadata | undefined {
|
||||
const entry = this.registry.get(methodName);
|
||||
return entry?.metadata;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取RPC方法处理器
|
||||
*/
|
||||
public getMethodHandler(methodName: string): Function | undefined {
|
||||
const entry = this.registry.get(methodName);
|
||||
return entry?.handler;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查方法是否存在
|
||||
*/
|
||||
public hasMethod(methodName: string): boolean {
|
||||
return this.registry.has(methodName);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有服务端RPC方法
|
||||
*/
|
||||
public getServerRpcMethods(): RpcMethodMetadata[] {
|
||||
const methods: RpcMethodMetadata[] = [];
|
||||
|
||||
for (const [, entry] of this.registry) {
|
||||
if (entry.metadata.isServerRpc) {
|
||||
methods.push(entry.metadata);
|
||||
}
|
||||
}
|
||||
|
||||
return methods;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有客户端RPC方法
|
||||
*/
|
||||
public getClientRpcMethods(): RpcMethodMetadata[] {
|
||||
const methods: RpcMethodMetadata[] = [];
|
||||
|
||||
for (const [, entry] of this.registry) {
|
||||
if (!entry.metadata.isServerRpc) {
|
||||
methods.push(entry.metadata);
|
||||
}
|
||||
}
|
||||
|
||||
return methods;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取类的所有RPC方法
|
||||
*/
|
||||
public getClassMethods(className: string): RpcMethodMetadata[] {
|
||||
const methodNames = this.classMethods.get(className);
|
||||
if (!methodNames) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const methods: RpcMethodMetadata[] = [];
|
||||
|
||||
for (const methodName of methodNames) {
|
||||
const fullMethodName = `${className}.${methodName}`;
|
||||
const entry = this.registry.get(fullMethodName);
|
||||
if (entry) {
|
||||
methods.push(entry.metadata);
|
||||
}
|
||||
}
|
||||
|
||||
return methods;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取已注册的类名列表
|
||||
*/
|
||||
public getRegisteredClasses(): string[] {
|
||||
return Array.from(this.classMethods.keys());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有已注册的方法名
|
||||
*/
|
||||
public getAllMethodNames(): string[] {
|
||||
return Array.from(this.registry.keys());
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据方法名获取所属类
|
||||
*/
|
||||
public getMethodClass(methodName: string): string | undefined {
|
||||
return this.methodToClass.get(methodName);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取类实例
|
||||
*/
|
||||
public getClassInstance(className: string): object | undefined {
|
||||
return this.instances.get(className);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取注册统计信息
|
||||
*/
|
||||
public getStats(): {
|
||||
totalMethods: number;
|
||||
serverRpcMethods: number;
|
||||
clientRpcMethods: number;
|
||||
registeredClasses: number;
|
||||
} {
|
||||
let serverRpcCount = 0;
|
||||
let clientRpcCount = 0;
|
||||
|
||||
for (const [, entry] of this.registry) {
|
||||
if (entry.metadata.isServerRpc) {
|
||||
serverRpcCount++;
|
||||
} else {
|
||||
clientRpcCount++;
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
totalMethods: this.registry.size,
|
||||
serverRpcMethods: serverRpcCount,
|
||||
clientRpcMethods: clientRpcCount,
|
||||
registeredClasses: this.classMethods.size
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证方法调用
|
||||
*/
|
||||
public validateMethodCall(
|
||||
methodName: string,
|
||||
args: unknown[],
|
||||
callerId?: string
|
||||
): { valid: boolean; error?: string } {
|
||||
const metadata = this.getMethodMetadata(methodName);
|
||||
if (!metadata) {
|
||||
return {
|
||||
valid: false,
|
||||
error: `RPC方法不存在: ${methodName}`
|
||||
};
|
||||
}
|
||||
|
||||
return RpcMethodValidator.validateCall(metadata, args, callerId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 搜索方法
|
||||
*/
|
||||
public searchMethods(query: {
|
||||
className?: string;
|
||||
isServerRpc?: boolean;
|
||||
requireAuth?: boolean;
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 清空所有注册
|
||||
*/
|
||||
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注册');
|
||||
}
|
||||
|
||||
/**
|
||||
* 销毁管理器
|
||||
*/
|
||||
public destroy(): void {
|
||||
this.clear();
|
||||
this.removeAllListeners();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user