Skip to content

Commit 50c65f5

Browse files
committed
feat(core): add getCurrentRpcSession support on node side
1 parent cc24a53 commit 50c65f5

File tree

6 files changed

+108
-19
lines changed

6 files changed

+108
-19
lines changed
Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
1-
import type { DevToolsNodeContext, DevToolsRpcClientFunctions, DevToolsRpcServerFunctions, RpcFunctionsHost as RpcFunctionsHostType } from '@vitejs/devtools-kit'
1+
import type { DevToolsNodeContext, DevToolsNodeRpcSession, DevToolsRpcClientFunctions, DevToolsRpcServerFunctions, RpcFunctionsHost as RpcFunctionsHostType } from '@vitejs/devtools-kit'
22
import type { BirpcGroup } from 'birpc'
3+
import type { AsyncLocalStorage } from 'node:async_hooks'
34
import { RpcFunctionsCollectorBase } from 'birpc-x'
45

56
export class RpcFunctionsHost extends RpcFunctionsCollectorBase<DevToolsRpcServerFunctions, DevToolsNodeContext> implements RpcFunctionsHostType {
67
/**
78
* @internal
89
*/
9-
rpcGroup: BirpcGroup<DevToolsRpcClientFunctions, DevToolsRpcServerFunctions, false> = undefined!
10+
_rpcGroup: BirpcGroup<DevToolsRpcClientFunctions, DevToolsRpcServerFunctions, false> = undefined!
11+
_asyncStorage: AsyncLocalStorage<DevToolsNodeRpcSession> = undefined!
1012

1113
constructor(context: DevToolsNodeContext) {
1214
super(context)
@@ -19,9 +21,15 @@ export class RpcFunctionsHost extends RpcFunctionsCollectorBase<DevToolsRpcServe
1921
name: T,
2022
...args: Args
2123
): Promise<(Awaited<ReturnType<DevToolsRpcClientFunctions[T]>> | undefined)[]> {
22-
if (!this.rpcGroup)
23-
throw new Error('RpcFunctionsHost.rpcGroup is not set, it likely to be an internal bug of Vite DevTools')
24+
if (!this._rpcGroup)
25+
throw new Error('RpcFunctionsHost] RpcGroup is not set, it likely to be an internal bug of Vite DevTools')
2426
// @ts-expect-error - BirpcGroup.broadcast.$callOptional is not typed correctly
25-
return this.rpcGroup.broadcast.$callOptional<T>(name, ...args)
27+
return this._rpcGroup.broadcast.$callOptional<T>(name, ...args)
28+
}
29+
30+
getCurrentRpcSession(): DevToolsNodeRpcSession | undefined {
31+
if (!this._asyncStorage)
32+
throw new Error('RpcFunctionsHost] AsyncLocalStorage is not set, it likely to be an internal bug of Vite DevTools')
33+
return this._asyncStorage.getStore()
2634
}
2735
}

packages/core/src/node/rpc/internal/docks-list.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,14 @@ export const docksList = defineRpcFunction({
1818
]
1919

2020
return {
21-
handler: (): DevToolsDockEntry[] => [
22-
...Array.from(context.docks.values()),
23-
...builtinDocksEntries,
24-
],
21+
handler(): DevToolsDockEntry[] {
22+
// const session = context.rpc.getCurrentRpcSession()
23+
// console.log('session', session?.meta.id)
24+
return [
25+
...Array.from(context.docks.values()),
26+
...builtinDocksEntries,
27+
]
28+
},
2529
}
2630
},
2731
})

packages/core/src/node/ws.ts

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
/* eslint-disable no-console */
2-
import type { ConnectionMeta, DevToolsNodeContext, DevToolsRpcClientFunctions, DevToolsRpcServerFunctions } from '@vitejs/devtools-kit'
2+
import type { ConnectionMeta, DevToolsNodeContext, DevToolsNodeRpcSession, DevToolsRpcClientFunctions, DevToolsRpcServerFunctions } from '@vitejs/devtools-kit'
33
import type { WebSocket } from 'ws'
44
import type { RpcFunctionsHost } from './host-functions'
5+
import { AsyncLocalStorage } from 'node:async_hooks'
56
import { createRpcServer } from '@vitejs/devtools-rpc'
67
import { createWsRpcPreset } from '@vitejs/devtools-rpc/presets/ws/server'
78
import c from 'ansis'
@@ -23,16 +24,18 @@ export async function createWsServer(options: CreateWsServerOptions) {
2324

2425
const preset = createWsRpcPreset({
2526
port: port!,
26-
onConnected: (ws) => {
27+
onConnected: (ws, meta) => {
2728
wsClients.add(ws)
28-
console.log(c.green`${MARK_CHECK} Websocket client connected`)
29+
console.log(c.green`${MARK_CHECK} Websocket client [${meta.id}] connected`)
2930
},
30-
onDisconnected: (ws) => {
31+
onDisconnected: (ws, meta) => {
3132
wsClients.delete(ws)
32-
console.log(c.red`${MARK_CHECK} Websocket client disconnected`)
33+
console.log(c.red`${MARK_CHECK} Websocket client [${meta.id}] disconnected`)
3334
},
3435
})
3536

37+
const asyncStorage = new AsyncLocalStorage<DevToolsNodeRpcSession>()
38+
3639
const rpcGroup = createRpcServer<DevToolsRpcClientFunctions, DevToolsRpcServerFunctions>(
3740
rpcHost.functions,
3841
{
@@ -46,11 +49,26 @@ export async function createWsServer(options: CreateWsServerOptions) {
4649
console.error(c.red`⬢ RPC error on executing rpc`)
4750
console.error(error)
4851
},
52+
resolver(name, fn) {
53+
if (!fn)
54+
return undefined
55+
// eslint-disable-next-line ts/no-this-alias
56+
const rpc = this
57+
return async function (this: any, ...args) {
58+
return await asyncStorage.run({
59+
rpc,
60+
meta: rpc.$meta,
61+
}, async () => {
62+
return (await fn).apply(this, args)
63+
})
64+
}
65+
},
4966
},
5067
},
5168
)
5269

53-
rpcHost.rpcGroup = rpcGroup
70+
rpcHost._rpcGroup = rpcGroup
71+
rpcHost._asyncStorage = asyncStorage
5472

5573
const getConnectionMeta = async (): Promise<ConnectionMeta> => {
5674
return {

packages/kit/src/types/rpc.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,35 @@
1+
import type { BirpcReturn } from 'birpc'
12
import type { RpcFunctionsCollectorBase } from 'birpc-x'
3+
import type { WebSocket } from 'ws'
24
import type { DevToolsRpcClientFunctions, DevToolsRpcServerFunctions } from './rpc-augments'
35
import type { DevToolsNodeContext } from './vite-plugin'
46

7+
export interface DevToolsNodeRpcSessionMeta {
8+
id: number
9+
ws?: WebSocket
10+
}
11+
12+
export interface DevToolsNodeRpcSession {
13+
meta: DevToolsNodeRpcSessionMeta
14+
rpc: BirpcReturn<DevToolsRpcClientFunctions, DevToolsRpcServerFunctions, false>
15+
}
16+
517
export type RpcFunctionsHost = RpcFunctionsCollectorBase<DevToolsRpcServerFunctions, DevToolsNodeContext> & {
18+
/**
19+
* Broadcast a message to all connected clients
20+
*/
621
boardcast: <
722
T extends keyof DevToolsRpcClientFunctions,
823
Args extends Parameters<DevToolsRpcClientFunctions[T]>,
924
>(
1025
name: T,
1126
...args: Args
1227
) => Promise<(Awaited<ReturnType<DevToolsRpcClientFunctions[T]>> | undefined)[]>
28+
29+
/**
30+
* Get the current RPC client
31+
*
32+
* Available in RPC functions to get the current RPC client
33+
*/
34+
getCurrentRpcSession: () => DevToolsNodeRpcSession | undefined
1335
}

packages/kit/src/types/vite-plugin.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,43 @@ export interface DevToolsPluginOptions {
1919
}
2020

2121
export interface DevToolsNodeContext {
22+
/**
23+
* Current working directory of Vite DevTools
24+
*/
2225
readonly cwd: string
26+
/**
27+
* Current mode of Vite DevTools
28+
* - 'dev' - when Vite DevTools is running in dev mode
29+
* - 'build' - when Vite DevTools is running in build mode (no server)
30+
*/
2331
readonly mode: 'dev' | 'build'
32+
/**
33+
* Resolved Vite configuration
34+
*/
2435
readonly viteConfig: ResolvedConfig
36+
/**
37+
* Vite dev server instance (only available in dev mode)
38+
*/
2539
readonly viteServer?: ViteDevServer
40+
/**
41+
* RPC functions host, for registering server-side RPC functions and calling client-side RPC functions
42+
*/
2643
rpc: RpcFunctionsHost
44+
/**
45+
* Docks host, for registering dock entries
46+
*/
2747
docks: DevToolsDockHost
48+
/**
49+
* Views host, for registering static views
50+
*/
2851
views: DevToolsViewHost
52+
/**
53+
* Utils for the node context
54+
*/
2955
utils: DevToolsNodeUtils
56+
/**
57+
* Terminals host, for registering terminal sessions and streaming terminal output
58+
*/
3059
terminals: DevToolsTerminalHost
3160
}
3261

packages/rpc/src/presets/ws/server.ts

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import type { DevToolsNodeRpcSessionMeta } from '@vitejs/devtools-kit'
12
import type { BirpcGroup, BirpcOptions, ChannelOptions } from 'birpc'
23
import type { WebSocket } from 'ws'
34
import type { RpcServerPreset } from '..'
@@ -7,10 +8,12 @@ import { defineRpcServerPreset } from '..'
78

89
export interface WebSocketRpcServerOptions {
910
port: number
10-
onConnected?: (ws: WebSocket) => void
11-
onDisconnected?: (ws: WebSocket) => void
11+
onConnected?: (ws: WebSocket, meta: DevToolsNodeRpcSessionMeta) => void
12+
onDisconnected?: (ws: WebSocket, meta: DevToolsNodeRpcSessionMeta) => void
1213
}
1314

15+
let id = 0
16+
1417
function NOOP() {}
1518

1619
export const createWsRpcPreset: RpcServerPreset<
@@ -43,6 +46,10 @@ export const createWsRpcPreset: RpcServerPreset<
4346
} = options ?? {}
4447

4548
wss.on('connection', (ws) => {
49+
const meta: DevToolsNodeRpcSessionMeta = {
50+
id: id++,
51+
ws,
52+
}
4653
const channel: ChannelOptions = {
4754
post: (data) => {
4855
ws.send(data)
@@ -54,6 +61,7 @@ export const createWsRpcPreset: RpcServerPreset<
5461
},
5562
serialize,
5663
deserialize,
64+
meta,
5765
}
5866

5967
rpc.updateChannels((channels) => {
@@ -66,9 +74,9 @@ export const createWsRpcPreset: RpcServerPreset<
6674
if (index >= 0)
6775
channels.splice(index, 1)
6876
})
69-
onDisconnected(ws)
77+
onDisconnected(ws, meta)
7078
})
71-
onConnected(ws)
79+
onConnected(ws, meta)
7280
})
7381
}
7482
})

0 commit comments

Comments
 (0)