mirror of
https://github.com/status-im/status-go.git
synced 2025-01-11 23:25:29 +00:00
a19e502686
As fetch.go was the only consumer of go.rice, it could be safely removed in favour of go-bindata and go generate. Motivation to do that was the fact that go.rice throws panic in iOS when compiled with gomobile.
177 lines
3.4 KiB
Go
177 lines
3.4 KiB
Go
package fetch
|
|
|
|
//go:generate go-bindata -pkg fetch -o dist_fetch.go ./dist-fetch/
|
|
|
|
import (
|
|
"io"
|
|
"io/ioutil"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"strings"
|
|
|
|
"github.com/robertkrimen/otto"
|
|
|
|
"github.com/status-im/status-go/geth/jail/internal/loop"
|
|
"github.com/status-im/status-go/geth/jail/internal/promise"
|
|
"github.com/status-im/status-go/geth/jail/internal/vm"
|
|
)
|
|
|
|
func mustValue(v otto.Value, err error) otto.Value {
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
return v
|
|
}
|
|
|
|
type fetchTask struct {
|
|
id int64
|
|
jsReq, jsRes *otto.Object
|
|
cb otto.Value
|
|
err error
|
|
status int
|
|
statusText string
|
|
headers map[string][]string
|
|
body []byte
|
|
}
|
|
|
|
func (t *fetchTask) SetID(id int64) { t.id = id }
|
|
func (t *fetchTask) GetID() int64 { return t.id }
|
|
|
|
func (t *fetchTask) Execute(vm *vm.VM, l *loop.Loop) error {
|
|
var arguments []interface{}
|
|
|
|
if t.err != nil {
|
|
e, err := vm.Call(`new Error`, nil, t.err.Error())
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
arguments = append(arguments, e)
|
|
}
|
|
|
|
// We're locking on VM here because underlying otto's VM
|
|
// is not concurrently safe, and this function indirectly
|
|
// access vm's functions in cb.Call/h.Set.
|
|
vm.Lock()
|
|
defer vm.Unlock()
|
|
|
|
err := t.jsRes.Set("status", t.status)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
err = t.jsRes.Set("statusText", t.statusText)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
h := mustValue(t.jsRes.Get("headers")).Object()
|
|
for k, vs := range t.headers {
|
|
for _, v := range vs {
|
|
if _, err = h.Call("append", k, v); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
}
|
|
err = t.jsRes.Set("_body", string(t.body))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
_, err = t.cb.Call(otto.NullValue(), arguments...)
|
|
return err
|
|
}
|
|
|
|
func (t *fetchTask) Cancel() {
|
|
}
|
|
|
|
// Define fetch
|
|
func Define(vm *vm.VM, l *loop.Loop) error {
|
|
return DefineWithHandler(vm, l, nil)
|
|
}
|
|
|
|
//DefineWithHandler fetch with handler
|
|
func DefineWithHandler(vm *vm.VM, l *loop.Loop, h http.Handler) error {
|
|
if err := promise.Define(vm, l); err != nil {
|
|
return err
|
|
}
|
|
|
|
jsData := MustAsset("dist-fetch/bundle.js")
|
|
smData := MustAsset("dist-fetch/bundle.js.map")
|
|
|
|
s, err := vm.CompileWithSourceMap("fetch-bundle.js", jsData, smData)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
_, err = vm.Run(s)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
err = vm.Set("__private__fetch_execute", func(c otto.FunctionCall) otto.Value {
|
|
jsReq := c.Argument(0).Object()
|
|
jsRes := c.Argument(1).Object()
|
|
cb := c.Argument(2)
|
|
|
|
method := mustValue(jsReq.Get("method")).String()
|
|
urlStr := mustValue(jsReq.Get("url")).String()
|
|
jsBody := mustValue(jsReq.Get("body"))
|
|
var body io.Reader
|
|
if jsBody.IsString() {
|
|
body = strings.NewReader(jsBody.String())
|
|
}
|
|
|
|
t := &fetchTask{
|
|
jsReq: jsReq,
|
|
jsRes: jsRes,
|
|
cb: cb,
|
|
}
|
|
|
|
l.Add(t)
|
|
|
|
go func() {
|
|
defer l.Ready(t)
|
|
|
|
req, rqErr := http.NewRequest(method, urlStr, body)
|
|
if rqErr != nil {
|
|
t.err = rqErr
|
|
return
|
|
}
|
|
|
|
if h != nil && urlStr[0] == '/' {
|
|
res := httptest.NewRecorder()
|
|
|
|
h.ServeHTTP(res, req)
|
|
|
|
t.status = res.Code
|
|
t.statusText = http.StatusText(res.Code)
|
|
t.headers = res.Header()
|
|
t.body = res.Body.Bytes()
|
|
} else {
|
|
res, e := http.DefaultClient.Do(req)
|
|
if e != nil {
|
|
t.err = e
|
|
return
|
|
}
|
|
|
|
d, e := ioutil.ReadAll(res.Body)
|
|
if e != nil {
|
|
t.err = e
|
|
return
|
|
}
|
|
|
|
t.status = res.StatusCode
|
|
t.statusText = res.Status
|
|
t.headers = res.Header
|
|
t.body = d
|
|
}
|
|
}()
|
|
|
|
return otto.UndefinedValue()
|
|
})
|
|
|
|
return err
|
|
}
|