#!/usr/bin/env python3 """Локальный веб-сервер для проверки сборки, повторяет боевой nginx: заголовки COOP/COEP (нужны Godot web) и gzip без Content-Length (чанками). Так я поймал баг: браузер сам распаковывает gzip, и HTTPRequest в движке не должен делать это второй раз. python3 tools/serve_web.py ../grid-world 8080 # открой http://127.0.0.1:8080 """ import gzip, http.server, os, sys ROOT = sys.argv[1] if len(sys.argv) > 1 else '../grid-world' PORT = int(sys.argv[2]) if len(sys.argv) > 2 else 8080 CACHE = {} TYPES = {'.wasm': 'application/wasm', '.js': 'application/javascript', '.html': 'text/html', '.pck': 'application/octet-stream', '.png': 'image/png'} class Handler(http.server.BaseHTTPRequestHandler): protocol_version = 'HTTP/1.1' def do_GET(self): path = os.path.join(ROOT, self.path.split('?')[0].lstrip('/') or 'index.html') if not os.path.isfile(path): self.send_response(404); self.send_header('Content-Length', '0'); self.end_headers(); return data = open(path, 'rb').read() self.send_response(200) self.send_header('Content-Type', TYPES.get(os.path.splitext(path)[1], 'application/octet-stream')) self.send_header('Cross-Origin-Opener-Policy', 'same-origin') self.send_header('Cross-Origin-Embedder-Policy', 'require-corp') if len(data) > 1024: key = (path, os.path.getmtime(path)) gz = CACHE.get(key) or CACHE.setdefault(key, gzip.compress(data, 1)) self.send_header('Content-Encoding', 'gzip') self.send_header('Transfer-Encoding', 'chunked') self.end_headers() for i in range(0, len(gz), 65536): chunk = gz[i:i + 65536] self.wfile.write(b'%x\r\n' % len(chunk) + chunk + b'\r\n') self.wfile.write(b'0\r\n\r\n') else: self.send_header('Content-Length', str(len(data))) self.end_headers() self.wfile.write(data) print('GET', self.path, flush=True) def log_message(self, *args): pass print(f'http://127.0.0.1:{PORT} ← {os.path.abspath(ROOT)}') http.server.ThreadingHTTPServer(('127.0.0.1', PORT), Handler).serve_forever()