moving from python to GOAT nginx

This commit is contained in:
Victor Vobis 2026-02-21 19:49:05 +01:00
parent 7db8be7dc0
commit 02d47513d6
9 changed files with 121 additions and 185 deletions

1
.env
View File

@ -0,0 +1 @@

Binary file not shown.

View File

@ -1,93 +0,0 @@
import sys
import os
from aiohttp import web
from proxy import proxy_ws, proxy_http
[_, host, port, file_root] = sys.argv
def print_usage():
print("""Usage: python3 ./backend.py <host> <port> <file_root>""")
async def handle_service(request: web.Request):
[service, medium, target] = [
request.match_info.get('service'),
request.match_info.get('medium'),
request.match_info.get('target')
]
if not target or target == '':
return web.json_response(status=404, data={"success": "false", "message": "Not Found"})
if 'vnc' in request.url.path:
return await proxy_http(request)
if not service or not medium:
return web.json_response({"success": "false", "message": "Missing Serice or Medium"})
if not target:
target = "index.html"
serve_path = f"{file_root}/service/{service}/{medium}/{target}"
if not os.path.exists(serve_path):
data = { "success": "false", "message": "Not Found" }
return web.json_response(
status=404,
data=data,
)
return web.FileResponse(serve_path)
async def serve_http(request: web.Request):
path_info = request.match_info.get('path_info', '')
print(f"Req: {request} with path: {path_info}")
if '..' in path_info:
data = {"success": "false", "message": "Forbidden"}
return web.json_response(
status=403,
data=data,
content_type='application/json'
)
elif path_info == '':
path_info = "index.html"
serve_path = f"{file_root}/{path_info}"
print(f"looking for path {serve_path}")
if not os.path.exists(serve_path):
data = { "success": "false", "message": "Not Found" }
return web.json_response(
status=404,
data=data,
)
return web.FileResponse(serve_path)
def build_http_server():
app = web.Application()
app.add_routes([
web.get('/{service}/{medium}/{target:.*}', handle_service),
web.get("/{service}/websockify", proxy_ws),
web.get("/{path_info:.*}", serve_http),
])
return app
def main(host, port):
app = build_http_server()
web.run_app(app, host=host, port=int(port))
try:
main(host, port)
except ValueError as e:
print(f"Argv Error: {e}")
print_usage()
except Exception as e:
print("Caught exception: {e}")
print_usage()

111
nginx.conf Normal file
View File

@ -0,0 +1,111 @@
#user http;
worker_processes 1;
#error_log logs/error.log;
#error_log logs/error.log notice;
#error_log logs/error.log info;
pid /tmp/nginx.pid;
# Load all installed modules
include /etc/nginx/modules.d/*.conf;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
#log_format main '$remote_addr - $remote_user [$time_local] "$request" '
# '$status $body_bytes_sent "$http_referer" '
# '"$http_user_agent" "$http_x_forwarded_for"';
#access_log logs/access.log main;
sendfile on;
#tcp_nopush on;
#keepalive_timeout 0;
keepalive_timeout 65;
#gzip on;
upstream minirt {
# server 127.0.0.1:7080;
}
upstream minishell {
# server 127.0.0.1:6080;
}
server {
listen 8080;
server_name localhost;
root ./site;
#charset koi8-r;
#access_log logs/host.access.log main;
location / {
try_files $uri $uri/ /index.html;
}
location /proxy/minirt/websockify {
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_http_version 1.1;
proxy_read_timeout 61s;
proxy_buffering off;
proxy_pass http://minirt/websockify;
}
location /proxy/minirt/ {
proxy_pass http://minirt/;
}
}
# another virtual host using mix of IP-, name-, and port-based configuration
#
#server {
# listen 8000;
# listen somename:8080;
# server_name somename alias another.alias;
# location / {
# root html;
# index index.html index.htm;
# }
#}
# HTTPS server
#
#server {
# listen 443 ssl;
# server_name localhost;
# ssl_certificate cert.pem;
# ssl_certificate_key cert.key;
# ssl_session_cache shared:SSL:1m;
# ssl_session_timeout 5m;
# ssl_ciphers HIGH:!aNULL:!MD5;
# ssl_prefer_server_ciphers on;
# location / {
# root html;
# index index.html index.htm;
# }
#}
}

View File

@ -1,83 +0,0 @@
import aiohttp
from aiohttp import web
import asyncio
from datetime import datetime
from services import services
connections = {}
max_duration = 60
async def proxy_http(request: web.Request):
service_name = request.match_info.get('service')
if not service_name or not services[service_name]:
return web.json_response(status=404, data={ "success": "false", "message": "Unknown service name" })
url = services[service_name]
target = request.match_info.get('target')
target = f"{url}/{target}"
async with aiohttp.ClientSession() as session:
async with session.request(
request.method,
f"http://{target}",
headers=request.headers,
data=await request.read()
) as resp:
return web.Response(
body=await resp.read(),
status=resp.status,
headers=resp.headers
)
async def proxy_ws(request: web.Request):
service_name = request.match_info.get('service')
if service_name in connections:
return web.Response(text='Service already in use', status=409)
if not service_name or not services[service_name]:
return web.json_response(status=404, data={ "success": "false", "message": "Unknown service name" })
ws = web.WebSocketResponse()
await ws.prepare(request)
connections[service_name] = (ws, datetime.now())
url = services[service_name]
target = request.match_info.get('target')
target = f"{url}/{target}"
try:
async with aiohttp.ClientSession() as session:
async with session.ws_connect(f"ws://{target}/websockify") as remote_ws:
async def forward_to_remote():
async for msg in ws:
if msg.type == aiohttp.WSMsgType.BINARY:
await remote_ws.send_bytes(msg.data)
async def forward_to_client():
async for msg in remote_ws:
if msg.type == aiohttp.WSMsgType.BINARY:
await ws.send_bytes(msg.data)
async def check_timeout():
while True:
await asyncio.sleep(10)
elapsed = (datetime.now() - connections[service_name][1]).total_seconds()
if elapsed > max_duration:
await ws.close()
break
await asyncio.gather(forward_to_remote(), forward_to_client(), check_timeout())
finally:
if service_name in connections:
del connections[service_name]
return ws

View File

@ -1,4 +0,0 @@
services: dict[str, str] = {
"minirt": "localhost:7080",
"minishell": "localhost:8080"
}

View File

@ -63,7 +63,7 @@
</p>
<p>
As a final note: since we finished the project, I was planning on showcasing it here, and so I have reimplemented the graphical part to use <a href="https://github.com/raysan5/raylib">Raylib</a> since it seemed more appropriate to use.
As a final note: since we finished the project, I was planning on showcasing it here, and so I have reimplemented the rendering layer to use <a href="https://github.com/raysan5/raylib">Raylib</a> since it seemed more appropriate to use.
</p>
<p>
@ -71,7 +71,9 @@
</p>
<p>
There are two ways to run the app: either directly in your browser with the WASM compiled program, or over a live noVNC connection to a running instance on the server. The raytracer itself is multithreaded, but since JS/WASM runs on a single thread, the WASM version is very slow. I scaled down the resolution for that version in order to have it not run at -5 FPS.
There are two ways to run the app: either directly in your browser with the WASM compiled program, or over a live noVNC connection to a running instance on the server. The connection to the VNC server will automatically be closed after 60 seconds in order to save resources.
</p>
<p>The raytracer itself is multithreaded, but since JS/WASM runs on a single thread, the WASM version is very slow. I scaled down the resolution for that version in order to have it not run at -5 FPS.
</p>
<p>
@ -80,10 +82,9 @@
<div class="button-group">
<a href="/minirt/wasm/miniRT.html" target="_blank" class="button">WASM Version (Raylib)</a>
<a href="/minirt/vnc/vnc_lite.html?path=minirt/websockify&scale=resize" target="_blank" class="button">VNC Version (noVNC)</a>
<a href="/proxy/minirt/vnc_lite.html?path=proxy/minirt/websockify&scale=resize" target="_blank" class="button">VNC Version (noVNC)</a>
</div>
</section>
</main>
</body>
</html>

View File

@ -86,7 +86,7 @@
Have fun!
</p>
<div id="shell-container">
<button id="shell-start-button">
<a href="/minishell/" id="shell-start-button">
Start Shell
</button>
</div>

3
start_app.sh Executable file
View File

@ -0,0 +1,3 @@
#!/bin/sh
nginx -p $(pwd) -c ./nginx.conf -g "daemon off;"