Neffos is a cross-platform real-time framework with an expressive, elegant API written in Go. Neffos eases common tasks needed in real-time backend and frontend applications, such as:
- Scale-out using redis or nats*, with
StackExchangeCloserto release it on shutdown andNSConn.Broadcastfor a same-server send - Adaptive request upgradation and server dialing
- Three backends: gorilla, gobwas, coder
- Acknowledgements
- Namespaces
- Rooms
- Broadcast
- Event-Driven architecture
- Request-Response architecture
- Error Awareness
- Asynchronous Broadcast
- Heartbeat, close status codes and a message size limit
- Graceful shutdown
- Timeouts
- Encoding
- Reconnection (neffos.js)
- Modern neffos API client for Browsers, Node.js* and Go
Go 1.27 or later is required.
go get github.com/kataras/neffos@latestOne Conn per websocket, one NSConn per namespace it connects to, one Room per room it joins. Server and client sides share the same types and methods.
classDiagram
direction LR
class Conn {
ID() string
IsClient() bool
Server() *Server
Connect(ctx, namespace) *NSConn, error
Namespace(namespace) *NSConn
Send(Message) error
Ask(ctx, Message) Message, error
Set(key, value)
Value~T~(key) T, bool
Terminate(code, reason)
Close()
Err() error
}
class NSConn {
Conn *Conn
Send(event, body) error
SendObject(event, v) error
Ask(ctx, event, body) Message, error
AskObject~Reply~(ctx, event, v) Reply, error
JoinRoom(ctx, name) *Room, error
Room(name) *Room
Rooms() []*Room
Broadcast(msgs...)
Disconnect(ctx) error
}
class Room {
NSConn *NSConn
Name string
Send(event, body) error
SendObject(event, v) error
Leave(ctx) error
}
class Message {
Namespace string
Room string
Event string
Body []byte
Err error
As~T~() T, error
Unmarshal(ptr) error
}
Conn "1" --> "0..*" NSConn : Connect(namespace)
NSConn "1" --> "0..*" Room : JoinRoom(name)
NSConn ..> Message : Send fills Namespace
Room ..> Message : Send fills Namespace and Room
Quick View
import (
// [...]
"github.com/kataras/neffos"
"github.com/kataras/neffos/gorilla"
)
func runServer() {
events := make(neffos.Namespaces)
events.On("/v1", "workday", func(ns *neffos.NSConn, msg neffos.Message) error {
date := string(msg.Body)
t, err := time.Parse("01-02-2006", date)
if err != nil {
// Return the parse error back to the client.
return err
}
if t.Weekday() == time.Saturday || t.Weekday() == time.Sunday {
// Fire the "notify" client event instead of replying.
return ns.Send("notify", []byte("day off"))
}
// Reply back to the client.
responseText := fmt.Sprintf("it is %s, do your job.", t.Weekday())
return neffos.Reply([]byte(responseText))
})
// WithTimeout adds a read timeout and a heartbeat on top of the namespaces.
websocketServer := neffos.New(gorilla.DefaultUpgrader, neffos.WithTimeout{
ReadTimeout: 60 * time.Second,
PingInterval: 20 * time.Second,
Namespaces: events,
})
router := http.NewServeMux()
router.Handle("/", websocketServer)
log.Println("Serving websockets on localhost:8080")
log.Fatal(http.ListenAndServe(":8080", router))
}func runClient() {
ctx := context.TODO()
events := make(neffos.Namespaces)
events.On("/v1", "notify", func(c *neffos.NSConn, msg neffos.Message) error {
log.Printf("Server says: %s\n", string(msg.Body))
return nil
})
// Connect to the server.
client, err := neffos.Dial(ctx,
gorilla.DefaultDialer,
"ws://localhost:8080",
events)
if err != nil {
panic(err)
}
// Connect to a namespace.
c, err := client.Connect(ctx, "/v1")
if err != nil {
panic(err)
}
fmt.Println("Please specify a date of format: mm-dd-yyyy")
for {
fmt.Print(">> ")
var date string
fmt.Scanf("%s", &date)
// Send to the server and wait for a reply to this message.
response, err := c.Ask(ctx, "workday", []byte(date))
if err != nil {
if neffos.IsCloseError(err) {
// Check if the error is a close signal,
// or make use of the `<- client.NotifyClose`
// read-only channel instead.
break
}
// >> 13-29-2019
// error received: parsing time "13-29-2019": month out of range
fmt.Printf("error received: %v\n", err)
continue
}
// >> 06-29-2019
// it is a day off!
//
// >> 06-24-2019
// it is Monday, do your job.
fmt.Println(string(response.Body))
}
}<script src="https://cdn.jsdelivr.net/npm/neffos.js@0.3/dist/neffos.global.min.js"></script>
<script>(async () => {
const conn = await neffos.dial("ws://localhost:8080", { "/v1": { notify: (ns, msg) => console.log(msg.Body) } });
const nsConn = await conn.connect("/v1");
await nsConn.ask("workday", "06-24-2019");
})();</script>Navigate to: https://github.com/kataras/neffos.js
The wiki covers every feature with a page of its own, from the first echo server to scaling out over Redis or NATS.
For detailed technical documentation, head over to pkg.go.dev. For executable code, visit the _examples directory.
See HISTORY.md for the full changelog. If you are upgrading from a v0.0.x release, read the migration guide on the wiki: Migrating-to-v0.1.0.
We'd love to see your contribution to the neffos real-time framework! For more information about contributing to the neffos project please check the CONTRIBUTING.md file.
- neffos-contrib github organisation for more programming languages support, please invite yourself.
If you discover a security vulnerability within neffos, please send an e-mail to neffos-go@outlook.com. All security vulnerabilities will be promptly addressed.
The word "neffos" has a greek origin and it is translated to "cloud" in English dictionary.
This project is licensed under the MIT license.
