Skip to content

Commit 0b17d45

Browse files
authored
examples : update server.py to match github pages app [no ci] (#3004)
This commit updates examples/server.py which is used to serve the wasm examples locally. The changes include: - Added a redirect from the root URL to /whisper.cpp. So now accessing http://localhost:8000/ will redirect to http://localhost:8000/whisper.cpp/ which matches the url for the app deployed to github pages. - Custom handling for coi-serviceworker.js to serve it to avoid and error in the console. This file is not strictly necessary for the local server to work as the headers are provided already but it is nice to not have an error in the console. - Fixed the shutdown of the server to ensure it exits cleanly on Ctrl+C. Previously it would continue to hang onto the port even after the processed had exited.
1 parent 77e0c86 commit 0b17d45

File tree

1 file changed

+85
-9
lines changed

1 file changed

+85
-9
lines changed

examples/server.py

Lines changed: 85 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,115 @@
11
import http.server
22
import socketserver
33
import os
4+
import sys
45
from pathlib import Path
6+
import urllib.parse
57

68
SCRIPT_DIR = Path(__file__).parent.absolute()
79
DIRECTORY = os.path.join(SCRIPT_DIR, "../build-em/bin")
810
DIRECTORY = os.path.abspath(DIRECTORY)
911

12+
# The context root we want for all applications
13+
CONTEXT_ROOT = "/whisper.cpp"
14+
1015
class CustomHTTPRequestHandler(http.server.SimpleHTTPRequestHandler):
1116
def __init__(self, *args, **kwargs):
1217
super().__init__(*args, directory=DIRECTORY, **kwargs)
1318

1419
def do_GET(self):
15-
# If requesting a worker file from any subdirectory
16-
if '.worker.js' in self.path:
20+
# Redirect root to the context root
21+
if self.path == '/':
22+
self.send_response(302)
23+
self.send_header('Location', CONTEXT_ROOT + '/')
24+
self.end_headers()
25+
return
26+
27+
# Handle requests under the context root
28+
if self.path.startswith(CONTEXT_ROOT):
29+
# Remove the context root prefix to get the actual path
30+
actual_path = self.path[len(CONTEXT_ROOT):]
31+
32+
if not actual_path:
33+
self.send_response(302)
34+
self.send_header('Location', CONTEXT_ROOT + '/')
35+
self.end_headers()
36+
return
37+
38+
if '.worker.js' in actual_path:
39+
worker_file = os.path.basename(actual_path)
40+
worker_path = os.path.join(DIRECTORY, worker_file)
41+
42+
if os.path.exists(worker_path):
43+
print(f"Found worker file: {worker_path}")
44+
self.path = '/' + worker_file
45+
else:
46+
print(f"Worker file not found: {worker_path}")
47+
48+
elif actual_path == '/':
49+
self.path = '/whisper.wasm/index.html'
50+
elif actual_path.startswith('/bench.wasm/') or actual_path.startswith('/command.wasm/') or actual_path.startswith('/stream.wasm/'):
51+
# Keep the path as is, just remove the context root
52+
self.path = actual_path
53+
# For all other paths under the context root
54+
else:
55+
# Check if this is a request to a file in whisper.wasm
56+
potential_file = os.path.join(DIRECTORY, 'whisper.wasm', actual_path.lstrip('/'))
57+
if os.path.exists(potential_file) and not os.path.isdir(potential_file):
58+
self.path = '/whisper.wasm' + actual_path
59+
else:
60+
# Try to resolve the file from the base directory
61+
potential_file = os.path.join(DIRECTORY, actual_path.lstrip('/'))
62+
if os.path.exists(potential_file):
63+
self.path = actual_path
64+
65+
# For direct requests to worker files (without context root as these
66+
# are in the build-em/bin directory
67+
elif '.worker.js' in self.path:
1768
worker_file = os.path.basename(self.path)
1869
worker_path = os.path.join(DIRECTORY, worker_file)
1970

2071
if os.path.exists(worker_path):
2172
self.path = '/' + worker_file
2273

74+
# Handle coi-serviceworker.js separately
75+
if 'coi-serviceworker.js' in self.path:
76+
worker_file = "coi-serviceworker.js"
77+
worker_path = os.path.join(SCRIPT_DIR, worker_file)
78+
if os.path.exists(worker_path):
79+
self.send_response(200)
80+
self.send_header('Content-type', 'application/javascript')
81+
self.end_headers()
82+
with open(worker_path, 'rb') as file:
83+
self.wfile.write(file.read())
84+
return
85+
else:
86+
print(f"Warning: Could not find {worker_path}")
87+
2388
return super().do_GET()
2489

2590
def end_headers(self):
2691
# Add required headers for SharedArrayBuffer
2792
self.send_header("Cross-Origin-Opener-Policy", "same-origin")
2893
self.send_header("Cross-Origin-Embedder-Policy", "require-corp")
29-
self.send_header("Access-Control-Allow-Origin", "*");
94+
self.send_header("Access-Control-Allow-Origin", "*")
3095
super().end_headers()
3196

3297
PORT = 8000
3398

34-
with socketserver.TCPServer(("", PORT), CustomHTTPRequestHandler) as httpd:
35-
print(f"Serving directory '{DIRECTORY}' at http://localhost:{PORT}")
36-
try:
37-
httpd.serve_forever()
38-
except KeyboardInterrupt:
39-
print("\nServer stopped.")
99+
# Enable address reuse
100+
class CustomServer(socketserver.TCPServer):
101+
allow_reuse_address = True
102+
103+
try:
104+
with CustomServer(("", PORT), CustomHTTPRequestHandler) as httpd:
105+
print(f"Serving directory '{DIRECTORY}' at http://localhost:{PORT}")
106+
print(f"Application context root: http://localhost:{PORT}{CONTEXT_ROOT}/")
107+
try:
108+
httpd.serve_forever()
109+
except KeyboardInterrupt:
110+
print("\nServer stopped.")
111+
# Force complete exit
112+
sys.exit(0)
113+
except OSError as e:
114+
print(f"Error: {e}")
115+
sys.exit(1)

0 commit comments

Comments
 (0)