๐Ÿ๐Ÿ๐Ÿ

webserver improvements mostly

Changed files
+147 -54
sketch
webui
content
+26 -9
sketch/gamma.py
··· 18 18 # renderer config 19 19 scale_power = 12 20 20 scale = 2 ** scale_power 21 - origin = -0.5, 0.5 22 - span = 1, 1 21 + origin = 0, 0 22 + span = 15, 15 23 23 stretch = 1, 1 24 24 zooms = [ 25 - ((0.45, 0.55), (0.3,0.4)), 26 - ((0.25, 0.5), (0.25,0.5)) 27 25 ] 28 26 29 27 # particle distribution: sample domain points ··· 66 64 core = math.sqrt(2 * math.pi) * torch.exp(t * torch.log(zpos) - zpos) 67 65 z[~reflect] = core 68 66 return z 67 + 68 + 69 + a = 2.0j 70 + b = 2.0 71 + kernel_xs = torch.tensor([a + b, a - b, -a + b, -a - b], device=device) 72 + kernel_xs -= kernel_xs.mean() 73 + 74 + def velu_like(z): 75 + acc = z 76 + for xQ in kernel_xs: 77 + acc += 1 / (z - xQ) 78 + return acc 69 79 70 80 71 81 def gamma_to_rgb(gz): ··· 118 128 # compute Gamma(p) 119 129 gz = grid.clone()#gamma_approx(p_positions) 120 130 121 - for i in range(20): 122 - gz = gamma_approx(gz) 131 + for i in range(2): 132 + gz = gamma_approx(gz)#velu_like(gz) 123 133 124 134 naniter += gz.isnan() * 1.0 125 135 ··· 131 141 #insert_at_coords(coords, rgb, scratch, mapping) 132 142 133 143 134 - scratch[:,:,0] = gz.real 135 - scratch[:,:,2] = gz.imag 136 - scratch[:,:,1] = naniter / naniter.max() 144 + #scratch[:,:,0] = gz.real 145 + #scratch[:,:,2] = gz.imag 146 + #scratch[:,:,1] = naniter / naniter.max() 147 + 148 + scratch[:,:,0] = (torch.angle(gz) + math.pi) 149 + scratch[:,:,1] = torch.log(torch.abs(gz) + 1e-12) / 30 150 + scratch[:,:,1] /= scratch[:,:,2].max() 151 + scratch[:,:,2] = torch.cos(scratch[:,:,0] / 2) 152 + scratch[:,:,0] = torch.abs(torch.sin(scratch[:,:,0] / 2)) 153 + 137 154 138 155 # normalization/centering like plume_c does 139 156 #scratch[:,:,2] -= scratch[:,:,2].mean()
+120 -44
sketch/webserver.py
··· 6 6 7 7 #from lib import log 8 8 9 - # TODO make it upgrade to https instead of just fucking throwing exceptions 9 + MODE = "local" 10 10 11 - HOST = "0.0.0.0" 12 - PORT = 1313 13 - BASE_DIR = Path("./webui").resolve() 14 - USE_SSL = False 11 + if MODE == "local": 12 + HOST = "0.0.0.0" 13 + PORT, SSL_PORT = 1313, None 14 + BASE_DIR = Path("./webui").resolve() 15 + USE_SSL = False 16 + SSL_CERT = "/home/ponder/ponder/certs/cert.pem" 17 + SSL_KEY = "/home/ponder/ponder/certs/key.pem" 18 + elif MODE == "remote": 19 + HOST = "ponder.ooo" 20 + PORT, SSL_PORT = 80, 443 21 + BASE_DIR = Path("./webui").resolve() 22 + USE_SSL = True 23 + SSL_KEY="/etc/letsencrypt/live/ponder.ooo/privkey.pem" 24 + SSL_CERT="/etc/letsencrypt/live/ponder.ooo/fullchain.pem" 15 25 16 26 ROUTES = { 17 27 "/": "content/main.html", ··· 26 36 ".orb": "text/x-orb" 27 37 } 28 38 29 - SSL_CERT = "/home/ponder/ponder/certs/cert.pem" 30 - SSL_KEY = "/home/ponder/ponder/certs/key.pem" 31 39 32 40 def guess_mime_type(path): 33 41 return MIME_TYPES.get(Path(path).suffix, "application/octet-stream") ··· 35 43 def build_response(status_code, body=b"", content_type="text/plain"): 36 44 reason = { 37 45 200: "OK", 46 + 301: "Moved Permanently", 38 47 400: "Bad Request", 39 48 404: "Not Found", 40 49 405: "Method Not Allowed", ··· 48 57 f"\r\n" 49 58 ).encode() + body 50 59 51 - def route(req_path): 52 - if req_path == "/": 53 - return "content/main.html" 54 - if any(req_path.endswith(x) for x in [".html", ".png"]): 55 - return f"content/{req_path}" 56 - if any(req_path.endswith(x) for x in [".wgsl"]): 57 - return f"content/wgsl/{req_path}" 58 - if any(req_path.endswith(x) for x in [".orb"]): 59 - return f"content/orb/{req_path}" 60 - if req_path.endswith(".js"): 61 - return f"js/{req_path}" 62 - return req_path[1:] 60 + def route(path): 61 + path = path.relative_to('/') if path.is_absolute() else path 62 + 63 + if path == Path(): 64 + return BASE_DIR / "content/main.html" 65 + 66 + suffix = path.suffix 67 + 68 + if suffix in [".html", ".png"]: 69 + return BASE_DIR / Path("content") / path 70 + if suffix in [".wgsl"]: 71 + return BASE_DIR / Path("content/wgsl") / path 72 + if suffix in [".orb"]: 73 + return BASE_DIR / Path("content/orb") / path 74 + if suffix in [".js"]: 75 + return BASE_DIR / Path("js") / path 76 + return BASE_DIR / path 63 77 64 78 def handle_request(request_data): 65 79 try: ··· 71 85 if method != "GET": 72 86 return build_response(405, b"Method Not Allowed") 73 87 74 - req_path = urlparse(unquote(raw_path)).path 88 + req_path = Path(urlparse(unquote(raw_path)).path).resolve(strict=False) 75 89 76 - norm_path = os.path.normpath(req_path) 90 + routed_path = route(req_path).resolve(strict=False) 77 91 78 - if ".." in norm_path: 92 + if not routed_path.is_relative_to(BASE_DIR): 79 93 return build_response(400, b"Fuck You") 80 94 81 - file_path = route(norm_path) 82 - 83 - if not file_path: 84 - return build_response(404, b"Not Found") 85 - 86 - full_path = BASE_DIR / file_path 87 - if not full_path.exists(): 95 + if not routed_path.exists(): 88 96 return build_response(404, b"File not found") 89 97 90 - with open(full_path, "rb") as f: 98 + with open(routed_path, "rb") as f: 91 99 body = f.read() 92 - return build_response(200, body, guess_mime_type(file_path)) 100 + return build_response(200, body, guess_mime_type(routed_path)) 93 101 94 102 except Exception as e: 95 103 return build_response(500, f"Server error: {e}".encode()) 96 104 97 - def main(): 105 + 106 + 107 + def build_redirect_response(location): 108 + return ( 109 + f"HTTP/1.1 301 Moved Permanently\r\n" 110 + f"Location: {location}\r\n" 111 + f"Content-Length: 0\r\n" 112 + f"Connection: close\r\n" 113 + f"\r\n" 114 + ).encode() 115 + 116 + def handle_http_redirect(conn): 117 + request = conn.recv(4096) 118 + try: 119 + lines = request.decode().split("\r\n") 120 + if lines: 121 + method, raw_path, *_ = lines[0].split() 122 + path = urlparse(unquote(raw_path)).path 123 + else: 124 + path = "/" 125 + except: 126 + path = "/" 127 + redirect = build_redirect_response(f"https://{HOST}{path}") 128 + conn.sendall(redirect) 129 + 130 + def http_redirect_server(): 131 + with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as server: 132 + server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 133 + server.bind((HOST, PORT)) 134 + server.listen() 135 + print(f"redirecting on {HOST}:{PORT}") 136 + while True: 137 + try: 138 + conn, addr = server.accept() 139 + except KeyboardInterrupt: 140 + break 141 + except: 142 + continue 143 + with conn: 144 + try: 145 + handle_http_redirect(conn) 146 + except: 147 + pass 148 + 149 + 150 + def ssl_main(): 98 151 ssl_ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER) 99 152 ssl_ctx.load_cert_chain(certfile=SSL_CERT, keyfile=SSL_KEY) 100 153 154 + #threading.Thread(target=http_redirect_server, daemon=True).start() 155 + 101 156 with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as server: 102 157 server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 103 - server.bind((HOST, PORT)) 158 + server.bind((HOST, SSL_PORT)) 104 159 server.listen() 105 - print(f"Serving HTTPS on {HOST}:{PORT}") 160 + print(f"Serving HTTPS on {HOST}:{SSL_PORT}") 106 161 while True: 107 162 try: 108 163 conn, addr = server.accept() 109 - if USE_SSL: 110 - with ssl_ctx.wrap_socket(conn, server_side=True) as ssl_conn: 111 - request = ssl_conn.recv(4096) 112 - response = handle_request(request) 113 - ssl_conn.sendall(response) 114 - else: 115 - request = conn.recv(4096) 164 + conn.settimeout(10.0) 165 + with ssl_ctx.wrap_socket(conn, server_side=True) as ssl_conn: 166 + request = ssl_conn.recv(4096) 116 167 response = handle_request(request) 117 - conn.sendall(response) 168 + ssl_conn.sendall(response) 169 + except KeyboardInterrupt: 170 + raise 171 + except TimeoutError: 172 + continue 173 + except Exception as e: 174 + print(f"Error: {e}") 175 + exit() 176 + 177 + 178 + def main(): 179 + with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as server: 180 + server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 181 + server.bind((HOST, PORT)) 182 + server.listen() 183 + print(f"Serving HTTP on {HOST}:{PORT}") 184 + while True: 185 + try: 186 + conn, addr = server.accept() 187 + request = conn.recv(4096) 188 + response = handle_request(request) 189 + conn.sendall(response) 118 190 except KeyboardInterrupt: 119 191 raise 120 - except: 192 + except Exception as e: 193 + print(e) 121 194 break 122 195 123 196 if __name__ == "__main__": 124 - main() 197 + if USE_SSL: 198 + ssl_main() 199 + else: 200 + main()
+1 -1
webui/content/orb/projective_shift.orb
··· 8 8 in 9 9 10 10 z_{n+1} = (r + cos(theta-phi))e^{i theta psi} - c 11 - where z_n = r cos theta 11 + where z_n = r e^{i theta} 12 12 } } 13 13 14 14 b{click and drag} to move around, b{scroll} to zoom in and out; b{press F} to go fullscreen