Skip to content

Commit f1315c8

Browse files
authored
Merge pull request #32 from bytebot-ai/codex/move-urls-behind-api-routes-and-proxy-websockets
Proxy agent via Next API
2 parents fb4dd67 + aae2494 commit f1315c8

File tree

12 files changed

+277
-58
lines changed

12 files changed

+277
-58
lines changed

infrastructure/docker/docker-compose.yml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,14 +57,16 @@ services:
5757
context: ../../packages/
5858
dockerfile: bytebot-ui/Dockerfile
5959
args:
60-
- NEXT_PUBLIC_BYTEBOT_AGENT_BASE_URL=${BYTEBOT_AGENT_BASE_URL:-http://localhost:9991}
61-
- NEXT_PUBLIC_BYTEBOT_DESKTOP_VNC_URL=${BYTEBOT_DESKTOP_VNC_URL:-ws://localhost:9990/websockify}
60+
- BYTEBOT_AGENT_BASE_URL=${BYTEBOT_AGENT_BASE_URL:-http://localhost:9991}
61+
- BYTEBOT_DESKTOP_VNC_URL=${BYTEBOT_DESKTOP_VNC_URL:-ws://localhost:9990/websockify}
6262
container_name: bytebot-ui
6363
restart: unless-stopped
6464
ports:
6565
- "9992:9992"
6666
environment:
6767
- NODE_ENV=production
68+
- BYTEBOT_AGENT_BASE_URL=${BYTEBOT_AGENT_BASE_URL:-http://bytebot-agent:9991}
69+
- BYTEBOT_DESKTOP_VNC_URL=${BYTEBOT_DESKTOP_VNC_URL:-ws://bytebotd:9990/websockify}
6870
depends_on:
6971
- bytebot-agent
7072
networks:

packages/bytebot-agent/src/main.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ async function bootstrap() {
1515

1616
// Enable CORS
1717
app.enableCors({
18-
origin: "*",
18+
origin: 'http://localhost:9992',
1919
methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],
2020
credentials: true,
2121
});

packages/bytebot-agent/src/tasks/tasks.gateway.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import { Injectable } from '@nestjs/common';
1111
@Injectable()
1212
@WebSocketGateway({
1313
cors: {
14-
origin: '*',
14+
origin: 'http://localhost:9992',
1515
methods: ['GET', 'POST'],
1616
},
1717
})
@@ -54,4 +54,4 @@ export class TasksGateway implements OnGatewayConnection, OnGatewayDisconnect {
5454
emitTaskDeleted(taskId: string) {
5555
this.server.emit('task_deleted', taskId);
5656
}
57-
}
57+
}

packages/bytebot-ui/Dockerfile

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,12 @@
22
FROM node:20-alpine
33

44
# Declare build arguments
5-
ARG NEXT_PUBLIC_BYTEBOT_AGENT_BASE_URL
6-
ARG NEXT_PUBLIC_BYTEBOT_DESKTOP_VNC_URL
5+
ARG BYTEBOT_AGENT_BASE_URL
6+
ARG BYTEBOT_DESKTOP_VNC_URL
77

88
# Set environment variables for the build process
9-
ENV NEXT_PUBLIC_BYTEBOT_AGENT_BASE_URL=${NEXT_PUBLIC_BYTEBOT_AGENT_BASE_URL}
10-
ENV NEXT_PUBLIC_BYTEBOT_DESKTOP_VNC_URL=${NEXT_PUBLIC_BYTEBOT_DESKTOP_VNC_URL}
9+
ENV BYTEBOT_AGENT_BASE_URL=${BYTEBOT_AGENT_BASE_URL}
10+
ENV BYTEBOT_DESKTOP_VNC_URL=${BYTEBOT_DESKTOP_VNC_URL}
1111

1212
# Create app directory
1313
WORKDIR /app

packages/bytebot-ui/next.config.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,14 @@ import type { NextConfig } from "next";
33
const nextConfig: NextConfig = {
44
/* config options here */
55
transpilePackages: ["@bytebot/shared"],
6+
async rewrites() {
7+
return [
8+
{
9+
source: "/api/proxy/websockify",
10+
destination: "http://localhost:9990/websockify",
11+
},
12+
];
13+
},
614
};
715

816
export default nextConfig;

packages/bytebot-ui/package-lock.json

Lines changed: 82 additions & 8 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/bytebot-ui/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@
33
"version": "0.1.0",
44
"private": true,
55
"scripts": {
6-
"dev": "next dev -p 9992",
6+
"dev": "tsx server.ts",
77
"build": "npm run build --prefix ../shared && next build",
8-
"start": "next start -p 9992",
8+
"start": "tsx server.ts",
99
"lint": "next lint"
1010
},
1111
"dependencies": {

packages/bytebot-ui/server.ts

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
import express from "express";
2+
import { createProxyMiddleware } from "http-proxy-middleware";
3+
import next from "next";
4+
import { createServer } from "http";
5+
import dotenv from "dotenv";
6+
7+
// Load environment variables
8+
dotenv.config();
9+
10+
const dev = process.env.NODE_ENV !== "production";
11+
const hostname = process.env.HOSTNAME || "localhost";
12+
const port = parseInt(process.env.PORT || "9992", 10);
13+
14+
// Backend URLs
15+
const BYTEBOT_AGENT_BASE_URL = process.env.BYTEBOT_AGENT_BASE_URL;
16+
const BYTEBOT_DESKTOP_VNC_URL = process.env.BYTEBOT_DESKTOP_VNC_URL;
17+
18+
const app = next({ dev, hostname, port });
19+
20+
app
21+
.prepare()
22+
.then(() => {
23+
const handle = app.getRequestHandler();
24+
const nextUpgradeHandler = app.getUpgradeHandler();
25+
26+
const expressApp = express();
27+
const server = createServer(expressApp);
28+
29+
// WebSocket proxy for Socket.IO connections to backend
30+
const tasksProxy = createProxyMiddleware({
31+
target: BYTEBOT_AGENT_BASE_URL,
32+
ws: true,
33+
pathRewrite: { "^/api/proxy/tasks": "/socket.io" },
34+
});
35+
36+
// WebSocket proxy for VNC websockify
37+
// const vncProxy = createProxyMiddleware({
38+
// target: BYTEBOT_DESKTOP_VNC_URL,
39+
// ws: true,
40+
// pathRewrite: (path) =>
41+
// path.replace(/^\/api\/proxy\/websockify/, "/websockify"),
42+
// });
43+
44+
// Apply HTTP proxies
45+
expressApp.use("/api/proxy/tasks", tasksProxy);
46+
// expressApp.use("/api/proxy/websockify", vncProxy);
47+
48+
// Handle all other requests with Next.js
49+
expressApp.all("*", (req, res) => handle(req, res));
50+
51+
// Properly upgrade WebSocket connections
52+
server.on("upgrade", (request, socket, head) => {
53+
const { pathname } = new URL(
54+
request.url!,
55+
`http://${request.headers.host}`,
56+
);
57+
58+
if (pathname.startsWith("/api/proxy/tasks")) {
59+
return tasksProxy.upgrade(request, socket as any, head);
60+
}
61+
62+
// if (pathname.startsWith("/api/proxy/websockify")) {
63+
// console.log(`[UPGRADE] ${pathname}`);
64+
// return vncProxy.upgrade(request, socket as any, head);
65+
// }
66+
nextUpgradeHandler(request, socket, head);
67+
});
68+
69+
server.listen(port, hostname, () => {
70+
console.log(`> Ready on http://${hostname}:${port}`);
71+
console.log(`> Proxying tasks to: ${BYTEBOT_AGENT_BASE_URL}`);
72+
console.log(`> Proxying VNC to: ${BYTEBOT_DESKTOP_VNC_URL}`);
73+
});
74+
})
75+
.catch((err) => {
76+
console.error("Server failed to start:", err);
77+
process.exit(1);
78+
});

0 commit comments

Comments
 (0)