// Client handler package wsrpc import ( "sync" "github.com/google/uuid" "golang.org/x/net/websocket" ) // Call object type CallObj struct { OP string `json:"op"` // operation ID string `json:"id"` // Id of the call Method string `json:"method"` // could be param 0 instead? Params []interface{} `json:"params"` Response interface{} `json:"response"` } // DataObj common structure for dymanic json object type DataObj map[string]interface{} // ListenerFunc function type to handle browser events type ListenerFunc func(...interface{}) interface{} // Request request type for handling requests channels // ClientCtx main client struct type ClientCtx struct { locker sync.Mutex WS *websocket.Conn // stuff listeners map[string]ListenerFunc requests map[string]chan interface{} } //NewHandler creates a new WsRPC client handler func NewHandler(id string, ws *websocket.Conn) *ClientCtx { var c = ClientCtx{ WS: ws, listeners: map[string]ListenerFunc{}, requests: map[string]chan interface{}{}, } return &c } // Process messages func (c *ClientCtx) Process(data CallObj) { switch data.OP { case "call": params := data.Params var idn = data.Method var reqId = data.ID var fn, ok = c.listeners[idn] if !ok { return } go func() { ret := fn(params...) var responseObj = CallObj{ OP: "response", ID: reqId, Response: ret, } //log.Println("Sending response") websocket.JSON.Send(c.WS, responseObj) }() case "response": c.locker.Lock() mchan, ok := c.requests[data.ID] delete(c.requests, data.ID) c.locker.Unlock() if ok { mchan <- data.Response } } } // Call a client method and estabilishes a request id func (c *ClientCtx) Call(method string, params ...interface{}) interface{} { u := uuid.New() uuidStr := u.String() var callObj = CallObj{ OP: "call", ID: uuidStr, Method: method, Params: params, } res := make(chan interface{}, 1) c.locker.Lock() c.requests[uuidStr] = res c.locker.Unlock() websocket.JSON.Send(c.WS, &callObj) return <-res // Block until value } //On add a event listener on browser func (c *ClientCtx) Define(name string, listener ListenerFunc) { c.listeners[name] = listener }