Alvin3y1 commited on
Commit
b04e5e3
·
verified ·
1 Parent(s): 955d8ae

Update Dockerfile

Browse files
Files changed (1) hide show
  1. Dockerfile +90 -22
Dockerfile CHANGED
@@ -1,22 +1,90 @@
1
- FROM python:3.11-slim
2
-
3
- RUN apt-get update && apt-get install -y \
4
- xvfb guacd \
5
- wget curl gnupg \
6
- # Browser
7
- libnss3 libatk1.0-0 libatk-bridge2.0-0 libcups2 libdrm2 libgbm1 \
8
- libasound2 libpangocairo-1.0-0 libgtk-3-0 fonts-liberation \
9
- && rm -rf /var/lib/apt/lists/*
10
-
11
- # Install Opera
12
- RUN curl -fsSL https://deb.opera.com/archive.key | gpg --dearmor -o /usr/share/keyrings/opera-browser-keyring.gpg && \
13
- echo "deb [signed-by=/usr/share/keyrings/opera-browser-keyring.gpg] https://deb.opera.com/opera-stable/ stable non-free" \
14
- | tee /etc/apt/sources.list.d/opera-stable.list && \
15
- apt-get update && \
16
- apt-get install -y opera-stable
17
-
18
- RUN pip install aiortc aiohttp
19
-
20
- COPY . .
21
- EXPOSE 7860
22
- CMD ["python", "app.py"]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import asyncio
2
+ import json
3
+ import os
4
+ import subprocess
5
+ import time
6
+ from aiohttp import web
7
+ from aiortc import RTCPeerConnection, RTCSessionDescription, RTCIceServer, RTCConfiguration
8
+
9
+ # --- System Logic ---
10
+
11
+ def start_backend():
12
+ os.environ["DISPLAY"] = ":99"
13
+ # Start virtual X server
14
+ subprocess.Popen(["Xvfb", ":99", "-screen", "0", "1280x720x24", "-ac"])
15
+ # Start the Guacamole Proxy (translates X11 to drawing commands)
16
+ subprocess.Popen(["guacd", "-b", "127.0.0.1", "-l", "4822"])
17
+ time.sleep(2)
18
+ # Start the application
19
+ subprocess.Popen("opera --no-sandbox --start-maximized", shell=True)
20
+
21
+ # --- Protocol Bridge ---
22
+
23
+ async def bridge_x11_commands(channel):
24
+ """
25
+ Connects to guacd and performs the binary handshake.
26
+ Pipes drawing commands to WebRTC.
27
+ """
28
+ try:
29
+ reader, writer = await asyncio.open_connection('127.0.0.1', 4822)
30
+
31
+ # 1. Handshake: Select X11 Protocol
32
+ writer.write(b"6.select,3.x11;")
33
+ await writer.drain()
34
+
35
+ # 2. Receive Args (Guacamole sends requirements)
36
+ # We skip reading them for speed and send our connection string
37
+ # Format: width, height, dpi, etc.
38
+ # 0.,,,0.,,,...;
39
+ connection_args = (
40
+ f"4.size,4.1280,3.720,2.96;" # Res, DPI
41
+ f"5.audio,9.audio/ogg;" # Audio support
42
+ f"5.video,9.video/ogg;" # Video support
43
+ f"7.connect,;" # Final connect
44
+ )
45
+ writer.write(connection_args.encode())
46
+ await writer.drain()
47
+
48
+ # 3. Bidirectional Pipe
49
+ async def guac_to_webrtc():
50
+ while True:
51
+ data = await reader.read(32768)
52
+ if not data: break
53
+ channel.send(data.decode('utf-8', errors='ignore'))
54
+
55
+ @channel.on("message")
56
+ def on_message(message):
57
+ # Forward input commands (mouse/keys) back to guacd
58
+ writer.write(message.encode())
59
+
60
+ await guac_to_webrtc()
61
+ except Exception as e:
62
+ print(f"Bridge Error: {e}")
63
+ finally:
64
+ writer.close()
65
+
66
+ # --- WebRTC Signaling ---
67
+
68
+ async def offer(request):
69
+ params = await request.json()
70
+ pc = RTCPeerConnection()
71
+
72
+ @pc.on("datachannel")
73
+ def on_dc(channel):
74
+ asyncio.create_task(bridge_x11_commands(channel))
75
+
76
+ await pc.setRemoteDescription(RTCSessionDescription(sdp=params["sdp"], type=params["type"]))
77
+ await pc.setLocalDescription(await pc.createAnswer())
78
+
79
+ return web.Response(
80
+ content_type="application/json",
81
+ text=json.dumps({"sdp": pc.localDescription.sdp, "type": pc.localDescription.type}),
82
+ headers={"Access-Control-Allow-Origin": "*"}
83
+ )
84
+
85
+ if __name__ == "__main__":
86
+ start_backend()
87
+ app = web.Application()
88
+ app.router.add_get("/", lambda r: web.Response(text="hello world"))
89
+ app.router.add_post("/offer", offer)
90
+ web.run_app(app, host="0.0.0.0", port=7860)