clientctx.go 2.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. // Client handler
  2. package wsrpc
  3. import (
  4. "sync"
  5. "github.com/google/uuid"
  6. "golang.org/x/net/websocket"
  7. )
  8. // Call object
  9. type CallObj struct {
  10. OP string `json:"op"` // operation
  11. ID string `json:"id"` // Id of the call
  12. Method string `json:"method"` // could be param 0 instead?
  13. Params []interface{} `json:"params"`
  14. Response interface{} `json:"response"`
  15. }
  16. // DataObj common structure for dymanic json object
  17. type DataObj map[string]interface{}
  18. // ListenerFunc function type to handle browser events
  19. type ListenerFunc func(...interface{}) interface{}
  20. // Request request type for handling requests channels
  21. // ClientCtx main client struct
  22. type ClientCtx struct {
  23. locker sync.Mutex
  24. WS *websocket.Conn
  25. // stuff
  26. listeners map[string]ListenerFunc
  27. requests map[string]chan interface{}
  28. }
  29. //NewHandler creates a new WsRPC client handler
  30. func NewHandler(id string, ws *websocket.Conn) *ClientCtx {
  31. var c = ClientCtx{
  32. WS: ws,
  33. listeners: map[string]ListenerFunc{},
  34. requests: map[string]chan interface{}{},
  35. }
  36. return &c
  37. }
  38. // Process messages
  39. func (c *ClientCtx) Process(data CallObj) {
  40. switch data.OP {
  41. case "call":
  42. params := data.Params
  43. var idn = data.Method
  44. var reqId = data.ID
  45. var fn, ok = c.listeners[idn]
  46. if !ok {
  47. return
  48. }
  49. go func() {
  50. ret := fn(params...)
  51. var responseObj = CallObj{
  52. OP: "response",
  53. ID: reqId,
  54. Response: ret,
  55. }
  56. //log.Println("Sending response")
  57. websocket.JSON.Send(c.WS, responseObj)
  58. }()
  59. case "response":
  60. c.locker.Lock()
  61. mchan, ok := c.requests[data.ID]
  62. delete(c.requests, data.ID)
  63. c.locker.Unlock()
  64. if ok {
  65. mchan <- data.Response
  66. }
  67. }
  68. }
  69. // Call a client method and estabilishes a request id
  70. func (c *ClientCtx) Call(method string, params ...interface{}) interface{} {
  71. u := uuid.New()
  72. uuidStr := u.String()
  73. var callObj = CallObj{
  74. OP: "call",
  75. ID: uuidStr,
  76. Method: method,
  77. Params: params,
  78. }
  79. res := make(chan interface{}, 1)
  80. c.locker.Lock()
  81. c.requests[uuidStr] = res
  82. c.locker.Unlock()
  83. websocket.JSON.Send(c.WS, &callObj)
  84. return <-res // Block until value
  85. }
  86. //On add a event listener on browser
  87. func (c *ClientCtx) Define(name string, listener ListenerFunc) {
  88. c.listeners[name] = listener
  89. }