at main 2.4 kB view raw
1package fetch 2 3import ( 4 "encoding/json" 5 "fmt" 6 "io" 7 "net/http" 8 "strings" 9 10 "github.com/dop251/goja" 11) 12 13type response struct { 14 status int 15 statusText string 16 url string 17 body []byte 18} 19 20func (r *response) toObject(runtime *goja.Runtime) *goja.Object { 21 obj := runtime.NewObject() 22 23 obj.Set("ok", runtime.ToValue(r.status > 199 && r.status < 300)) 24 obj.Set("status", runtime.ToValue(r.status)) 25 obj.Set("statusText", runtime.ToValue(r.statusText)) 26 obj.Set("url", runtime.ToValue(r.url)) 27 obj.Set("text", runtime.ToValue(r.getText(runtime))) 28 obj.Set("json", runtime.ToValue(r.getJSON(runtime))) 29 30 return obj 31} 32 33func (r *response) getText(runtime *goja.Runtime) func(goja.FunctionCall) goja.Value { 34 return func(goja.FunctionCall) goja.Value { 35 return runtime.ToValue(string(r.body)) 36 } 37} 38 39func (r *response) getJSON(runtime *goja.Runtime) func(goja.FunctionCall) goja.Value { 40 return func(goja.FunctionCall) goja.Value { 41 data := map[string]any{} 42 43 if err := json.Unmarshal(r.body, &data); err != nil { 44 // TODO: throw exception? 45 return runtime.NewGoError(err) 46 } 47 48 return runtime.ToValue(data) 49 } 50} 51 52type fetchOptions struct { 53 Headers map[string]string 54} 55 56func doFetch(runtime *goja.Runtime) func(goja.FunctionCall) goja.Value { 57 return func(fc goja.FunctionCall) goja.Value { 58 url := fc.Argument(0).String() 59 60 opts := map[string]any{} 61 62 params := fc.Argument(1) 63 if !goja.IsUndefined(params) { 64 if err := runtime.ExportTo(params, &opts); err != nil { 65 return runtime.NewGoError(err) 66 } 67 } 68 69 headers := map[string][]string{} 70 if hdrs, ok := opts["headers"]; ok { 71 if h, ok := hdrs.(map[string]any); ok { 72 for k, v := range h { 73 switch vt := v.(type) { 74 case string: 75 headers[k] = []string{vt} 76 case int: 77 headers[k] = []string{fmt.Sprintf("%d", vt)} 78 } 79 } 80 } 81 } 82 83 res := &response{} 84 85 req, err := http.NewRequest("GET", url, nil) 86 if err != nil { 87 return runtime.NewGoError(err) 88 } 89 90 req.Header = headers 91 92 client := &http.Client{} 93 resp, err := client.Do(req) 94 if err != nil { 95 return runtime.NewGoError(err) 96 } 97 defer resp.Body.Close() 98 99 res.status = resp.StatusCode 100 res.statusText = strings.TrimPrefix(resp.Status, fmt.Sprintf("%d ", resp.StatusCode)) 101 res.url = resp.Request.URL.String() 102 103 res.body, _ = io.ReadAll(resp.Body) 104 105 return res.toObject(runtime) 106 } 107} 108 109func Enable(runtime *goja.Runtime) { 110 runtime.Set("fetch", doFetch(runtime)) 111}