From 33dfb42d733c61811578943280568eda458a8ac3 Mon Sep 17 00:00:00 2001 From: "Gerasimos (Makis) Maropoulos" Date: Thu, 11 Jul 2019 12:59:11 +0300 Subject: [PATCH] add the new neffos StackExchange feature to the type aliases and shortcuts of the websocket subpackage and auto-enable debug mode on websocket MVC application when iris logger's level is set to debug Former-commit-id: 4d8cb79d01a4172fc1ed7a9b626da0228d902b3c --- _examples/mvc/websocket/main.go | 26 +++++++---------- _examples/websocket/README.md | 14 ++++++++++ _examples/websocket/basic/go-client/client.go | 14 ++++------ _examples/websocket/basic/server.go | 18 ++++++------ _examples/websocket/native-messages/main.go | 10 +++---- go.mod | 2 +- mvc/mvc.go | 6 +++- sessions/sessiondb/redis/service.go | 28 +++++++++---------- websocket/websocket.go | 9 ++++++ websocket/websocket_go19.go | 13 +++++++++ 10 files changed, 83 insertions(+), 57 deletions(-) create mode 100644 _examples/websocket/README.md diff --git a/_examples/mvc/websocket/main.go b/_examples/mvc/websocket/main.go index 82f32caf..762644fa 100644 --- a/_examples/mvc/websocket/main.go +++ b/_examples/mvc/websocket/main.go @@ -7,18 +7,12 @@ import ( "github.com/kataras/iris" "github.com/kataras/iris/mvc" "github.com/kataras/iris/websocket" - - "github.com/kataras/neffos" ) func main() { app := iris.New() app.Logger().SetLevel("debug") - // optionally enable debug messages to the neffos real-time framework - // and print them through the iris' logger. - neffos.EnableDebug(app.Logger()) - // load templates. app.RegisterView(iris.HTML("./views", ".html")) @@ -33,7 +27,7 @@ func main() { ) m.HandleWebsocket(&websocketController{Namespace: "default", Age: 42, Otherstring: "other string"}) - websocketServer := neffos.New(websocket.DefaultGorillaUpgrader, m) + websocketServer := websocket.New(websocket.DefaultGorillaUpgrader, m) websocketAPI.Get("/", websocket.Handler(websocketServer)) // http://localhost:8080 @@ -51,10 +45,10 @@ func decrement() uint64 { } type websocketController struct { - *neffos.NSConn `stateless:"true"` - Namespace string - Age int - Otherstring string + *websocket.NSConn `stateless:"true"` + Namespace string + Age int + Otherstring string Logger LoggerService } @@ -64,13 +58,13 @@ type websocketController struct { // return "default" // } -func (c *websocketController) OnNamespaceDisconnect(msg neffos.Message) error { +func (c *websocketController) OnNamespaceDisconnect(msg websocket.Message) error { c.Logger.Log("Disconnected") // visits-- newCount := decrement() // This will call the "OnVisit" event on all clients, except the current one, // (it can't because it's left but for any case use this type of design) - c.Conn.Server().Broadcast(nil, neffos.Message{ + c.Conn.Server().Broadcast(nil, websocket.Message{ Namespace: msg.Namespace, Event: "OnVisit", Body: []byte(fmt.Sprintf("%d", newCount)), @@ -79,7 +73,7 @@ func (c *websocketController) OnNamespaceDisconnect(msg neffos.Message) error { return nil } -func (c *websocketController) OnNamespaceConnected(msg neffos.Message) error { +func (c *websocketController) OnNamespaceConnected(msg websocket.Message) error { // println("Broadcast prefix is: " + c.BroadcastPrefix) c.Logger.Log("Connected") @@ -91,7 +85,7 @@ func (c *websocketController) OnNamespaceConnected(msg neffos.Message) error { // // There are many ways that u can do it and faster, for example u can just send a new visitor // and client can increment itself, but here we are just "showcasing" the websocket controller. - c.Conn.Server().Broadcast(nil, neffos.Message{ + c.Conn.Server().Broadcast(nil, websocket.Message{ Namespace: msg.Namespace, Event: "OnVisit", Body: []byte(fmt.Sprintf("%d", newCount)), @@ -100,7 +94,7 @@ func (c *websocketController) OnNamespaceConnected(msg neffos.Message) error { return nil } -func (c *websocketController) OnChat(msg neffos.Message) error { +func (c *websocketController) OnChat(msg websocket.Message) error { ctx := websocket.GetContext(c.Conn) ctx.Application().Logger().Infof("[IP: %s] [ID: %s] broadcast to other clients the message [%s]", diff --git a/_examples/websocket/README.md b/_examples/websocket/README.md new file mode 100644 index 00000000..8c8d9967 --- /dev/null +++ b/_examples/websocket/README.md @@ -0,0 +1,14 @@ +# Websocket + +[WebSocket](https://wikipedia.org/wiki/WebSocket) is a protocol that enables two-way persistent communication channels over TCP connections. It is used for applications such as chat, stock tickers, games, anywhere you want real-time functionality in a web application. + +Iris websocket library is now merged with the [neffos real-time framework](https://github.com/kataras/neffos) and Iris-specific helpers and type aliases live on the [iris/websocket](https://github.com/kataras/iris/tree/master/websocket) subpackage. Learn neffos from its [wiki](https://github.com/kataras/neffos#learning-neffos). + +Helpers and type aliases improves your code speed when writing a websocket module. +For example, instead of importing both `kataras/iris/websocket` - in order to use its `websocket.Handler` - and `github.com/kataras/neffos` - to create a new websocket server `neffos.New` - you can use the `websocket.New` instead, another example is the `neffos.Conn` which can be declared as `websocket.Conn`. + +All neffos and its subpackage's types and package-level functions exist as type aliases on the `kataras/iris/websocket` package too, there are too many of those and there is no need to write each one of those here, some common types: + +- `github.com/kataras/neffos/#Conn` -> `github.com/kataras/iris/websocket/#Conn` +- `github.com/kataras/neffos/gorilla/#DefaultUpgrader` -> `github.com/kataras/iris/websocket/#DefaultGorillaUpgrader` +- `github.com/kataras/neffos/stackexchange/redis/#NewStackExchange` -> `github.com/kataras/iris/websocket/#NewRedisStackExchange` diff --git a/_examples/websocket/basic/go-client/client.go b/_examples/websocket/basic/go-client/client.go index effb51e7..edfff936 100644 --- a/_examples/websocket/basic/go-client/client.go +++ b/_examples/websocket/basic/go-client/client.go @@ -10,8 +10,6 @@ import ( "time" "github.com/kataras/iris/websocket" - - "github.com/kataras/neffos" ) const ( @@ -23,17 +21,17 @@ const ( // this can be shared with the server.go's. // `NSConn.Conn` has the `IsClient() bool` method which can be used to // check if that's is a client or a server-side callback. -var clientEvents = neffos.Namespaces{ - namespace: neffos.Events{ - neffos.OnNamespaceConnected: func(c *neffos.NSConn, msg neffos.Message) error { +var clientEvents = websocket.Namespaces{ + namespace: websocket.Events{ + websocket.OnNamespaceConnected: func(c *websocket.NSConn, msg websocket.Message) error { log.Printf("connected to namespace: %s", msg.Namespace) return nil }, - neffos.OnNamespaceDisconnect: func(c *neffos.NSConn, msg neffos.Message) error { + websocket.OnNamespaceDisconnect: func(c *websocket.NSConn, msg websocket.Message) error { log.Printf("disconnected from namespace: %s", msg.Namespace) return nil }, - "chat": func(c *neffos.NSConn, msg neffos.Message) error { + "chat": func(c *websocket.NSConn, msg websocket.Message) error { log.Printf("%s", string(msg.Body)) return nil }, @@ -44,7 +42,7 @@ func main() { ctx, cancel := context.WithDeadline(context.Background(), time.Now().Add(dialAndConnectTimeout)) defer cancel() - client, err := neffos.Dial(ctx, websocket.DefaultGorillaDialer, endpoint, clientEvents) + client, err := websocket.Dial(ctx, websocket.DefaultGorillaDialer, endpoint, clientEvents) if err != nil { panic(err) } diff --git a/_examples/websocket/basic/server.go b/_examples/websocket/basic/server.go index 38d09353..230ecf20 100644 --- a/_examples/websocket/basic/server.go +++ b/_examples/websocket/basic/server.go @@ -6,8 +6,6 @@ import ( "github.com/kataras/iris" "github.com/kataras/iris/websocket" - "github.com/kataras/neffos" - // Used when "enableJWT" constant is true: "github.com/dgrijalva/jwt-go" jwtmiddleware "github.com/iris-contrib/middleware/jwt" @@ -17,10 +15,10 @@ import ( const enableJWT = true const namespace = "default" -// if namespace is empty then simply neffos.Events{...} can be used instead. -var serverEvents = neffos.Namespaces{ - namespace: neffos.Events{ - neffos.OnNamespaceConnected: func(nsConn *neffos.NSConn, msg neffos.Message) error { +// if namespace is empty then simply websocket.Events{...} can be used instead. +var serverEvents = websocket.Namespaces{ + namespace: websocket.Events{ + websocket.OnNamespaceConnected: func(nsConn *websocket.NSConn, msg websocket.Message) error { // with `websocket.GetContext` you can retrieve the Iris' `Context`. ctx := websocket.GetContext(nsConn.Conn) @@ -29,11 +27,11 @@ var serverEvents = neffos.Namespaces{ ctx.RemoteAddr()) return nil }, - neffos.OnNamespaceDisconnect: func(nsConn *neffos.NSConn, msg neffos.Message) error { + websocket.OnNamespaceDisconnect: func(nsConn *websocket.NSConn, msg websocket.Message) error { log.Printf("[%s] disconnected from namespace [%s]", nsConn, msg.Namespace) return nil }, - "chat": func(nsConn *neffos.NSConn, msg neffos.Message) error { + "chat": func(nsConn *websocket.NSConn, msg websocket.Message) error { // room.String() returns -> NSConn.String() returns -> Conn.String() returns -> Conn.ID() log.Printf("[%s] sent: %s", nsConn, string(msg.Body)) @@ -48,7 +46,7 @@ var serverEvents = neffos.Namespaces{ func main() { app := iris.New() - websocketServer := neffos.New( + websocketServer := websocket.New( websocket.DefaultGorillaUpgrader, /* DefaultGobwasUpgrader can be used too. */ serverEvents) @@ -76,7 +74,7 @@ func main() { // // Check for token through the jwt middleware // on websocket connection or on any event: - /* websocketServer.OnConnect = func(c *neffos.Conn) error { + /* websocketServer.OnConnect = func(c *websocket.Conn) error { ctx := websocket.GetContext(c) if err := j.CheckJWT(ctx); err != nil { // will send the above error on the client diff --git a/_examples/websocket/native-messages/main.go b/_examples/websocket/native-messages/main.go index 648047a0..46a55dca 100644 --- a/_examples/websocket/native-messages/main.go +++ b/_examples/websocket/native-messages/main.go @@ -5,8 +5,6 @@ import ( "github.com/kataras/iris" "github.com/kataras/iris/websocket" - - "github.com/kataras/neffos" ) type clientPage struct { @@ -26,8 +24,8 @@ func main() { // and contains only one registered event which is the `OnNativeMessage`. // When `Events{...}` is used instead of `Namespaces{ "namespaceName": Events{...}}` // then the namespace is empty "". - ws := neffos.New(websocket.DefaultGorillaUpgrader, neffos.Events{ - neffos.OnNativeMessage: func(nsConn *neffos.NSConn, msg neffos.Message) error { + ws := websocket.New(websocket.DefaultGorillaUpgrader, websocket.Events{ + websocket.OnNativeMessage: func(nsConn *websocket.NSConn, msg websocket.Message) error { log.Printf("Server got: %s from [%s]", msg.Body, nsConn.Conn.ID()) nsConn.Conn.Server().Broadcast(nsConn, msg) @@ -35,12 +33,12 @@ func main() { }, }) - ws.OnConnect = func(c *neffos.Conn) error { + ws.OnConnect = func(c *websocket.Conn) error { log.Printf("[%s] Connected to server!", c.ID()) return nil } - ws.OnDisconnect = func(c *neffos.Conn) { + ws.OnDisconnect = func(c *websocket.Conn) { log.Printf("[%s] Disconnected from server", c.ID()) } diff --git a/go.mod b/go.mod index 90ac4507..4fa268db 100644 --- a/go.mod +++ b/go.mod @@ -15,7 +15,7 @@ require ( github.com/iris-contrib/go.uuid v2.0.0+incompatible github.com/json-iterator/go v1.1.6 // vendor removed. github.com/kataras/golog v0.0.0-20180321173939-03be10146386 - github.com/kataras/neffos v0.0.5 + github.com/kataras/neffos v0.0.6 github.com/kataras/pio v0.0.0-20190103105442-ea782b38602d // indirect github.com/microcosm-cc/bluemonday v1.0.2 github.com/ryanuber/columnize v2.1.0+incompatible diff --git a/mvc/mvc.go b/mvc/mvc.go index 4b18e303..85b5a041 100644 --- a/mvc/mvc.go +++ b/mvc/mvc.go @@ -64,6 +64,7 @@ func New(party router.Party) *Application { if HeroDependencies { values = hero.Dependencies().Clone() } + return newApp(party, values) } @@ -195,6 +196,10 @@ var _ websocket.ConnHandler = (*Application)(nil) // It returns a collection of namespace and events that // were registered through `HandleWebsocket` controllers. func (app *Application) GetNamespaces() websocket.Namespaces { + if golog.Default.Level == golog.DebugLevel { + websocket.EnableDebug(golog.Default) + } + makeInjector := func(injector *di.StructInjector) websocket.StructInjector { return func(_ reflect.Type, nsConn *websocket.NSConn) reflect.Value { v := injector.Acquire() @@ -212,7 +217,6 @@ func (app *Application) GetNamespaces() websocket.Namespaces { wsInjector := makeInjector(c.injector) s := websocket.NewStruct(c.Value).SetInjector(wsInjector) websocketControllers = append(websocketControllers, s) - } } diff --git a/sessions/sessiondb/redis/service.go b/sessions/sessiondb/redis/service.go index 75bf377e..dca58963 100644 --- a/sessions/sessiondb/redis/service.go +++ b/sessions/sessiondb/redis/service.go @@ -335,22 +335,20 @@ func (r *Service) GetKeys(prefix string) ([]string, error) { return r.getKeys(prefix) } -// GetBytes returns value, err by its key -// you can use utils.Deserialize((.GetBytes("yourkey"),&theobject{}) -//returns nil and a filled error if something wrong happens -func (r *Service) GetBytes(key string) ([]byte, error) { - var redisVal []byte - mn := radix.MaybeNil{Rcv: &redisVal} - err := r.pool.Do(radix.Cmd(&mn, "GET", r.Config.Prefix+key)) - if err != nil { - return nil, err - } - if mn.Nil { - return nil, ErrKeyNotFound.Format(key) - } +// // GetBytes returns bytes representation of a value based on given "key". +// func (r *Service) GetBytes(key string) ([]byte, error) { +// var redisVal []byte +// mn := radix.MaybeNil{Rcv: &redisVal} +// err := r.pool.Do(radix.Cmd(&mn, "GET", r.Config.Prefix+key)) +// if err != nil { +// return nil, err +// } +// if mn.Nil { +// return nil, ErrKeyNotFound.Format(key) +// } - return redisVal, nil -} +// return redisVal, nil +// } // Delete removes redis entry by specific key func (r *Service) Delete(key string) error { diff --git a/websocket/websocket.go b/websocket/websocket.go index c771af7d..e415b1b1 100644 --- a/websocket/websocket.go +++ b/websocket/websocket.go @@ -4,11 +4,17 @@ import ( "github.com/kataras/iris/context" "github.com/kataras/neffos" + "github.com/kataras/neffos/gobwas" "github.com/kataras/neffos/gorilla" + "github.com/kataras/neffos/stackexchange/redis" ) var ( + // EnableDebug enables debug mode for websocket module, + // for MVC this is done automatically + // when the app's logger level is set to "debug". + EnableDebug = neffos.EnableDebug // GorillaUpgrader is an upgrader type for the gorilla/websocket subprotocol implementation. // Should be used on `New` to construct the websocket server. GorillaUpgrader = gorilla.Upgrader @@ -32,6 +38,9 @@ var ( DefaultIDGenerator = func(ctx context.Context) string { return neffos.DefaultIDGenerator(ctx.ResponseWriter(), ctx.Request()) } + // NewRedisStackExchange returns a new redis StackExchange. + // The "channel" input argument is the channel prefix for publish and subscribe. + NewRedisStackExchange = redis.NewStackExchange // GorillaDialer is a `Dialer` type for the gorilla/websocket subprotocol implementation. // Should be used on `Dial` to create a new client/client-side connection. diff --git a/websocket/websocket_go19.go b/websocket/websocket_go19.go index b787fbb0..e5cccb3b 100644 --- a/websocket/websocket_go19.go +++ b/websocket/websocket_go19.go @@ -6,6 +6,7 @@ import ( "github.com/kataras/neffos" "github.com/kataras/neffos/gobwas" "github.com/kataras/neffos/gorilla" + "github.com/kataras/neffos/stackexchange/redis" ) type ( @@ -76,4 +77,16 @@ type ( // when incoming native message then the `Message.Event` is the `OnNativeMessage`, // native messages are allowed only when an empty namespace("") and its `OnNativeMessage` callback are present. Message = neffos.Message + // StackExchange is an optional interface + // that can be used to change the way neffos + // sends messages to its clients, i.e + // communication between multiple neffos servers. + // + // See `NewRedisStackExchange` to create a new redis StackExchange. + StackExchange = neffos.StackExchange + // RedisStackExchange is a `neffos.StackExchange` for redis. + RedisStackExchange = redis.StackExchange + // RedisConfig is used on the `NewRedisStackExchange` package-level function. + // Can be used to customize the redis client dialer. + RedisConfig = redis.Config )