feat: add ws-proxy

This commit is contained in:
熊潇 2025-05-22 14:33:24 +08:00
parent 1e2f891f31
commit 28a5d82e52
8 changed files with 438 additions and 190 deletions

37
bun.config.mjs Normal file
View File

@ -0,0 +1,37 @@
// @ts-check
import { resolvePath } from '@kevisual/use-config/env';
import { execSync } from 'node:child_process';
const entry = 'src/index.ts';
const naming = 'app';
const external = ['sequelize', 'pg', 'sqlite3', 'ioredis', 'pm2'];
/**
* @type {import('bun').BuildConfig}
*/
await Bun.build({
target: 'node',
format: 'esm',
entrypoints: [resolvePath(entry, { meta: import.meta })],
outdir: resolvePath('./dist', { meta: import.meta }),
naming: {
entry: `${naming}.js`,
},
external,
env: 'KEVISUAL_*',
});
// const cmd = `dts -i src/index.ts -o app.d.ts`;
// const cmd = `dts -i ${entry} -o ${naming}.d.ts`;
// execSync(cmd, { stdio: 'inherit' });
// await Bun.build({
// target: 'node',
// format: 'esm',
// entrypoints: [resolvePath('./src/run.ts', { meta: import.meta })],
// outdir: resolvePath('./dist', { meta: import.meta }),
// naming: {
// entry: `${'run'}.js`,
// },
// external,
// env: 'KEVISUAL_*',
// });

View File

@ -7,7 +7,7 @@
"basename": "/root/page-proxy",
"app": {
"key": "page-proxy",
"entry": "dist/app.mjs",
"entry": "dist/app.js",
"type": "pm2-system-app",
"files": [
"dist"
@ -17,10 +17,10 @@
"dist"
],
"scripts": {
"watch": "rollup -c --watch",
"dev": "cross-env NODE_ENV=development nodemon --ignore proxy-upload --exec tsx src/index.ts",
"dev:watch": "cross-env NODE_ENV=development concurrently -n \"Watch,Dev\" -c \"green,blue\" \"npm run watch\" \"sleep 1 && npm run dev\" ",
"build": "rimraf dist && rollup -c",
"dev": "bun run --watch --hot --inspect src/index.ts",
"cmd": "bun run src/run.ts ",
"prebuild": "rimraf dist",
"build": "NODE_ENV=production bun bun.config.mjs",
"start": "pm2 start dist/app.mjs --name page-proxy",
"release": "node ./scripts/release/index.mjs",
"deploy": "envision pack -p -u",
@ -31,7 +31,7 @@
"author": "",
"license": "ISC",
"devDependencies": {
"@kevisual/logger": "^0.0.3",
"@kevisual/logger": "^0.0.4",
"@kevisual/oss": "^0.0.11",
"@rollup/plugin-commonjs": "^28.0.3",
"@rollup/plugin-json": "^6.1.0",
@ -39,22 +39,24 @@
"@rollup/plugin-typescript": "^12.1.2",
"@types/busboy": "^1.5.4",
"@types/http-proxy": "^1.17.16",
"@types/node": "^22.15.17",
"@types/node": "^22.15.21",
"@types/send": "^0.17.4",
"@types/ws": "^8.18.1",
"concurrently": "^9.1.2",
"cross-env": "^7.0.3",
"nodemon": "^3.1.10",
"rollup": "^4.40.2",
"rollup": "^4.41.0",
"tslib": "^2.8.1",
"typescript": "^5.8.3"
"typescript": "^5.8.3",
"ws": "npm:@kevisual/ws"
},
"dependencies": {
"@kevisual/code-center-module": "0.0.18",
"@kevisual/permission": "^0.0.1",
"@kevisual/query": "^0.0.17",
"@kevisual/permission": "^0.0.3",
"@kevisual/query": "^0.0.18",
"@kevisual/query-config": "^0.0.2",
"@kevisual/router": "0.0.14",
"@kevisual/use-config": "^1.0.15",
"@kevisual/router": "0.0.21",
"@kevisual/use-config": "^1.0.17",
"@types/lodash-es": "^4.17.12",
"archiver": "^7.0.1",
"busboy": "^1.6.0",

340
pnpm-lock.yaml generated
View File

@ -13,22 +13,22 @@ importers:
dependencies:
'@kevisual/code-center-module':
specifier: 0.0.18
version: 0.0.18(@kevisual/auth@1.0.5)(@kevisual/router@0.0.14)(@kevisual/use-config@1.0.15(dotenv@16.4.7))(ioredis@5.6.1)(pg@8.13.3)(sequelize@6.37.7(pg@8.13.3))
version: 0.0.18(@kevisual/auth@1.0.5)(@kevisual/router@0.0.21)(@kevisual/use-config@1.0.17(dotenv@16.4.7))(ioredis@5.6.1)(pg@8.13.3)(sequelize@6.37.7(pg@8.13.3))
'@kevisual/permission':
specifier: ^0.0.1
version: 0.0.1
specifier: ^0.0.3
version: 0.0.3
'@kevisual/query':
specifier: ^0.0.17
version: 0.0.17(ws@8.18.0)(zod@3.24.2)
specifier: ^0.0.18
version: 0.0.18(@kevisual/ws@8.0.0)(zod@3.24.2)
'@kevisual/query-config':
specifier: ^0.0.2
version: 0.0.2(@kevisual/query@0.0.17(ws@8.18.0)(zod@3.24.2))
version: 0.0.2(@kevisual/query@0.0.18(@kevisual/ws@8.0.0)(zod@3.24.2))
'@kevisual/router':
specifier: 0.0.14
version: 0.0.14
specifier: 0.0.21
version: 0.0.21
'@kevisual/use-config':
specifier: ^1.0.15
version: 1.0.15(dotenv@16.4.7)
specifier: ^1.0.17
version: 1.0.17(dotenv@16.4.7)
'@types/lodash-es':
specifier: ^4.17.12
version: 4.17.12
@ -61,23 +61,23 @@ importers:
version: 6.37.7(pg@8.13.3)
devDependencies:
'@kevisual/logger':
specifier: ^0.0.3
version: 0.0.3
specifier: ^0.0.4
version: 0.0.4
'@kevisual/oss':
specifier: ^0.0.11
version: 0.0.11
'@rollup/plugin-commonjs':
specifier: ^28.0.3
version: 28.0.3(rollup@4.40.2)
version: 28.0.3(rollup@4.41.0)
'@rollup/plugin-json':
specifier: ^6.1.0
version: 6.1.0(rollup@4.40.2)
version: 6.1.0(rollup@4.41.0)
'@rollup/plugin-node-resolve':
specifier: ^16.0.1
version: 16.0.1(rollup@4.40.2)
version: 16.0.1(rollup@4.41.0)
'@rollup/plugin-typescript':
specifier: ^12.1.2
version: 12.1.2(rollup@4.40.2)(tslib@2.8.1)(typescript@5.8.3)
version: 12.1.2(rollup@4.41.0)(tslib@2.8.1)(typescript@5.8.3)
'@types/busboy':
specifier: ^1.5.4
version: 1.5.4
@ -85,11 +85,14 @@ importers:
specifier: ^1.17.16
version: 1.17.16
'@types/node':
specifier: ^22.15.17
version: 22.15.17
specifier: ^22.15.21
version: 22.15.21
'@types/send':
specifier: ^0.17.4
version: 0.17.4
'@types/ws':
specifier: ^8.18.1
version: 8.18.1
concurrently:
specifier: ^9.1.2
version: 9.1.2
@ -100,14 +103,17 @@ importers:
specifier: ^3.1.10
version: 3.1.10
rollup:
specifier: ^4.40.2
version: 4.40.2
specifier: ^4.41.0
version: 4.41.0
tslib:
specifier: ^2.8.1
version: 2.8.1
typescript:
specifier: ^5.8.3
version: 5.8.3
ws:
specifier: npm:@kevisual/ws
version: '@kevisual/ws@8.0.0'
packages:
@ -137,31 +143,35 @@ packages:
'@kevisual/load@0.0.6':
resolution: {integrity: sha512-+3YTFehRcZ1haGel5DKYMUwmi5i6f2psyaPZlfkKU/cOXgkpwoG9/BEqPCnPjicKqqnksEpixVRkyHJ+5bjLVA==}
'@kevisual/logger@0.0.3':
resolution: {integrity: sha512-8emqxg+ab62WAK6VY4FQqetXPSSVKFAjGctD1NDbdnxt7YWuI/PyuDltCpsVz+uvWpV1dO5OKZOoHU7ow59Omw==}
'@kevisual/logger@0.0.4':
resolution: {integrity: sha512-+fpr92eokSxoGOW1SIRl/27lPuO+zyY+feR5o2Q4YCNlAdt2x64NwC/w8r/3NEC5QenLgd4K0azyKTI2mHbARw==}
'@kevisual/oss@0.0.11':
resolution: {integrity: sha512-oxC6KVTNeDUaoAAVHyNVhSg9JPj1FzwbP5PkYvTj2VHC3PvFtvG//m6Zii7yKpFv7itKzMuS7/9xDMdI5lPhaA==}
'@kevisual/permission@0.0.1':
resolution: {integrity: sha512-nSX2LzbPkU3YAMegbUFGU8tfmtFb7dcF5edqzm+gI6crcyCL1JzIB9HAYNEeEVIljLxuREwM/vVg9aFmF4cz9Q==}
'@kevisual/permission@0.0.3':
resolution: {integrity: sha512-8JsA/5O5Ax/z+M+MYpFYdlioHE6jNmWMuFSokBWYs9CCAHNiSKMR01YLkoVDoPvncfH/Y8F5K/IEXRCbptuMNA==}
'@kevisual/query-config@0.0.2':
resolution: {integrity: sha512-JcDq/gS0Y1FQfGm9OxNGZwxm4Pgmu24NEvWrZ6TLf3VCk/WsaOtzkNX5pf2rnwxF9FETaLAwa0g2nAYVLsELRA==}
peerDependencies:
'@kevisual/query': ^0.0.13
'@kevisual/query@0.0.17':
resolution: {integrity: sha512-WMvWM+3pNlPKNhoxPX9fldMp1tOeJrkRM/tXA4bvOnftIoX2yeI4v0wTpbGJXES/bLlo7OC2kV8SeKF0K6dnxQ==}
'@kevisual/query@0.0.18':
resolution: {integrity: sha512-I2vHTu0I6AyD9PJyr+vxyp9jIJ6rd2EZqLVHTv/+zrVKVc2SS76Tg7aGNkmAFqqLSCB8kLLsmMGtSJU1Qb8VVg==}
'@kevisual/router@0.0.14':
resolution: {integrity: sha512-eHOSD6gzs/Ed9DDTq9VCEM3uw3Wh1vPFlyPo91cEe2rA44t8oJm8g905qmwHVUEjbo5s/rA306ZW/ub06jlNlg==}
'@kevisual/router@0.0.21':
resolution: {integrity: sha512-XKTxbNO924cT18UOAGplWErZ+hMze8Y53F2jYCk18v4jsdsvjRho5uXXjJb6HSVsuITMtQR4R3rG0IcM3jkDKQ==}
'@kevisual/use-config@1.0.15':
resolution: {integrity: sha512-bLWdGMOPHgIKV4qY3U18cLoOKmSBL72K1wL0MneyEsqj9jRXoc98OMMyQm2/BlBddFTL1olOfByRET2DvwmWAA==}
'@kevisual/use-config@1.0.17':
resolution: {integrity: sha512-EsuMJ5bhAbdERvpD55td1diRxx4kSxtYVaIHo0vDvnLetuXLfq+j2DPGmWl/oRdO48op0dme5oo1DctCqpgYcQ==}
peerDependencies:
dotenv: ^16.4.7
'@kevisual/ws@8.0.0':
resolution: {integrity: sha512-jlFxSlXUEz93cFW+UYT5BXv/rFVgiMQnIfqRYZ0gj1hSP8PMGRqMqUoHSLfKvfRRS4jseLSvTTeEKSQpZJtURg==}
engines: {node: '>=10.0.0'}
'@pkgjs/parseargs@0.11.0':
resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==}
engines: {node: '>=14'}
@ -215,103 +225,103 @@ packages:
rollup:
optional: true
'@rollup/rollup-android-arm-eabi@4.40.2':
resolution: {integrity: sha512-JkdNEq+DFxZfUwxvB58tHMHBHVgX23ew41g1OQinthJ+ryhdRk67O31S7sYw8u2lTjHUPFxwar07BBt1KHp/hg==}
'@rollup/rollup-android-arm-eabi@4.41.0':
resolution: {integrity: sha512-KxN+zCjOYHGwCl4UCtSfZ6jrq/qi88JDUtiEFk8LELEHq2Egfc/FgW+jItZiOLRuQfb/3xJSgFuNPC9jzggX+A==}
cpu: [arm]
os: [android]
'@rollup/rollup-android-arm64@4.40.2':
resolution: {integrity: sha512-13unNoZ8NzUmnndhPTkWPWbX3vtHodYmy+I9kuLxN+F+l+x3LdVF7UCu8TWVMt1POHLh6oDHhnOA04n8oJZhBw==}
'@rollup/rollup-android-arm64@4.41.0':
resolution: {integrity: sha512-yDvqx3lWlcugozax3DItKJI5j05B0d4Kvnjx+5mwiUpWramVvmAByYigMplaoAQ3pvdprGCTCE03eduqE/8mPQ==}
cpu: [arm64]
os: [android]
'@rollup/rollup-darwin-arm64@4.40.2':
resolution: {integrity: sha512-Gzf1Hn2Aoe8VZzevHostPX23U7N5+4D36WJNHK88NZHCJr7aVMG4fadqkIf72eqVPGjGc0HJHNuUaUcxiR+N/w==}
'@rollup/rollup-darwin-arm64@4.41.0':
resolution: {integrity: sha512-2KOU574vD3gzcPSjxO0eyR5iWlnxxtmW1F5CkNOHmMlueKNCQkxR6+ekgWyVnz6zaZihpUNkGxjsYrkTJKhkaw==}
cpu: [arm64]
os: [darwin]
'@rollup/rollup-darwin-x64@4.40.2':
resolution: {integrity: sha512-47N4hxa01a4x6XnJoskMKTS8XZ0CZMd8YTbINbi+w03A2w4j1RTlnGHOz/P0+Bg1LaVL6ufZyNprSg+fW5nYQQ==}
'@rollup/rollup-darwin-x64@4.41.0':
resolution: {integrity: sha512-gE5ACNSxHcEZyP2BA9TuTakfZvULEW4YAOtxl/A/YDbIir/wPKukde0BNPlnBiP88ecaN4BJI2TtAd+HKuZPQQ==}
cpu: [x64]
os: [darwin]
'@rollup/rollup-freebsd-arm64@4.40.2':
resolution: {integrity: sha512-8t6aL4MD+rXSHHZUR1z19+9OFJ2rl1wGKvckN47XFRVO+QL/dUSpKA2SLRo4vMg7ELA8pzGpC+W9OEd1Z/ZqoQ==}
'@rollup/rollup-freebsd-arm64@4.41.0':
resolution: {integrity: sha512-GSxU6r5HnWij7FoSo7cZg3l5GPg4HFLkzsFFh0N/b16q5buW1NAWuCJ+HMtIdUEi6XF0qH+hN0TEd78laRp7Dg==}
cpu: [arm64]
os: [freebsd]
'@rollup/rollup-freebsd-x64@4.40.2':
resolution: {integrity: sha512-C+AyHBzfpsOEYRFjztcYUFsH4S7UsE9cDtHCtma5BK8+ydOZYgMmWg1d/4KBytQspJCld8ZIujFMAdKG1xyr4Q==}
'@rollup/rollup-freebsd-x64@4.41.0':
resolution: {integrity: sha512-KGiGKGDg8qLRyOWmk6IeiHJzsN/OYxO6nSbT0Vj4MwjS2XQy/5emsmtoqLAabqrohbgLWJ5GV3s/ljdrIr8Qjg==}
cpu: [x64]
os: [freebsd]
'@rollup/rollup-linux-arm-gnueabihf@4.40.2':
resolution: {integrity: sha512-de6TFZYIvJwRNjmW3+gaXiZ2DaWL5D5yGmSYzkdzjBDS3W+B9JQ48oZEsmMvemqjtAFzE16DIBLqd6IQQRuG9Q==}
'@rollup/rollup-linux-arm-gnueabihf@4.41.0':
resolution: {integrity: sha512-46OzWeqEVQyX3N2/QdiU/CMXYDH/lSHpgfBkuhl3igpZiaB3ZIfSjKuOnybFVBQzjsLwkus2mjaESy8H41SzvA==}
cpu: [arm]
os: [linux]
'@rollup/rollup-linux-arm-musleabihf@4.40.2':
resolution: {integrity: sha512-urjaEZubdIkacKc930hUDOfQPysezKla/O9qV+O89enqsqUmQm8Xj8O/vh0gHg4LYfv7Y7UsE3QjzLQzDYN1qg==}
'@rollup/rollup-linux-arm-musleabihf@4.41.0':
resolution: {integrity: sha512-lfgW3KtQP4YauqdPpcUZHPcqQXmTmH4nYU0cplNeW583CMkAGjtImw4PKli09NFi2iQgChk4e9erkwlfYem6Lg==}
cpu: [arm]
os: [linux]
'@rollup/rollup-linux-arm64-gnu@4.40.2':
resolution: {integrity: sha512-KlE8IC0HFOC33taNt1zR8qNlBYHj31qGT1UqWqtvR/+NuCVhfufAq9fxO8BMFC22Wu0rxOwGVWxtCMvZVLmhQg==}
'@rollup/rollup-linux-arm64-gnu@4.41.0':
resolution: {integrity: sha512-nn8mEyzMbdEJzT7cwxgObuwviMx6kPRxzYiOl6o/o+ChQq23gfdlZcUNnt89lPhhz3BYsZ72rp0rxNqBSfqlqw==}
cpu: [arm64]
os: [linux]
'@rollup/rollup-linux-arm64-musl@4.40.2':
resolution: {integrity: sha512-j8CgxvfM0kbnhu4XgjnCWJQyyBOeBI1Zq91Z850aUddUmPeQvuAy6OiMdPS46gNFgy8gN1xkYyLgwLYZG3rBOg==}
'@rollup/rollup-linux-arm64-musl@4.41.0':
resolution: {integrity: sha512-l+QK99je2zUKGd31Gh+45c4pGDAqZSuWQiuRFCdHYC2CSiO47qUWsCcenrI6p22hvHZrDje9QjwSMAFL3iwXwQ==}
cpu: [arm64]
os: [linux]
'@rollup/rollup-linux-loongarch64-gnu@4.40.2':
resolution: {integrity: sha512-Ybc/1qUampKuRF4tQXc7G7QY9YRyeVSykfK36Y5Qc5dmrIxwFhrOzqaVTNoZygqZ1ZieSWTibfFhQ5qK8jpWxw==}
'@rollup/rollup-linux-loongarch64-gnu@4.41.0':
resolution: {integrity: sha512-WbnJaxPv1gPIm6S8O/Wg+wfE/OzGSXlBMbOe4ie+zMyykMOeqmgD1BhPxZQuDqwUN+0T/xOFtL2RUWBspnZj3w==}
cpu: [loong64]
os: [linux]
'@rollup/rollup-linux-powerpc64le-gnu@4.40.2':
resolution: {integrity: sha512-3FCIrnrt03CCsZqSYAOW/k9n625pjpuMzVfeI+ZBUSDT3MVIFDSPfSUgIl9FqUftxcUXInvFah79hE1c9abD+Q==}
'@rollup/rollup-linux-powerpc64le-gnu@4.41.0':
resolution: {integrity: sha512-eRDWR5t67/b2g8Q/S8XPi0YdbKcCs4WQ8vklNnUYLaSWF+Cbv2axZsp4jni6/j7eKvMLYCYdcsv8dcU+a6QNFg==}
cpu: [ppc64]
os: [linux]
'@rollup/rollup-linux-riscv64-gnu@4.40.2':
resolution: {integrity: sha512-QNU7BFHEvHMp2ESSY3SozIkBPaPBDTsfVNGx3Xhv+TdvWXFGOSH2NJvhD1zKAT6AyuuErJgbdvaJhYVhVqrWTg==}
'@rollup/rollup-linux-riscv64-gnu@4.41.0':
resolution: {integrity: sha512-TWrZb6GF5jsEKG7T1IHwlLMDRy2f3DPqYldmIhnA2DVqvvhY2Ai184vZGgahRrg8k9UBWoSlHv+suRfTN7Ua4A==}
cpu: [riscv64]
os: [linux]
'@rollup/rollup-linux-riscv64-musl@4.40.2':
resolution: {integrity: sha512-5W6vNYkhgfh7URiXTO1E9a0cy4fSgfE4+Hl5agb/U1sa0kjOLMLC1wObxwKxecE17j0URxuTrYZZME4/VH57Hg==}
'@rollup/rollup-linux-riscv64-musl@4.41.0':
resolution: {integrity: sha512-ieQljaZKuJpmWvd8gW87ZmSFwid6AxMDk5bhONJ57U8zT77zpZ/TPKkU9HpnnFrM4zsgr4kiGuzbIbZTGi7u9A==}
cpu: [riscv64]
os: [linux]
'@rollup/rollup-linux-s390x-gnu@4.40.2':
resolution: {integrity: sha512-B7LKIz+0+p348JoAL4X/YxGx9zOx3sR+o6Hj15Y3aaApNfAshK8+mWZEf759DXfRLeL2vg5LYJBB7DdcleYCoQ==}
'@rollup/rollup-linux-s390x-gnu@4.41.0':
resolution: {integrity: sha512-/L3pW48SxrWAlVsKCN0dGLB2bi8Nv8pr5S5ocSM+S0XCn5RCVCXqi8GVtHFsOBBCSeR+u9brV2zno5+mg3S4Aw==}
cpu: [s390x]
os: [linux]
'@rollup/rollup-linux-x64-gnu@4.40.2':
resolution: {integrity: sha512-lG7Xa+BmBNwpjmVUbmyKxdQJ3Q6whHjMjzQplOs5Z+Gj7mxPtWakGHqzMqNER68G67kmCX9qX57aRsW5V0VOng==}
'@rollup/rollup-linux-x64-gnu@4.41.0':
resolution: {integrity: sha512-XMLeKjyH8NsEDCRptf6LO8lJk23o9wvB+dJwcXMaH6ZQbbkHu2dbGIUindbMtRN6ux1xKi16iXWu6q9mu7gDhQ==}
cpu: [x64]
os: [linux]
'@rollup/rollup-linux-x64-musl@4.40.2':
resolution: {integrity: sha512-tD46wKHd+KJvsmije4bUskNuvWKFcTOIM9tZ/RrmIvcXnbi0YK/cKS9FzFtAm7Oxi2EhV5N2OpfFB348vSQRXA==}
'@rollup/rollup-linux-x64-musl@4.41.0':
resolution: {integrity: sha512-m/P7LycHZTvSQeXhFmgmdqEiTqSV80zn6xHaQ1JSqwCtD1YGtwEK515Qmy9DcB2HK4dOUVypQxvhVSy06cJPEg==}
cpu: [x64]
os: [linux]
'@rollup/rollup-win32-arm64-msvc@4.40.2':
resolution: {integrity: sha512-Bjv/HG8RRWLNkXwQQemdsWw4Mg+IJ29LK+bJPW2SCzPKOUaMmPEppQlu/Fqk1d7+DX3V7JbFdbkh/NMmurT6Pg==}
'@rollup/rollup-win32-arm64-msvc@4.41.0':
resolution: {integrity: sha512-4yodtcOrFHpbomJGVEqZ8fzD4kfBeCbpsUy5Pqk4RluXOdsWdjLnjhiKy2w3qzcASWd04fp52Xz7JKarVJ5BTg==}
cpu: [arm64]
os: [win32]
'@rollup/rollup-win32-ia32-msvc@4.40.2':
resolution: {integrity: sha512-dt1llVSGEsGKvzeIO76HToiYPNPYPkmjhMHhP00T9S4rDern8P2ZWvWAQUEJ+R1UdMWJ/42i/QqJ2WV765GZcA==}
'@rollup/rollup-win32-ia32-msvc@4.41.0':
resolution: {integrity: sha512-tmazCrAsKzdkXssEc65zIE1oC6xPHwfy9d5Ta25SRCDOZS+I6RypVVShWALNuU9bxIfGA0aqrmzlzoM5wO5SPQ==}
cpu: [ia32]
os: [win32]
'@rollup/rollup-win32-x64-msvc@4.40.2':
resolution: {integrity: sha512-bwspbWB04XJpeElvsp+DCylKfF4trJDa2Y9Go8O6A7YLX2LIKGcNK/CYImJN6ZP4DcuOHB4Utl3iCbnR62DudA==}
'@rollup/rollup-win32-x64-msvc@4.41.0':
resolution: {integrity: sha512-h1J+Yzjo/X+0EAvR2kIXJDuTuyT7drc+t2ALY0nIcGPbTatNOf0VWdhEA2Z4AAjv6X1NJV7SYo5oCTYRJhSlVA==}
cpu: [x64]
os: [win32]
@ -357,8 +367,8 @@ packages:
'@types/node@18.19.86':
resolution: {integrity: sha512-fifKayi175wLyKyc5qUfyENhQ1dCNI1UNjp653d8kuYcPQN5JhX3dGuP/XmvPTg/xRBn1VTLpbmi+H/Mr7tLfQ==}
'@types/node@22.15.17':
resolution: {integrity: sha512-wIX2aSZL5FE+MR0JlvF87BNVrtFWf6AE6rxSE9X7OwnVvoyCQjpzSRJ+M87se/4QCkCiebQAqrJ0y6fwIyi7nw==}
'@types/node@22.15.21':
resolution: {integrity: sha512-EV/37Td6c+MgKAbkcLG6vqZ2zEYHD7bvSrzqqs2RIhbA6w3x+Dqz8MZM3sP6kGTeLrdoOgKZe+Xja7tUB2DNkQ==}
'@types/resolve@1.20.2':
resolution: {integrity: sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==}
@ -369,6 +379,9 @@ packages:
'@types/validator@13.12.2':
resolution: {integrity: sha512-6SlHBzUW8Jhf3liqrGGXyTJSIFe4nqlJ5A5KaMZ2l/vbM3Wh3KSybots/wfWVzNLK4D1NZluDlSQIbIEPx6oyA==}
'@types/ws@8.18.1':
resolution: {integrity: sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==}
'@zxing/text-encoding@0.9.0':
resolution: {integrity: sha512-U/4aVJ2mxI0aDNI8Uq0wEhMgY+u4CNtEb0om3+y3+niDAsoTCOB33UF0sxpzqzdqXLqmvc+vZyAt4O8pPdfkwA==}
@ -977,8 +990,8 @@ packages:
resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==}
engines: {node: '>= 0.8'}
openai@4.91.1:
resolution: {integrity: sha512-DbjrR0hIMQFbxz8+3qBsfPJnh3+I/skPgoSlT7f9eiZuhGBUissPQULNgx6gHNkLoZ3uS0uYS6eXPUdtg4nHzw==}
openai@4.102.0:
resolution: {integrity: sha512-CWk15CMhPSHNZnjz+6rwVYV551xaC8CwOd7/zxImrC1btEo37dX/Ii5tBKWfqqxqyzpJ6p3Y4bICzzKhW03WhQ==}
hasBin: true
peerDependencies:
ws: ^8.18.0
@ -1120,8 +1133,8 @@ packages:
retry-as-promised@7.1.1:
resolution: {integrity: sha512-hMD7odLOt3LkTjcif8aRZqi/hybjpLNgSk5oF5FCowfCjok6LukpN2bDX7R5wDmbgBQFn7YoBxSagmtXHaJYJw==}
rollup@4.40.2:
resolution: {integrity: sha512-tfUOg6DTP4rhQ3VjOO6B4wyrJnGOX85requAXvqYTHsOgb2TFJdZ3aWpT8W2kPoypSGP7dZUyzxJ9ee4buM5Fg==}
rollup@4.41.0:
resolution: {integrity: sha512-HqMFpUbWlf/tvcxBFNKnJyzc7Lk+XO3FGc3pbNBLqEbOz0gPLRgcrlS3UF4MfUrVlstOaP/q0kM6GVvi+LrLRg==}
engines: {node: '>=18.0.0', npm: '>=8.0.0'}
hasBin: true
@ -1413,18 +1426,6 @@ packages:
utf-8-validate:
optional: true
ws@8.18.0:
resolution: {integrity: sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==}
engines: {node: '>=10.0.0'}
peerDependencies:
bufferutil: ^4.0.1
utf-8-validate: '>=5.0.2'
peerDependenciesMeta:
bufferutil:
optional: true
utf-8-validate:
optional: true
xml2js@0.6.2:
resolution: {integrity: sha512-T4rieHaC1EXcES0Kxxj4JWgaUQHDk+qwHcYOCFHfiwKz7tOVPLq7Hjq9dM1WCMhylqMEfP7hMcOIChvotiZegA==}
engines: {node: '>=4.0.0'}
@ -1473,11 +1474,11 @@ snapshots:
'@kevisual/auth@1.0.5': {}
'@kevisual/code-center-module@0.0.18(@kevisual/auth@1.0.5)(@kevisual/router@0.0.14)(@kevisual/use-config@1.0.15(dotenv@16.4.7))(ioredis@5.6.1)(pg@8.13.3)(sequelize@6.37.7(pg@8.13.3))':
'@kevisual/code-center-module@0.0.18(@kevisual/auth@1.0.5)(@kevisual/router@0.0.21)(@kevisual/use-config@1.0.17(dotenv@16.4.7))(ioredis@5.6.1)(pg@8.13.3)(sequelize@6.37.7(pg@8.13.3))':
dependencies:
'@kevisual/auth': 1.0.5
'@kevisual/router': 0.0.14
'@kevisual/use-config': 1.0.15(dotenv@16.4.7)
'@kevisual/router': 0.0.21
'@kevisual/use-config': 1.0.17(dotenv@16.4.7)
ioredis: 5.6.1
nanoid: 5.1.5
pg: 8.13.3
@ -1493,40 +1494,42 @@ snapshots:
dependencies:
eventemitter3: 5.0.1
'@kevisual/logger@0.0.3': {}
'@kevisual/logger@0.0.4': {}
'@kevisual/oss@0.0.11': {}
'@kevisual/permission@0.0.1': {}
'@kevisual/permission@0.0.3': {}
'@kevisual/query-config@0.0.2(@kevisual/query@0.0.17(ws@8.18.0)(zod@3.24.2))':
'@kevisual/query-config@0.0.2(@kevisual/query@0.0.18(@kevisual/ws@8.0.0)(zod@3.24.2))':
dependencies:
'@kevisual/query': 0.0.17(ws@8.18.0)(zod@3.24.2)
'@kevisual/query': 0.0.18(@kevisual/ws@8.0.0)(zod@3.24.2)
'@kevisual/query@0.0.17(ws@8.18.0)(zod@3.24.2)':
'@kevisual/query@0.0.18(@kevisual/ws@8.0.0)(zod@3.24.2)':
dependencies:
openai: 4.91.1(ws@8.18.0)(zod@3.24.2)
openai: 4.102.0(@kevisual/ws@8.0.0)(zod@3.24.2)
transitivePeerDependencies:
- encoding
- ws
- zod
'@kevisual/router@0.0.14':
'@kevisual/router@0.0.21':
dependencies:
path-to-regexp: 8.2.0
selfsigned: 2.4.1
'@kevisual/use-config@1.0.15(dotenv@16.4.7)':
'@kevisual/use-config@1.0.17(dotenv@16.4.7)':
dependencies:
'@kevisual/load': 0.0.6
dotenv: 16.4.7
'@kevisual/ws@8.0.0': {}
'@pkgjs/parseargs@0.11.0':
optional: true
'@rollup/plugin-commonjs@28.0.3(rollup@4.40.2)':
'@rollup/plugin-commonjs@28.0.3(rollup@4.41.0)':
dependencies:
'@rollup/pluginutils': 5.1.2(rollup@4.40.2)
'@rollup/pluginutils': 5.1.2(rollup@4.41.0)
commondir: 1.0.1
estree-walker: 2.0.2
fdir: 6.4.0(picomatch@4.0.2)
@ -1534,110 +1537,110 @@ snapshots:
magic-string: 0.30.11
picomatch: 4.0.2
optionalDependencies:
rollup: 4.40.2
rollup: 4.41.0
'@rollup/plugin-json@6.1.0(rollup@4.40.2)':
'@rollup/plugin-json@6.1.0(rollup@4.41.0)':
dependencies:
'@rollup/pluginutils': 5.1.2(rollup@4.40.2)
'@rollup/pluginutils': 5.1.2(rollup@4.41.0)
optionalDependencies:
rollup: 4.40.2
rollup: 4.41.0
'@rollup/plugin-node-resolve@16.0.1(rollup@4.40.2)':
'@rollup/plugin-node-resolve@16.0.1(rollup@4.41.0)':
dependencies:
'@rollup/pluginutils': 5.1.2(rollup@4.40.2)
'@rollup/pluginutils': 5.1.2(rollup@4.41.0)
'@types/resolve': 1.20.2
deepmerge: 4.3.1
is-module: 1.0.0
resolve: 1.22.8
optionalDependencies:
rollup: 4.40.2
rollup: 4.41.0
'@rollup/plugin-typescript@12.1.2(rollup@4.40.2)(tslib@2.8.1)(typescript@5.8.3)':
'@rollup/plugin-typescript@12.1.2(rollup@4.41.0)(tslib@2.8.1)(typescript@5.8.3)':
dependencies:
'@rollup/pluginutils': 5.1.2(rollup@4.40.2)
'@rollup/pluginutils': 5.1.2(rollup@4.41.0)
resolve: 1.22.8
typescript: 5.8.3
optionalDependencies:
rollup: 4.40.2
rollup: 4.41.0
tslib: 2.8.1
'@rollup/pluginutils@5.1.2(rollup@4.40.2)':
'@rollup/pluginutils@5.1.2(rollup@4.41.0)':
dependencies:
'@types/estree': 1.0.6
estree-walker: 2.0.2
picomatch: 4.0.2
optionalDependencies:
rollup: 4.40.2
rollup: 4.41.0
'@rollup/rollup-android-arm-eabi@4.40.2':
'@rollup/rollup-android-arm-eabi@4.41.0':
optional: true
'@rollup/rollup-android-arm64@4.40.2':
'@rollup/rollup-android-arm64@4.41.0':
optional: true
'@rollup/rollup-darwin-arm64@4.40.2':
'@rollup/rollup-darwin-arm64@4.41.0':
optional: true
'@rollup/rollup-darwin-x64@4.40.2':
'@rollup/rollup-darwin-x64@4.41.0':
optional: true
'@rollup/rollup-freebsd-arm64@4.40.2':
'@rollup/rollup-freebsd-arm64@4.41.0':
optional: true
'@rollup/rollup-freebsd-x64@4.40.2':
'@rollup/rollup-freebsd-x64@4.41.0':
optional: true
'@rollup/rollup-linux-arm-gnueabihf@4.40.2':
'@rollup/rollup-linux-arm-gnueabihf@4.41.0':
optional: true
'@rollup/rollup-linux-arm-musleabihf@4.40.2':
'@rollup/rollup-linux-arm-musleabihf@4.41.0':
optional: true
'@rollup/rollup-linux-arm64-gnu@4.40.2':
'@rollup/rollup-linux-arm64-gnu@4.41.0':
optional: true
'@rollup/rollup-linux-arm64-musl@4.40.2':
'@rollup/rollup-linux-arm64-musl@4.41.0':
optional: true
'@rollup/rollup-linux-loongarch64-gnu@4.40.2':
'@rollup/rollup-linux-loongarch64-gnu@4.41.0':
optional: true
'@rollup/rollup-linux-powerpc64le-gnu@4.40.2':
'@rollup/rollup-linux-powerpc64le-gnu@4.41.0':
optional: true
'@rollup/rollup-linux-riscv64-gnu@4.40.2':
'@rollup/rollup-linux-riscv64-gnu@4.41.0':
optional: true
'@rollup/rollup-linux-riscv64-musl@4.40.2':
'@rollup/rollup-linux-riscv64-musl@4.41.0':
optional: true
'@rollup/rollup-linux-s390x-gnu@4.40.2':
'@rollup/rollup-linux-s390x-gnu@4.41.0':
optional: true
'@rollup/rollup-linux-x64-gnu@4.40.2':
'@rollup/rollup-linux-x64-gnu@4.41.0':
optional: true
'@rollup/rollup-linux-x64-musl@4.40.2':
'@rollup/rollup-linux-x64-musl@4.41.0':
optional: true
'@rollup/rollup-win32-arm64-msvc@4.40.2':
'@rollup/rollup-win32-arm64-msvc@4.41.0':
optional: true
'@rollup/rollup-win32-ia32-msvc@4.40.2':
'@rollup/rollup-win32-ia32-msvc@4.41.0':
optional: true
'@rollup/rollup-win32-x64-msvc@4.40.2':
'@rollup/rollup-win32-x64-msvc@4.41.0':
optional: true
'@socket.io/component-emitter@3.1.2': {}
'@types/busboy@1.5.4':
dependencies:
'@types/node': 22.15.17
'@types/node': 22.15.21
'@types/cors@2.8.17':
dependencies:
'@types/node': 22.15.17
'@types/node': 22.15.21
'@types/debug@4.1.12':
dependencies:
@ -1649,7 +1652,7 @@ snapshots:
'@types/http-proxy@1.17.16':
dependencies:
'@types/node': 22.15.17
'@types/node': 22.15.21
'@types/lodash-es@4.17.12':
dependencies:
@ -1663,18 +1666,18 @@ snapshots:
'@types/node-fetch@2.6.12':
dependencies:
'@types/node': 22.15.17
'@types/node': 22.15.21
form-data: 4.0.2
'@types/node-forge@1.3.11':
dependencies:
'@types/node': 22.15.17
'@types/node': 22.15.21
'@types/node@18.19.86':
dependencies:
undici-types: 5.26.5
'@types/node@22.15.17':
'@types/node@22.15.21':
dependencies:
undici-types: 6.21.0
@ -1683,10 +1686,14 @@ snapshots:
'@types/send@0.17.4':
dependencies:
'@types/mime': 1.3.5
'@types/node': 22.15.17
'@types/node': 22.15.21
'@types/validator@13.12.2': {}
'@types/ws@8.18.1':
dependencies:
'@types/node': 22.15.21
'@zxing/text-encoding@0.9.0':
optional: true
@ -1944,7 +1951,7 @@ snapshots:
engine.io@6.6.4:
dependencies:
'@types/cors': 2.8.17
'@types/node': 22.15.17
'@types/node': 22.15.21
accepts: 1.3.8
base64id: 2.0.0
cookie: 0.7.2
@ -2288,7 +2295,7 @@ snapshots:
dependencies:
ee-first: 1.1.1
openai@4.91.1(ws@8.18.0)(zod@3.24.2):
openai@4.102.0(@kevisual/ws@8.0.0)(zod@3.24.2):
dependencies:
'@types/node': 18.19.86
'@types/node-fetch': 2.6.12
@ -2298,7 +2305,7 @@ snapshots:
formdata-node: 4.4.1
node-fetch: 2.7.0
optionalDependencies:
ws: 8.18.0
ws: '@kevisual/ws@8.0.0'
zod: 3.24.2
transitivePeerDependencies:
- encoding
@ -2428,30 +2435,30 @@ snapshots:
retry-as-promised@7.1.1: {}
rollup@4.40.2:
rollup@4.41.0:
dependencies:
'@types/estree': 1.0.7
optionalDependencies:
'@rollup/rollup-android-arm-eabi': 4.40.2
'@rollup/rollup-android-arm64': 4.40.2
'@rollup/rollup-darwin-arm64': 4.40.2
'@rollup/rollup-darwin-x64': 4.40.2
'@rollup/rollup-freebsd-arm64': 4.40.2
'@rollup/rollup-freebsd-x64': 4.40.2
'@rollup/rollup-linux-arm-gnueabihf': 4.40.2
'@rollup/rollup-linux-arm-musleabihf': 4.40.2
'@rollup/rollup-linux-arm64-gnu': 4.40.2
'@rollup/rollup-linux-arm64-musl': 4.40.2
'@rollup/rollup-linux-loongarch64-gnu': 4.40.2
'@rollup/rollup-linux-powerpc64le-gnu': 4.40.2
'@rollup/rollup-linux-riscv64-gnu': 4.40.2
'@rollup/rollup-linux-riscv64-musl': 4.40.2
'@rollup/rollup-linux-s390x-gnu': 4.40.2
'@rollup/rollup-linux-x64-gnu': 4.40.2
'@rollup/rollup-linux-x64-musl': 4.40.2
'@rollup/rollup-win32-arm64-msvc': 4.40.2
'@rollup/rollup-win32-ia32-msvc': 4.40.2
'@rollup/rollup-win32-x64-msvc': 4.40.2
'@rollup/rollup-android-arm-eabi': 4.41.0
'@rollup/rollup-android-arm64': 4.41.0
'@rollup/rollup-darwin-arm64': 4.41.0
'@rollup/rollup-darwin-x64': 4.41.0
'@rollup/rollup-freebsd-arm64': 4.41.0
'@rollup/rollup-freebsd-x64': 4.41.0
'@rollup/rollup-linux-arm-gnueabihf': 4.41.0
'@rollup/rollup-linux-arm-musleabihf': 4.41.0
'@rollup/rollup-linux-arm64-gnu': 4.41.0
'@rollup/rollup-linux-arm64-musl': 4.41.0
'@rollup/rollup-linux-loongarch64-gnu': 4.41.0
'@rollup/rollup-linux-powerpc64le-gnu': 4.41.0
'@rollup/rollup-linux-riscv64-gnu': 4.41.0
'@rollup/rollup-linux-riscv64-musl': 4.41.0
'@rollup/rollup-linux-s390x-gnu': 4.41.0
'@rollup/rollup-linux-x64-gnu': 4.41.0
'@rollup/rollup-linux-x64-musl': 4.41.0
'@rollup/rollup-win32-arm64-msvc': 4.41.0
'@rollup/rollup-win32-ia32-msvc': 4.41.0
'@rollup/rollup-win32-x64-msvc': 4.41.0
fsevents: 2.3.3
rxjs@7.8.2:
@ -2726,7 +2733,7 @@ snapshots:
wkx@0.5.0:
dependencies:
'@types/node': 22.15.17
'@types/node': 22.15.21
wrap-ansi@7.0.0:
dependencies:
@ -2742,9 +2749,6 @@ snapshots:
ws@8.17.1: {}
ws@8.18.0:
optional: true
xml2js@0.6.2:
dependencies:
sax: 1.4.1

View File

@ -3,6 +3,8 @@ import { config } from './module/config.ts';
import { app } from './app.ts';
import './route/route.ts';
import net from 'net';
import { WssApp } from './module/ws-proxy/index.ts';
const port = config?.proxy?.port || 3005;
app
@ -21,10 +23,16 @@ app.listen(port, () => {
app.server.on(handleRequest);
const wssApp = new WssApp();
const main = () => {
console.log('Upgrade initialization started');
app.server.server.on('upgrade', (req, socket, head) => {
app.server.server.on('upgrade', async (req, socket, head) => {
const isUpgrade = wssApp.upgrade(req, socket, head);
if (isUpgrade) {
console.log('WebSocket upgrade successful for path:', req.url);
return;
}
const proxyApiList = config?.apiList || [];
const proxyApi = proxyApiList.find((item) => req.url.startsWith(item.path));
@ -40,12 +48,12 @@ const main = () => {
const proxySocket = net.connect(options.port, options.hostname, () => {
proxySocket.write(
`GET ${options.path} HTTP/1.1\r\n` +
`Host: ${options.hostname}\r\n` +
`Connection: Upgrade\r\n` +
`Upgrade: websocket\r\n` +
`Sec-WebSocket-Key: ${req.headers['sec-websocket-key']}\r\n` +
`Sec-WebSocket-Version: ${req.headers['sec-websocket-version']}\r\n` +
`\r\n`
`Host: ${options.hostname}\r\n` +
`Connection: Upgrade\r\n` +
`Upgrade: websocket\r\n` +
`Sec-WebSocket-Key: ${req.headers['sec-websocket-key']}\r\n` +
`Sec-WebSocket-Version: ${req.headers['sec-websocket-version']}\r\n` +
`\r\n`,
);
proxySocket.pipe(socket);
socket.pipe(proxySocket);

View File

@ -13,6 +13,7 @@ import { getLoginUser } from '@/middleware/auth.ts';
import { rediretHome } from './user-home/index.ts';
import { aiProxy } from './proxy/ai-proxy.ts';
import { logger } from './logger.ts';
import { UserV1Proxy } from './ws-proxy/proxy.ts';
const domain = config?.proxy?.domain;
const allowedOrigins = config?.proxy?.allowedOrigin || [];
@ -221,8 +222,8 @@ export const handleRequest = async (req: http.IncomingMessage, res: http.ServerR
res.write('Server Error\n');
res.end();
};
const createNotFoundPage = async (msg?: string) => {
res.writeHead(404, { 'Content-Type': 'text/html; charset=utf-8' });
const createNotFoundPage = async (msg?: string, code = 404) => {
res.writeHead(code, { 'Content-Type': 'text/html; charset=utf-8' });
res.write(msg || 'Not Found App\n');
res.end();
};
@ -231,6 +232,11 @@ export const handleRequest = async (req: http.IncomingMessage, res: http.ServerR
createNotFoundPage,
});
}
if (user !== 'api' && app === 'v1') {
return UserV1Proxy(req, res, {
createNotFoundPage,
});
}
const userApp = new UserApp({ user, app });
let isExist = await userApp.getExist();

View File

@ -0,0 +1,72 @@
import { WebSocketServer } from 'ws';
import { nanoid } from 'nanoid';
import { WsProxyManager } from './manager.ts';
import { getLoginUser } from '@/middleware/auth.ts';
export const wsProxyManager = new WsProxyManager();
export const upgrade = async (request: any, socket: any, head: any) => {
const req = request as any;
const url = new URL(req.url, 'http://localhost');
const id = url.searchParams.get('id');
if (url.pathname === '/ws/proxy') {
console.log('upgrade', request.url, id);
wss.handleUpgrade(req, socket, head, (ws) => {
// 这里手动触发 connection 事件
// @ts-ignore
wss.emit('connection', ws, req);
});
return true;
}
return false;
};
export const wss = new WebSocketServer({
noServer: true,
path: '/ws/proxy',
});
wss.on('connection', async (ws, req) => {
console.log('connected', req.url);
// const user = await getLoginUser(req);
// if (!user) {
// ws.send(
// JSON.stringify({
// type: 'error',
// message: 'Invalid authorization',
// }),
// );
// ws.close();
// return;
// }
const url = new URL(req.url, 'http://localhost');
const id = url?.searchParams?.get('id') || nanoid();
const user = 'root';
wsProxyManager.register(id, { user, ws });
ws.send(
JSON.stringify({
type: 'connected',
id,
}),
);
ws.on('message', async (event: Buffer) => {
const eventData = event.toString();
if (!eventData) {
return;
}
const data = JSON.parse(eventData);
console.log('message', data);
});
ws.on('close', () => {
console.log('ws closed');
wsProxyManager.unregister(id, user);
});
});
export class WssApp {
wss: WebSocketServer;
constructor() {
this.wss = wss;
}
upgrade(request: any, socket: any, head: any) {
return upgrade(request, socket, head);
}
}

View File

@ -0,0 +1,84 @@
import { nanoid } from 'nanoid';
import { WebSocket } from 'ws';
import { logger } from '../logger.ts';
class WsMessage {
ws: WebSocket;
user?: string;
constructor({ ws, user }: WssMessageOptions) {
this.ws = ws;
this.user = user;
}
async sendData(data: any, opts?: { timeout?: number }) {
if (this.ws.readyState !== WebSocket.OPEN) {
return { code: 500, message: 'WebSocket is not open' };
}
const timeout = opts?.timeout || 10 * 6 * 1000; // 10 minutes
const id = nanoid();
const message = JSON.stringify({
id,
type: 'proxy',
data,
});
logger.info('ws-proxy sendData', message);
this.ws.send(message);
return new Promise((resolve) => {
const timer = setTimeout(() => {
resolve({
code: 500,
message: 'timeout',
});
}, timeout);
this.ws.once('message', (event: Buffer) => {
const eventData = event.toString();
if (!eventData) {
return;
}
const data = JSON.parse(eventData);
if (data.id === id) {
resolve(data.data);
clearTimeout(timer);
}
});
});
}
}
type WssMessageOptions = {
ws: WebSocket;
user?: string;
};
export class WsProxyManager {
wssMap: Map<string, WsMessage> = new Map();
constructor() {}
getId(id: string, user?: string) {
return id + '/' + user;
}
register(id: string, opts?: { ws: WebSocket; user: string }) {
const _id = this.getId(id, opts?.user || '');
if (this.wssMap.has(_id)) {
const value = this.wssMap.get(_id);
if (value) {
value.ws.close();
}
}
const value = new WsMessage({ ws: opts?.ws, user: opts?.user });
this.wssMap.set(_id, value);
}
unregister(id: string, user?: string) {
const _id = this.getId(id, user || '');
const value = this.wssMap.get(_id);
if (value) {
value.ws.close();
}
this.wssMap.delete(_id);
}
getIds() {
return Array.from(this.wssMap.keys());
}
get(id: string, user?: string) {
if (user) {
const _id = this.getId(id, user);
return this.wssMap.get(_id);
}
return this.wssMap.get(id);
}
}

View File

@ -0,0 +1,35 @@
import { IncomingMessage, ServerResponse } from 'http';
import { wsProxyManager } from './index.ts';
import { App } from '@kevisual/router';
import { log } from 'console';
import { logger } from '../logger.ts';
type ProxyOptions = {
createNotFoundPage: (msg?: string) => any;
};
export const UserV1Proxy = async (req: IncomingMessage, res: ServerResponse, opts?: ProxyOptions) => {
const { url } = req;
const { pathname } = new URL(url || '', `http://localhost`);
const [user, app, userAppKey] = pathname.split('/').slice(1);
if (!user || !app || !userAppKey) {
opts?.createNotFoundPage?.('应用未启动');
return false;
}
const data = await App.handleRequest(req, res);
logger.debug('data', data);
const client = wsProxyManager.get(userAppKey, user);
const ids = wsProxyManager.getIds();
if (!client) {
opts?.createNotFoundPage?.(`应用未启动, 未找到应用, ${userAppKey}, ${ids.join(',')}`);
return false;
}
const value = await client.sendData(data);
if (value) {
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(JSON.stringify(value));
return true;
}
opts?.createNotFoundPage?.('应用未启动');
return true;
};