From d936af9793596dfad714c7d8a5043e7aabbd8609 Mon Sep 17 00:00:00 2001 From: tone Date: Tue, 2 Dec 2025 15:03:33 +0800 Subject: [PATCH] feat: add RPCContext --- __tests__/e2e/rpc-context.test.ts | 41 +++++++++++++++++++++++++++++++ src/core/RPCContext.ts | 27 ++++++++++++++++++++ src/core/RPCSession.ts | 10 +++++++- 3 files changed, 77 insertions(+), 1 deletion(-) create mode 100644 __tests__/e2e/rpc-context.test.ts create mode 100644 src/core/RPCContext.ts diff --git a/__tests__/e2e/rpc-context.test.ts b/__tests__/e2e/rpc-context.test.ts new file mode 100644 index 0000000..98f2a99 --- /dev/null +++ b/__tests__/e2e/rpc-context.test.ts @@ -0,0 +1,41 @@ +import { getRPCContext, RPCContextKey } from "@/core/RPCContext"; +import { RPCHandler, RPCSession } from "@/index" +import { getRandomAvailablePort } from "@/utils/utils"; + +describe('rpc-context.test', () => { + test('context.session', async () => { + const accessed = new WeakMap(); + const provider = { + login(name: string) { + const context = getRPCContext(this); + if (!context) { + throw new Error('context is null'); + } + + accessed.set(context.session, name); + return name; + }, + me() { + const context = getRPCContext(this); + if (!context) { + throw new Error('context is null'); + } + + return accessed.get(context.session) || 'unknown user'; + }, + } + + const server = new RPCHandler(); + const client = new RPCHandler(); + + server.setProvider(provider); + const port = await getRandomAvailablePort(); + await server.listen({ port }); + + const session = await client.connect({ url: `http://localhost:${port}` }); + const api = session.getAPI(); + const clientname = 'clientname'; + await expect(api.login(clientname)).resolves.toBe(clientname); + await expect(api.me()).resolves.toBe(clientname); + }) +}) \ No newline at end of file diff --git a/src/core/RPCContext.ts b/src/core/RPCContext.ts new file mode 100644 index 0000000..89ede25 --- /dev/null +++ b/src/core/RPCContext.ts @@ -0,0 +1,27 @@ +import { isObject } from "@/utils/utils"; +import { RPCSession } from "./RPCSession"; + +export interface RPCContext { + session: RPCSession; +} + +export const RPCContextFlag = Symbol(); +export const RPCContextKey = '__rpc_context'; + +export class RPCContextConstractor { + public [RPCContextKey] = RPCContextFlag; + constructor(public session: RPCSession) { } +} + +export const getRPCContext = (self: unknown): RPCContext | null => { + if (!isObject(self)) { + return null; + } + + const rpcContext = self[RPCContextKey]; + if (!isObject(rpcContext) || rpcContext[RPCContextKey] !== RPCContextFlag) { + return null; + } + + return rpcContext as unknown as RPCContext; +} \ No newline at end of file diff --git a/src/core/RPCSession.ts b/src/core/RPCSession.ts index 8c66044..9285fb0 100644 --- a/src/core/RPCSession.ts +++ b/src/core/RPCSession.ts @@ -9,6 +9,7 @@ import { makeCallPacket, makeCallResponsePacket, parseCallPacket, parseCallRespo import { RPCPacket } from "./RPCPacket"; import { EventEmitter } from "@/utils/EventEmitter"; import { createHookRunner } from "./RPCPlugin"; +import { RPCContextConstractor, RPCContextKey } from "./RPCContext"; function getProviderFunction(provider: RPCProvider, fnPath: string): [(...args: any[]) => Promise, object] | null { @@ -372,7 +373,14 @@ export class RPCSession { } try { - const result = await fn.bind(fnThis)(...args); + const result = await fn.bind(new Proxy(fnThis, { + get(target, p, receiver) { + if (p === RPCContextKey) { + return new RPCContextConstractor(instance); + } + return Reflect.get(target, p, receiver); + }, + }))(...args); return makeResponse({ status: 'success', requestPacket: packet,