From 1c2472c53fc2742b1afbafe9ef364cb333fa819d Mon Sep 17 00:00:00 2001 From: "Gerasimos (Makis) Maropoulos" Date: Mon, 15 Jul 2019 18:45:22 +0300 Subject: [PATCH] update the online visitors and vuejs +iris mvc todo app (this gave me some ideas to make the api a bit easier) Former-commit-id: 8c84486a22505b7137669bde52383d2564a6b382 --- _examples/tutorial/online-visitors/main.go | 108 ++++++++++-------- .../static/assets/js/visitors.js | 35 +++--- .../online-visitors/templates/index.html | 8 +- .../online-visitors/templates/other.html | 8 +- .../src/web/controllers/todo_controller.go | 19 +-- .../tutorial/vuejs-todo-mvc/src/web/main.go | 35 +++--- .../vuejs-todo-mvc/src/web/public/index.html | 3 +- .../vuejs-todo-mvc/src/web/public/js/app.js | 27 +++-- mvc/mvc.go | 47 ++++---- 9 files changed, 159 insertions(+), 131 deletions(-) diff --git a/_examples/tutorial/online-visitors/main.go b/_examples/tutorial/online-visitors/main.go index 968ad284..c47ce0a8 100644 --- a/_examples/tutorial/online-visitors/main.go +++ b/_examples/tutorial/online-visitors/main.go @@ -1,6 +1,7 @@ package main import ( + "fmt" "sync/atomic" "github.com/kataras/iris" @@ -8,6 +9,13 @@ import ( "github.com/kataras/iris/websocket" ) +var events = websocket.Namespaces{ + "default": websocket.Events{ + websocket.OnRoomJoined: onRoomJoined, + websocket.OnRoomLeft: onRoomLeft, + }, +} + func main() { // init the web application instance // app := iris.New() @@ -16,11 +24,9 @@ func main() { // load templates app.RegisterView(iris.HTML("./templates", ".html").Reload(true)) // setup the websocket server - ws := websocket.New(websocket.Config{}) - ws.OnConnection(HandleWebsocketConnection) + ws := websocket.New(websocket.DefaultGorillaUpgrader, events) - app.Get("/my_endpoint", ws.Handler()) - app.Any("/iris-ws.js", websocket.ClientHandler()) + app.Get("/my_endpoint", websocket.Handler(ws)) // register static assets request path and system directory app.HandleDir("/js", "./static/assets/js") @@ -114,48 +120,54 @@ func (v *pageViews) Reset() { var v pageViews -// HandleWebsocketConnection handles the online viewers per example(gist source) -func HandleWebsocketConnection(c websocket.Connection) { - - c.On("watch", func(pageSource string) { - v.Add(pageSource) - // join the socket to a room linked with the page source - c.Join(pageSource) - - viewsCount := v.Get(pageSource).getCount() - if viewsCount == 0 { - viewsCount++ // count should be always > 0 here - } - c.To(pageSource).Emit("watch", viewsCount) - }) - - c.OnLeave(func(roomName string) { - if roomName != c.ID() { // if the roomName it's not the connection iself - // the roomName here is the source, this is the only room(except the connection's ID room) which we join the users to. - pageV := v.Get(roomName) - if pageV == nil { - return // for any case that this room is not a pageView source - } - // decrement -1 the specific counter for this page source. - pageV.decrement() - // 1. open 30 tabs. - // 2. close the browser. - // 3. re-open the browser - // 4. should be v.getCount() = 1 - // in order to achieve the previous flow we should decrement exactly when the user disconnects - // but emit the result a little after, on a goroutine - // getting all connections within this room and emit the online views one by one. - // note: - // we can also add a time.Sleep(2-3 seconds) inside the goroutine at the future if we don't need 'real-time' updates. - go func(currentConnID string) { - for _, conn := range c.Server().GetConnectionsByRoom(roomName) { - if conn.ID() != currentConnID { - conn.Emit("watch", pageV.getCount()) - } - - } - }(c.ID()) - } - - }) +func viewsCountBytes(viewsCount uint64) []byte { + // * there are other methods to convert uint64 to []byte + return []byte(fmt.Sprintf("%d", viewsCount)) +} + +func onRoomJoined(ns *websocket.NSConn, msg websocket.Message) error { + // the roomName here is the source. + pageSource := string(msg.Room) + + v.Add(pageSource) + + viewsCount := v.Get(pageSource).getCount() + if viewsCount == 0 { + viewsCount++ // count should be always > 0 here + } + + // fire the "onNewVisit" client event + // on each connection joined to this room (source page) + // and notify of the new visit, + // including this connection (see nil on first input arg). + ns.Conn.Server().Broadcast(nil, websocket.Message{ + Namespace: msg.Namespace, + Room: pageSource, + Event: "onNewVisit", // fire the "onNewVisit" client event. + Body: viewsCountBytes(viewsCount), + }) + + return nil +} + +func onRoomLeft(ns *websocket.NSConn, msg websocket.Message) error { + // the roomName here is the source. + pageV := v.Get(msg.Room) + if pageV == nil { + return nil // for any case that this room is not a pageView source + } + // decrement -1 the specific counter for this page source. + pageV.decrement() + + // fire the "onNewVisit" client event + // on each connection joined to this room (source page) + // and notify of the new, decremented by one, visits count. + ns.Conn.Server().Broadcast(nil, websocket.Message{ + Namespace: msg.Namespace, + Room: msg.Room, + Event: "onNewVisit", + Body: viewsCountBytes(pageV.getCount()), + }) + + return nil } diff --git a/_examples/tutorial/online-visitors/static/assets/js/visitors.js b/_examples/tutorial/online-visitors/static/assets/js/visitors.js index dd7f9e68..d083e210 100644 --- a/_examples/tutorial/online-visitors/static/assets/js/visitors.js +++ b/_examples/tutorial/online-visitors/static/assets/js/visitors.js @@ -1,21 +1,24 @@ -(function() { - var socket = new Ws("ws://localhost:8080/my_endpoint"); - - socket.OnConnect(function () { - socket.Emit("watch", PAGE_SOURCE); - }); - - - socket.On("watch", function (onlineViews) { - var text = "1 online view"; - if (onlineViews > 1) { +(function () { + var events = { + default: { + _OnNamespaceConnected: function (ns, msg) { + ns.joinRoom(PAGE_SOURCE); + }, + _OnNamespaceDisconnect: function (ns, msg) { + document.getElementById("online_views").innerHTML = "you've been disconnected"; + }, + onNewVisit: function (ns, msg) { + var text = "1 online view"; + var onlineViews = Number(msg.Body); + if (onlineViews > 1) { text = onlineViews + " online views"; + } + document.getElementById("online_views").innerHTML = text; } - document.getElementById("online_views").innerHTML = text; - }); + } + }; - socket.OnDisconnect(function () { - document.getElementById("online_views").innerHTML = "you've been disconnected"; + neffos.dial("ws://localhost:8080/my_endpoint", events).then(function (client) { + client.connect("default"); }); - })(); diff --git a/_examples/tutorial/online-visitors/templates/index.html b/_examples/tutorial/online-visitors/templates/index.html index d84f5f35..d544b4a5 100644 --- a/_examples/tutorial/online-visitors/templates/index.html +++ b/_examples/tutorial/online-visitors/templates/index.html @@ -30,14 +30,14 @@ - + - + \ No newline at end of file diff --git a/_examples/tutorial/online-visitors/templates/other.html b/_examples/tutorial/online-visitors/templates/other.html index c6108f2d..ea8e8696 100644 --- a/_examples/tutorial/online-visitors/templates/other.html +++ b/_examples/tutorial/online-visitors/templates/other.html @@ -16,14 +16,14 @@ - + - + \ No newline at end of file diff --git a/_examples/tutorial/vuejs-todo-mvc/src/web/controllers/todo_controller.go b/_examples/tutorial/vuejs-todo-mvc/src/web/controllers/todo_controller.go index c3fd0724..bf83019b 100644 --- a/_examples/tutorial/vuejs-todo-mvc/src/web/controllers/todo_controller.go +++ b/_examples/tutorial/vuejs-todo-mvc/src/web/controllers/todo_controller.go @@ -14,6 +14,8 @@ type TodoController struct { Service todo.Service Session *sessions.Session + + NS *websocket.NSConn } // BeforeActivation called once before the server ran, and before @@ -51,15 +53,14 @@ func (c *TodoController) Post(newItems []todo.Item) PostItemResponse { return PostItemResponse{Success: true} } -func (c *TodoController) GetSync(conn websocket.Connection) { - // join to the session in order to send "saved" - // events only to a single user, that means - // that if user has opened more than one browser window/tab - // of the same session then the changes will be reflected to one another. - conn.Join(c.Session.ID()) - conn.On("save", func() { // "save" event from client. - conn.To(c.Session.ID()).Emit("saved", nil) // fire a "saved" event to the rest of the clients w. +func (c *TodoController) Save(msg websocket.Message) error { + id := c.Session.ID() + c.NS.Conn.Server().Broadcast(nil, websocket.Message{ + Namespace: msg.Namespace, + Event: "saved", + To: id, + Body: websocket.Marshal(c.Service.Get(id)), }) - conn.Wait() + return nil } diff --git a/_examples/tutorial/vuejs-todo-mvc/src/web/main.go b/_examples/tutorial/vuejs-todo-mvc/src/web/main.go index d1c3815b..e4ea0b3d 100644 --- a/_examples/tutorial/vuejs-todo-mvc/src/web/main.go +++ b/_examples/tutorial/vuejs-todo-mvc/src/web/main.go @@ -1,14 +1,15 @@ package main import ( + "strings" + "github.com/kataras/iris/_examples/tutorial/vuejs-todo-mvc/src/todo" "github.com/kataras/iris/_examples/tutorial/vuejs-todo-mvc/src/web/controllers" "github.com/kataras/iris" + "github.com/kataras/iris/mvc" "github.com/kataras/iris/sessions" "github.com/kataras/iris/websocket" - - "github.com/kataras/iris/mvc" ) func main() { @@ -26,16 +27,8 @@ func main() { Cookie: "iris_session", }) - // configure the websocket server. - ws := websocket.New(websocket.Config{}) - - // create a sub router and register the client-side library for the iris websockets, - // you could skip it but iris websockets supports socket.io-like API. + // create a sub router and register the http controllers. todosRouter := app.Party("/todos") - // http://localhost:8080/todos/iris-ws.js - // serve the javascript client library to communicate with - // the iris high level websocket event system. - todosRouter.Any("/iris-ws.js", websocket.ClientHandler()) // create our mvc application targeted to /todos relative sub path. todosApp := mvc.New(todosRouter) @@ -44,11 +37,27 @@ func main() { todosApp.Register( todo.NewMemoryService(), sess.Start, - ws.Upgrade, ) + todosController := new(controllers.TodoController) // controllers registration here... - todosApp.Handle(new(controllers.TodoController)) + todosApp.Handle(todosController) + + // Create a sub mvc app for websocket controller. + // Inherit the parent's dependencies. + todosWebsocketApp := todosApp.Party("/sync") + todosWebsocketApp.HandleWebsocket(todosController). + SetNamespace("todos"). + SetEventMatcher(func(methodName string) (string, bool) { + return strings.ToLower(methodName), true + }) + + websocketServer := websocket.New(websocket.DefaultGorillaUpgrader, todosWebsocketApp) + idGenerator := func(ctx iris.Context) string { + id := sess.Start(ctx).ID() + return id + } + todosWebsocketApp.Router.Get("/", websocket.Handler(websocketServer, idGenerator)) // start the web server at http://localhost:8080 app.Run(iris.Addr(":8080")) diff --git a/_examples/tutorial/vuejs-todo-mvc/src/web/public/index.html b/_examples/tutorial/vuejs-todo-mvc/src/web/public/index.html index 38cca166..4f44b0d6 100644 --- a/_examples/tutorial/vuejs-todo-mvc/src/web/public/index.html +++ b/_examples/tutorial/vuejs-todo-mvc/src/web/public/index.html @@ -11,8 +11,7 @@ - - +