Update Dockerfile
Browse files- Dockerfile +90 -22
Dockerfile
CHANGED
|
@@ -1,22 +1,90 @@
|
|
| 1 |
-
|
| 2 |
-
|
| 3 |
-
|
| 4 |
-
|
| 5 |
-
|
| 6 |
-
|
| 7 |
-
|
| 8 |
-
|
| 9 |
-
|
| 10 |
-
|
| 11 |
-
|
| 12 |
-
|
| 13 |
-
|
| 14 |
-
|
| 15 |
-
|
| 16 |
-
|
| 17 |
-
|
| 18 |
-
|
| 19 |
-
|
| 20 |
-
|
| 21 |
-
|
| 22 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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)
|