//go:build js && wasm package auth import ( "encoding/json" "fmt" "net/url" "syscall/js" ) // WASMHTTPClient handles HTTP requests in WASM environment type WASMHTTPClient struct{} // HTTPResult represents the result of an HTTP request type HTTPResult struct { Data []byte Error error } // HTTPCallback is called when HTTP request completes type HTTPCallback func(result HTTPResult) // FetchJSON performs a GET request and unmarshals JSON response // This method blocks and should only be called from the main thread func (c *WASMHTTPClient) FetchJSON(url string, dest interface{}) error { result := make(chan HTTPResult, 1) c.FetchJSONAsync(url, func(r HTTPResult) { result <- r }) r := <-result if r.Error != nil { return r.Error } return json.Unmarshal(r.Data, dest) } // FetchJSONAsync performs a GET request asynchronously using callback func (c *WASMHTTPClient) FetchJSONAsync(url string, callback HTTPCallback) { // Create fetch promise promise := js.Global().Call("fetch", url) // Success handler var successFunc js.Func successFunc = js.FuncOf(func(this js.Value, args []js.Value) interface{} { response := args[0] if !response.Get("ok").Bool() { callback(HTTPResult{ Error: fmt.Errorf("HTTP %d: %s", response.Get("status").Int(), response.Get("statusText").String()), }) successFunc.Release() return nil } // Get response text textPromise := response.Call("text") var textFunc js.Func textFunc = js.FuncOf(func(this js.Value, args []js.Value) interface{} { text := args[0].String() callback(HTTPResult{ Data: []byte(text), }) // Cleanup after callback completes textFunc.Release() successFunc.Release() return nil }) // Error handler for text promise var textErrorFunc js.Func textErrorFunc = js.FuncOf(func(this js.Value, args []js.Value) interface{} { callback(HTTPResult{ Error: fmt.Errorf("failed to read response text: %v", args[0]), }) // Cleanup textFunc.Release() textErrorFunc.Release() successFunc.Release() return nil }) textPromise.Call("then", textFunc).Call("catch", textErrorFunc) return nil }) // Error handler var errorFunc js.Func errorFunc = js.FuncOf(func(this js.Value, args []js.Value) interface{} { callback(HTTPResult{ Error: fmt.Errorf("fetch error: %s", args[0].String()), }) // Cleanup after callback completes errorFunc.Release() successFunc.Release() return nil }) promise.Call("then", successFunc).Call("catch", errorFunc) } // PostForm performs a POST request with form data func (c *WASMHTTPClient) PostForm(url string, data url.Values, dest interface{}) error { result := make(chan HTTPResult, 1) c.PostFormAsync(url, data, func(r HTTPResult) { result <- r }) r := <-result if r.Error != nil { return r.Error } return json.Unmarshal(r.Data, dest) } // PostFormAsync performs a POST request asynchronously using callback func (c *WASMHTTPClient) PostFormAsync(url string, data url.Values, callback HTTPCallback) { // Prepare fetch options headers := map[string]interface{}{ "Content-Type": "application/x-www-form-urlencoded", } options := map[string]interface{}{ "method": "POST", "headers": headers, "body": data.Encode(), } // Convert options to JS object jsOptions := js.ValueOf(options) // Make the request promise := js.Global().Call("fetch", url, jsOptions) // Success handler var successFunc js.Func successFunc = js.FuncOf(func(this js.Value, args []js.Value) interface{} { response := args[0] if !response.Get("ok").Bool() { callback(HTTPResult{ Error: fmt.Errorf("HTTP %d: %s", response.Get("status").Int(), response.Get("statusText").String()), }) successFunc.Release() return nil } // Get response text textPromise := response.Call("text") var textFunc js.Func textFunc = js.FuncOf(func(this js.Value, args []js.Value) interface{} { text := args[0].String() callback(HTTPResult{ Data: []byte(text), }) // Cleanup after callback completes textFunc.Release() successFunc.Release() return nil }) // Error handler for text promise var textErrorFunc js.Func textErrorFunc = js.FuncOf(func(this js.Value, args []js.Value) interface{} { callback(HTTPResult{ Error: fmt.Errorf("failed to read response text: %v", args[0]), }) // Cleanup textFunc.Release() textErrorFunc.Release() successFunc.Release() return nil }) textPromise.Call("then", textFunc).Call("catch", textErrorFunc) return nil }) // Error handler var errorFunc js.Func errorFunc = js.FuncOf(func(this js.Value, args []js.Value) interface{} { callback(HTTPResult{ Error: fmt.Errorf("fetch error: %s", args[0].String()), }) // Cleanup after callback completes errorFunc.Release() successFunc.Release() return nil }) promise.Call("then", successFunc).Call("catch", errorFunc) }