forked from ry/v8worker
/
worker.go
128 lines (105 loc) · 3.41 KB
/
worker.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
package v8worker
/*
#cgo CXXFLAGS: -std=c++11
#cgo pkg-config: v8.pc
#include <stdlib.h>
#include "binding.h"
*/
import "C"
import "errors"
import "unsafe"
import "sync"
import "runtime"
// To receive messages from javascript...
type ReceiveMessageCallback func(msg string)
// To send a message from javascript and synchronously return a string.
type ReceiveSyncMessageCallback func(msg string) string
// DiscardSend can be used in the worker constructor when you don't use the builtin $send.
func DiscardSend(msg string) {}
// DiscardSendSync can be used in the worker constructor when you don't use the builtin $sendSync.
func DiscardSendSync(msg string) string { return "" }
// Don't init V8 more than once.
var initV8Once sync.Once
// This is a golang wrapper around a single V8 Isolate.
type Worker struct {
cWorker *C.worker
cb ReceiveMessageCallback
recvSync_cb ReceiveSyncMessageCallback
}
// Return the V8 version E.G. "4.3.59"
func Version() string {
return C.GoString(C.worker_version())
}
//export recvCb
func recvCb(msg_s *C.char, ptr unsafe.Pointer) {
msg := C.GoString(msg_s)
worker := (*Worker)(ptr)
worker.cb(msg)
}
//export recvSyncCb
func recvSyncCb(msg_s *C.char, ptr unsafe.Pointer) *C.char {
msg := C.GoString(msg_s)
worker := (*Worker)(ptr)
return_s := C.CString(worker.recvSync_cb(msg))
return return_s
}
// New creates a new worker, which corresponds to a V8 isolate. A single threaded
// standalone execution context.
func New(cb ReceiveMessageCallback, recvSync_cb ReceiveSyncMessageCallback) *Worker {
worker := &Worker{
cb: cb,
recvSync_cb: recvSync_cb,
}
initV8Once.Do(func() {
C.v8_init()
})
callback := C.worker_recv_cb(C.go_recv_cb)
receiveSync_callback := C.worker_recvSync_cb(C.go_recvSync_cb)
worker.cWorker = C.worker_new(callback, receiveSync_callback, unsafe.Pointer(worker))
runtime.SetFinalizer(worker, func(final_worker *Worker) {
C.worker_dispose(final_worker.cWorker) // Delete this worker on finalize (GC)
})
return worker
}
// Breaks execution of javascript
func (w *Worker) Break() {
C.worker_break(w.cWorker)
}
// Load and executes a javascript file with the filename specified by
// scriptName and the contents of the file specified by the param code.
func (w *Worker) Load(scriptName string, code string, _offset ...int) error {
scriptName_s := C.CString(scriptName)
code_s := C.CString(code)
defer C.free(unsafe.Pointer(scriptName_s))
defer C.free(unsafe.Pointer(code_s))
var offset int
if _offset != nil {
offset = _offset[0]
}
offset_s := C.int(offset)
r := C.worker_load(w.cWorker, scriptName_s, code_s, offset_s)
if r != 0 {
errStr := C.GoString(C.worker_last_exception(w.cWorker))
return errors.New(errStr)
}
return nil
}
// Sends a message to a worker. The $recv callback in js will be called.
func (w *Worker) Send(msg string) error {
msg_s := C.CString(string(msg))
defer C.free(unsafe.Pointer(msg_s))
r := C.worker_send(w.cWorker, msg_s)
if r != 0 {
errStr := C.GoString(C.worker_last_exception(w.cWorker))
return errors.New(errStr)
}
return nil
}
// SendSync sends a message to a worker. The $recvSync callback in js will be called.
// That callback will return a string which is passed to golang and used as the return value of SendSync.
func (w *Worker) SendSync(msg string) string {
msg_s := C.CString(string(msg))
defer C.free(unsafe.Pointer(msg_s))
svalue := C.worker_sendSync(w.cWorker, msg_s)
return C.GoString(svalue)
}