Преглед на файлове

Clean up and changed the way to register handler

luis преди 7 години
родител
ревизия
02c50c8f27

+ 104 - 107
client/wsrpc.js

@@ -1,110 +1,107 @@
+(function (window) {
+  window.WsRpc = function () {
+    var ctx = this
+    this._requests = {}
+    /**
+     * Connect with reconnection
+     */
+    this.connect = function (loc) {
+      var ws = this.ws = new window.WebSocket(loc)
+      ws.onopen = function () {
+        ctx._requests = {}
+        ctx.connected = true
+        if (ctx.onopen !== undefined) {
+          ctx.onopen(ctx)
+        }
+      }
+      ws.onmessage = function (evt) {
+        // console.log("RCV:",evt.data)
+        var obj = JSON.parse(evt.data)
+        var arrObj = [].concat(obj) // if object add, if array concat
+        for (var i = 0; i < arrObj.length; i++) {
+          ctx.process(arrObj[i])
+        }
+      }
+      ws.onerror = function () { }
+      ws.onclose = function () {
+        if (ctx.connected === true) {
+          ctx.connected = false
+          if (ctx.onclose !== undefined) {
+            ctx.onclose(ctx)
+          }
+        }
+        // Retry
+        setTimeout(function () {
+          ctx.connect(loc)
+        }, 3000) // 3 seconds reconnect
+      }
+    }
+    /**
+     * Process requests
+     */
+    this.process = function (obj) {
+      switch (obj.op) {
+        case 'call':
+          if (obj.method === undefined || this._exports[obj.method] === undefined) {
+            // TODO: Send object to inform error
+            return
+          }
+          // Send response
+          var nparams = [].concat((data) => {
+            var dataObj = {
+              'op': 'response',
+              'id': obj.id,
+              'response': data
+            }
+            ctx.ws.send(JSON.stringify(dataObj))
+          }, obj.param)
+          this._exports[obj.method].apply(this._exports[obj.method], nparams)
+          break
+        case 'response':
+          ctx._requests[obj.id](obj.response)
+          delete ctx._requests[obj.reqId]
+          break
+      }
+    }
 
-/*
-  Goal having something like:
- 
-	wsrpc.Connect("/ws");
-	wsrpc.Connect("ws://127.0.0.1/ws");
-
-
-	obj = {
-		method1:function() {
-			//Hello
-		}
-	}
-	wsrpc.Export(obj);
- */
-
-function WsRpc() {
-	var ctx = this
-	this._requests = {}
-	this.connect = function(loc) {
-			var ws = this.ws = new WebSocket(loc)
-			ws.onopen = function() {
-				ctx._requests = {}
-				ctx.connected = true;
-				if(ctx.onopen != undefined) {
-					ctx.onopen(ctx)
-				}
-			}	
-			ws.onmessage = function(evt) {
-				//console.log("RCV:",evt.data)
-				var obj = JSON.parse(evt.data)
-				var arrObj = [].concat(obj); // if object add, if array concat
-				for( var i = 0; i <arrObj.length; i++) {
-					ctx.process(arrObj[i]);
-				}
-			}
-			ws.onerror = function() { }
-			ws.onclose = function() {
-				if(ctx.connected == true) {
-					ctx.connected = false;
-					if(ctx.onclose != undefined) {
-						ctx.onclose(ctx)
-					}
-				}
-				
-				// Retry
-				setTimeout(function() {
-					ctx.connect(loc)
-				},3000) // 3 seconds reconnect
-			}
-		}
-	this.process =  function(obj) {
-		if (obj.op == "call") {
-			if(obj.method == undefined || this._exports[obj.method] == undefined) {
-				//TODO: Send objet to inform error
-				return
-			}
-			function response(data) {
-				var dataObj = {
-					"op":"response",
-					"reqId":obj.reqId,
-					"data":data
-				}
-				ctx.ws.send(JSON.stringify(dataObj));
-			}
-			var nparams = [].concat(response,obj.param)
-			this._exports[obj.method].apply(this._exports[obj.method],nparams)
-		}
-		if( obj.op == "response" ) {
-			//console.log("Receiving response for:", obj.reqId)
-			ctx._requests[obj.reqId](obj.data)
-			delete ctx._requests[obj.reqId]
-		}
-	}
-	this.call = function(method) {
-		var aparam = Array.prototype.slice.call(arguments,1)
-		return new Promise(function(resolve,reject) {
-			if(ctx.connected == false ) {
-				reject(Error("Not connected"))
-			}
-
-			var uuidStr = uuid();
-			var callObj = {
-				"reqId":uuidStr,
-				"op":"call",
-				"method":method,
-				"param":aparam
-			}
-			ctx._requests[uuidStr] = resolve;
-			//console.log("Sending a call:", method)
-			ctx.ws.send(JSON.stringify(callObj));
-		})
-	}
-	this.export = function(obj){
-		this._exports = obj;
-	}
-			
-	return this
-}
-
-
-function uuid() {
-	var ret = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
-	    var r = Math.random()*16|0, v = c == 'x' ? r : (r&0x3|0x8);
-	    return v.toString(16);
-	});
-	return ret;
-}
+    /**
+     * Call with variadic params
+     */
+    this.call = function (method, ...params) {
+      // var aparam = Array.prototype.slice.call(arguments, 1)
+      var aparam = params
+      return new Promise(function (resolve, reject) {
+        if (ctx.connected === false) {
+          reject(Error('Not connected'))
+        }
 
+        var uuidStr = uuid()
+        var callObj = {
+          'op': 'call',
+          'id': uuidStr,
+          'method': method,
+          'params': aparam
+        }
+        ctx._requests[uuidStr] = resolve
+        // console.log("Sending a call:", method)
+        ctx.ws.send(JSON.stringify(callObj)) // if error delete request
+      })
+    }
+    /**
+     * Export function, binds export methods
+     */
+    this.export = function (obj) {
+      this._exports = obj
+    }
 
+    return this
+  }
+  function uuid () {
+    var ret = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
+      var r = Math.random() * 16 | 0
+      var v = c === 'x' ? r : (r & 0x3 | 0x8)
+      return v.toString(16)
+    })
+    return ret
+  }
+})(window)

+ 39 - 40
clientctx.go

@@ -5,10 +5,19 @@ 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{}
 
@@ -27,78 +36,68 @@ type ClientCtx struct {
 	requests  map[string]chan interface{}
 }
 
-//NewHandler creates a new handler
+//NewHandler creates a new WsRPC client handler
 func NewHandler(id string, ws *websocket.Conn) *ClientCtx {
-	var c = ClientCtx{}
-	c.WS = ws
-	c.listeners = map[string]ListenerFunc{}
-	c.requests = map[string]chan interface{}{}
+	var c = ClientCtx{
+		WS:        ws,
+		listeners: map[string]ListenerFunc{},
+		requests:  map[string]chan interface{}{},
+	}
 	return &c
 }
 
 // Process messages
-func (c *ClientCtx) Process(data DataObj) {
-	if data["op"].(string) == "call" {
-		params := data["param"].([]interface{})
-		var idn = data["method"].(string)
-		var reqId = data["reqId"].(string)
+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 = DataObj{
-				"op":    "response",
-				"reqId": reqId,
-				"data":  ret,
+			var responseObj = CallObj{
+				OP:       "response",
+				ID:       reqId,
+				Response: ret,
 			}
 			//log.Println("Sending response")
 			websocket.JSON.Send(c.WS, responseObj)
 		}()
-	}
-
-	if data["op"].(string) == "response" {
+	case "response":
 		c.locker.Lock()
-		mchan, ok := c.requests[data["reqId"].(string)]
-		delete(c.requests, data["reqId"].(string))
+		mchan, ok := c.requests[data.ID]
+		delete(c.requests, data.ID)
 		c.locker.Unlock()
-
 		if ok {
-			mchan <- data["data"]
+			mchan <- data.Response
 		}
 	}
 }
 
 // Call a client method and estabilishes a request id
-func (c *ClientCtx) Call(method string, params ...interface{}) chan interface{} {
+func (c *ClientCtx) Call(method string, params ...interface{}) interface{} {
 	u := uuid.New()
 	uuidStr := u.String()
 
-	var callObj = DataObj{
-		"op":     "call",
-		"reqId":  uuidStr,
-		"method": method,
-		"param":  params,
+	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
-}
 
-//Emit emit event listener
-/*func (c *ClientCtx) Emit(name string, data DataObj) (interface{}, error) {
-	fn, ok := c.listeners[name]
-	if !ok {
-		return nil, fmt.Errorf("Not found") // Dont execute
-	}
-	return fn(data), nil
-
-}*/
+	return <-res // Block until value
+}
 
 //On add a event listener on browser
 func (c *ClientCtx) Define(name string, listener ListenerFunc) {

+ 47 - 0
sample/basic/basic.go

@@ -0,0 +1,47 @@
+package main
+
+//go:generate folder2go -handler web webGenerated
+import (
+	"log"
+	"net/http"
+	"time"
+
+	"dev.hexasoftware.com/stdio/wsrpc"
+	"dev.hexasoftware.com/stdio/wsrpc/sample/basic/webGenerated"
+	"github.com/gohxs/webu"
+)
+
+func MyCliFunc(cli *wsrpc.ClientCtx) {
+
+	cli.Define("btn1.click", func(param ...interface{}) interface{} {
+		log.Println("Async button clicked")
+		return "The thing clicked in the button"
+	})
+
+	for { // do multiple calls
+		select {
+		case <-time.After(10 * time.Second):
+			ret := cli.Call("Hello", wsrpc.DataObj{
+				"couldbe": "interface",
+			})
+			log.Println("Response:", ret)
+		}
+	}
+
+}
+
+func main() {
+	var mux = http.NewServeMux()
+
+	var rpc = wsrpc.New(MyCliFunc)
+
+	mux.Handle("/wsrpc/", webu.LogHandler("wsrpc", rpc.ServeHTTP))
+	mux.HandleFunc("/", webu.LogHandler("/", webGenerated.AssetHandleFunc))
+
+	log.Println("Listening :8080")
+	err := http.ListenAndServe(":8081", mux)
+	if err != nil {
+		panic(err)
+	}
+
+}

+ 0 - 36
sample/basic/test.go

@@ -1,36 +0,0 @@
-package main
-
-//go:generate folder2go web webGenerated
-import (
-	"log"
-	"net/http"
-
-	"dev.hexasoftware.com/stdio/wsrpc"
-	"dev.hexasoftware.com/stdio/wsrpc/sample/basic/webGenerated"
-)
-
-func MyCliFunc(cli *wsrpc.ClientCtx) {
-
-	cli.Define("btn1.click", func(param ...interface{}) interface{} {
-		log.Println("Async button clicked")
-		return "ok"
-
-	})
-	ret := cli.Call("Hello", wsrpc.DataObj{
-		"couldbe": "interface",
-	})
-	t := <-ret
-
-	log.Println("Response:", t)
-}
-
-func main() {
-	var mux = http.NewServeMux()
-
-	wsrpc.RegisterTo(mux, MyCliFunc)
-	mux.HandleFunc("/", webGenerated.AssetHandleFunc)
-
-	log.Println("Listening :8080")
-	http.ListenAndServe(":8080", mux)
-
-}

+ 1 - 1
sample/basic/web/index.html

@@ -1,6 +1,6 @@
 <html>
 	<head>
-		<script src='wsrpc/client.js'></script>	
+		<script src='wsrpc/cli.js'></script>	
 		<script src='js/main.js'></script>	
 	</head>
 	<body>

+ 18 - 23
sample/basic/web/js/main.js

@@ -6,32 +6,27 @@
 
 // http://stackoverflow.com/questions/105034/create-guid-uuid-in-javascript
 
-window.onload = function() {
+window.onload = function () {
+  var wsrpc = new WsRpc()
+  wsrpc.connect('ws://' + window.location.host + '/wsrpc/ws')
 
-	wsrpc = new WsRpc();
-	wsrpc.connect("ws://"+location.host +"/wsrpc");
+  console.log('Trying to connect')
 
-	console.log("Trying to connect")
+  var obj = {
+    Hello: function (response, param) {
+      console.log('Hello world')
+      response({ok: 'OK'})
+    }
+  }
 
+  wsrpc.export(obj)
 
-	obj = {
-		Hello: function(response,param) {
-			console.log("Hello world")
-			response({ok:"OK"})
-		}
-	}
-	wsrpc.export(obj)
+  var btn = document.querySelector('#btn1')
 
-
-	btn = document.querySelector("#btn1")
-
-	btn.addEventListener("click",function(){
-		console.log("Button clicked")
-		wsrpc.call("btn1.click",{"hello":"ok"}, (res) =>{
-			console.log("Answered:",res	);
-		})
-	})
+  btn.addEventListener('click', function () {
+    console.log('Button clicked')
+    wsrpc.call('btn1.click', {'hello': 'ok'}).then((res) => {
+      console.log('answered:', res)
+    })
+  })
 }
-	
-	
-

Файловите разлики са ограничени, защото са твърде много
+ 19 - 9
sample/basic/webGenerated/webGenerated.go


Файловите разлики са ограничени, защото са твърде много
+ 37 - 0
sample/basic/webGenerated/webGenerated.go.bak


+ 0 - 2
sample/canvas/canvas/canvas.go

@@ -1,8 +1,6 @@
 package canvas
 
 import (
-	//"hexasoftware/lib/vnode/vfunc"
-
 	"hexasoftware/lib/vnode/vfunc"
 
 	"dev.hexasoftware.com/stdio/wsrpc"

+ 44 - 15
wsrpc.go

@@ -5,34 +5,63 @@ package wsrpc
 import (
 	"log"
 	"net/http"
+	"strings"
 
 	"dev.hexasoftware.com/stdio/wsrpc/wsrpcAssets" // embed assets
 
 	"golang.org/x/net/websocket"
 )
 
-// Return a specific handler
-type ServerContext interface {
-	Handle(string, http.Handler)
-	HandleFunc(string, func(http.ResponseWriter, *http.Request))
+// Handler wsrpc.Handler
+type Handler struct {
+	wsHandler http.Handler
+
+	prefix string
 }
-type HandleFunc func(*ClientCtx)
 
-// Write wsrpc.js
-func wsrpcjsFunc(w http.ResponseWriter, r *http.Request) {
-	w.Header().Set("Content-type", "application/javascript")
-	w.WriteHeader(200)
-	w.Write(wsrpcAssets.Data["/wsrpc.js"])
+func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+	// Get relative path
+	if h.prefix == "" {
+		server := r.Context().Value(http.ServerContextKey).(*http.Server)
+		mux, ok := server.Handler.(*http.ServeMux)
+		if ok {
+			_, h.prefix = mux.Handler(r)
+		}
+	}
+	urlPath := strings.TrimPrefix(r.URL.String(), h.prefix)
+
+	switch urlPath {
+	case "ws", "wsrpc":
+		log.Println("Provide ws connection")
+		h.wsHandler.ServeHTTP(w, r)
+	case "cli.js": // Serve client JS file
+		log.Println("Sending cli")
+		w.Header().Set("Content-type", "application/javascript")
+		w.WriteHeader(200)
+		w.Write(wsrpcAssets.Data["wsrpc.js"])
+	default:
+		w.WriteHeader(http.StatusNotFound)
+		w.Write([]byte(http.StatusText(http.StatusNotFound)))
+	}
 }
 
+// New create a new WSRpc handler
+func New(WSRPC Func) *Handler {
+	return &Handler{
+		wsHandler: websocket.Handler(createCliHandler(WSRPC)),
+	}
+}
+
+// Func for wsrpc
+type Func func(*ClientCtx)
+
 // Create a client websocket handler on connection
-func createCliHandler(handler HandleFunc) websocket.Handler {
+func createCliHandler(handler Func) websocket.Handler {
 	return func(ws *websocket.Conn) {
 		ch := NewHandler("main", ws)
 		go handler(ch)
-
 		for {
-			var data = map[string]interface{}{}
+			var data = CallObj{}
 			err := websocket.JSON.Receive(ws, &data)
 			if err != nil {
 				log.Println("Error: ", err)
@@ -44,7 +73,7 @@ func createCliHandler(handler HandleFunc) websocket.Handler {
 }
 
 // RegisterTo register both js and websocket in the servermux
-func RegisterTo(server ServerContext, handler HandleFunc) {
+/*func RegisterTo(server ServerContext, handler HandleFunc) {
 	server.Handle("/wsrpc", websocket.Handler(createCliHandler(handler)))
 	server.HandleFunc("/wsrpc/client.js", wsrpcjsFunc)
 }
@@ -55,4 +84,4 @@ func Handler(handler HandleFunc) http.Handler {
 	RegisterTo(mux, handler)
 	// When we receive a connection
 	return mux
-}
+}*/

Файловите разлики са ограничени, защото са твърде много
+ 3 - 22
wsrpcAssets/wsrpcAssets.go


Файловите разлики са ограничени, защото са твърде много
+ 7 - 0
wsrpcAssets/wsrpcAssets.go.bak