diff --git a/_examples/README.md b/_examples/README.md
index f9b1c3c5..44db87de 100644
--- a/_examples/README.md
+++ b/_examples/README.md
@@ -363,9 +363,9 @@ You can serve [quicktemplate](https://github.com/valyala/quicktemplate) and [her
- [Basic Authentication](authentication/basicauth/main.go)
- [OAUth2](authentication/oauth2/main.go)
-- [JWT](experimental-handlers/jwt/main.go)
+- [Request Auth](request/main.go) **NEW**
+- [Request Auth(JWT)](experimental-handlers/jwt/main.go)
- [Sessions](#sessions)
-- [Request Authentication](authentication/request/main.go) **NEW**
### File Server
diff --git a/_examples/authentication/README.md b/_examples/authentication/README.md
index c7c132ca..4072c7b9 100644
--- a/_examples/authentication/README.md
+++ b/_examples/authentication/README.md
@@ -2,5 +2,6 @@
- [Basic Authentication](basicauth/main.go)
- [OAUth2](oauth2/main.go)
-- [JWT](https://github.com/kataras/iris/blob/master/_examples/experimental-handlers/jwt/main.go)
+- [Request Auth](request/main.go)
+- [Request Auth(JWT)](https://github.com/kataras/iris/blob/master/_examples/experimental-handlers/jwt/main.go)
- [Sessions](https://github.com/kataras/iris/tree/master/_examples/#sessions)
\ No newline at end of file
diff --git a/_examples/authentication/request/main.go b/_examples/authentication/request/main.go
index c097dff8..d273eb70 100644
--- a/_examples/authentication/request/main.go
+++ b/_examples/authentication/request/main.go
@@ -134,3 +134,5 @@ func main() {
// You can read more examples and run testable code
// at the `iris/crypto`, `iris/crypto/sign`
// and `iris/crypto/gcm` packages themselves.
+//
+// See experimental-handlers/jwt example to use JWT for request authentication instead.
diff --git a/_examples/experimental-handlers/jwt/main.go b/_examples/experimental-handlers/jwt/main.go
index c0109268..58b945f6 100644
--- a/_examples/experimental-handlers/jwt/main.go
+++ b/_examples/experimental-handlers/jwt/main.go
@@ -23,7 +23,7 @@ func myHandler(ctx iris.Context) {
ctx.Writef("This is an authenticated request\n")
ctx.Writef("Claim content:\n")
- ctx.Writef("%s", user.Signature)
+ ctx.Writef("%#+v\n", user.Claims)
}
func main() {
@@ -42,5 +42,12 @@ func main() {
app.Use(jwtHandler.Serve)
app.Get("/ping", myHandler)
+
+ // Example request:
+ // curl -X GET -H\
+ // "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjozMjEzMjF9.8waEX7-vPKACa-Soi1pQvW3Rl8QY-SUFcHKTLZI4mvU"\
+ // http://localhost:3001/ping
+ //
+ //Read more at: https://jwt.io/
app.Run(iris.Addr("localhost:3001"))
-} // don't forget to look ../jwt_test.go to see how to set your own custom claims
+}
diff --git a/_examples/mvc/websocket/browser/index.html b/_examples/mvc/websocket/browser/index.html
new file mode 100644
index 00000000..c7a2f910
--- /dev/null
+++ b/_examples/mvc/websocket/browser/index.html
@@ -0,0 +1,106 @@
+
+
+
+ Online visitors MVC example
+
+
+
+
+
+ 1 online visitor
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/_examples/mvc/websocket/main.go b/_examples/mvc/websocket/main.go
index c94ec5f9..9e611e38 100644
--- a/_examples/mvc/websocket/main.go
+++ b/_examples/mvc/websocket/main.go
@@ -1,41 +1,45 @@
package main
import (
+ "fmt"
"sync/atomic"
"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"))
- // render the ./views/index.html.
- app.Get("/", func(ctx iris.Context) {
- ctx.View("index.html")
- })
+ // render the ./browser/index.html.
+ app.HandleDir("/", "./browser")
- mvc.Configure(app.Party("/websocket"), configureMVC)
- // Or mvc.New(app.Party(...)).Configure(configureMVC)
+ websocketAPI := app.Party("/websocket")
+ m := mvc.New(websocketAPI)
+ m.Register(
+ &prefixedLogger{prefix: "DEV"},
+ )
+ m.HandleWebsocket(&websocketController{Namespace: "default", Age: 42, Otherstring: "other string"})
+
+ websocketServer := neffos.New(websocket.DefaultGorillaUpgrader, m)
+
+ websocketAPI.Get("/", websocket.Handler(websocketServer))
// http://localhost:8080
app.Run(iris.Addr(":8080"))
}
-func configureMVC(m *mvc.Application) {
- ws := websocket.New(websocket.Config{})
- // http://localhost:8080/websocket/iris-ws.js
- m.Router.Any("/iris-ws.js", websocket.ClientHandler())
-
- // This will bind the result of ws.Upgrade which is a websocket.Connection
- // to the controller(s) served by the `m.Handle`.
- m.Register(ws.Upgrade)
- m.Handle(new(websocketController))
-}
-
var visits uint64
func increment() uint64 {
@@ -47,36 +51,74 @@ func decrement() uint64 {
}
type websocketController struct {
- // Note that you could use an anonymous field as well, it doesn't matter, binder will find it.
- //
- // This is the current websocket connection, each client has its own instance of the *websocketController.
- Conn websocket.Connection
+ *neffos.NSConn `stateless:"true"`
+ Namespace string
+ Age int
+ Otherstring string
+
+ Logger LoggerService
}
-func (c *websocketController) onLeave(roomName string) {
+// or
+// func (c *websocketController) Namespace() string {
+// return "default"
+// }
+
+func (c *websocketController) OnNamespaceDisconnect(msg neffos.Message) error {
+ c.Logger.Log("Disconnected")
// visits--
newCount := decrement()
- // This will call the "visit" 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)
- c.Conn.To(websocket.Broadcast).Emit("visit", newCount)
+ c.Conn.Server().Broadcast(nil, neffos.Message{
+ Namespace: msg.Namespace,
+ Event: "OnVisit",
+ Body: []byte(fmt.Sprintf("%d", newCount)),
+ })
+
+ return nil
}
-func (c *websocketController) update() {
+func (c *websocketController) OnNamespaceConnected(msg neffos.Message) error {
+ // println("Broadcast prefix is: " + c.BroadcastPrefix)
+ c.Logger.Log("Connected")
+
// visits++
newCount := increment()
- // This will call the "visit" event on all clients, including the current
+ // This will call the "OnVisit" event on all clients, including the current
// with the 'newCount' variable.
//
// 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.To(websocket.All).Emit("visit", newCount)
+ c.Conn.Server().Broadcast(c, neffos.Message{
+ Namespace: msg.Namespace,
+ Event: "OnVisit",
+ Body: []byte(fmt.Sprintf("%d", newCount)),
+ })
+
+ return nil
}
-func (c *websocketController) Get( /* websocket.Connection could be lived here as well, it doesn't matter */ ) {
- c.Conn.OnLeave(c.onLeave)
- c.Conn.On("visit", c.update)
+func (c *websocketController) OnChat(msg neffos.Message) error {
+ ctx := websocket.GetContext(c.Conn)
- // call it after all event callbacks registration.
- c.Conn.Wait()
+ ctx.Application().Logger().Infof("[IP: %s] [ID: %s] broadcast to other clients the message [%s]",
+ ctx.RemoteAddr(), c, string(msg.Body))
+
+ c.Conn.Server().Broadcast(c, msg)
+
+ return nil
+}
+
+type LoggerService interface {
+ Log(string)
+}
+
+type prefixedLogger struct {
+ prefix string
+}
+
+func (s *prefixedLogger) Log(msg string) {
+ fmt.Printf("%s: %s\n", s.prefix, msg)
}
diff --git a/_examples/mvc/websocket/views/index.html b/_examples/mvc/websocket/views/index.html
deleted file mode 100644
index ecedcff2..00000000
--- a/_examples/mvc/websocket/views/index.html
+++ /dev/null
@@ -1,63 +0,0 @@
-
-
-
- Online visitors MVC example
-
-
-
-
-
- 1 online visitor
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/_examples/websocket/basic/server.go b/_examples/websocket/basic/server.go
index fa8150b0..ab028ca6 100644
--- a/_examples/websocket/basic/server.go
+++ b/_examples/websocket/basic/server.go
@@ -68,7 +68,7 @@ func main() {
// serves the endpoint of ws://localhost:8080/echo
websocketRoute := app.Get("/echo", websocket.Handler(websocketServer))
-
+ j.Get()
if enableJWT {
// Register the jwt middleware (on handshake):
websocketRoute.Use(j.Serve)
@@ -76,20 +76,25 @@ func main() {
//
// Check for token through the jwt middleware
// on websocket connection or on any event:
- /*
- websocketServer.OnConnect = func(c *neffos.Conn) error {
- ctx := websocket.GetContext(c)
- if err := j.CheckJWT(ctx); err != nil {
- // will send the above error on the client
- // and will not allow it to connect to the websocket server at all.
- return err
- }
+ /* websocketServer.OnConnect = func(c *neffos.Conn) error {
+ ctx := websocket.GetContext(c)
+ if err := j.CheckJWT(ctx); err != nil {
+ // will send the above error on the client
+ // and will not allow it to connect to the websocket server at all.
+ return err
+ }
- log.Printf("[%s] connected to the server", c.ID())
+ user := ctx.Values().Get("jwt").(*jwt.Token)
+ // or just: user := j.Get(ctx)
- return nil
- }
- */
+ log.Printf("This is an authenticated request\n")
+ log.Printf("Claim content:")
+ log.Printf("%#+v\n", user.Claims)
+
+ log.Printf("[%s] connected to the server", c.ID())
+
+ return nil
+ } */
}
// serves the browser-based websocket client.
diff --git a/configuration.go b/configuration.go
index e31a9c76..2a6f42f0 100644
--- a/configuration.go
+++ b/configuration.go
@@ -401,7 +401,7 @@ type Configuration struct {
// DisablePathCorrectionRedirection works whenever configuration.DisablePathCorrection is set to false
// and if DisablePathCorrectionRedirection set to true then it will fire the handler of the matching route without
- // the last slash ("/") instead of send a redirection status.
+ // the trailing slash ("/") instead of send a redirection status.
//
// Defaults to false.
DisablePathCorrectionRedirection bool `json:"disablePathCorrectionRedirection,omitempty" yaml:"DisablePathCorrectionRedirection" toml:"DisablePathCorrectionRedirection"`
diff --git a/go.mod b/go.mod
index b364ad4c..90ac4507 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.3
+ github.com/kataras/neffos v0.0.5
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/hero/di/reflect.go b/hero/di/reflect.go
index e9ae06af..48fbc708 100644
--- a/hero/di/reflect.go
+++ b/hero/di/reflect.go
@@ -1,6 +1,8 @@
package di
-import "reflect"
+import (
+ "reflect"
+)
// EmptyIn is just an empty slice of reflect.Value.
var EmptyIn = []reflect.Value{}
@@ -164,6 +166,13 @@ func structFieldIgnored(f reflect.StructField) bool {
return s == "true" // if has an ignore tag then ignore it.
}
+// for controller's fields only. Explicit set a stateless to a field
+// in order to make the controller a Stateless one even if no other dynamic dependencies exist.
+func structFieldStateless(f reflect.StructField) bool {
+ s := f.Tag.Get("stateless")
+ return s == "true"
+}
+
type field struct {
Type reflect.Type
Name string // the actual name.
@@ -190,7 +199,7 @@ func lookupFields(elemTyp reflect.Type, skipUnexported bool, parentIndex []int)
for i, n := 0, elemTyp.NumField(); i < n; i++ {
f := elemTyp.Field(i)
if IndirectType(f.Type).Kind() == reflect.Struct &&
- !structFieldIgnored(f) {
+ !structFieldIgnored(f) && !structFieldStateless(f) {
fields = append(fields, lookupFields(f.Type, skipUnexported, append(parentIndex, i))...)
continue
}
@@ -230,7 +239,8 @@ func LookupNonZeroFieldsValues(v reflect.Value, skipUnexported bool) (bindValues
for _, f := range fields {
if fieldVal := elem.FieldByIndex(f.Index); /*f.Type.Kind() == reflect.Ptr &&*/
- !IsZero(fieldVal) {
+ goodVal(fieldVal) && !IsZero(fieldVal) {
+ // fmt.Printf("[%d][field index = %d] append to bindValues: %s = %s\n", i, f.Index[0], f.Name, fieldVal.String())
bindValues = append(bindValues, fieldVal)
}
}
diff --git a/hero/di/struct.go b/hero/di/struct.go
index b2779765..53384c01 100644
--- a/hero/di/struct.go
+++ b/hero/di/struct.go
@@ -20,6 +20,22 @@ const (
Singleton
)
+// read-only on runtime.
+var scopeNames = map[Scope]string{
+ Stateless: "Stateless",
+ Singleton: "Singleton",
+}
+
+// Return "Stateless" for 0 or "Singleton" for 1.
+func (scope Scope) String() string {
+ name, ok := scopeNames[scope]
+ if !ok {
+ return "Unknown"
+ }
+
+ return name
+}
+
type (
targetStructField struct {
Object *BindObject
@@ -65,6 +81,20 @@ func MakeStructInjector(v reflect.Value, hijack Hijacker, goodFunc TypeChecker,
elemType: IndirectType(v.Type()),
}
+ // Optionally check and keep good values only here,
+ // but not required because they are already checked by users of this function.
+ //
+ // for i, v := range values {
+ // if !goodVal(v) || IsZero(v) {
+ // if last := len(values) - 1; last > i {
+ // values = append(values[:i], values[i+1:]...)
+ // } else {
+ // values = values[0:last]
+ // }
+ // }
+ // }
+
+ visited := make(map[int]struct{}, 0) // add a visited to not add twice a single value (09-Jul-2019).
fields := lookupFields(s.elemType, true, nil)
for _, f := range fields {
if hijack != nil {
@@ -78,15 +108,19 @@ func MakeStructInjector(v reflect.Value, hijack Hijacker, goodFunc TypeChecker,
}
}
- for _, val := range values {
+ for idx, val := range values {
+ if _, alreadySet := visited[idx]; alreadySet {
+ continue
+ }
+
// the binded values to the struct's fields.
b, err := MakeBindObject(val, goodFunc)
-
if err != nil {
return s // if error stop here.
}
if b.IsAssignable(f.Type) {
+ visited[idx] = struct{}{}
// fmt.Printf("bind the object to the field: %s at index: %#v and type: %s\n", f.Name, f.Index, f.Type.String())
s.fields = append(s.fields, &targetStructField{
FieldIndex: f.Index,
@@ -126,13 +160,14 @@ func (s *StructInjector) setState() {
// if so then set the temp staticBindingsFieldsLength to that number, so for example:
// if static binding length is 0
// but an unexported field is set-ed then act that as singleton.
+
if allStructFieldsLength > staticBindingsFieldsLength {
structFieldsUnexportedNonZero := LookupNonZeroFieldsValues(s.initRef, false)
staticBindingsFieldsLength = len(structFieldsUnexportedNonZero)
}
- // println("staticBindingsFieldsLength: ", staticBindingsFieldsLength)
// println("allStructFieldsLength: ", allStructFieldsLength)
+ // println("staticBindingsFieldsLength: ", staticBindingsFieldsLength)
// if the number of static values binded is equal to the
// total struct's fields(including unexported fields this time) then set as singleton.
@@ -169,9 +204,23 @@ func (s *StructInjector) fillStruct() {
func (s *StructInjector) String() (trace string) {
for i, f := range s.fields {
elemField := s.elemType.FieldByIndex(f.FieldIndex)
- trace += fmt.Sprintf("[%d] %s binding: '%s' for field '%s %s'\n",
- i+1, bindTypeString(f.Object.BindType), f.Object.Type.String(),
- elemField.Name, elemField.Type.String())
+
+ format := "\t[%d] %s binding: %#+v for field '%s %s'"
+ if len(s.fields) > i+1 {
+ format += "\n"
+ }
+
+ if !f.Object.Value.IsValid() {
+ continue // probably a Context.
+ }
+
+ valuePresent := f.Object.Value.Interface()
+
+ if f.Object.BindType == Dynamic {
+ valuePresent = f.Object.Type.String()
+ }
+
+ trace += fmt.Sprintf(format, i+1, bindTypeString(f.Object.BindType), valuePresent, elemField.Name, elemField.Type.String())
}
return
diff --git a/hero/di/values.go b/hero/di/values.go
index 1033b957..0ffdd23f 100644
--- a/hero/di/values.go
+++ b/hero/di/values.go
@@ -29,7 +29,22 @@ func (bv Values) CloneWithFieldsOf(s interface{}) Values {
// add the manual filled fields to the dependencies.
filledFieldValues := LookupNonZeroFieldsValues(ValueOf(s), true)
+
+ for i, filled := range filledFieldValues {
+ for _, v := range values {
+ // do NOT keep duplicate equal values (09-Jul-2019).
+ if reflect.DeepEqual(v, filled) {
+ if last := len(filledFieldValues) - 1; last > i {
+ filledFieldValues = append(filledFieldValues[:i], filledFieldValues[i+1:]...)
+ } else {
+ filledFieldValues = filledFieldValues[0:last]
+ }
+ break
+ }
+ }
+ }
values = append(values, filledFieldValues...)
+
return values
}
diff --git a/mvc/controller.go b/mvc/controller.go
index c2121dc4..ef3813a7 100644
--- a/mvc/controller.go
+++ b/mvc/controller.go
@@ -87,8 +87,11 @@ type ControllerActivator struct {
errorHandler hero.ErrorHandler
- // initialized on the first `Handle`.
+ // initialized on the first `Handle` or immediately when "servesWebsocket" is true.
injector *di.StructInjector
+
+ // true if this controller listens and serves to websocket events.
+ servesWebsocket bool
}
// NameOf returns the package name + the struct type's name,
@@ -145,6 +148,11 @@ func whatReservedMethods(typ reflect.Type) map[string]*router.Route {
return routes
}
+func (c *ControllerActivator) markAsWebsocket() {
+ c.servesWebsocket = true
+ c.attachInjector()
+}
+
// Dependencies returns the write and read access of the dependencies that are
// came from the parent MVC Application, with this you can customize
// the dependencies per controller, used at the `BeforeActivation`.
@@ -325,6 +333,21 @@ func (c *ControllerActivator) Handle(method, path, funcName string, middleware .
var emptyIn = []reflect.Value{}
+func (c *ControllerActivator) attachInjector() {
+ if c.injector == nil {
+ c.injector = di.Struct(c.Value, c.dependencies...)
+ if !c.servesWebsocket {
+ golog.Debugf("MVC Controller [%s] [Scope=%s]", c.fullName, c.injector.Scope)
+ } else {
+ golog.Debugf("MVC Websocket Controller [%s]", c.fullName)
+ }
+
+ if c.injector.Has {
+ golog.Debugf("Dependencies:\n%s", c.injector.String())
+ }
+ }
+}
+
func (c *ControllerActivator) handlerOf(m reflect.Method, funcDependencies []reflect.Value) context.Handler {
// Remember:
// The `Handle->handlerOf` can be called from `BeforeActivation` event
@@ -333,12 +356,7 @@ func (c *ControllerActivator) handlerOf(m reflect.Method, funcDependencies []ref
// To solve this we're doing a check on the FIRST `Handle`,
// if c.injector is nil, then set it with the current bindings,
// these bindings can change after, so first add dependencies and after register routes.
- if c.injector == nil {
- c.injector = di.Struct(c.Value, c.dependencies...)
- if c.injector.Has {
- golog.Debugf("MVC dependencies of '%s':\n%s", c.fullName, c.injector.String())
- }
- }
+ c.attachInjector()
// fmt.Printf("for %s | values: %s\n", funcName, funcDependencies)
diff --git a/mvc/mvc.go b/mvc/mvc.go
index da438c63..4b18e303 100644
--- a/mvc/mvc.go
+++ b/mvc/mvc.go
@@ -1,12 +1,14 @@
package mvc
import (
+ "reflect"
"strings"
"github.com/kataras/iris/context"
"github.com/kataras/iris/core/router"
"github.com/kataras/iris/hero"
"github.com/kataras/iris/hero/di"
+ "github.com/kataras/iris/websocket"
"github.com/kataras/golog"
)
@@ -172,6 +174,52 @@ Set the Logger's Level to "debug" to view the active dependencies per controller
//
// Examples at: https://github.com/kataras/iris/tree/master/_examples/mvc
func (app *Application) Handle(controller interface{}) *Application {
+ app.handle(controller)
+ return app
+}
+
+// HandleWebsocket handles a websocket specific controller.
+// Its exported methods are the events.
+// If a "Namespace" field or method exists then namespace is set, otherwise empty namespace.
+// Note that a websocket controller is registered and ran under a specific connection connected to a namespace
+// and it cannot send HTTP responses on that state.
+// However all static and dynamic dependency injection features are working, as expected, like any regular MVC Controller.
+func (app *Application) HandleWebsocket(controller interface{}) {
+ c := app.handle(controller)
+ c.markAsWebsocket()
+}
+
+var _ websocket.ConnHandler = (*Application)(nil)
+
+// GetNamespaces completes the websocket ConnHandler interface.
+// It returns a collection of namespace and events that
+// were registered through `HandleWebsocket` controllers.
+func (app *Application) GetNamespaces() websocket.Namespaces {
+ makeInjector := func(injector *di.StructInjector) websocket.StructInjector {
+ return func(_ reflect.Type, nsConn *websocket.NSConn) reflect.Value {
+ v := injector.Acquire()
+ if injector.CanInject {
+ injector.InjectElem(v.Elem(), reflect.ValueOf(websocket.GetContext(nsConn.Conn)))
+ }
+ return v
+ }
+ }
+
+ var websocketControllers []websocket.ConnHandler
+
+ for _, c := range app.Controllers {
+ if c.servesWebsocket {
+ wsInjector := makeInjector(c.injector)
+ s := websocket.NewStruct(c.Value).SetInjector(wsInjector)
+ websocketControllers = append(websocketControllers, s)
+
+ }
+ }
+
+ return websocket.JoinConnHandlers(websocketControllers...).GetNamespaces()
+}
+
+func (app *Application) handle(controller interface{}) *ControllerActivator {
// initialize the controller's activator, nothing too magical so far.
c := newControllerActivator(app.Router, controller, app.Dependencies, app.ErrorHandler)
@@ -193,7 +241,7 @@ func (app *Application) Handle(controller interface{}) *Application {
}
app.Controllers = append(app.Controllers, c)
- return app
+ return c
}
// HandleError registers a `hero.ErrorHandlerFunc` which will be fired when
diff --git a/mvc/session_controller.go b/mvc/session_controller.go
deleted file mode 100644
index a4885fa5..00000000
--- a/mvc/session_controller.go
+++ /dev/null
@@ -1,48 +0,0 @@
-package mvc
-
-import (
- "github.com/kataras/iris/context"
- "github.com/kataras/iris/sessions"
-)
-
-var defaultSessionManager = sessions.New(sessions.Config{})
-
-// SessionController is a simple `Controller` implementation
-// which requires a binded session manager in order to give
-// direct access to the current client's session via its `Session` field.
-//
-// SessionController is deprecated please use the new dependency injection's methods instead,
-// i.e `mvcApp.Register(sessions.New(sessions.Config{}).Start)`.
-// It's more controlled by you,
-// also *sessions.Session type can now `Destroy` itself without the need of the manager, embrace it.
-type SessionController struct {
- Manager *sessions.Sessions
- Session *sessions.Session
-}
-
-// BeforeActivation called, once per application lifecycle NOT request,
-// every single time the dev registers a specific SessionController-based controller.
-// It makes sure that its "Manager" field is filled
-// even if the caller didn't provide any sessions manager via the MVC's Application's `Handle` function.
-func (s *SessionController) BeforeActivation(b BeforeActivation) {
- if didntBindManually := b.Dependencies().AddOnce(defaultSessionManager); didntBindManually {
- b.Router().GetReporter().Add(
- `MVC SessionController: couldn't find any "*sessions.Sessions" bindable value to fill the "Manager" field,
- therefore this controller is using the default sessions manager instead.
- Please refer to the documentation to learn how you can provide the session manager`)
- }
-}
-
-// BeginRequest initializes the current user's Session.
-func (s *SessionController) BeginRequest(ctx context.Context) {
- if s.Manager == nil {
- ctx.Application().Logger().Errorf(`MVC SessionController: sessions manager is nil, report this as a bug
-because the SessionController should predict this on its activation state and use a default one automatically`)
- return
- }
-
- s.Session = s.Manager.Start(ctx)
-}
-
-// EndRequest is here to complete the `BaseController`.
-func (s *SessionController) EndRequest(ctx context.Context) {}
diff --git a/websocket/websocket.go b/websocket/websocket.go
index 893c8e2e..c771af7d 100644
--- a/websocket/websocket.go
+++ b/websocket/websocket.go
@@ -53,13 +53,15 @@ var (
//
// See examples for more.
Dial = neffos.Dial
-
// IsTryingToReconnect reports whether the returning "err" from the `Server#Upgrade`
// is from a client that was trying to reconnect to the websocket server.
//
// Look the `Conn#WasReconnected` and `Conn#ReconnectTries` too.
IsTryingToReconnect = neffos.IsTryingToReconnect
-
+ // NewStruct returns the `Struct` Conn Handler based on ptr value.
+ NewStruct = neffos.NewStruct
+ // JoinConnHandlers combines two or more ConnHandlers as one.
+ JoinConnHandlers = neffos.JoinConnHandlers
// OnNamespaceConnect is the event name which its callback is fired right before namespace connect,
// if non-nil error then the remote connection's `Conn.Connect` will fail and send that error text.
// Connection is not ready to emit data to the namespace.
diff --git a/websocket/websocket_go19.go b/websocket/websocket_go19.go
index af0f3c57..b787fbb0 100644
--- a/websocket/websocket_go19.go
+++ b/websocket/websocket_go19.go
@@ -39,7 +39,8 @@ type (
// i.e on `OnNamespaceConnect` it will abort a remote namespace connection.
// See examples for more.
MessageHandlerFunc = neffos.MessageHandlerFunc
-
+ // ConnHandler is the interface which namespaces and events can be retrieved through.
+ ConnHandler = neffos.ConnHandler
// Events completes the `ConnHandler` interface.
// It is a map which its key is the event name
// and its value the event's callback.
@@ -63,6 +64,11 @@ type (
//
// See `New` and `Dial`.
WithTimeout = neffos.WithTimeout
+ // Struct completes the `ConnHandler` interface.
+ // It uses a structure to register a specific namespace and its events.
+ Struct = neffos.Struct
+ // StructInjector can be used to customize the value creation that can is used on serving events.
+ StructInjector = neffos.StructInjector
// The Message is the structure which describes the incoming and outcoming data.
// Emitter's "body" argument is the `Message.Body` field.
// Emitter's return non-nil error is the `Message.Err` field.