From b61699a450f5432c09bb81f445b1b76e64aca26a Mon Sep 17 00:00:00 2001 From: "pengfei.zhou" Date: Fri, 11 Aug 2023 16:24:10 +0800 Subject: [PATCH] cli: add proxy server --- doric-cli/src/index.ts | 19 ++++++--- doric-cli/src/proxy.ts | 51 +++++++++++++++++++++++++ doric-cli/src/proxyServer.ts | 74 ++++++++++++++++++++++++++++++++++++ doric-cli/src/server.ts | 6 ++- 4 files changed, 143 insertions(+), 7 deletions(-) create mode 100644 doric-cli/src/proxy.ts create mode 100644 doric-cli/src/proxyServer.ts diff --git a/doric-cli/src/index.ts b/doric-cli/src/index.ts index e4569a23..d6f220ab 100644 --- a/doric-cli/src/index.ts +++ b/doric-cli/src/index.ts @@ -5,6 +5,8 @@ import { build, clean, ssr } from "./actions"; import { create, createLib } from "./create" import dev from "./dev" import { run } from "./run"; +import { linkProxyServer } from "./proxy"; +import { createControlServer, startProxyServer } from "./proxyServer"; (process.env.FORCE_COLOR as any) = true @@ -26,14 +28,21 @@ commander commander .command('dev') .option('--proxy', 'Link proxy') - .action(async function (cmd, args) { - const [proxy] = args + .action(async function (_, args) { + const serverPort = 7777, resourcePort = 7778 + await dev(serverPort, resourcePort) + const [proxy] = args ?? [] if (proxy) { - console.log("Running in proxy mode", proxy) - } else { - await dev() + await linkProxyServer(`localhost:${serverPort}`, proxy) } }) +commander + .command('proxy') + .option('--port', 'Link port') + .action(async function (_, args) { + const [proxy] = args ?? ["7780"] + await startProxyServer(parseInt(proxy)) + }) commander .command('build') .action(async function () { diff --git a/doric-cli/src/proxy.ts b/doric-cli/src/proxy.ts new file mode 100644 index 00000000..89241ed0 --- /dev/null +++ b/doric-cli/src/proxy.ts @@ -0,0 +1,51 @@ +import WebSocket from "ws" +import { MSG } from "./server" + +export async function linkProxyServer(server: string, proxy: string) { + console.log("Running in proxy mode", proxy) + return new Promise((resolve, reject) => { + const serverListener = new WebSocket(`ws://${server}`, { + headers: { + "role": "PROXY" + } + }) + let proxyUserId: string | undefined = undefined + const controlConnector = new WebSocket(`ws://${proxy}`) + let transferConnector: WebSocket | undefined = undefined; + serverListener.on('open', () => { + console.log('Proxy attached to server', server) + resolve() + }) + serverListener.on('message', (data) => { + transferConnector?.send(data) + }) + serverListener.on('error', (error) => { + console.log(error) + transferConnector?.close() + controlConnector?.close() + reject(error) + }) + + controlConnector.on('open', () => { + console.log('Connected to proxy', proxy) + }) + controlConnector.on('message', (data) => { + const msg = JSON.parse(data as string) as MSG + const payload = msg.payload + if (msg.cmd === "SetUserId") { + proxyUserId = payload.userId + const nextPort = payload.port + const transferAddr = proxy.replace(/:[0-9]*/, "") + ":" + nextPort + console.log("Get proxy UserId", proxyUserId, "addr", transferAddr) + transferConnector = new WebSocket("ws://" + transferAddr) + } + }) + controlConnector.on('error', (error) => { + console.log(error) + transferConnector?.close() + controlConnector?.close() + reject(error) + }) + }) + +} \ No newline at end of file diff --git a/doric-cli/src/proxyServer.ts b/doric-cli/src/proxyServer.ts new file mode 100644 index 00000000..e1700a32 --- /dev/null +++ b/doric-cli/src/proxyServer.ts @@ -0,0 +1,74 @@ +import WebSocket from "ws" +import { MSG } from "./server"; +import net from "net"; + + +function findAvailablePort(startPort: number, callback: (port: number) => void) { + const port = startPort || 3000; + const server = net.createServer(); + + server.listen(port, () => { + server.once('close', () => { + callback(port); + }); + server.close(); + }); + + server.on('error', () => { + findAvailablePort(port + 1, callback); + }); +} + +export async function findAvailablePortAsync(startPort: number) { + return new Promise((resolve) => { + findAvailablePort(startPort, (v) => { + resolve(v) + }) + }) +} + +export async function createControlServer(port: number) { + let userId = 0 + const wss = new WebSocket.Server({ port }) + wss.on("connection", async (ws, request) => { + let thisUserId = `User#${userId++}` + const avaliablePort = await findAvailablePortAsync(3000) + console.log('Connected', request.headers.host) + console.log(`${thisUserId} attached to proxy server, port is ${avaliablePort}`.green) + ws.send(JSON.stringify({ + type: "P2U", + cmd: "SetUserId", + payload: { + "userId": thisUserId, + "port": avaliablePort + } + })) + const transferServer = await createTransferServer(avaliablePort) + transferServer.on("connection", async function (ws) { + console.log(`${thisUserId} transferServer connection`) + ws.on("message", async function (result: string) { + console.log(`${thisUserId} received message`) + transferServer.clients.forEach(e => e.send(result)) + }) + }) + + ws.on('close', function (code: number) { + console.log('close: code = ' + code, thisUserId); + transferServer.close() + }); + ws.on('error', function (code: number) { + console.log('error', code) + transferServer.close() + }); + }); + return wss; +} +export async function createTransferServer(port: number) { + const wss = new WebSocket.Server({ port }) + return wss +} + +export async function startProxyServer(port: number) { + const controlServer = await createControlServer(port) + console.log("Open Control Server on " + port) +} \ No newline at end of file diff --git a/doric-cli/src/server.ts b/doric-cli/src/server.ts index 2a389b09..cf8ebdcc 100644 --- a/doric-cli/src/server.ts +++ b/doric-cli/src/server.ts @@ -20,8 +20,10 @@ export async function createServer(port: number) { const wss = new WebSocket.Server({ port }) .on("connection", (ws, request) => { let thisDeviceId: string - console.log('Connected', request.headers.host) - if (request.headers.host?.startsWith("localhost")) { + if (request.headers["role"] === "PROXY") { + thisDeviceId = `Client#${deviceId++}` + console.log(`PROXY ${thisDeviceId} attached to dev kit`.green) + } else if (request.headers["role"] === "DEBUGGER" || request.headers.host?.startsWith("localhost")) { thisDeviceId = `Debugger#${deviceId++}` console.log(`${thisDeviceId} attached to dev kit`.green) debug = ws;