更新 @kevisual/api 版本至 0.0.16,增强 RouterViewItem 类型,添加 question、response 和 action 属性,重构 initRouterViewQuery 和 callWorker 方法以优化路由视图初始化和工作线程调用

This commit is contained in:
2026-01-03 01:54:55 +08:00
parent 31e8c0346f
commit cb8723c172
2 changed files with 158 additions and 74 deletions

View File

@@ -4,13 +4,26 @@ import { filter } from '@kevisual/js-filter'
import { EventEmitter } from 'eventemitter3';
export const RouteTypeList = ['api', 'context', 'worker', 'page'] as const;
export type RouterViewItem = RouterViewApi | RouterViewContext | RouterViewWorker | RouteViewPage;
export type RouterViewItemInfo = RouterViewApi | RouterViewContext | RouterViewWorker | RouteViewPage;
export type RouterViewItem<T = {}> = RouterViewItemInfo & T;
type RouteViewBase = {
id: string;
title: string;
description: string;
enabled?: boolean;
/**
* 提示问题
*/
question?: string;
/**
* 响应数据
*/
response?: any;
/**
* 默认动作配置
*/
action?: { path?: string; key?: string; id?: string; payload?: any;[key: string]: any };
}
export type RouterViewApi = {
type: 'api',
@@ -46,6 +59,30 @@ export type RouterViewWorker = {
}
} & RouteViewBase;
/**
* 去掉不需要保存都服务器的数据
* @param item
* @returns
*/
export const pickRouterViewData = (item: RouterViewItem) => {
const { question, action, response, ...rest } = item;
if (rest.type === 'api') {
if (rest.api) {
delete rest.api.query;
}
}
if (rest.type === 'worker') {
if (rest.worker) {
delete rest.worker.worker;
}
}
if (rest.type === 'context') {
if (rest.context) {
delete rest.context.router;
}
}
return rest
}
/**
* 注入 js 的url地址使用importScripts加载
*/
@@ -91,58 +128,63 @@ export class QueryProxy {
return undefined;
}
}
async initRouterViewQuery() {
initRouterViewQuery() {
this.routerViewItems = this.routerViewItems.map(item => {
if (item.type === 'api' && item.api?.url) {
const url = item.api.url;
if (item?.api?.query) return item;
item['api'] = { url: url, query: new Query({ url: url }) };
}
if (item.type === 'worker' && item.worker?.url) {
let viewItem = item as RouterViewWorker;
if (!item.worker?.workerOptions?.type) {
item.worker.workerOptions = { ...item.worker.workerOptions, type: 'module' };
}
if (item.worker.worker) {
return item;
}
let worker: Worker | SharedWorker | ServiceWorker | undefined = undefined;
if (item.worker.type === 'SharedWorker') {
worker = new SharedWorker(item.worker.url, item.worker.workerOptions);
worker.port.start();
} else if (viewItem.worker.type === 'serviceWorker') {
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register(viewItem.worker.url, item.worker.workerOptions).then(function (registration) {
console.debug('注册serviceWorker成功 ', registration.scope);
}, function (err) {
console.debug('注册 serviceWorker 失败: ', err);
});
} else {
console.warn('当前浏览器不支持serviceWorker');
}
} else {
worker = new Worker(viewItem.worker.url, item.worker.workerOptions);
}
viewItem['worker']['worker'] = worker;
}
if (item.type === 'context' && item.context?.key) {
if (item.context?.router) {
return item;
}
// @ts-ignore
const context = globalThis['context'] || {}
const router = context[item.context.key] as QueryRouterServer;
if (router) {
item['context']['router'] = router;
}
}
return item;
return this.initRouterView(item);
}).filter(item => {
const enabled = item.enabled ?? true;
return enabled;
});
}
initRouterView(item: RouterViewItem) {
if (item.type === 'api' && item.api?.url) {
const url = item.api.url;
if (item?.api?.query) return item;
item['api'] = { url: url, query: new Query({ url: url }) };
}
if (item.type === 'worker' && item.worker?.url) {
let viewItem = item as RouterViewWorker;
if (!item.worker?.workerOptions?.type) {
item.worker.workerOptions = { ...item.worker.workerOptions, type: 'module' };
}
if (item.worker.worker) {
return item;
}
let worker: Worker | SharedWorker | ServiceWorker | undefined = undefined;
if (item.worker.type === 'SharedWorker') {
worker = new SharedWorker(item.worker.url, item.worker.workerOptions);
worker.port.start();
} else if (viewItem.worker.type === 'serviceWorker') {
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register(viewItem.worker.url, item.worker.workerOptions).then(function (registration) {
console.debug('注册serviceWorker成功 ', registration.scope);
}, function (err) {
console.debug('注册 serviceWorker 失败: ', err);
});
} else {
console.warn('当前浏览器不支持serviceWorker');
}
} else {
worker = new Worker(viewItem.worker.url, item.worker.workerOptions);
}
viewItem['worker']['worker'] = worker;
}
if (item.type === 'context' && item.context?.key) {
if (item.context?.router) {
return item;
}
// @ts-ignore
const context = globalThis['context'] || {}
const router = context[item.context.key] as QueryRouterServer;
if (router) {
item['context']['router'] = router;
}
}
return item;
}
/**
* 初始化路由
* @returns
@@ -248,7 +290,35 @@ export class QueryProxy {
generateId() {
return 'route_' + Math.random().toString(36).substring(2, 9);
}
async initWorker(item?: RouterViewWorker) {
async callWorker(msg: any, viewItem: RouterViewWorker['worker']): Promise<Result> {
const that = this;
const requestId = this.generateId();
const worker = viewItem?.worker;
if (!worker) {
return { code: 500, message: 'Worker未初始化' };
}
let port: MessagePort | Worker | ServiceWorker;
if (viewItem.type === 'SharedWorker') {
port = (worker as SharedWorker).port;
} else {
port = worker as Worker | ServiceWorker;
}
port.postMessage({
...msg,
requestId: requestId,
})
return new Promise((resolve) => {
const timer = setTimeout(() => {
that.emitter.removeAllListeners(requestId);
resolve({ code: 500, message: '请求超时' });
}, 3 * 60 * 1000); // 3分钟超时
that.emitter.once(requestId, (res: any) => {
clearTimeout(timer);
resolve(res);
});
});
}
async initWorker(item?: RouterViewWorker, initRoutes: boolean = true) {
const that = this;
if (!item?.worker?.url) {
console.warn('Worker URL not provided');
@@ -278,33 +348,10 @@ export class QueryProxy {
} else {
(worker as Worker).onmessage = callResponse;
}
const callWorker = async (msg: any, viewItem: RouterViewWorker['worker']): Promise<Result> => {
const requestId = this.generateId();
const worker = viewItem?.worker;
if (!worker) {
return { code: 500, message: 'Worker未初始化' };
}
let port: MessagePort | Worker | ServiceWorker;
if (viewItem.type === 'SharedWorker') {
port = (worker as SharedWorker).port;
} else {
port = worker as Worker | ServiceWorker;
}
port.postMessage({
...msg,
requestId: requestId,
})
return new Promise((resolve) => {
const timer = setTimeout(() => {
that.emitter.removeAllListeners(requestId);
resolve({ code: 500, message: '请求超时' });
}, 3 * 60 * 1000); // 3分钟超时
that.emitter.once(requestId, (res: any) => {
clearTimeout(timer);
resolve(res);
});
});
if (!initRoutes) {
return;
}
const callWorker = this.callWorker.bind(this);
const res = await callWorker({
path: "router",
@@ -393,6 +440,43 @@ export class QueryProxy {
async run(msg: { id?: string, path?: string, key?: string }) {
return await this.router.run(msg);
}
async runByRouteView(routeView: RouterViewItem) {
if (routeView.response) {
return routeView;
}
const item = this.initRouterView(routeView);
if (item.type === 'api' && item.api?.url) {
const query = item.api.query!;
const res = await query.post<any>(item.action || {});
item.response = res;
return item;
} else if (item.type === 'api') {
item.response = { code: 500, message: 'API URL未配置' };
return item;
}
if (item.type === 'context' && item.context?.router) {
const router = item.context.router;
const res = await router.run(item.action || {});
item.response = res;
return item;
}
if (item.type === 'page') {
await this.initPage(item);
const res = await this.router.run(item.action || {});
item.response = res;
return item;
}
if (item.type === 'worker' && item.worker?.worker) {
await this.initWorker(item, false);
const callWorker = this.callWorker.bind(this);
const res = await callWorker(item.action || {}, item.worker);
item.response = res;
return item;
}
item.response = { code: 500, message: '无法处理的路由类型' };
return item;
}
}
type RouterItem = {