feat: add WASM client web server and improve service worker
- Implement serverWorker in main_js.go to start an HTTP server within the WASM client, serving a basic HTML page with server ID - Update service-worker.js to handle fetch events asynchronously, ensure WASM initialization, and provide better error responses - Increase page reload timeout in index.html from 500ms to 1000ms for improved stability after service worker registration This enables the web client to act as a server in the WASM environment, enhancing functionality for proxy and serving capabilities.
lemon-mint committed
Oct 31, 2025 at 14:49 UTC
7293e53bdfa8809eeac3cb1b824da272c8f255eb
3 files changed
+46
-9
cmd/webclient/index.html
+1
-1
@@ -28,7 +28,7 @@
28
setTimeout(() => {
29
showStatus('Reloading page...', 'loading');
30
location.reload();
31
- }, 500);
31
+ }, 1000);
32
} catch (error) {
33
showStatus('Service Worker registration failed: ' + error.message, 'error');
34
}
cmd/webclient/main_js.go
+33
-1
@@ -118,9 +118,10 @@ func main() {
118
jsReq := args[0]
119
return httpjs.ServeHTTPAsyncWithStreaming(&Proxy{}, jsReq)
120
}))
121
-
121
log.Info().Msg("Portal proxy handler registered as __go_jshttp")
122
123
+ go serverWorker(rdClient)
124
+
125
if runtime.Compiler == "tinygo" {
126
return
127
}
@@ -128,3 +129,34 @@ func main() {
129
ch := make(chan bool)
130
<-ch
131
}
132
+
133
+func serverWorker(client *sdk.RDClient) {
134
+ time.Sleep(time.Second)
135
+
136
+ cred := sdk.NewCredential()
137
+ ln, err := client.Listen(cred, "WASM-Client-WebServer-"+cred.ID()[:8], []string{"http/1.1"})
138
+ if err != nil {
139
+ log.Error().Err(err).Msg("Failed to start listener")
140
+ return
141
+ }
142
+ defer ln.Close()
143
+
144
+ mux := http.NewServeMux()
145
+ mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
146
+ w.WriteHeader(http.StatusOK)
147
+ w.Write([]byte(`<!DOCTYPE html>
148
+<html>
149
+<head>
150
+ <title>WASM Client Server</title>
151
+</head>
152
+<body>
153
+ <h1>Hello, World! This server is running in a WASM client</h1>
154
+ <p>Server ID: ` + cred.ID() + `</p>
155
+</body>
156
+</html>`))
157
+ })
158
+
159
+ if err := http.Serve(ln, mux); err != nil {
160
+ log.Error().Err(err).Msg("Failed to start server")
161
+ }
162
+}
cmd/webclient/service-worker.js
+12
-7
@@ -1,8 +1,10 @@
1
// const wasm_exec_URL = "https://cdn.jsdelivr.net/gh/golang/go@go1.25.3/misc/wasm/wasm_exec.js";
2
+global = {};
3
const wasm_exec_URL = "/wasm_exec.js";
4
const wasm_URL = "/main.wasm";
5
importScripts(wasm_exec_URL);
6
7
+
8
async function runWASM() {
9
const go = new Go();
10
const cache = await caches.open("WASM_Cache_v1");
@@ -36,16 +38,21 @@ self.addEventListener('activate', (e) => {
38
e.waitUntil(Activate());
39
});
40
39
-self.addEventListener('fetch', (e) => {
41
+self.addEventListener('fetch', async (e) => {
42
console.log(e.request);
41
- if (typeof __go_jshttp != 'undefined') {
42
- e.respondWith((async () => {
43
+
44
+ if (typeof __go_jshttp == 'undefined') {
45
+ await runWASM();
46
+ }
47
+
48
+ if (__go_jshttp) {
49
+ e.respondWith((async () => {
50
try {
51
const resp = await __go_jshttp(e.request);
52
return resp;
53
} catch {
54
__go_jshttp = undefined;
48
- runWASM();
55
+ await runWASM();
56
const resp = await __go_jshttp(e.request);
57
return resp;
58
}
@@ -53,7 +60,5 @@ self.addEventListener('fetch', (e) => {
60
return;
61
}
62
56
- console.log("__go_jshttp not found");
57
- runWASM();
58
- e.respondWith(fetch(e.request));
63
+ e.respondWith(new Response("Sorry, Service Worker failed to process the request. Please refresh the page."));
64
});
\ No newline at end of file