perf: 优化监听进程
This commit is contained in:
12
package.json
12
package.json
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"$schema": "https://json.schemastore.org/package",
|
"$schema": "https://json.schemastore.org/package",
|
||||||
"name": "@kevisual/router",
|
"name": "@kevisual/router",
|
||||||
"version": "0.0.69",
|
"version": "0.0.70",
|
||||||
"description": "",
|
"description": "",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "./dist/router.js",
|
"main": "./dist/router.js",
|
||||||
@@ -29,7 +29,7 @@
|
|||||||
"@kevisual/local-proxy": "^0.0.8",
|
"@kevisual/local-proxy": "^0.0.8",
|
||||||
"@kevisual/query": "^0.0.39",
|
"@kevisual/query": "^0.0.39",
|
||||||
"@kevisual/use-config": "^1.0.30",
|
"@kevisual/use-config": "^1.0.30",
|
||||||
"@opencode-ai/plugin": "^1.1.48",
|
"@opencode-ai/plugin": "^1.1.49",
|
||||||
"@rollup/plugin-alias": "^6.0.0",
|
"@rollup/plugin-alias": "^6.0.0",
|
||||||
"@rollup/plugin-commonjs": "29.0.0",
|
"@rollup/plugin-commonjs": "29.0.0",
|
||||||
"@rollup/plugin-node-resolve": "^16.0.3",
|
"@rollup/plugin-node-resolve": "^16.0.3",
|
||||||
@@ -41,6 +41,7 @@
|
|||||||
"@types/xml2js": "^0.4.14",
|
"@types/xml2js": "^0.4.14",
|
||||||
"eventemitter3": "^5.0.4",
|
"eventemitter3": "^5.0.4",
|
||||||
"fast-glob": "^3.3.3",
|
"fast-glob": "^3.3.3",
|
||||||
|
"hono": "^4.11.7",
|
||||||
"nanoid": "^5.1.6",
|
"nanoid": "^5.1.6",
|
||||||
"path-to-regexp": "^8.3.0",
|
"path-to-regexp": "^8.3.0",
|
||||||
"rollup": "^4.57.1",
|
"rollup": "^4.57.1",
|
||||||
@@ -53,14 +54,15 @@
|
|||||||
"typescript": "^5.9.3",
|
"typescript": "^5.9.3",
|
||||||
"ws": "npm:@kevisual/ws",
|
"ws": "npm:@kevisual/ws",
|
||||||
"xml2js": "^0.6.2",
|
"xml2js": "^0.6.2",
|
||||||
"zod": "^4.3.6",
|
"zod": "^4.3.6"
|
||||||
"hono": "^4.11.7"
|
|
||||||
},
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "git+https://github.com/abearxiong/kevisual-router.git"
|
"url": "git+https://github.com/abearxiong/kevisual-router.git"
|
||||||
},
|
},
|
||||||
"dependencies": {},
|
"dependencies": {
|
||||||
|
"es-toolkit": "^1.44.0"
|
||||||
|
},
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
"access": "public"
|
"access": "public"
|
||||||
},
|
},
|
||||||
|
|||||||
9
pnpm-lock.yaml
generated
9
pnpm-lock.yaml
generated
@@ -7,6 +7,10 @@ settings:
|
|||||||
importers:
|
importers:
|
||||||
|
|
||||||
.:
|
.:
|
||||||
|
dependencies:
|
||||||
|
es-toolkit:
|
||||||
|
specifier: ^1.44.0
|
||||||
|
version: 1.44.0
|
||||||
devDependencies:
|
devDependencies:
|
||||||
'@kevisual/context':
|
'@kevisual/context':
|
||||||
specifier: ^0.0.4
|
specifier: ^0.0.4
|
||||||
@@ -775,6 +779,9 @@ packages:
|
|||||||
es-module-lexer@2.0.0:
|
es-module-lexer@2.0.0:
|
||||||
resolution: {integrity: sha512-5POEcUuZybH7IdmGsD8wlf0AI55wMecM9rVBTI/qEAy2c1kTOm3DjFYjrBdI2K3BaJjJYfYFeRtM0t9ssnRuxw==}
|
resolution: {integrity: sha512-5POEcUuZybH7IdmGsD8wlf0AI55wMecM9rVBTI/qEAy2c1kTOm3DjFYjrBdI2K3BaJjJYfYFeRtM0t9ssnRuxw==}
|
||||||
|
|
||||||
|
es-toolkit@1.44.0:
|
||||||
|
resolution: {integrity: sha512-6penXeZalaV88MM3cGkFZZfOoLGWshWWfdy0tWw/RlVVyhvMaWSBTOvXNeiW3e5FwdS5ePW0LGEu17zT139ktg==}
|
||||||
|
|
||||||
esbuild@0.27.2:
|
esbuild@0.27.2:
|
||||||
resolution: {integrity: sha512-HyNQImnsOC7X9PMNaCIeAm4ISCQXs5a5YasTXVliKv4uuBo1dKrG0A+uQS8M5eXjVMnLg3WgXaKvprHlFJQffw==}
|
resolution: {integrity: sha512-HyNQImnsOC7X9PMNaCIeAm4ISCQXs5a5YasTXVliKv4uuBo1dKrG0A+uQS8M5eXjVMnLg3WgXaKvprHlFJQffw==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
@@ -1725,6 +1732,8 @@ snapshots:
|
|||||||
|
|
||||||
es-module-lexer@2.0.0: {}
|
es-module-lexer@2.0.0: {}
|
||||||
|
|
||||||
|
es-toolkit@1.44.0: {}
|
||||||
|
|
||||||
esbuild@0.27.2:
|
esbuild@0.27.2:
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
'@esbuild/aix-ppc64': 0.27.2
|
'@esbuild/aix-ppc64': 0.27.2
|
||||||
|
|||||||
@@ -14,5 +14,5 @@ export { CustomError } from './result/error.ts';
|
|||||||
|
|
||||||
export * from './router-define.ts';
|
export * from './router-define.ts';
|
||||||
|
|
||||||
export { MockProcess } from './utils/listen-process.ts'
|
export { MockProcess, type ListenProcessParams, type ListenProcessResponse } from './utils/listen-process.ts'
|
||||||
// --- 以上同步更新至 browser.ts ---
|
// --- 以上同步更新至 browser.ts ---
|
||||||
@@ -14,7 +14,7 @@ export { CustomError } from './result/error.ts';
|
|||||||
|
|
||||||
export * from './router-define.ts';
|
export * from './router-define.ts';
|
||||||
|
|
||||||
export { MockProcess } from './utils/listen-process.ts'
|
export { MockProcess, type ListenProcessParams, type ListenProcessResponse } from './utils/listen-process.ts'
|
||||||
// --- 以上同步更新至 browser.ts ---
|
// --- 以上同步更新至 browser.ts ---
|
||||||
|
|
||||||
export { ServerNode, handleServer } from './server/index.ts';
|
export { ServerNode, handleServer } from './server/index.ts';
|
||||||
|
|||||||
18
src/route.ts
18
src/route.ts
@@ -61,7 +61,7 @@ export type RouteContext<T = { code?: number }, S = any> = {
|
|||||||
} & T;
|
} & T;
|
||||||
export type SimpleObject = Record<string, any>;
|
export type SimpleObject = Record<string, any>;
|
||||||
export type Run<T extends SimpleObject = {}> = (ctx: Required<RouteContext<T>>) => Promise<typeof ctx | null | void>;
|
export type Run<T extends SimpleObject = {}> = (ctx: Required<RouteContext<T>>) => Promise<typeof ctx | null | void>;
|
||||||
|
export type RunMessage = { path?: string; key?: string; id?: string; payload?: any; };
|
||||||
export type NextRoute = Pick<Route, 'id' | 'path' | 'key'>;
|
export type NextRoute = Pick<Route, 'id' | 'path' | 'key'>;
|
||||||
export type RouteMiddleware =
|
export type RouteMiddleware =
|
||||||
| {
|
| {
|
||||||
@@ -262,17 +262,17 @@ export const toJSONSchema = (route: RouteInfo) => {
|
|||||||
return pickValues;
|
return pickValues;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const fromJSONSchema = (route: RouteInfo): {
|
export const fromJSONSchema = (route: RouteInfo): RouteInfo => {
|
||||||
[key: string]: z.ZodTypeAny
|
const args = route?.metadata?.args;
|
||||||
} => {
|
if (!args) return route;
|
||||||
const args = route?.metadata?.args || {};
|
|
||||||
const keys = Object.keys(args);
|
const keys = Object.keys(args);
|
||||||
const newArgs: { [key: string]: any } = {};
|
const newArgs: { [key: string]: any } = {};
|
||||||
for (let key of keys) {
|
for (let key of keys) {
|
||||||
const item = args[key];
|
const item = args[key];
|
||||||
newArgs[key] = z.fromJSONSchema(item);
|
newArgs[key] = z.fromJSONSchema(item);
|
||||||
}
|
}
|
||||||
return newArgs;
|
route.metadata.args = newArgs;
|
||||||
|
return route;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -680,7 +680,7 @@ export class QueryRouter {
|
|||||||
* -- .on
|
* -- .on
|
||||||
* -- .send
|
* -- .send
|
||||||
*/
|
*/
|
||||||
wait(params?: { path?: string; key?: string; payload?: any }, opts?: {
|
wait(params?: { message: RunMessage }, opts?: {
|
||||||
mockProcess?: MockProcess,
|
mockProcess?: MockProcess,
|
||||||
timeout?: number,
|
timeout?: number,
|
||||||
getList?: boolean
|
getList?: boolean
|
||||||
@@ -693,8 +693,8 @@ export class QueryRouter {
|
|||||||
}
|
}
|
||||||
return listenProcess({ app: this as any, params, ...opts });
|
return listenProcess({ app: this as any, params, ...opts });
|
||||||
}
|
}
|
||||||
static toJSONSchema = toJSONSchema;
|
toJSONSchema = toJSONSchema;
|
||||||
static fromJSONSchema = fromJSONSchema;
|
fromJSONSchema = fromJSONSchema;
|
||||||
}
|
}
|
||||||
|
|
||||||
type QueryRouterServerOpts = {
|
type QueryRouterServerOpts = {
|
||||||
|
|||||||
@@ -1,25 +1,7 @@
|
|||||||
import { fork } from 'child_process'
|
import { fork } from 'child_process'
|
||||||
|
import { ListenProcessParams, ListenProcessResponse } from '@/utils/listen-process.ts';
|
||||||
export type RunCodeParams = {
|
export type RunCodeParams = ListenProcessParams
|
||||||
path?: string;
|
export type RunCode = ListenProcessResponse
|
||||||
key?: string;
|
|
||||||
payload?: string;
|
|
||||||
[key: string]: any
|
|
||||||
}
|
|
||||||
type RunCode = {
|
|
||||||
// 调用进程的功能
|
|
||||||
success?: boolean
|
|
||||||
data?: {
|
|
||||||
// 调用router的结果
|
|
||||||
code?: number
|
|
||||||
data?: any
|
|
||||||
message?: string
|
|
||||||
[key: string]: any
|
|
||||||
};
|
|
||||||
error?: any
|
|
||||||
timestamp?: string
|
|
||||||
[key: string]: any
|
|
||||||
}
|
|
||||||
export const runCode = async (tsPath: string, params: RunCodeParams = {}): Promise<RunCode> => {
|
export const runCode = async (tsPath: string, params: RunCodeParams = {}): Promise<RunCode> => {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
// 使用 Bun 的 fork 模式启动子进程
|
// 使用 Bun 的 fork 模式启动子进程
|
||||||
@@ -52,8 +34,11 @@ import path from 'node:path'
|
|||||||
const res = await runCode(path.join(process.cwd(), './src/test/mini.ts'), {
|
const res = await runCode(path.join(process.cwd(), './src/test/mini.ts'), {
|
||||||
// path: 'main'
|
// path: 'main'
|
||||||
// id: 'abc'
|
// id: 'abc'
|
||||||
path: 'router',
|
message: {
|
||||||
key: 'list'
|
path: 'router',
|
||||||
|
key: 'list'
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
console.log('res', res.data.data.list)
|
console.log('success', res)
|
||||||
|
console.log('res', res.data?.data?.list)
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
import { App } from "../app.ts";
|
import { App } from "../app.ts";
|
||||||
|
|
||||||
const app = new App({
|
const app = new App({
|
||||||
io: true
|
|
||||||
});
|
});
|
||||||
|
|
||||||
app
|
app
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { EventEmitter } from "eventemitter3";
|
import { EventEmitter } from "eventemitter3";
|
||||||
import { QueryRouterServer } from "../route.ts"
|
import { QueryRouterServer, RouterContextT, RunMessage } from "../route.ts"
|
||||||
|
import { merge } from 'es-toolkit'
|
||||||
export class MockProcess {
|
export class MockProcess {
|
||||||
emitter?: EventEmitter
|
emitter?: EventEmitter
|
||||||
process?: NodeJS.Process;
|
process?: NodeJS.Process;
|
||||||
@@ -37,13 +38,31 @@ export class MockProcess {
|
|||||||
this.process = undefined;
|
this.process = undefined;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
export type ListenProcessParams = {
|
||||||
|
message?: RunMessage,
|
||||||
|
context?: any
|
||||||
|
}
|
||||||
|
export type ListenProcessResponse = {
|
||||||
|
// 调用进程的功能
|
||||||
|
success?: boolean
|
||||||
|
data?: {
|
||||||
|
// 调用router的结果
|
||||||
|
code?: number
|
||||||
|
data?: any
|
||||||
|
message?: string
|
||||||
|
[key: string]: any
|
||||||
|
};
|
||||||
|
error?: any
|
||||||
|
timestamp?: string
|
||||||
|
[key: string]: any
|
||||||
|
}
|
||||||
export type ListenProcessOptions = {
|
export type ListenProcessOptions = {
|
||||||
app?: QueryRouterServer; // 传入的应用实例
|
app?: QueryRouterServer; // 传入的应用实例
|
||||||
mockProcess?: MockProcess; // 可选的事件发射器
|
mockProcess?: MockProcess; // 可选的事件发射器
|
||||||
params?: any; // 可选的参数
|
params?: ListenProcessParams; // 可选的参数
|
||||||
timeout?: number; // 可选的超时时间 (单位: 毫秒) 默认 10 分钟
|
timeout?: number; // 可选的超时时间 (单位: 毫秒) 默认 10 分钟
|
||||||
};
|
};
|
||||||
export const listenProcess = async ({ app, mockProcess, params, timeout = 10 * 60 * 60 * 1000 }: ListenProcessOptions) => {
|
export const listenProcess = async ({ app, mockProcess, params = {}, timeout = 10 * 60 * 60 * 1000 }: ListenProcessOptions) => {
|
||||||
const process = mockProcess || new MockProcess();
|
const process = mockProcess || new MockProcess();
|
||||||
let isEnd = false;
|
let isEnd = false;
|
||||||
const timer = setTimeout(() => {
|
const timer = setTimeout(() => {
|
||||||
@@ -57,11 +76,11 @@ export const listenProcess = async ({ app, mockProcess, params, timeout = 10 * 6
|
|||||||
// 监听来自主进程的消息
|
// 监听来自主进程的消息
|
||||||
const getParams = async (): Promise<any> => {
|
const getParams = async (): Promise<any> => {
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
process.on((msg) => {
|
process.on((params) => {
|
||||||
if (isEnd) return;
|
if (isEnd) return;
|
||||||
isEnd = true;
|
isEnd = true;
|
||||||
clearTimeout(timer);
|
clearTimeout(timer);
|
||||||
resolve(msg)
|
resolve(params || {})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -70,11 +89,11 @@ export const listenProcess = async ({ app, mockProcess, params, timeout = 10 * 6
|
|||||||
/**
|
/**
|
||||||
* 如果不提供path,默认是main
|
* 如果不提供path,默认是main
|
||||||
*/
|
*/
|
||||||
const {
|
const _params = await getParams()
|
||||||
payload = {},
|
const mergeParams = merge(params, _params)
|
||||||
...rest
|
|
||||||
} = await getParams()
|
const msg = mergeParams?.message || {};
|
||||||
const msg = { ...params, ...rest, payload: { ...params?.payload, ...payload } }
|
const ctx: RouterContextT = mergeParams?.context || {}
|
||||||
/**
|
/**
|
||||||
* 如果没有提供path和id,默认取第一个路由, 而且路由path不是router的
|
* 如果没有提供path和id,默认取第一个路由, 而且路由path不是router的
|
||||||
*/
|
*/
|
||||||
@@ -83,7 +102,7 @@ export const listenProcess = async ({ app, mockProcess, params, timeout = 10 * 6
|
|||||||
msg.id = route?.id
|
msg.id = route?.id
|
||||||
}
|
}
|
||||||
// 执行主要逻辑
|
// 执行主要逻辑
|
||||||
const result = await app.run(msg)
|
const result = await app.run(msg, ctx);
|
||||||
// 发送结果回主进程
|
// 发送结果回主进程
|
||||||
const response = {
|
const response = {
|
||||||
success: true,
|
success: true,
|
||||||
@@ -95,6 +114,7 @@ export const listenProcess = async ({ app, mockProcess, params, timeout = 10 * 6
|
|||||||
process.exit?.(0)
|
process.exit?.(0)
|
||||||
})
|
})
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
console.error('Error in listenProcess:', error);
|
||||||
process.send?.({
|
process.send?.({
|
||||||
success: false,
|
success: false,
|
||||||
error: error.message
|
error: error.message
|
||||||
|
|||||||
Reference in New Issue
Block a user