Commit 12b95982 authored by nanahira's avatar nanahira

room thing

parent f51e04d7
...@@ -19,12 +19,13 @@ ...@@ -19,12 +19,13 @@
"pino": "^10.3.1", "pino": "^10.3.1",
"pino-pretty": "^13.1.3", "pino-pretty": "^13.1.3",
"rxjs": "^7.8.2", "rxjs": "^7.8.2",
"typed-reflector": "^1.0.14",
"ws": "^8.19.0", "ws": "^8.19.0",
"yaml": "^2.8.2", "yaml": "^2.8.2",
"ygopro-cdb-encode": "^1.0.1", "ygopro-cdb-encode": "^1.0.1",
"ygopro-deck-encode": "^1.0.15", "ygopro-deck-encode": "^1.0.15",
"ygopro-lflist-encode": "^1.0.3", "ygopro-lflist-encode": "^1.0.3",
"ygopro-msg-encode": "^1.1.8", "ygopro-msg-encode": "^1.1.9",
"ygopro-yrp-encode": "^1.0.1" "ygopro-yrp-encode": "^1.0.1"
}, },
"devDependencies": { "devDependencies": {
...@@ -74,6 +75,7 @@ ...@@ -74,6 +75,7 @@
"integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==", "integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"@babel/code-frame": "^7.29.0", "@babel/code-frame": "^7.29.0",
"@babel/generator": "^7.29.0", "@babel/generator": "^7.29.0",
...@@ -1600,6 +1602,7 @@ ...@@ -1600,6 +1602,7 @@
"resolved": "https://registry.npmjs.org/@types/node/-/node-25.2.3.tgz", "resolved": "https://registry.npmjs.org/@types/node/-/node-25.2.3.tgz",
"integrity": "sha512-m0jEgYlYz+mDJZ2+F4v8D1AyQb+QzsNqRuI7xg1VQX/KlKS0qT9r1Mo16yo5F/MtifXFgaofIFsdFMox2SxIbQ==", "integrity": "sha512-m0jEgYlYz+mDJZ2+F4v8D1AyQb+QzsNqRuI7xg1VQX/KlKS0qT9r1Mo16yo5F/MtifXFgaofIFsdFMox2SxIbQ==",
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"undici-types": "~7.16.0" "undici-types": "~7.16.0"
} }
...@@ -1683,6 +1686,7 @@ ...@@ -1683,6 +1686,7 @@
"integrity": "sha512-4z2nCSBfVIMnbuu8uinj+f0o4qOeggYJLbjpPHka3KH1om7e+H9yLKTYgksTaHcGco+NClhhY2vyO3HsMH1RGw==", "integrity": "sha512-4z2nCSBfVIMnbuu8uinj+f0o4qOeggYJLbjpPHka3KH1om7e+H9yLKTYgksTaHcGco+NClhhY2vyO3HsMH1RGw==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"@typescript-eslint/scope-manager": "8.55.0", "@typescript-eslint/scope-manager": "8.55.0",
"@typescript-eslint/types": "8.55.0", "@typescript-eslint/types": "8.55.0",
...@@ -2163,6 +2167,7 @@ ...@@ -2163,6 +2167,7 @@
"integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"bin": { "bin": {
"acorn": "bin/acorn" "acorn": "bin/acorn"
}, },
...@@ -2553,6 +2558,7 @@ ...@@ -2553,6 +2558,7 @@
} }
], ],
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"baseline-browser-mapping": "^2.9.0", "baseline-browser-mapping": "^2.9.0",
"caniuse-lite": "^1.0.30001759", "caniuse-lite": "^1.0.30001759",
...@@ -3213,6 +3219,7 @@ ...@@ -3213,6 +3219,7 @@
"deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/eslint-utils": "^4.2.0",
"@eslint-community/regexpp": "^4.6.1", "@eslint-community/regexpp": "^4.6.1",
...@@ -3269,6 +3276,7 @@ ...@@ -3269,6 +3276,7 @@
"integrity": "sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w==", "integrity": "sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"bin": { "bin": {
"eslint-config-prettier": "bin/cli.js" "eslint-config-prettier": "bin/cli.js"
}, },
...@@ -4139,6 +4147,7 @@ ...@@ -4139,6 +4147,7 @@
"resolved": "https://registry.npmjs.org/ioredis/-/ioredis-5.9.2.tgz", "resolved": "https://registry.npmjs.org/ioredis/-/ioredis-5.9.2.tgz",
"integrity": "sha512-tAAg/72/VxOUW7RQSX1pIxJVucYKcjFjfvj60L57jrZpYCHC3XN0WCQ3sNYL4Gmvv+7GPvTAjc+KSdeNuE8oWQ==", "integrity": "sha512-tAAg/72/VxOUW7RQSX1pIxJVucYKcjFjfvj60L57jrZpYCHC3XN0WCQ3sNYL4Gmvv+7GPvTAjc+KSdeNuE8oWQ==",
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"@ioredis/commands": "1.5.0", "@ioredis/commands": "1.5.0",
"cluster-key-slot": "^1.1.0", "cluster-key-slot": "^1.1.0",
...@@ -4383,6 +4392,7 @@ ...@@ -4383,6 +4392,7 @@
"integrity": "sha512-F26gjC0yWN8uAA5m5Ss8ZQf5nDHWGlN/xWZIh8S5SRbsEKBovwZhxGd6LJlbZYxBgCYOtreSUyb8hpXyGC5O4A==", "integrity": "sha512-F26gjC0yWN8uAA5m5Ss8ZQf5nDHWGlN/xWZIh8S5SRbsEKBovwZhxGd6LJlbZYxBgCYOtreSUyb8hpXyGC5O4A==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"@jest/core": "30.2.0", "@jest/core": "30.2.0",
"@jest/types": "30.2.0", "@jest/types": "30.2.0",
...@@ -5788,6 +5798,7 @@ ...@@ -5788,6 +5798,7 @@
"integrity": "sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==", "integrity": "sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"bin": { "bin": {
"prettier": "bin/prettier.cjs" "prettier": "bin/prettier.cjs"
}, },
...@@ -6636,6 +6647,7 @@ ...@@ -6636,6 +6647,7 @@
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"engines": { "engines": {
"node": ">=12" "node": ">=12"
}, },
...@@ -6788,6 +6800,7 @@ ...@@ -6788,6 +6800,7 @@
"integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"peer": true,
"dependencies": { "dependencies": {
"@cspotcode/source-map-support": "^0.8.0", "@cspotcode/source-map-support": "^0.8.0",
"@tsconfig/node10": "^1.0.7", "@tsconfig/node10": "^1.0.7",
...@@ -6897,6 +6910,7 @@ ...@@ -6897,6 +6910,7 @@
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
"dev": true, "dev": true,
"license": "Apache-2.0", "license": "Apache-2.0",
"peer": true,
"bin": { "bin": {
"tsc": "bin/tsc", "tsc": "bin/tsc",
"tsserver": "bin/tsserver" "tsserver": "bin/tsserver"
...@@ -7346,9 +7360,9 @@ ...@@ -7346,9 +7360,9 @@
} }
}, },
"node_modules/ygopro-msg-encode": { "node_modules/ygopro-msg-encode": {
"version": "1.1.8", "version": "1.1.9",
"resolved": "https://registry.npmjs.org/ygopro-msg-encode/-/ygopro-msg-encode-1.1.8.tgz", "resolved": "https://registry.npmjs.org/ygopro-msg-encode/-/ygopro-msg-encode-1.1.9.tgz",
"integrity": "sha512-KrGUuyRLftmiD51KNRs/IRInsw+Xz/ISlCTmg+2W+6VLD6MtO9qF9SgBI78tXJ4/zsxifYekSDYfMuzJf2PuUA==", "integrity": "sha512-sY/jveNdcN25pcTsf8MpC0hvZnNQ2vTpIjuVhP3zjAZw8Uw8+8kEqTZSFEnnpS4QAmu3QYSEaFH1Rb0CfG2jFA==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"typed-reflector": "^1.0.14", "typed-reflector": "^1.0.14",
......
...@@ -3,7 +3,7 @@ import { ConfigService } from './services/config'; ...@@ -3,7 +3,7 @@ import { ConfigService } from './services/config';
import { Logger } from './services/logger'; import { Logger } from './services/logger';
import { Emitter } from './services/emitter'; import { Emitter } from './services/emitter';
import { SSLFinder } from './services/ssl-finder'; import { SSLFinder } from './services/ssl-finder';
import { ClientHandler } from './services/client-handler'; import { ClientHandler } from './client/client-handler';
import { IpResolver } from './services/ip-resolver'; import { IpResolver } from './services/ip-resolver';
import { HttpClient } from './services/http-client'; import { HttpClient } from './services/http-client';
import { Chnroute } from './services/chnroute'; import { Chnroute } from './services/chnroute';
...@@ -14,6 +14,7 @@ import { WsServer } from './transport/ws/server'; ...@@ -14,6 +14,7 @@ import { WsServer } from './transport/ws/server';
import { ClientVersionCheck } from './services/client-version-check'; import { ClientVersionCheck } from './services/client-version-check';
import { AragamiService } from './services/aragami'; import { AragamiService } from './services/aragami';
import { RoomManager } from './room/room-manager'; import { RoomManager } from './room/room-manager';
import { RoomEventRegister } from './room/room-event-register';
import { DefaultHostInfoProvider } from './room/default-hostinfo-provder'; import { DefaultHostInfoProvider } from './room/default-hostinfo-provder';
import { YGOProResourceLoader } from './services/ygopro-resource-loader'; import { YGOProResourceLoader } from './services/ygopro-resource-loader';
...@@ -41,6 +42,7 @@ export const app = core ...@@ -41,6 +42,7 @@ export const app = core
.provide(DefaultHostInfoProvider) .provide(DefaultHostInfoProvider)
.provide(YGOProResourceLoader) .provide(YGOProResourceLoader)
.provide(RoomManager) .provide(RoomManager)
.provide(RoomEventRegister)
.define(); .define();
app.middleware(YGOProCtosJoinGame, async (msg, client, _next) => { app.middleware(YGOProCtosJoinGame, async (msg, client, _next) => {
......
...@@ -6,8 +6,8 @@ import { ...@@ -6,8 +6,8 @@ import {
YGOProCtosPlayerInfo, YGOProCtosPlayerInfo,
} from 'ygopro-msg-encode'; } from 'ygopro-msg-encode';
import { Context } from '../app'; import { Context } from '../app';
import { Client } from '../client'; import { Client } from './client';
import { IpResolver } from './ip-resolver'; import { IpResolver } from '../services/ip-resolver';
import { WsClient } from '../transport/ws/client'; import { WsClient } from '../transport/ws/client';
import { forkJoin, filter, takeUntil, timeout, firstValueFrom } from 'rxjs'; import { forkJoin, filter, takeUntil, timeout, firstValueFrom } from 'rxjs';
......
import { filter, merge, Observable, Subject } from 'rxjs'; import { filter, merge, Observable, Subject } from 'rxjs';
import { map, share, take, takeUntil } from 'rxjs/operators'; import { map, share, take, takeUntil } from 'rxjs/operators';
import { Context } from './app'; import { Context } from '../app';
import { import {
YGOProCtos, YGOProCtos,
YGOProStocBase, YGOProStocBase,
...@@ -13,9 +13,9 @@ import { ...@@ -13,9 +13,9 @@ import {
YGOProStocHsPlayerChange, YGOProStocHsPlayerChange,
PlayerChangeState, PlayerChangeState,
} from 'ygopro-msg-encode'; } from 'ygopro-msg-encode';
import { YGOProProtoPipe } from './utility/ygopro-proto-pipe'; import { YGOProProtoPipe } from '../utility/ygopro-proto-pipe';
import { I18nService } from './services/i18n'; import { I18nService } from '../services/i18n';
import { Chnroute } from './services/chnroute'; import { Chnroute } from '../services/chnroute';
import YGOProDeck from 'ygopro-deck-encode'; import YGOProDeck from 'ygopro-deck-encode';
export abstract class Client { export abstract class Client {
...@@ -124,6 +124,7 @@ export abstract class Client { ...@@ -124,6 +124,7 @@ export abstract class Client {
established = false; established = false;
// in room // in room
roomName?: string;
isHost = false; isHost = false;
pos = -1; pos = -1;
deck?: YGOProDeck; deck?: YGOProDeck;
......
import 'reflect-metadata';
import { Context } from '../app';
import { getSpecificFields } from '../utility/metadata';
import { Room } from './room';
import { Client } from '../client/client';
import { YGOProCtosBase } from 'ygopro-msg-encode';
import { RoomManager } from './room-manager';
export class RoomEventRegister {
private logger = this.ctx.createLogger('RoomEventRegister');
constructor(private ctx: Context) {
this.registerRoomEvents();
}
private registerRoomEvents() {
const roomMethods = getSpecificFields('roomMethod', Room);
for (const { key: method } of roomMethods) {
// 获取方法的参数类型
const paramTypes: any[] =
Reflect.getMetadata('design:paramtypes', Room.prototype, method) || [];
// 如果找不到参数类型,输出警告
if (!paramTypes || paramTypes.length === 0) {
this.logger.warn(
`Method ${method} has no parameter types metadata. Make sure tsconfig has "emitDecoratorMetadata": true`,
);
continue;
}
// 查找 Client 类型的参数和 YGOProCtosBase 派生类的参数
let clientParamIndex = -1;
let ctosParamIndex = -1;
let ctosParamType: any = null;
for (let i = 0; i < paramTypes.length; i++) {
const paramType = paramTypes[i];
if (paramType === Client) {
clientParamIndex = i;
} else if (paramType && paramType.prototype instanceof YGOProCtosBase) {
ctosParamIndex = i;
ctosParamType = paramType;
}
}
// 如果没有 YGOProCtosBase 派生类参数,跳过
if (ctosParamIndex === -1 || !ctosParamType) {
continue;
}
// 注册 middleware
this.ctx.middleware(ctosParamType, async (msg, client, next) => {
// 如果 client 没有关联的 room,直接跳过
if (!client.roomName) {
return next();
}
// 通过 roomName 查找 room
const roomManager = this.ctx.get(() => RoomManager);
const room = roomManager.findByName(client.roomName);
if (!room) {
return next();
}
// 构造参数数组
const args = new Array(paramTypes.length);
for (let i = 0; i < paramTypes.length; i++) {
if (i === clientParamIndex) {
args[i] = client;
} else if (i === ctosParamIndex) {
args[i] = msg;
}
}
// 调用 Room 实例的方法
await (room as any)[method](...args);
return next();
});
}
}
}
...@@ -10,7 +10,7 @@ import { DefaultHostInfoProvider } from './default-hostinfo-provder'; ...@@ -10,7 +10,7 @@ import { DefaultHostInfoProvider } from './default-hostinfo-provder';
import { CardReaderFinalized } from 'koishipro-core.js'; import { CardReaderFinalized } from 'koishipro-core.js';
import { YGOProResourceLoader } from '../services/ygopro-resource-loader'; import { YGOProResourceLoader } from '../services/ygopro-resource-loader';
import { blankLFList } from '../utility/blank-lflist'; import { blankLFList } from '../utility/blank-lflist';
import { Client } from '../client'; import { Client } from '../client/client';
export type RoomFinalizor = (self: Room) => Awaitable<any>; export type RoomFinalizor = (self: Room) => Awaitable<any>;
...@@ -93,6 +93,7 @@ export class Room { ...@@ -93,6 +93,7 @@ export class Room {
} }
async join(client: Client) { async join(client: Client) {
client.roomName = this.name;
client.disconnect$.subscribe(({ bySystem }) => client.disconnect$.subscribe(({ bySystem }) =>
this.onPlayerDisconnect(client, bySystem), this.onPlayerDisconnect(client, bySystem),
); );
...@@ -122,7 +123,7 @@ export class Room { ...@@ -122,7 +123,7 @@ export class Room {
} }
} }
async onPlayerDisconnect(client: Client, bySystem: boolean) { async onPlayerDisconnect(client: Client) {
if (client.pos === NetPlayerType.OBSERVER) { if (client.pos === NetPlayerType.OBSERVER) {
this.watchers.delete(client); this.watchers.delete(client);
for (const p of this.allPlayers) { for (const p of this.allPlayers) {
...@@ -130,5 +131,6 @@ export class Room { ...@@ -130,5 +131,6 @@ export class Room {
} }
return; return;
} }
client.roomName = undefined;
} }
} }
import { AppContext, ProtoMiddlewareDispatcher } from 'nfkit'; import { AppContext, ProtoMiddlewareDispatcher } from 'nfkit';
import { Client } from '../client'; import { Client } from '../client/client';
export class Emitter extends ProtoMiddlewareDispatcher<[Client]> { export class Emitter extends ProtoMiddlewareDispatcher<[Client]> {
constructor(private ctx: AppContext) { constructor(private ctx: AppContext) {
......
import { Context } from '../app'; import { Context } from '../app';
import { Client } from '../client'; import { Client } from '../client/client';
import * as ipaddr from 'ipaddr.js'; import * as ipaddr from 'ipaddr.js';
import { convertStringArray } from '../utility/convert-string-array'; import { convertStringArray } from '../utility/convert-string-array';
......
...@@ -2,7 +2,7 @@ import { Socket } from 'node:net'; ...@@ -2,7 +2,7 @@ import { Socket } from 'node:net';
import { Observable, fromEvent, merge } from 'rxjs'; import { Observable, fromEvent, merge } from 'rxjs';
import { map, take } from 'rxjs/operators'; import { map, take } from 'rxjs/operators';
import { Context } from '../../app'; import { Context } from '../../app';
import { Client } from '../../client'; import { Client } from '../../client/client';
export class TcpClient extends Client { export class TcpClient extends Client {
constructor( constructor(
......
import { Server as NetServer, Socket, createServer } from 'node:net'; import { Server as NetServer, Socket, createServer } from 'node:net';
import { Context } from '../../app'; import { Context } from '../../app';
import { ClientHandler } from '../../services/client-handler'; import { ClientHandler } from '../../client/client-handler';
import { TcpClient } from './client'; import { TcpClient } from './client';
export class TcpServer { export class TcpServer {
......
...@@ -4,7 +4,7 @@ import { Observable, fromEvent, merge } from 'rxjs'; ...@@ -4,7 +4,7 @@ import { Observable, fromEvent, merge } from 'rxjs';
import { map, take } from 'rxjs/operators'; import { map, take } from 'rxjs/operators';
import WebSocket, { RawData } from 'ws'; import WebSocket, { RawData } from 'ws';
import { Context } from '../../app'; import { Context } from '../../app';
import { Client } from '../../client'; import { Client } from '../../client/client';
export class WsClient extends Client { export class WsClient extends Client {
constructor( constructor(
......
...@@ -2,7 +2,7 @@ import { IncomingMessage, createServer as createHttpServer } from 'node:http'; ...@@ -2,7 +2,7 @@ import { IncomingMessage, createServer as createHttpServer } from 'node:http';
import { createServer as createHttpsServer } from 'node:https'; import { createServer as createHttpsServer } from 'node:https';
import { Server as WebSocketServer } from 'ws'; import { Server as WebSocketServer } from 'ws';
import { Context } from '../../app'; import { Context } from '../../app';
import { ClientHandler } from '../../services/client-handler'; import { ClientHandler } from '../../client/client-handler';
import { SSLFinder } from '../../services/ssl-finder'; import { SSLFinder } from '../../services/ssl-finder';
import { WsClient } from './client'; import { WsClient } from './client';
import { WebSocket } from 'ws'; import { WebSocket } from 'ws';
...@@ -67,7 +67,8 @@ export class WsServer { ...@@ -67,7 +67,8 @@ export class WsServer {
private handleConnection(ws: WebSocket, req: IncomingMessage): void { private handleConnection(ws: WebSocket, req: IncomingMessage): void {
const client = new WsClient(this.ctx, ws, req); const client = new WsClient(this.ctx, ws, req);
if (this.ctx.get(() => IpResolver).setClientIp(client, client.xffIp())) return; if (this.ctx.get(() => IpResolver).setClientIp(client, client.xffIp()))
return;
client.hostname = req.headers.host?.split(':')[0] || ''; client.hostname = req.headers.host?.split(':')[0] || '';
const handler = this.ctx.get(() => ClientHandler); const handler = this.ctx.get(() => ClientHandler);
handler.handleClient(client).catch((err) => { handler.handleClient(client).catch((err) => {
......
import { Metadata } from './metadata';
export const RoomMethod = () =>
Metadata.set('roomMethod', true, 'roomMethodKeys');
import { MetadataSetter, Reflector } from 'typed-reflector';
interface MetadataMap {
roomMethod: boolean;
}
type MetadataArrayMap = {
[K in keyof MetadataMap as `${K & string}Keys`]: string;
};
export const Metadata = new MetadataSetter<MetadataMap, MetadataArrayMap>();
export const reflector = new Reflector<MetadataMap, MetadataArrayMap>();
export function getSpecificFields<K extends keyof MetadataMap>(
key: K,
target: any,
): { key: string; metadata: MetadataMap[K] }[] {
const arrayKey = `${key}Keys` as keyof MetadataArrayMap;
const keys = reflector.getArray(arrayKey, target);
return keys
.map((k) => ({
key: k,
metadata: reflector.get(key, target, k),
}))
.filter((item) => item.metadata !== undefined) as {
key: string;
metadata: MetadataMap[K];
}[];
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment