-
-
Notifications
You must be signed in to change notification settings - Fork 53
Namespaces
- You need to scope events into independent groups (different feature areas, different protocol versions).
- You're handling the connect/disconnect lifecycle and want to know when each event fires.
- You want to disallow a client from connecting to a namespace.
A namespace is a named collection of event handlers on a single underlying connection. One websocket connection (Conn) can be connected to many namespaces at once; each one is represented by an NSConn.
Think of namespaces like channels on a chat server, or independent API surfaces ("admin", "metrics", "chat") sharing a single transport. They are static: declared up front in the handler map on both server and client.
namespaces := neffos.Namespaces{
"chat": neffos.Events{
neffos.OnNamespaceConnect: func(c *neffos.NSConn, msg neffos.Message) error {
// return non-nil to deny the connect
return nil
},
"message": func(c *neffos.NSConn, msg neffos.Message) error {
log.Printf("%s says: %s", c.Conn.ID(), string(msg.Body))
return nil
},
},
"admin": neffos.Events{
"shutdown": func(c *neffos.NSConn, msg neffos.Message) error { /* ... */ return nil },
},
}A client can choose to connect to one, the other, or both. Clients that never call conn.Connect("admin", ...) never receive admin messages.
These event names are fired by neffos itself. They start with _ to avoid colliding with your event names — use the neffos.OnNamespace* / neffos.OnRoom* constants instead of the literals.
| Event | Fires when | Return non-nil error to... |
|---|---|---|
OnNamespaceConnect |
Before the namespace handshake completes. | ...deny the connection. The remote side gets the error text. |
OnNamespaceConnected |
After the namespace handshake succeeded. | ...the return is ignored; the connection is already up. |
OnNamespaceDisconnect |
When either side disconnects from the namespace. | ...for server-side, refuse the disconnect (client retries). For client-side, the return is ignored. |
OnRoomJoin |
Before joining a room. | ...deny the join. |
OnRoomJoined |
After the join succeeded. | (Ignored.) |
OnRoomLeave |
Before leaving a room. | ...deny the leave. |
OnRoomLeft |
After the leave succeeded. | (Ignored.) |
OnAnyEvent |
Wildcard: any incoming event with no matching handler. | ...send the error back. |
OnNativeMessage |
Raw WebSocket frames (only in the empty namespace). | ...send the error back. |
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
ns, err := conn.Connect(ctx, "chat")
if err != nil {
log.Fatal(err)
}
ns.Emit("message", []byte("hello"))Connect blocks until the namespace handshake completes or ctx fires. The first parameter MUST have a deadline in production — otherwise a server that refuses to ack will pin this goroutine.
ns := c.Namespace("chat") // nil if not connectedConn.Namespace(name) is cheap (one map lookup under a sync.RWMutex.RLock).
err := ns.Disconnect(ctx)Sends OnNamespaceDisconnect to the other side and fires the local event. Fail-safe: if the connection is dead, Disconnect still cleans up the local state.
Disconnect from every namespace at once:
err := c.DisconnectAll(ctx)DisconnectAll walks the connected namespaces under the lock; the remote side is notified for each.
Use namespaces when:
- Authorization differs. Admin events vs. user events on the same socket.
-
Versioning.
v1andv2namespaces during a rolling upgrade. - Independent feature surfaces. Chat and notifications, where you don't want a noisy chat to drown out time-sensitive notifications (they're queued per-namespace).
Use a single empty namespace ("") when your app has one event surface — it's simpler and most public examples use this pattern.
"chat": neffos.Events{
neffos.OnNamespaceConnect: func(c *neffos.NSConn, msg neffos.Message) error {
user, _ := c.Conn.Get("user").(*User)
if user == nil {
return errors.New("not authenticated")
}
if !user.CanChat() {
return errors.New("chat is disabled for your account")
}
return nil
},
}The error text is sent to the client and surfaces as msg.Err (or a rejected Connect promise on the JS side). Register the error via neffos.RegisterKnownError if you want equality matching across the wire — see Errors.
flowchart TB
S[Server]
S --> C1[Conn user-1]
S --> C2[Conn user-2]
C1 --> NS1A[NSConn chat]
C1 --> NS1B[NSConn admin]
C2 --> NS2A[NSConn chat]
NS1A --> R1[Room lobby]
NS1A --> R2[Room support]
NS2A --> R1
A Conn can have many NSConns; an NSConn can be in many Rooms. Rooms are scoped to their namespace — lobby in chat is unrelated to lobby in admin.
- Rooms — joining and broadcasting inside a namespace
- The ask method — request/response inside an event handler
- Authentication — gating namespace connects on auth
-
Errors — meaningful errors from
OnNamespaceConnect
Home | About | Project | Getting Started | Technical Docs | Copyright © 2019-2023 Gerasimos Maropoulos. Documentation terms of use.
Getting started
Concepts
Messaging
Production
Scale out