func (t *timerTask) Execute(vm *otto.Otto, l *loop.Loop) error { var arguments []interface{} if len(t.call.ArgumentList) > 2 { tmp := t.call.ArgumentList[2:] arguments = make([]interface{}, 2+len(tmp)) for i, value := range tmp { arguments[i+2] = value } } else { arguments = make([]interface{}, 1) } arguments[0] = t.call.ArgumentList[0] if _, err := vm.Call(`Function.call.call`, nil, arguments...); err != nil { return err } if t.interval && !t.stopped { t.timer.Reset(t.duration) l.Add(t) } return nil }
func Define(vm *otto.Otto, l *loop.Loop) error { if v, err := vm.Get("setTimeout"); err != nil { return err } else if !v.IsUndefined() { return nil } newTimer := func(interval bool) func(call otto.FunctionCall) otto.Value { return func(call otto.FunctionCall) otto.Value { delay, _ := call.Argument(1).ToInteger() if delay < minDelay[interval] { delay = minDelay[interval] } t := &timerTask{ duration: time.Duration(delay) * time.Millisecond, call: call, interval: interval, } l.Add(t) t.timer = time.AfterFunc(t.duration, func() { l.Ready(t) }) value, err := call.Otto.ToValue(t) if err != nil { panic(err) } return value } } vm.Set("setTimeout", newTimer(false)) vm.Set("setInterval", newTimer(true)) vm.Set("setImmediate", func(call otto.FunctionCall) otto.Value { t := &timerTask{ duration: time.Millisecond, call: call, } l.Add(t) t.timer = time.AfterFunc(t.duration, func() { l.Ready(t) }) value, err := call.Otto.ToValue(t) if err != nil { panic(err) } return value }) clearTimeout := func(call otto.FunctionCall) otto.Value { v, _ := call.Argument(0).Export() if t, ok := v.(*timerTask); ok { t.stopped = true t.timer.Stop() l.Remove(t) } return otto.UndefinedValue() } vm.Set("clearTimeout", clearTimeout) vm.Set("clearInterval", clearTimeout) vm.Set("clearImmediate", clearTimeout) return nil }
// RunWithPromptAndPrelude runs a REPL with the given prompt and prelude. func RunWithPromptAndPrelude(l *loop.Loop, prompt, prelude string) error { if prompt == "" { prompt = ">" } prompt = strings.Trim(prompt, " ") prompt += " " rl, err := readline.New(prompt) if err != nil { return err } l.VM().Set("console", map[string]interface{}{ "log": func(c otto.FunctionCall) otto.Value { s := make([]string, len(c.ArgumentList)) for i := 0; i < len(c.ArgumentList); i++ { s[i] = c.Argument(i).String() } rl.Stdout().Write([]byte(strings.Join(s, " ") + "\n")) rl.Refresh() return otto.UndefinedValue() }, "warn": func(c otto.FunctionCall) otto.Value { s := make([]string, len(c.ArgumentList)) for i := 0; i < len(c.ArgumentList); i++ { s[i] = c.Argument(i).String() } rl.Stderr().Write([]byte(strings.Join(s, " ") + "\n")) rl.Refresh() return otto.UndefinedValue() }, }) if prelude != "" { if _, err := io.Copy(rl.Stderr(), strings.NewReader(prelude+"\n")); err != nil { return err } rl.Refresh() } var d []string for { ll, err := rl.Readline() if err != nil { if err == readline.ErrInterrupt { if d != nil { d = nil rl.SetPrompt(prompt) rl.Refresh() continue } break } return err } if len(d) == 0 && ll == "" { continue } d = append(d, ll) s := strings.Join(d, "\n") if _, err := parser.ParseFile(nil, "repl", s, 0); err != nil { rl.SetPrompt(strings.Repeat(" ", len(prompt))) } else { rl.SetPrompt(prompt) d = nil t := looptask.NewEvalTask(s) // don't report errors to the loop - this lets us handle them and // resume normal operation t.SoftError = true l.Add(t) l.Ready(t) v, err := <-t.Value, <-t.Error if err != nil { if oerr, ok := err.(*otto.Error); ok { io.Copy(rl.Stdout(), strings.NewReader(oerr.String())) } else { io.Copy(rl.Stdout(), strings.NewReader(err.Error())) } } else { f, err := format(v, 80, 2, 5) if err != nil { panic(err) } rl.Stdout().Write([]byte(f + "\n")) } } rl.Refresh() } return rl.Close() }
func DefineWithHandler(vm *otto.Otto, l *loop.Loop, h http.Handler) error { if err := promise.Define(vm, l); err != nil { return err } s, err := vm.Compile("fetch.js", rice.MustFindBox("dist-fetch").MustString("bundle.js")) if err != nil { return err } if _, err := vm.Run(s); err != nil { return 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, err := http.NewRequest(method, urlStr, body) if err != nil { t.err = err return } if h != nil && urlStr[0] == '/' { res := httptest.NewRecorder() h.ServeHTTP(res, req) jsRes.Set("status", res.Code) jsRes.Set("statusText", http.StatusText(res.Code)) h := mustValue(jsRes.Get("headers")).Object() for k, vs := range res.Header() { for _, v := range vs { if _, err := h.Call("append", k, v); err != nil { t.err = err return } } } jsRes.Set("_body", string(res.Body.Bytes())) } else { res, err := http.DefaultClient.Do(req) if err != nil { t.err = err return } jsRes.Set("status", res.StatusCode) jsRes.Set("statusText", res.Status) h := mustValue(jsRes.Get("headers")).Object() for k, vs := range res.Header { for _, v := range vs { if _, err := h.Call("append", k, v); err != nil { t.err = err return } } } d, err := ioutil.ReadAll(res.Body) if err != nil { t.err = err return } jsRes.Set("_body", string(d)) } }() return otto.UndefinedValue() }) return nil }
func DefineWithHandler(vm *otto.Otto, l *loop.Loop, h http.Handler) error { if err := promise.Define(vm, l); err != nil { return err } jsData := rice.MustFindBox("dist-fetch").MustString("bundle.js") smData := rice.MustFindBox("dist-fetch").MustString("bundle.js.map") s, err := vm.CompileWithSourceMap("fetch-bundle.js", jsData, smData) if err != nil { return err } if _, err := vm.Run(s); err != nil { return 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, err := http.NewRequest(method, urlStr, body) if err != nil { t.err = err 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, err := http.DefaultClient.Do(req) if err != nil { t.err = err return } d, err := ioutil.ReadAll(res.Body) if err != nil { t.err = err return } t.status = res.StatusCode t.statusText = res.Status t.headers = res.Header t.body = d } }() return otto.UndefinedValue() }) return nil }