|
@@ -2,12 +2,24 @@
|
|
|
package wsrpc
|
|
|
|
|
|
import (
|
|
|
+ "errors"
|
|
|
+ "log"
|
|
|
+ "reflect"
|
|
|
+ "strings"
|
|
|
"sync"
|
|
|
|
|
|
"github.com/google/uuid"
|
|
|
"golang.org/x/net/websocket"
|
|
|
)
|
|
|
|
|
|
+var (
|
|
|
+ ErrNParam = errors.New("Invalid number of parameters")
|
|
|
+ ErrNReturn = errors.New("Number of outputs mismatch")
|
|
|
+ ErrBadImplementation = errors.New("Bad implementation")
|
|
|
+
|
|
|
+ errorInterface = reflect.TypeOf((*error)(nil)).Elem()
|
|
|
+)
|
|
|
+
|
|
|
// Call object
|
|
|
type CallObj struct {
|
|
|
OP string `json:"op"` // operation
|
|
@@ -19,10 +31,10 @@ type CallObj struct {
|
|
|
}
|
|
|
|
|
|
// DataObj common structure for dymanic json object
|
|
|
-type DataObj map[string]interface{}
|
|
|
+//type DataObj map[string]interface{}
|
|
|
|
|
|
// ListenerFunc function type to handle browser events
|
|
|
-type ListenerFunc func(...interface{}) interface{}
|
|
|
+type ListenerFunc func(...interface{}) (interface{}, error)
|
|
|
|
|
|
// Request request type for handling requests channels
|
|
|
|
|
@@ -52,16 +64,19 @@ func (c *ClientCtx) Process(data CallObj) {
|
|
|
case "call":
|
|
|
params := data.Params
|
|
|
var idn = data.Method
|
|
|
- var reqId = data.ID
|
|
|
+ var reqID = data.ID
|
|
|
var fn, ok = c.listeners[idn]
|
|
|
if !ok {
|
|
|
return
|
|
|
}
|
|
|
- go func() {
|
|
|
- ret := fn(params...)
|
|
|
+ go func() { // async send
|
|
|
+ ret, err := fn(params...)
|
|
|
+ if err != nil {
|
|
|
+ log.Println("Create error response, panic?")
|
|
|
+ }
|
|
|
var responseObj = CallObj{
|
|
|
OP: "response",
|
|
|
- ID: reqId,
|
|
|
+ ID: reqID,
|
|
|
Response: ret,
|
|
|
}
|
|
|
//log.Println("Sending response")
|
|
@@ -103,3 +118,48 @@ func (c *ClientCtx) Call(method string, params ...interface{}) interface{} {
|
|
|
func (c *ClientCtx) Define(name string, listener ListenerFunc) {
|
|
|
c.listeners[name] = listener
|
|
|
}
|
|
|
+
|
|
|
+func (c *ClientCtx) Export(obj interface{}) {
|
|
|
+ // Reflect here
|
|
|
+ typ := reflect.TypeOf(obj)
|
|
|
+ val := reflect.ValueOf(obj)
|
|
|
+
|
|
|
+ for i := 0; i < typ.NumField(); i++ {
|
|
|
+ fTyp := typ.Field(i)
|
|
|
+ if fTyp.Type.Kind() != reflect.Func {
|
|
|
+ log.Println("Ignore non func value")
|
|
|
+ continue
|
|
|
+ }
|
|
|
+ tag, ok := fTyp.Tag.Lookup("wsexport")
|
|
|
+ if !ok {
|
|
|
+ continue
|
|
|
+ }
|
|
|
+ tagParts := strings.Split(tag, ",")
|
|
|
+
|
|
|
+ exportName := tagParts[0]
|
|
|
+ fnVal := val.Field(i)
|
|
|
+ // Slow?
|
|
|
+ c.listeners[exportName] = func(params ...interface{}) (interface{}, error) {
|
|
|
+ if len(params) != fnVal.Type().NumIn() {
|
|
|
+ return nil, ErrNParam
|
|
|
+ }
|
|
|
+ if fnVal.Type().NumOut() != 2 {
|
|
|
+ return nil, ErrNReturn
|
|
|
+ }
|
|
|
+ if !fnVal.Type().Out(1).Implements(errorInterface) {
|
|
|
+ return nil, ErrBadImplementation
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ vparam := []reflect.Value{}
|
|
|
+ for _, p := range params {
|
|
|
+ vparam = append(vparam, reflect.ValueOf(p))
|
|
|
+ }
|
|
|
+ r := fnVal.Call(vparam)
|
|
|
+ return r[0].Interface(), r[1].Interface().(error)
|
|
|
+ }
|
|
|
+
|
|
|
+ // It is a func, check for tag
|
|
|
+ }
|
|
|
+
|
|
|
+}
|