feat: update WebSocket connection and add system version sending functionality
- Changed WebSocket connection URL to localhost for testing. - Added a function to send system version to the server upon connection and after a delay. - Improved logging for received messages. chore: update package dependencies - Bump versions for several dependencies including @kevisual/query, lucide-react, vue, and others. - Update package manager version to pnpm@10.26.1. fix: adjust app initialization to use sessionStorage - Modified the app initialization to use a custom sessionStorage implementation backed by an LRU cache. feat: implement sessionStorage with LRU cache - Added a new module for sessionStorage that utilizes LRUCache for efficient caching.
This commit is contained in:
@@ -10,7 +10,7 @@
|
||||
],
|
||||
"author": "abearxiong <xiongxiao@xiongxiao.me> (https://www.xiongxiao.me)",
|
||||
"license": "MIT",
|
||||
"packageManager": "pnpm@10.26.0",
|
||||
"packageManager": "pnpm@10.26.1",
|
||||
"type": "module",
|
||||
"files": [
|
||||
"dist",
|
||||
@@ -46,12 +46,12 @@
|
||||
"@kevisual/load": "^0.0.6",
|
||||
"@kevisual/local-app-manager": "^0.1.32",
|
||||
"@kevisual/logger": "^0.0.4",
|
||||
"@kevisual/query": "0.0.32",
|
||||
"@kevisual/query": "0.0.33",
|
||||
"@kevisual/query-login": "0.0.7",
|
||||
"@kevisual/router": "^0.0.39",
|
||||
"@kevisual/router": "^0.0.47",
|
||||
"@kevisual/types": "^0.0.10",
|
||||
"@kevisual/use-config": "^1.0.21",
|
||||
"@types/bun": "^1.3.4",
|
||||
"@types/bun": "^1.3.5",
|
||||
"@types/lodash-es": "^4.17.12",
|
||||
"@types/node": "^25.0.3",
|
||||
"@types/send": "^1.2.1",
|
||||
|
||||
@@ -41,7 +41,8 @@ export const app: App = useContextKey<App>('app', () => {
|
||||
httpType: 'http',
|
||||
cors: {
|
||||
origin: '*',
|
||||
}
|
||||
},
|
||||
io: true
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -54,7 +55,8 @@ export const app: App = useContextKey<App>('app', () => {
|
||||
httpsKey: httpsPem.key,
|
||||
cors: {
|
||||
origin: '*',
|
||||
}
|
||||
},
|
||||
io: true
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
@@ -2,6 +2,7 @@ import http from 'node:http';
|
||||
import https from 'node:https';
|
||||
import { rewriteCookieDomain } from '../https/cookie-rewrite.ts';
|
||||
import { ProxyInfo } from './proxy.ts';
|
||||
import { pipeStream } from './pipe.ts';
|
||||
export const defaultApiProxy = [
|
||||
{
|
||||
path: '/api/router',
|
||||
@@ -109,5 +110,6 @@ export const httpProxy = (req: http.IncomingMessage, res: http.ServerResponse, p
|
||||
});
|
||||
// 处理 POST 请求的请求体(传递数据到目标服务器),end:true 表示当请求体结束时,关闭请求
|
||||
req.pipe(proxyReq, { end: true });
|
||||
return;
|
||||
};
|
||||
// @ts-ignore
|
||||
// pipeStream(proxyReq, res);
|
||||
}
|
||||
@@ -1,5 +1,4 @@
|
||||
export * from './proxy.ts';
|
||||
export * from './file-proxy.ts';
|
||||
export { default as send } from 'send';
|
||||
export * from './http-proxy.ts';
|
||||
export * from './ws-proxy.ts';
|
||||
export * from './http-proxy.ts';
|
||||
19
assistant/src/module/assistant/proxy/pipe.ts
Normal file
19
assistant/src/module/assistant/proxy/pipe.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
import * as http from 'http';
|
||||
import * as fs from 'fs';
|
||||
import { isBun } from './utils.ts';
|
||||
|
||||
export const pipeFileStream = (filePath: string, res: http.ServerResponse) => {
|
||||
const readStream = fs.createReadStream(filePath);
|
||||
if (isBun) {
|
||||
res.pipe(readStream as any);
|
||||
} else {
|
||||
readStream.pipe(res, { end: true });
|
||||
}
|
||||
}
|
||||
export const pipeStream = (readStream: fs.ReadStream, res: http.ServerResponse) => {
|
||||
if (isBun) {
|
||||
res.pipe(readStream as any);
|
||||
} else {
|
||||
readStream.pipe(res, { end: true });
|
||||
}
|
||||
}
|
||||
6
assistant/src/module/assistant/proxy/utils.ts
Normal file
6
assistant/src/module/assistant/proxy/utils.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
export const isBun = typeof Bun !== 'undefined' && Bun?.version != null;
|
||||
|
||||
export const isNode = typeof process !== 'undefined' && process?.versions != null && process.versions?.node != null;
|
||||
|
||||
// @ts-ignore
|
||||
export const isDeno = typeof Deno !== 'undefined' && Deno?.version != null && Deno?.version?.deno != null;
|
||||
@@ -4,6 +4,7 @@ import type { Http2Server } from 'node:http2';
|
||||
import { WebSocket } from 'ws';
|
||||
import { ProxyInfo } from './proxy.ts';
|
||||
import { WebSocketServer } from 'ws';
|
||||
import { isBun, isNode } from './utils.ts';
|
||||
|
||||
export const wss = new WebSocketServer({
|
||||
noServer: true,
|
||||
@@ -97,7 +98,13 @@ export const wsProxy = (server: HttpServer | HttpsServer | Http2Server, config:
|
||||
await wssApp.handleConnection(ws, req);
|
||||
});
|
||||
// 处理升级请求
|
||||
server.on('upgrade', (request, socket, head) => {
|
||||
wssApp.upgrade(request, socket, head);
|
||||
});
|
||||
if (!isBun) {
|
||||
server.on('upgrade', (request, socket, head) => {
|
||||
wssApp.upgrade(request, socket, head);
|
||||
});
|
||||
} else if (isBun) {
|
||||
// @ts-ignore
|
||||
console.warn('Bun WebSocket proxy is not implemented yet.');
|
||||
console.log('server', server)
|
||||
}
|
||||
};
|
||||
|
||||
@@ -38,8 +38,12 @@ export const runServer = async (port: number = 51015, listenPath = '127.0.0.1')
|
||||
console.log(`Server is running on ${protocol}://${listenPath}:${_port}`);
|
||||
});
|
||||
}
|
||||
app.server.on(proxyRoute);
|
||||
proxyWs();
|
||||
app.server.on([{
|
||||
id: 'all',
|
||||
func: proxyRoute as any
|
||||
},
|
||||
...proxyWs()
|
||||
]);
|
||||
const manager = new AssistantApp(assistantConfig, app);
|
||||
setTimeout(() => {
|
||||
manager.load({ runtime: 'client' }).then(() => {
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
import { fileProxy, httpProxy, createApiProxy, wsProxy } from '@/module/assistant/index.ts';
|
||||
import { fileProxy, httpProxy, createApiProxy, ProxyInfo } from '@/module/assistant/index.ts';
|
||||
import http from 'node:http';
|
||||
import { LocalProxy } from './local-proxy.ts';
|
||||
import { assistantConfig, app } from '@/app.ts';
|
||||
import { log, logger } from '@/module/logger.ts';
|
||||
import { getToken } from '@/module/http-token.ts';
|
||||
import { getTokenUserCache } from '@/routes/index.ts';
|
||||
import type { WebSocketListenerFun } from "@kevisual/router";
|
||||
import WebSocket from 'ws';
|
||||
const localProxy = new LocalProxy({});
|
||||
localProxy.initFromAssistantConfig(assistantConfig);
|
||||
|
||||
@@ -175,8 +177,63 @@ export const proxyWs = () => {
|
||||
const apiProxy = assistantConfig.getCacheAssistantConfig()?.api?.proxy || [];
|
||||
const proxy = assistantConfig.getCacheAssistantConfig()?.proxy || [];
|
||||
const proxyApi = [...apiProxy, ...proxy].filter((item) => item.ws);
|
||||
log.debug('proxyApi ', proxyApi);
|
||||
wsProxy(app.server.server, {
|
||||
apiList: proxyApi,
|
||||
});
|
||||
|
||||
const demoProxy = [
|
||||
{
|
||||
path: '/api/ws/demo',
|
||||
target: 'https://kevisual.xiongxiao.me',
|
||||
pathname: '/api/router',
|
||||
ws: true,
|
||||
}
|
||||
]
|
||||
return proxyApi.map(createProxyInfo);
|
||||
};
|
||||
export const createProxyInfo = (proxyApiItem: ProxyInfo) => {
|
||||
const func: WebSocketListenerFun = async (req, res) => {
|
||||
const { ws, emitter, id, data } = req;
|
||||
if (!id) {
|
||||
ws.send(JSON.stringify({ type: 'error', message: 'not found id' }));
|
||||
ws.close();
|
||||
return;
|
||||
}
|
||||
// @ts-ignore
|
||||
let _proxySocket = ws.data.proxySocket;
|
||||
if (!_proxySocket) {
|
||||
const _u = new URL(proxyApiItem.path, `${proxyApiItem.target}`);
|
||||
if (proxyApiItem.pathname) {
|
||||
_u.pathname = proxyApiItem.pathname;
|
||||
}
|
||||
const isHttps = _u.protocol === 'https:';
|
||||
const wsProtocol = isHttps ? 'wss' : 'ws';
|
||||
const wsUrl = `${wsProtocol}://${_u.host}${_u.pathname}`;
|
||||
console.log('WebSocket proxy URL', { wsUrl });
|
||||
const proxySocket = new WebSocket(wsUrl);
|
||||
proxySocket.on('open', () => {
|
||||
proxySocket.on('message', (message) => {
|
||||
ws.send(message);
|
||||
});
|
||||
});
|
||||
|
||||
proxySocket.on('error', (err) => {
|
||||
console.error(`WebSocket proxy error: ${err.message}`);
|
||||
});
|
||||
proxySocket.on('close', () => {
|
||||
console.log('WebSocket proxy closed');
|
||||
});
|
||||
emitter.once('close--' + id, () => {
|
||||
console.log('WebSocket client closed');
|
||||
proxySocket?.close?.();
|
||||
});
|
||||
// @ts-ignore
|
||||
ws.data.proxySocket = proxySocket;
|
||||
return;
|
||||
}
|
||||
console.log('ws.data', data);
|
||||
_proxySocket.send(JSON.stringify(data))
|
||||
}
|
||||
return {
|
||||
path: proxyApiItem.path,
|
||||
io: true,
|
||||
func: func
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,11 +5,20 @@ const testRouter = () => {
|
||||
// const ws = new WebSocket('wss://kevisual.xiongxiao.me/ws/proxy');
|
||||
// const ws = new WebSocket('wss://kevisual.xiongxiao.me/api/router');
|
||||
|
||||
const ws = new WebSocket('ws://118.196.32.29:3005/api/router');
|
||||
// const ws = new WebSocket('ws://118.196.32.29:3005/api/router');
|
||||
// const ws = new WebSocket('wss://kevisual.cn/api/router');
|
||||
|
||||
const ws = new WebSocket('ws://localhost:51015/api/ws/demo?id=12345');
|
||||
console.log('Connecting to WebSocket server...');
|
||||
ws.on('open', () => {
|
||||
console.log('WebSocket connection opened');
|
||||
sendSystemVersion();
|
||||
setTimeout(() => {
|
||||
sendSystemVersion();
|
||||
console.log('第二次发送');
|
||||
}, 3000);
|
||||
});
|
||||
const sendSystemVersion = () => {
|
||||
ws.send(
|
||||
JSON.stringify({
|
||||
"type": "router",
|
||||
@@ -19,10 +28,10 @@ const testRouter = () => {
|
||||
}
|
||||
}),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
ws.on('message', (data) => {
|
||||
console.log('Received message from server:', data.toString());
|
||||
console.log('Received message from server e:', data.toString());
|
||||
});
|
||||
ws.on('close', () => {
|
||||
console.log('WebSocket connection closed');
|
||||
|
||||
Reference in New Issue
Block a user