apps
This commit is contained in:
parent
3fc9bfad4a
commit
e4b0ebc3e1
|
|
@ -9,7 +9,8 @@
|
|||
"subdomain:dev": "bun run --hot src/server.tsx"
|
||||
},
|
||||
"dependencies": {
|
||||
"hono": "catalog:"
|
||||
"hono": "catalog:",
|
||||
"unique-names-generator": "^4.7.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/bun": "latest"
|
||||
|
|
|
|||
|
|
@ -1,8 +1,10 @@
|
|||
import { Hono } from "hono"
|
||||
import { upgradeWebSocket, websocket } from "hono/bun"
|
||||
import { uniqueNamesGenerator, adjectives, animals, colors } from "unique-names-generator"
|
||||
|
||||
type Request = {
|
||||
id: string
|
||||
app: string
|
||||
method: string
|
||||
path: string
|
||||
headers: Record<string, string>,
|
||||
|
|
@ -16,23 +18,38 @@ type Response = {
|
|||
body: string
|
||||
}
|
||||
|
||||
const app = new Hono()
|
||||
let connection: any
|
||||
type Connection = { app: string, ws: any }
|
||||
let connections: Record<string, Connection> = {}
|
||||
const pending = new Map<string, (res: any) => void>
|
||||
|
||||
function send(msg: Request) {
|
||||
function send(connection: any, msg: Request) {
|
||||
console.log("sending", msg)
|
||||
connection?.send(JSON.stringify(msg))
|
||||
connection.send(JSON.stringify(msg))
|
||||
}
|
||||
|
||||
app.get("/tunnel", upgradeWebSocket(async c => {
|
||||
return {
|
||||
const app = new Hono
|
||||
|
||||
app.get("/tunnel", c => {
|
||||
const app = c.req.query("app")
|
||||
if (!app) {
|
||||
return c.text("need ?app name", 502)
|
||||
}
|
||||
|
||||
return upgradeWebSocket(c, {
|
||||
async onOpen(_event, ws) {
|
||||
console.log("connection opened")
|
||||
connection = ws
|
||||
const name = randomName()
|
||||
connections[name] = { app, ws }
|
||||
console.log(`connection opened: ${name} -> ${app}`)
|
||||
},
|
||||
onClose: (_event, _ws) => connection = undefined,
|
||||
async onMessage(event, ws) {
|
||||
onClose: (_event, ws) => {
|
||||
for (const name of Object.keys(connections))
|
||||
if (connections[name]?.ws === ws) {
|
||||
console.log("connection closed:", name)
|
||||
delete connections[name]
|
||||
break
|
||||
}
|
||||
},
|
||||
async onMessage(event, _ws) {
|
||||
const msg = JSON.parse(event.data.toString())
|
||||
const resolve = pending.get(msg.id)
|
||||
if (resolve) {
|
||||
|
|
@ -40,21 +57,32 @@ app.get("/tunnel", upgradeWebSocket(async c => {
|
|||
pending.delete(msg.id)
|
||||
}
|
||||
},
|
||||
}
|
||||
}))
|
||||
})
|
||||
})
|
||||
|
||||
app.get("*", async c => {
|
||||
const url = new URL(c.req.url)
|
||||
const localhost = url.hostname.endsWith("localhost")
|
||||
const domains = url.hostname.split(".")
|
||||
let subdomain = ""
|
||||
|
||||
if (domains.length > (localhost ? 1 : 2))
|
||||
subdomain = domains[0]!
|
||||
|
||||
const connection = connections[subdomain]
|
||||
if (!connection)
|
||||
return c.text("No tunnel", 502)
|
||||
|
||||
const id = randomID()
|
||||
const headers = Object.fromEntries(c.req.raw.headers)
|
||||
const body = await c.req.text()
|
||||
const app = connection.app
|
||||
|
||||
const result = await new Promise<Response>(resolve => {
|
||||
pending.set(id, resolve)
|
||||
send({
|
||||
send(connection.ws, {
|
||||
id,
|
||||
app,
|
||||
method: c.req.method,
|
||||
path: c.req.path,
|
||||
headers,
|
||||
|
|
@ -68,11 +96,18 @@ app.get("*", async c => {
|
|||
})
|
||||
})
|
||||
|
||||
// Generate a random 8 character string
|
||||
function randomID(): string {
|
||||
return Math.random().toString(36).slice(2, 10)
|
||||
}
|
||||
|
||||
function randomName(): string {
|
||||
return uniqueNamesGenerator({
|
||||
dictionaries: [adjectives, animals],
|
||||
separator: "-",
|
||||
style: "lowerCase",
|
||||
})
|
||||
}
|
||||
|
||||
export default {
|
||||
port: process.env.PORT || 3100,
|
||||
websocket,
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user