diff --git a/examples/bind.go b/examples/bind.go
index ece8a92f9..e8f4395c8 100644
--- a/examples/bind.go
+++ b/examples/bind.go
@@ -1,18 +1,32 @@
package main
-import "github.com/webview/webview"
+import (
+ "time"
+
+ "github.com/webview/webview"
+)
const html = `
You tapped 0 time(s).
+
+Result of computation: 0
`
@@ -33,6 +47,17 @@ func main() {
return IncrementResult{Count: count}
})
+ // A binding that performs a long-running computation and returns the result
+ w.Bind("compute", func(a, b int) chan webview.BindCallbackResult {
+ ch := make(chan webview.BindCallbackResult)
+ go func() {
+ defer close(ch)
+ time.Sleep(1 * time.Second)
+ ch <- webview.BindCallbackResult{Value: a * b, Error: nil}
+ }()
+ return ch
+ })
+
w.SetHtml(html)
w.Run()
}
diff --git a/webview.go b/webview.go
index cb70515a7..b6fd2a6d5 100644
--- a/webview.go
+++ b/webview.go
@@ -50,6 +50,16 @@ const (
HintMax = C.WEBVIEW_HINT_MAX
)
+type BindCallbackResult struct {
+ // Error is an error returned by the callback. If error is not nil - the
+ // result of the callback is ignored.
+ Error error
+
+ // Value is a value returned by the callback. If error is not nil - the
+ // result of the callback is ignored.
+ Value interface{}
+}
+
type WebView interface {
// Run runs the main loop until it's terminated. After this function exits -
@@ -108,7 +118,8 @@ type WebView interface {
// JavaScript function.
//
// f must be a function
- // f must return either value and error or just error
+ // f can return either value and error or just error
+ // f can return a channel of BindCallbackResult as the value
Bind(name string, f interface{}) error
}
@@ -222,21 +233,33 @@ func _webviewBindingGoCallback(w C.webview_t, id *C.char, req *C.char, index uin
m.Lock()
f := bindings[uintptr(index)]
m.Unlock()
- jsString := func(v interface{}) string { b, _ := json.Marshal(v); return string(b) }
- status, result := 0, ""
- if res, err := f(C.GoString(id), C.GoString(req)); err != nil {
- status = -1
- result = jsString(err.Error())
- } else if b, err := json.Marshal(res); err != nil {
- status = -1
- result = jsString(err.Error())
- } else {
- status = 0
- result = string(b)
- }
- s := C.CString(result)
- defer C.free(unsafe.Pointer(s))
- C.webview_return(w, id, C.int(status), s)
+
+ // retain a reference to the id and params strings
+ reqId := C.GoString(id)
+ reqParams := C.GoString(req)
+
+ // run the callback in a separate goroutine
+ go func() {
+ jsString := func(v interface{}) string { b, _ := json.Marshal(v); return string(b) }
+
+ status, result := 0, ""
+ if res, err := f(reqId, reqParams); err != nil {
+ status = -1
+ result = jsString(err.Error())
+ } else if b, err := json.Marshal(res); err != nil {
+ status = -1
+ result = jsString(err.Error())
+ } else {
+ status = 0
+ result = string(b)
+ }
+
+ cId := C.CString(reqId)
+ defer C.free(unsafe.Pointer(cId))
+ s := C.CString(result)
+ defer C.free(unsafe.Pointer(s))
+ C.webview_return(w, cId, C.int(status), s)
+ }()
}
func (w *webview) Bind(name string, f interface{}) error {
@@ -287,6 +310,25 @@ func (w *webview) Bind(name string, f interface{}) error {
return nil, res[0].Interface().(error)
}
return nil, nil
+ } else if res[0].Type().Kind() == reflect.Chan {
+ if res[0].Type().Elem() != reflect.TypeOf(BindCallbackResult{}) {
+ return nil, errors.New("channel must be of type CallbackResult")
+ }
+
+ // Wait for the channel to receive a value
+ val, ok := res[0].Recv()
+
+ if !ok {
+ return nil, errors.New("channel closed")
+ }
+
+ callbackResult := val.Interface().(BindCallbackResult)
+
+ if callbackResult.Error != nil {
+ return nil, callbackResult.Error
+ }
+
+ return callbackResult.Value, nil
}
return res[0].Interface(), nil
case 2:
diff --git a/webview_test.go b/webview_test.go
index 49f24d0c1..97206f938 100644
--- a/webview_test.go
+++ b/webview_test.go
@@ -11,12 +11,20 @@ func Example() {
w := New(true)
defer w.Destroy()
w.SetTitle("Hello")
- w.Bind("noop", func() string {
+ w.Bind("noop", func(id string) {
log.Println("hello")
- return "hello"
+ w.Return(id, StatusSuccess, "hello")
})
- w.Bind("add", func(a, b int) int {
- return a + b
+ w.Bind("add", func(id string, a, b int) {
+ w.Return(id, StatusSuccess, a+b)
+ })
+ w.Bind("subtract", func(a, b int) chan BindCallbackResult {
+ ch := make(chan BindCallbackResult)
+ go func() {
+ defer close(ch)
+ ch <- BindCallbackResult{Value: a - b, Error: nil}
+ }()
+ return ch
})
w.Bind("quit", func() {
w.Terminate()
@@ -31,7 +39,10 @@ func Example() {
console.log('noop res', res);
add(1, 2).then(function(res) {
console.log('add res', res);
- quit();
+ subtract(5, 3).then(function(res) {
+ console.log('subtract res', res);
+ quit();
+ });
});
});
};