Added chatterbox connections
This commit is contained in:
1 parent
41ef12f954
commit
e58ceeb192
58 files changed
+8931
-8
No files matched your search
@@ -0,0 +1,111 @@
|
||||
"""Same-origin static UI/gateway for the isolated room demo; never proxies arbitrary URLs."""
|
||||
import argparse
|
||||
import json
|
||||
import hint_library
|
||||
import re
|
||||
from functools import partial
|
||||
from http.server import SimpleHTTPRequestHandler, ThreadingHTTPServer
|
||||
from pathlib import Path
|
||||
from urllib.parse import urlsplit
|
||||
import urllib.request
|
||||
import urllib.error
|
||||
|
||||
ROOT = Path(__file__).resolve().parent
|
||||
ROUTES = {"/room/state": (18776, "/room/state"), "/room/trace": (18776, "/room/trace"),
|
||||
"/room/command": (18776, "/room/command"), "/speech/health": (18778, "/health")}
|
||||
|
||||
class Handler(SimpleHTTPRequestHandler):
|
||||
def list_directory(self, path):
|
||||
self.send_error(403)
|
||||
def relay(self):
|
||||
path = urlsplit(self.path).path
|
||||
route = ROUTES.get(path)
|
||||
if re.fullmatch(r"/speech/audio/[a-f0-9]{64}\.wav", path):
|
||||
route = (18778, path.removeprefix("/speech"))
|
||||
if not route or (self.command == "POST" and path != "/room/command") or (self.command == "GET" and path == "/room/command"):
|
||||
self.send_error(404)
|
||||
return
|
||||
if self.command == "POST":
|
||||
origin = self.headers.get("Origin")
|
||||
if origin and origin != "http://" + self.headers.get("Host", ""):
|
||||
self.send_error(403, "Use the room demo page to send commands")
|
||||
return
|
||||
try:
|
||||
size = int(self.headers.get("Content-Length", "0"))
|
||||
if size < 0 or size > 65536:
|
||||
self.send_error(413)
|
||||
return
|
||||
body = self.rfile.read(size) if self.command == "POST" else None
|
||||
request = urllib.request.Request(f"http://127.0.0.1:{route[0]}{route[1]}",
|
||||
data=body, method=self.command, headers={"Content-Type":"application/json", **({"Range":self.headers["Range"]} if "Range" in self.headers else {})})
|
||||
try:
|
||||
with urllib.request.urlopen(request, timeout=8) as response:
|
||||
data, status = response.read(), response.status
|
||||
content_type = response.headers.get("Content-Type","application/json")
|
||||
content_range = response.headers.get("Content-Range")
|
||||
except urllib.error.HTTPError as error:
|
||||
data, status = error.read(), error.code
|
||||
content_type, content_range = "text/plain", None
|
||||
self.send_response(status)
|
||||
self.send_header("Content-Type",content_type)
|
||||
self.send_header("Accept-Ranges","bytes")
|
||||
if content_range:
|
||||
self.send_header("Content-Range",content_range)
|
||||
self.send_header("Content-Length",str(len(data)))
|
||||
self.send_header("Cache-Control","no-store")
|
||||
self.end_headers()
|
||||
self.wfile.write(data)
|
||||
except (OSError, ValueError):
|
||||
self.send_error(503, "Local lab service unavailable")
|
||||
def hints(self):
|
||||
try:
|
||||
if self.command == "POST":
|
||||
origin=self.headers.get("Origin")
|
||||
if origin and origin != "http://" + self.headers.get("Host",""):
|
||||
self.send_error(403)
|
||||
return
|
||||
size=int(self.headers.get("Content-Length","0"))
|
||||
if not 0<size<=16384:
|
||||
self.send_error(413)
|
||||
return
|
||||
result=hint_library.save(json.loads(self.rfile.read(size)))
|
||||
else:
|
||||
result=hint_library.read()
|
||||
status=200
|
||||
except hint_library.Conflict as error:
|
||||
result,status={"error":str(error)},409
|
||||
except (ValueError, OSError) as error:
|
||||
result,status={"error":str(error)},400
|
||||
data=json.dumps(result).encode()
|
||||
self.send_response(status)
|
||||
self.send_header("Content-Type","application/json")
|
||||
self.send_header("Content-Length",str(len(data)))
|
||||
self.send_header("Cache-Control","no-store")
|
||||
self.end_headers()
|
||||
self.wfile.write(data)
|
||||
def do_GET(self):
|
||||
if urlsplit(self.path).path == "/hints":
|
||||
return self.hints()
|
||||
if urlsplit(self.path).path.startswith(("/room/", "/speech/")):
|
||||
self.relay()
|
||||
else:
|
||||
super().do_GET()
|
||||
def do_POST(self):
|
||||
if urlsplit(self.path).path == "/hints":
|
||||
return self.hints()
|
||||
self.relay()
|
||||
def end_headers(self):
|
||||
self.send_header("X-Content-Type-Options","nosniff")
|
||||
self.send_header("Cache-Control","no-store")
|
||||
super().end_headers()
|
||||
def log_message(self,*_): pass
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser=argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument("--bind",default="127.0.0.1")
|
||||
args=parser.parse_args()
|
||||
server=ThreadingHTTPServer((args.bind,18777),partial(Handler,directory=str(ROOT/"gm/build/web")))
|
||||
print(f"Room demo UI/gateway: http://{args.bind}:18777/?room=1",flush=True)
|
||||
try: server.serve_forever()
|
||||
finally: server.server_close()
|
||||
|
||||
Reference in new issue
Block a user