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
This commit is contained in:
Gerasimos (Makis) Maropoulos 2019-07-11 12:59:11 +03:00
parent 82d645e3cb
commit 33dfb42d73
10 changed files with 83 additions and 57 deletions

View File

@ -7,18 +7,12 @@ import (
"github.com/kataras/iris" "github.com/kataras/iris"
"github.com/kataras/iris/mvc" "github.com/kataras/iris/mvc"
"github.com/kataras/iris/websocket" "github.com/kataras/iris/websocket"
"github.com/kataras/neffos"
) )
func main() { func main() {
app := iris.New() app := iris.New()
app.Logger().SetLevel("debug") 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. // load templates.
app.RegisterView(iris.HTML("./views", ".html")) app.RegisterView(iris.HTML("./views", ".html"))
@ -33,7 +27,7 @@ func main() {
) )
m.HandleWebsocket(&websocketController{Namespace: "default", Age: 42, Otherstring: "other string"}) 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)) websocketAPI.Get("/", websocket.Handler(websocketServer))
// http://localhost:8080 // http://localhost:8080
@ -51,10 +45,10 @@ func decrement() uint64 {
} }
type websocketController struct { type websocketController struct {
*neffos.NSConn `stateless:"true"` *websocket.NSConn `stateless:"true"`
Namespace string Namespace string
Age int Age int
Otherstring string Otherstring string
Logger LoggerService Logger LoggerService
} }
@ -64,13 +58,13 @@ type websocketController struct {
// return "default" // return "default"
// } // }
func (c *websocketController) OnNamespaceDisconnect(msg neffos.Message) error { func (c *websocketController) OnNamespaceDisconnect(msg websocket.Message) error {
c.Logger.Log("Disconnected") c.Logger.Log("Disconnected")
// visits-- // visits--
newCount := decrement() newCount := decrement()
// This will call the "OnVisit" event on all clients, except the current one, // 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) // (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, Namespace: msg.Namespace,
Event: "OnVisit", Event: "OnVisit",
Body: []byte(fmt.Sprintf("%d", newCount)), Body: []byte(fmt.Sprintf("%d", newCount)),
@ -79,7 +73,7 @@ func (c *websocketController) OnNamespaceDisconnect(msg neffos.Message) error {
return nil return nil
} }
func (c *websocketController) OnNamespaceConnected(msg neffos.Message) error { func (c *websocketController) OnNamespaceConnected(msg websocket.Message) error {
// println("Broadcast prefix is: " + c.BroadcastPrefix) // println("Broadcast prefix is: " + c.BroadcastPrefix)
c.Logger.Log("Connected") 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 // 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. // 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, Namespace: msg.Namespace,
Event: "OnVisit", Event: "OnVisit",
Body: []byte(fmt.Sprintf("%d", newCount)), Body: []byte(fmt.Sprintf("%d", newCount)),
@ -100,7 +94,7 @@ func (c *websocketController) OnNamespaceConnected(msg neffos.Message) error {
return nil return nil
} }
func (c *websocketController) OnChat(msg neffos.Message) error { func (c *websocketController) OnChat(msg websocket.Message) error {
ctx := websocket.GetContext(c.Conn) ctx := websocket.GetContext(c.Conn)
ctx.Application().Logger().Infof("[IP: %s] [ID: %s] broadcast to other clients the message [%s]", ctx.Application().Logger().Infof("[IP: %s] [ID: %s] broadcast to other clients the message [%s]",

View File

@ -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`

View File

@ -10,8 +10,6 @@ import (
"time" "time"
"github.com/kataras/iris/websocket" "github.com/kataras/iris/websocket"
"github.com/kataras/neffos"
) )
const ( const (
@ -23,17 +21,17 @@ const (
// this can be shared with the server.go's. // this can be shared with the server.go's.
// `NSConn.Conn` has the `IsClient() bool` method which can be used to // `NSConn.Conn` has the `IsClient() bool` method which can be used to
// check if that's is a client or a server-side callback. // check if that's is a client or a server-side callback.
var clientEvents = neffos.Namespaces{ var clientEvents = websocket.Namespaces{
namespace: neffos.Events{ namespace: websocket.Events{
neffos.OnNamespaceConnected: func(c *neffos.NSConn, msg neffos.Message) error { websocket.OnNamespaceConnected: func(c *websocket.NSConn, msg websocket.Message) error {
log.Printf("connected to namespace: %s", msg.Namespace) log.Printf("connected to namespace: %s", msg.Namespace)
return nil 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) log.Printf("disconnected from namespace: %s", msg.Namespace)
return nil 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)) log.Printf("%s", string(msg.Body))
return nil return nil
}, },
@ -44,7 +42,7 @@ func main() {
ctx, cancel := context.WithDeadline(context.Background(), time.Now().Add(dialAndConnectTimeout)) ctx, cancel := context.WithDeadline(context.Background(), time.Now().Add(dialAndConnectTimeout))
defer cancel() defer cancel()
client, err := neffos.Dial(ctx, websocket.DefaultGorillaDialer, endpoint, clientEvents) client, err := websocket.Dial(ctx, websocket.DefaultGorillaDialer, endpoint, clientEvents)
if err != nil { if err != nil {
panic(err) panic(err)
} }

View File

@ -6,8 +6,6 @@ import (
"github.com/kataras/iris" "github.com/kataras/iris"
"github.com/kataras/iris/websocket" "github.com/kataras/iris/websocket"
"github.com/kataras/neffos"
// Used when "enableJWT" constant is true: // Used when "enableJWT" constant is true:
"github.com/dgrijalva/jwt-go" "github.com/dgrijalva/jwt-go"
jwtmiddleware "github.com/iris-contrib/middleware/jwt" jwtmiddleware "github.com/iris-contrib/middleware/jwt"
@ -17,10 +15,10 @@ import (
const enableJWT = true const enableJWT = true
const namespace = "default" const namespace = "default"
// if namespace is empty then simply neffos.Events{...} can be used instead. // if namespace is empty then simply websocket.Events{...} can be used instead.
var serverEvents = neffos.Namespaces{ var serverEvents = websocket.Namespaces{
namespace: neffos.Events{ namespace: websocket.Events{
neffos.OnNamespaceConnected: func(nsConn *neffos.NSConn, msg neffos.Message) error { websocket.OnNamespaceConnected: func(nsConn *websocket.NSConn, msg websocket.Message) error {
// with `websocket.GetContext` you can retrieve the Iris' `Context`. // with `websocket.GetContext` you can retrieve the Iris' `Context`.
ctx := websocket.GetContext(nsConn.Conn) ctx := websocket.GetContext(nsConn.Conn)
@ -29,11 +27,11 @@ var serverEvents = neffos.Namespaces{
ctx.RemoteAddr()) ctx.RemoteAddr())
return nil 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) log.Printf("[%s] disconnected from namespace [%s]", nsConn, msg.Namespace)
return nil 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() // room.String() returns -> NSConn.String() returns -> Conn.String() returns -> Conn.ID()
log.Printf("[%s] sent: %s", nsConn, string(msg.Body)) log.Printf("[%s] sent: %s", nsConn, string(msg.Body))
@ -48,7 +46,7 @@ var serverEvents = neffos.Namespaces{
func main() { func main() {
app := iris.New() app := iris.New()
websocketServer := neffos.New( websocketServer := websocket.New(
websocket.DefaultGorillaUpgrader, /* DefaultGobwasUpgrader can be used too. */ websocket.DefaultGorillaUpgrader, /* DefaultGobwasUpgrader can be used too. */
serverEvents) serverEvents)
@ -76,7 +74,7 @@ func main() {
// //
// Check for token through the jwt middleware // Check for token through the jwt middleware
// on websocket connection or on any event: // 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) ctx := websocket.GetContext(c)
if err := j.CheckJWT(ctx); err != nil { if err := j.CheckJWT(ctx); err != nil {
// will send the above error on the client // will send the above error on the client

View File

@ -5,8 +5,6 @@ import (
"github.com/kataras/iris" "github.com/kataras/iris"
"github.com/kataras/iris/websocket" "github.com/kataras/iris/websocket"
"github.com/kataras/neffos"
) )
type clientPage struct { type clientPage struct {
@ -26,8 +24,8 @@ func main() {
// and contains only one registered event which is the `OnNativeMessage`. // and contains only one registered event which is the `OnNativeMessage`.
// When `Events{...}` is used instead of `Namespaces{ "namespaceName": Events{...}}` // When `Events{...}` is used instead of `Namespaces{ "namespaceName": Events{...}}`
// then the namespace is empty "". // then the namespace is empty "".
ws := neffos.New(websocket.DefaultGorillaUpgrader, neffos.Events{ ws := websocket.New(websocket.DefaultGorillaUpgrader, websocket.Events{
neffos.OnNativeMessage: func(nsConn *neffos.NSConn, msg neffos.Message) error { websocket.OnNativeMessage: func(nsConn *websocket.NSConn, msg websocket.Message) error {
log.Printf("Server got: %s from [%s]", msg.Body, nsConn.Conn.ID()) log.Printf("Server got: %s from [%s]", msg.Body, nsConn.Conn.ID())
nsConn.Conn.Server().Broadcast(nsConn, msg) 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()) log.Printf("[%s] Connected to server!", c.ID())
return nil return nil
} }
ws.OnDisconnect = func(c *neffos.Conn) { ws.OnDisconnect = func(c *websocket.Conn) {
log.Printf("[%s] Disconnected from server", c.ID()) log.Printf("[%s] Disconnected from server", c.ID())
} }

2
go.mod
View File

@ -15,7 +15,7 @@ require (
github.com/iris-contrib/go.uuid v2.0.0+incompatible github.com/iris-contrib/go.uuid v2.0.0+incompatible
github.com/json-iterator/go v1.1.6 // vendor removed. github.com/json-iterator/go v1.1.6 // vendor removed.
github.com/kataras/golog v0.0.0-20180321173939-03be10146386 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/kataras/pio v0.0.0-20190103105442-ea782b38602d // indirect
github.com/microcosm-cc/bluemonday v1.0.2 github.com/microcosm-cc/bluemonday v1.0.2
github.com/ryanuber/columnize v2.1.0+incompatible github.com/ryanuber/columnize v2.1.0+incompatible

View File

@ -64,6 +64,7 @@ func New(party router.Party) *Application {
if HeroDependencies { if HeroDependencies {
values = hero.Dependencies().Clone() values = hero.Dependencies().Clone()
} }
return newApp(party, values) return newApp(party, values)
} }
@ -195,6 +196,10 @@ var _ websocket.ConnHandler = (*Application)(nil)
// It returns a collection of namespace and events that // It returns a collection of namespace and events that
// were registered through `HandleWebsocket` controllers. // were registered through `HandleWebsocket` controllers.
func (app *Application) GetNamespaces() websocket.Namespaces { func (app *Application) GetNamespaces() websocket.Namespaces {
if golog.Default.Level == golog.DebugLevel {
websocket.EnableDebug(golog.Default)
}
makeInjector := func(injector *di.StructInjector) websocket.StructInjector { makeInjector := func(injector *di.StructInjector) websocket.StructInjector {
return func(_ reflect.Type, nsConn *websocket.NSConn) reflect.Value { return func(_ reflect.Type, nsConn *websocket.NSConn) reflect.Value {
v := injector.Acquire() v := injector.Acquire()
@ -212,7 +217,6 @@ func (app *Application) GetNamespaces() websocket.Namespaces {
wsInjector := makeInjector(c.injector) wsInjector := makeInjector(c.injector)
s := websocket.NewStruct(c.Value).SetInjector(wsInjector) s := websocket.NewStruct(c.Value).SetInjector(wsInjector)
websocketControllers = append(websocketControllers, s) websocketControllers = append(websocketControllers, s)
} }
} }

View File

@ -335,22 +335,20 @@ func (r *Service) GetKeys(prefix string) ([]string, error) {
return r.getKeys(prefix) return r.getKeys(prefix)
} }
// GetBytes returns value, err by its key // // GetBytes returns bytes representation of a value based on given "key".
// you can use utils.Deserialize((.GetBytes("yourkey"),&theobject{}) // func (r *Service) GetBytes(key string) ([]byte, error) {
//returns nil and a filled error if something wrong happens // var redisVal []byte
func (r *Service) GetBytes(key string) ([]byte, error) { // mn := radix.MaybeNil{Rcv: &redisVal}
var redisVal []byte // err := r.pool.Do(radix.Cmd(&mn, "GET", r.Config.Prefix+key))
mn := radix.MaybeNil{Rcv: &redisVal} // if err != nil {
err := r.pool.Do(radix.Cmd(&mn, "GET", r.Config.Prefix+key)) // return nil, err
if err != nil { // }
return nil, err // if mn.Nil {
} // return nil, ErrKeyNotFound.Format(key)
if mn.Nil { // }
return nil, ErrKeyNotFound.Format(key)
}
return redisVal, nil // return redisVal, nil
} // }
// Delete removes redis entry by specific key // Delete removes redis entry by specific key
func (r *Service) Delete(key string) error { func (r *Service) Delete(key string) error {

View File

@ -4,11 +4,17 @@ import (
"github.com/kataras/iris/context" "github.com/kataras/iris/context"
"github.com/kataras/neffos" "github.com/kataras/neffos"
"github.com/kataras/neffos/gobwas" "github.com/kataras/neffos/gobwas"
"github.com/kataras/neffos/gorilla" "github.com/kataras/neffos/gorilla"
"github.com/kataras/neffos/stackexchange/redis"
) )
var ( 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. // GorillaUpgrader is an upgrader type for the gorilla/websocket subprotocol implementation.
// Should be used on `New` to construct the websocket server. // Should be used on `New` to construct the websocket server.
GorillaUpgrader = gorilla.Upgrader GorillaUpgrader = gorilla.Upgrader
@ -32,6 +38,9 @@ var (
DefaultIDGenerator = func(ctx context.Context) string { DefaultIDGenerator = func(ctx context.Context) string {
return neffos.DefaultIDGenerator(ctx.ResponseWriter(), ctx.Request()) 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. // GorillaDialer is a `Dialer` type for the gorilla/websocket subprotocol implementation.
// Should be used on `Dial` to create a new client/client-side connection. // Should be used on `Dial` to create a new client/client-side connection.

View File

@ -6,6 +6,7 @@ import (
"github.com/kataras/neffos" "github.com/kataras/neffos"
"github.com/kataras/neffos/gobwas" "github.com/kataras/neffos/gobwas"
"github.com/kataras/neffos/gorilla" "github.com/kataras/neffos/gorilla"
"github.com/kataras/neffos/stackexchange/redis"
) )
type ( type (
@ -76,4 +77,16 @@ type (
// when incoming native message then the `Message.Event` is the `OnNativeMessage`, // 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. // native messages are allowed only when an empty namespace("") and its `OnNativeMessage` callback are present.
Message = neffos.Message 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
) )