A modern, fast and scalable websocket framework with elegant API written in Go

neffos chat example

build status report card view examples chat frontend pkg

About neffos

Neffos is a cross-platform real-time framework with expressive, elegant API written in Go. Neffos takes the pain out of development by easing common tasks used in real-time backend and frontend applications such as:

  • Scale-out using redis or nats*
  • Adaptive request upgradation and server dialing
  • Acknowledgements
  • Namespaces
  • Rooms
  • Broadcast
  • Event-Driven architecture
  • Request-Response architecture
  • Error Awareness
  • Asynchronous Broadcast
  • Timeouts
  • Encoding
  • Reconnection
  • Modern neffos API client for Browsers, Nodejs* and Go

Learning neffos

Qick View

Server

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 {
            if n := ns.Conn.Increment("tries"); n >= 3 && n%3 == 0 {
                // Return custom error text to the client.
                return fmt.Errorf("Why not try this one? 06-24-2019")
            } else if n >= 6 && n%2 == 0 {
                // Fire the "notify" client event.
                ns.Emit("notify", []byte("What are you doing?"))
            }
            // Return the parse error back to the client.
            return err
        }

        weekday := t.Weekday()

        if weekday == time.Saturday || weekday == time.Sunday {
            return neffos.Reply([]byte("day off"))
        }

        // Reply back to the client.
        responseText := fmt.Sprintf("it's %s, do your job.", weekday)
        return neffos.Reply([]byte(responseText))
    })

    websocketServer := neffos.New(gorilla.DefaultUpgrader, events)

    // Fire the "/v1:notify" event to all clients after server's 1 minute.
    time.AfterFunc(1*time.Minute, func() {
        websocketServer.Broadcast(nil, neffos.Message{
            Namespace: "/v1",
            Event:     "notify",
            Body:      []byte("server is up and running for 1 minute"),
        })
    })

    router := http.NewServeMux()
    router.Handle("/", websocketServer)

    log.Println("Serving websockets on localhost:8080")
    log.Fatal(http.ListenAndServe(":8080", router))
}

Go Client

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 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's a day off!
        //
        // >> 06-24-2019
        // it's Monday, do your job.
        fmt.Println(string(response.Body))
    }
}

Javascript Client

Navigate to: https://github.com/kataras/neffos.js

Neffos contains extensive and thorough wiki making it easy to get started with the framework.

For a more detailed technical documentation you can head over to our godocs. And for executable code you can always visit the _examples repository's subdirectory.

Do you like to read while traveling?

You can request a PDF version of the E-Book today and be participated in the development of neffos.

https://iris-go.com/images/neffos-book-overview.png

Contributing

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.

Security Vulnerabilities

If you discover a security vulnerability within neffos, please send an e-mail to [email protected]. All security vulnerabilities will be promptly addressed.

License

The word "neffos" has a greek origin and it is translated to "cloud" in English dictionary.

This project is licensed under the MIT license.

Owner
Gerasimos (Makis) Maropoulos
🥇 That Greek Gopher | 💨 Senior Backend Engineer at PNOĒ | 🎓My dream is to create an international IT university that will produce flawless developers!
Gerasimos (Makis) Maropoulos
Comments
  • [Question\Websocket] How to send binary data with neffos(websocket)?

    [Question\Websocket] How to send binary data with neffos(websocket)?

    #387 I have read this issue. But cannot found, websocket.Config

    Then i found that, Iris websocket library is now merged with the neffos real-time framework But i cann't find a correct way to send binary data with neffos.

    Is there any config for neffos to send binary instead of string?

  • Problem with Broadcasting

    Problem with Broadcasting

    @kataras I have Issue with

    server.Broadcast(nil,neffos.Message{
    To: userID,
    Namespace: variable.Agent,
    Event:     "notif",
    Body:      neffos.Marshal(nf),	
    })
    

    i use gobwas.DefaultUpgrader

    when i use server.Broadcast in loop it is work but But not very good. You can test yourself. i open multiple browser tap with same userId(socketId)

    server.brodacast not send all message in loop;

    you can see cron example .

    c.write(neffos.Message{
    To: userID,
    Namespace: variable.Agent,
    Event:     "notif",
    Body:      neffos.Marshal(nf),	
    })
    
    

    write() mthod work very very good but it send message to one tap (last) with same userId .

    I'm going to send it to all the tabs. with same userId

  • Problem with CORS and websockets

    Problem with CORS and websockets

    Describe the bug I have an issue with cors, when i run it the example in 2 diferents ports (3000, 3001) and i try to conect a new socket from 3001 to 3000 then the console throw the next error: WebSocket connection to 'ws://localhost:3001/echo?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjozMjEzMjF9.8waEX7-vPKACa-Soi1pQvW3Rl8QY-SUFcHKTLZI4mvU' failed: Error during WebSocket handshake: Unexpected response code: 403.

    To Reproduce Use the example server.go on the route: _examples/websocket/basic/

    package main
    
    import (
    	"log"
    
    	"github.com/kataras/iris"
    	"github.com/kataras/iris/websocket"
    
    	// Used when "enableJWT" constant is true:
    	"github.com/iris-contrib/middleware/jwt"
    )
    
    // values should match with the client sides as well.
    const enableJWT = true
    const namespace = "default"
    
    // 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)
    
    			log.Printf("[%s] connected to namespace [%s] with IP [%s]",
    				nsConn, msg.Namespace,
    				ctx.RemoteAddr())
    			return nil
    		},
    		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 *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))
    
    			// Write message back to the client message owner with:
    			// nsConn.Emit("chat", msg)
    			// Write message to all except this client with:
    			nsConn.Conn.Server().Broadcast(nsConn, msg)
    			return nil
    		},
    	},
    }
    
    func main() {
    	app := iris.New()
    	websocketServer := websocket.New(
    		websocket.DefaultGorillaUpgrader, /* DefaultGobwasUpgrader can be used too. */
    		serverEvents)
    
    	j := jwt.New(jwt.Config{
    		// Extract by the "token" url,
    		// so the client should dial with ws://localhost:8080/echo?token=$token
    		Extractor: jwt.FromParameter("token"),
    
    		ValidationKeyGetter: func(token *jwt.Token) (interface{}, error) {
    			return []byte("My Secret"), nil
    		},
    
    		// When set, the middleware verifies that tokens are signed
    		// with the specific signing algorithm
    		// If the signing method is not constant the
    		// `Config.ValidationKeyGetter` callback field can be used
    		// to implement additional checks
    		// Important to avoid security issues described here:
    		// https://auth0.com/blog/2015/03/31/critical-vulnerabilities-in-json-web-token-libraries/
    		SigningMethod: jwt.SigningMethodHS256,
    	})
    
    	idGen := func(ctx iris.Context) string {
    		if username := ctx.GetHeader("X-Username"); username != "" {
    			return username
    		}
    
    		return websocket.DefaultIDGenerator(ctx)
    	}
    
    	// serves the endpoint of ws://localhost:8080/echo
    	// with optional custom ID generator.
    	websocketRoute := app.Get("/echo", websocket.Handler(websocketServer, idGen))
    
    	if enableJWT {
    		// Register the jwt middleware (on handshake):
    		websocketRoute.Use(j.Serve)
    		// OR
    		//
    		// Check for token through the jwt middleware
    		// on websocket connection or on any event:
    		/* 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
    			// and will not allow it to connect to the websocket server at all.
    			return err
    		}
    
    		user := ctx.Values().Get("jwt").(*jwt.Token)
    		// or just: user := j.Get(ctx)
    
    		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.
    	app.Get("/", func(ctx iris.Context) {
    		ctx.ServeFile("./browser/index.html", false)
    	})
    
    	// serves the npm browser websocket client usage example.
    	app.HandleDir("/browserify", "./browserify")
    
    	app.Run(iris.Addr(":8080"), iris.WithoutServerError(iris.ErrServerClosed))
    }
    

    Expected behavior I would like to make petitions from the 2 servers

    Posible fix To catch this i made a middleware function wich delete the origin header (but this will be a rellay bad practice), code above:

            app.Use(func(ctx iris.Context) {
    		ctx.Request().Header.Del("Origin")
    		ctx.Next()
    	})
    
  • [BUG] the neffos server hang up whole goroutines

    [BUG] the neffos server hang up whole goroutines

    Describe the bug After upgrade lastest version, it still happened on productions. Debugging by dlv tool, I found the neffos block whole process.

    Screenshots 4011585729190_ pic_hd 4021585729215_ pic_hd

    Desktop (please complete the following information):

    • OS: Centos
    • Version 7.7

    Could you have time to handle this questions?

  • [BUG] the process hang up, CPU become 100%

    [BUG] the process hang up, CPU become 100%

    Describe the bug

    I use neffos as WebSocket server to handler all WebSocket connects from browser. It is running well when first deploy the web Application on production server. However it became weird at some moment. The CPU became 100% usage, and the server could not handle any incoming WebSocket connection. Debugging by dlv tool, I found the neffos conn's goroutine block main process. I don't know how reproduce this bug, but it happened several times on productions environment.

    To Reproduce

    Expected behavior I hope how to avoid this situation or this is the bug.

    Screenshots image

    image

    Desktop (please complete the following information):

    • OS: Centos
    • Version 7
  •   在v12版本中,neffos的websocket在前后端分离的情况下提示403 In v12 version, the websocket of neffos prompts 403 when the front and back ends are separated

    在v12版本中,neffos的websocket在前后端分离的情况下提示403 In v12 version, the websocket of neffos prompts 403 when the front and back ends are separated

    WebSocket connection to 'ws://127.0.0.1:8888/echo?X-Websocket-Header-X-Username=yhm' failed: Error during WebSocket handshake: Unexpected response code: 403

  • Can you provide more programming language examples

    Can you provide more programming language examples

    I just use example in https://github.com/kataras/iris/blob/master/_examples/websocket/basic/server.go

    After run this server, I cannot access from python script.

    The Python Script:

    from websocket import create_connection
    ws = create_connection("ws://127.0.0.1:8080/echo?X-Websocket-Header-X-Username=ok&token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjozMjEzMjF9.8waEX7-vPKACa-Soi1pQvW3Rl8QY-SUFcHKTLZI4mvU")
    print("Sending 'Hello, World'...")
    ws.send("Hello, World")
    print("Sent")
    print("Receiving...")
    result =  ws.recv()
    print("Received '%s'" % result)
    ws.close()
    

    And the result shows that script can establish a connection, but when the client begins to receive , it shows that "WebSocketConnectionClosedException: Connection is already closed."

    This problem also happens when I serve "./broswer/index.html" at another port using another web quick server (the index.html file has been modified so that the websocket port is still the same as server-side, that is, 8080.), it shows that

    neffos.min.js:1 WebSocket connection to 'ws://0.0.0.0:8080/echo?X-Websocket-Header-X-Username=jhi&token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjozMjEzMjF9.8waEX7-vPKACa-Soi1pQvW3Rl8QY-SUFcHKTLZI4mvU' failed: Error during WebSocket handshake: Unexpected response code: 403
    

    So what should I do? And can you help me with a python websocket client script? Because I will use python script to listen and handle the websocket broadcasting message. Thank you.

  • [BUG]Binary data contains

    [BUG]Binary data contains ";" will be droped!

    Sorry to bother you. But i have found the bug. It is in neffos.js.

    I'm using protobuf with neffos.js. The data that protobuf make counld contain ;. So that my message will be drop in neffos.js in here.

      var isArrayBuffer = data instanceof ArrayBuffer;
        var dts;
    
        console.log(isArrayBuffer)
    
        if (isArrayBuffer) {
            var arr = new Uint8Array(data);
            var sepCount = 1;
            var lastSepIndex = 0;
            for (var i = 0; i < arr.length; i++) {
                if (arr[i] == messageSeparatorCharCode) { // sep char.
                    sepCount++;
                    lastSepIndex = i;
                }
            }
           // Drop here!!!!!!!!!!!!
            if (sepCount != validMessageSepCount) {
                msg.isInvalid = true;
                console.log("return at validMessageSepCount")
                return msg;
            }
            dts = splitN(textDecoder.decode(arr.slice(0, lastSepIndex)), messageSeparator, validMessageSepCount - 2);
            dts.push(data.slice(lastSepIndex + 1, data.length));
            msg.SetBinary = true;
        }
        else {
            dts = splitN(data, messageSeparator, validMessageSepCount - 1);
        }
    

    I thank it is a bug. Cannot just split message by ;.

    Here is the reproducible code.

    Server

    package main
    
    import (
    	"github.com/kataras/iris"
    	"fmt"
    	"github.com/kataras/iris/websocket"
    	"github.com/kataras/neffos"
    	"time"
    )
    
    // 全局变量
    var page = struct {
        Title string
    }{"Collector"}
    
    func main(){
    	app := iris.New()
    
    	ws_server := startWebSocketServer(app)
    
    	go pub_thread(ws_server)
    
    	app.RegisterView(iris.HTML("./static", ".html"))
    	app.Get("/" ,func(ctx iris.Context){
    		ctx.ViewData("Page", page)
    		ctx.View("index.html")
    	})
    
    	app.HandleDir("/", "./static")	
        app.Run(iris.Addr(":5000"), iris.WithoutPathCorrection)
    }
    
    var serverEvents = websocket.Namespaces{
    	"default": 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)
    
    			fmt.Printf("[%s] connected to namespace [%s] with IP [%s]\n",
    				nsConn, msg.Namespace,
    				ctx.RemoteAddr())
    			return nil
    		},
    		websocket.OnNamespaceDisconnect: func(nsConn *websocket.NSConn, msg websocket.Message) error {
    			fmt.Printf("[%s] disconnected from namespace [%s]\n", nsConn, msg.Namespace)
    			return nil
    		},
    		"stream": func(nsConn *websocket.NSConn, msg websocket.Message) error {
    			// room.String() returns -> NSConn.String() returns -> Conn.String() returns -> Conn.ID()
    			fmt.Printf("[%s] sent: %s", nsConn, string(msg.Body))
    
    			// Write message back to the client message owner with:
    			// nsConn.Emit("chat", msg)
    			// Write message to all except this client with:
    			nsConn.Conn.Server().Broadcast(nsConn, msg)
    			return nil
    		},
    	},
    }
    
    func startWebSocketServer(app *iris.Application) *neffos.Server{
    	server := websocket.New(websocket.DefaultGorillaUpgrader, serverEvents)
    	server.OnConnect = func(c *websocket.Conn) error {
    		fmt.Printf("[%s] connected to the server.\n", c)
    		
    		return nil
    	}
    
    	server.OnDisconnect = func(c *websocket.Conn){
    		fmt.Printf("[%s] disconnected from the server.", c)
    	}
    
    	fmt.Printf("Listening on: %d\nPress CTRL/CMD+C to interrupt.\n", 5000)
    
    	idGen := func(ctx iris.Context) string {
    		if username := ctx.GetHeader("X-Username"); username != "" {
    			return username
    		}
    
    		return websocket.DefaultIDGenerator(ctx)
    	}
    
    	app.Get("/stream", websocket.Handler(server, idGen))
    
    	return server
    }
    
    func pub_thread(serve *neffos.Server){
    	png:= [...] byte{';',';',';',';',';'}
    	slice := png[:]
    	for{
    		serve.Broadcast(nil, neffos.Message{SetBinary: true,  Body:slice, Namespace: "default"})
    		time.Sleep(1*time.Second)
    	}
    }
    

    Client

    <html>
        <button> useless button</button>
    
        <script src="https://cdn.jsdelivr.net/npm/neffos.js@latest/dist/neffos.js"></script>
        <script>
        
            var scheme = document.location.protocol == "https:" ? "wss" : "ws";
            var port = document.location.port ? ":" + document.location.port : "";
            var wsURL = scheme + "://" + document.location.hostname + port + "/stream";
            
            function handleError(reason) {
                console.log(reason);
            }
            
            function handleNamespaceConnectedConn(nsConn) {
    
            }
            // const username = window.prompt("Your username?");
            async function runExample() {
                // You can omit the "default" and simply define only Events, the namespace will be an empty string"",
                // however if you decide to make any changes on this example make sure the changes are reflecting inside the ../server.go file as well.
                try {
                    const conn = await neffos.dial(wsURL, {
                        default: { // "default" namespace.
                            _OnNamespaceConnected: function (nsConn, msg) {
                                handleNamespaceConnectedConn(nsConn)
                            },
                            _OnNamespaceDisconnect: function (nsConn, msg) {
                            },
                            stream: function (nsConn, msg) { // "stream" event.
                                console.log(msg.Body);
                                console.log(msg)
                            }
                        }
                    },{
                        headers: {
                            "X-Username": "",
                        }
                    });
                    // You can either wait to conenct or just conn.connect("connect")
                    // and put the `handleNamespaceConnectedConn` inside `_OnNamespaceConnected` callback instead.
                    // const nsConn = await conn.connect("default");
                    // nsConn.emit(...); handleNamespaceConnectedConn(nsConn);
                    conn.connect("default");
                } catch (err) {
                    handleError(err);
                }
            }
    
            runExample()
        </script>
    </html>
    
  • Is neffos.Conn.Socket().WriteText() Atomic?

    Is neffos.Conn.Socket().WriteText() Atomic?

    If I start several goroutines calling neffos.Conn.Socket().WriteText(text, timeout) concurrently, would the texts be blended? Thanks for your attention!

  • Hello, excuse me, I want to transfer my application to neffos. How does neffos send messages to websocket thread in web thread? Just like the socket.io-emitter package of node.js socketio

    Hello, excuse me, I want to transfer my application to neffos. How does neffos send messages to websocket thread in web thread? Just like the socket.io-emitter package of node.js socketio

    Hello, excuse me, I want to transfer my application to neffos. How does neffos send messages to websocket thread in web thread? Just like the socket.io-emitter package of node.js socketio

  • [question] Why brower loop print re-connected and send head endpoint request?

    [question] Why brower loop print re-connected and send head endpoint request?

    I'm use neffos.js code :

    image

    But i'm find console loop print re-connected , time is i'm set reconnect , This is keeplive?

    image

    And find console print send HEAD methods to set endpoint , I'm set iris to Any but is not work

    image

    The Head request how to success?

    I'm client how to keeplive? if use reconnect , I'm iris log all reconnected log , is not good~

    thanks for help ~ @kataras

  • How to assign some values to a socket connection?

    How to assign some values to a socket connection?

    Is there any option to assign some values to socket (like in node.js web socket )?When a client is connected, we can set some room id , seat id and status to socket and check its value when its disconnected or sending any messages.

    like socket.status = "connected" socket.room_id = "room1" socket.seat_id = "seat1"

  • how to react on native mode when a client or a server disconnected

    how to react on native mode when a client or a server disconnected

    as the title,when i connect to server with native mode (because server is not golang),so i can implement it as https://github.com/kataras/neffos/wiki/Native-messages,but now i wanna know how can i know that the server is disconnected,thank you

  • [BUG] basic in example, broswer message must be sent twice

    [BUG] basic in example, broswer message must be sent twice

    Describe the bug ① in app.js 45line toId is not defined! ②using example basic, broswer every send message need two times it worked, why it happend? server only recived An odd number of times message,the phenomena is every stable

    Note that if a bug is a browser-relative please report it at the neffos.js repository instead. Thanks! chrome and firefox

    To Reproduce Steps to reproduce the behavior: reproduce:https://github.com/kataras/neffos/tree/master/_examples/basic

  • [BUG] Broadcast deadlocks when concurrency

    [BUG] Broadcast deadlocks when concurrency

    Describe the bug I found in the actual application that the Broadcast() method will cause a deadlock

    To Reproduce Steps to reproduce the behavior:

    1. When nsConn is disconnected, it will cause Server.Broadcast() internal blocking'' when broadcasting a message on the websocket.OnNamespaceDisconnect or websocket.OnRoomLeft event
    2. code
    package main
    
    import (
    	"fmt"
    	gorilla "github.com/gorilla/websocket"
    	"github.com/kataras/iris/v12"
    	"github.com/kataras/iris/v12/websocket"
    	"github.com/kataras/neffos"
    	"net/http"
    	"time"
    )
    
    func main() {
    	namespace, room, event := "test", "ttt", "ch"
    	chatServer := websocket.New(
    		websocket.GorillaUpgrader(gorilla.Upgrader{
    			ReadBufferSize:  1024,
    			WriteBufferSize: 1024,
    			// todo 允许所有的CORS 跨域请求,正式环境可以关闭
    			CheckOrigin: func(r *http.Request) bool {
    				return true
    			},
    		}),
    		websocket.WithTimeout{
    			WriteTimeout: time.Second * 60,
    			ReadTimeout:  time.Second * 60,
    			Namespaces: websocket.Namespaces{
    				namespace: websocket.Events{
    					websocket.OnNamespaceConnected: func(nsConn *websocket.NSConn, msg websocket.Message) error {
    						fmt.Println("OnNamespaceConnected", nsConn.Conn.ID())
    						nsConn.JoinRoom(nil, room)
    						return nil
    					},
    					websocket.OnNamespaceDisconnect: func(nsConn *websocket.NSConn, msg websocket.Message) error {
    						fmt.Println("OnNamespaceDisconnect", nsConn.Conn.ID())
    						// Todo The broadcast here will cause blocking in `server.start()`
    						//nsConn.Conn.Server().Broadcast(nsConn, neffos.Message{
    						//	Body:      []byte("我离开了room" + nsConn.Conn.ID()),
    						//	Namespace: namespace,
    						//	Room:      room,
    						//	To:        "",
    						//	Event:     event,
    						//})
    
    						// Todo Add a certain delay and everything is normal
    						time.AfterFunc(time.Millisecond*50, func() {
    							nsConn.Conn.Server().Broadcast(nsConn, neffos.Message{
    								Body:      []byte("我离开了room" + nsConn.Conn.ID()),
    								Namespace: namespace,
    								Room:      room,
    								To:        "",
    								Event:     event,
    							})
    						})
    
    						return nil
    					},
    					websocket.OnRoomJoined: func(nsConn *websocket.NSConn, msg websocket.Message) error {
    						fmt.Println("OnRoomJoined", nsConn.Conn.ID())
    						nsConn.Emit(event, []byte("我是单独消息"))
    						nsConn.Conn.Server().Broadcast(nil, neffos.Message{
    							Body:      []byte("我加入了room" + nsConn.Conn.ID()),
    							Namespace: namespace,
    							Room:      room,
    							To:        "",
    							Event:     event,
    						})
    
    						return nil
    					},
    					websocket.OnRoomLeft: func(nsConn *websocket.NSConn, msg websocket.Message) error {
    						fmt.Println("OnRoomLeft", nsConn.Conn.ID(), nsConn.Conn.IsClosed())
    						// Todo The broadcast here will cause blocking in `server.start()`
    						//nsConn.Conn.Server().Broadcast(nsConn, neffos.Message{
    						//	Body:      []byte("我离开了room" + nsConn.Conn.ID()),
    						//	Namespace: namespace,
    						//	Room:      room,
    						//	To:        "",
    						//	Event:     event,
    						//})
    
    						// Todo Add a certain delay and everything is normal
    						time.AfterFunc(time.Millisecond*50, func() {
    							nsConn.Conn.Server().Broadcast(nsConn, neffos.Message{
    								Body:      []byte("我离开了room" + nsConn.Conn.ID()),
    								Namespace: namespace,
    								Room:      room,
    								To:        "",
    								Event:     event,
    							})
    						})
    						return nil
    					},
    				},
    			},
    		},
    	)
    
    	app := iris.New()
    	app.Get("/e", websocket.Handler(chatServer, func(ctx iris.Context) string {
    		return ctx.URLParam("id")
    	}))
    
    	// Todo If you don't want to lose messages, please turn it on
    	chatServer.SyncBroadcaster = true
    
    	app.Listen("0.0.0.0:8090")
    }
    
    
    
  • [BUG] Socket  missed a lot of msgs

    [BUG] Socket missed a lot of msgs

    Describe the bug neffos.Conn.Socket().ReadData(0) There is a case of missing messages, for example, I send 1-10, but it only receives 2,3

    To Reproduce

    package main
    
    import (
    	"fmt"
    	websocket2 "github.com/gorilla/websocket"
    	"github.com/kataras/iris/v12"
    	"github.com/kataras/iris/v12/context"
    	"github.com/kataras/iris/v12/websocket"
    	"github.com/kataras/neffos"
    	"github.com/kataras/neffos/gorilla"
    	uuid "github.com/satori/go.uuid"
    	"log"
    	"net/http"
    	"time"
    )
    
    var ws *neffos.Server
    
    func main() {
    	upgrade := websocket2.Upgrader{
    		// 允许跨域
    		CheckOrigin: func(r *http.Request) bool {
    			return true
    		},
    	}
    
    	ws = neffos.New(gorilla.Upgrader(upgrade), neffos.Namespaces{})
    	app := iris.New()
    	app.Get("/websocket_endpoint", Hello)
    	log.Fatal(app.Run(iris.Addr(":9999")))
    }
    
    // Hello
    func Hello(ctx iris.Context) {
    	conn := websocket.Upgrade(ctx, func(ctx context.Context) string {
    		return uuid.NewV4().String()
    	}, ws)
    	go production(conn)
    	go consumer(conn)
    }
    
    // production 生产
    func production(conn *neffos.Conn) {
    	for {
    		time.Sleep(1 * time.Second)
    		if err := conn.Socket().WriteText([]byte("111"), 0); err != nil {
    			if conn.IsClosed() {
    				return
    			}
    			fmt.Println("err: " + err.Error())
    		}
    	}
    }
    
    // consumer 消费 TODO 存在漏接消息的情况
    func consumer(conn *neffos.Conn) {
    	for {
    		data, _, err := conn.Socket().ReadData(0)
    		if err != nil {
    			if conn.IsClosed() {
    				return
    			}
    			fmt.Println("consumer err: " + err.Error())
    			continue
    		}
    		fmt.Println(fmt.Sprintf("consumer data: %v", string(data)))
    	}
    }
    
    

    Expected behavior

    Screenshots I missed a lot of msgs

Encrypted-websocket-chat - Encrypted websocket chat using golang

Encrypted websocket chat First version written in python This version should be

Sep 15, 2022
Websocket-chat - A simple websocket chat application
Websocket-chat - A simple websocket chat application

WebSocket Chat App This is a simple chat app based on websockets. It allows user

Jan 25, 2022
A fast, well-tested and widely used WebSocket implementation for Go.

Gorilla WebSocket Gorilla WebSocket is a Go implementation of the WebSocket protocol. Documentation API Reference Chat example Command example Client

Jan 2, 2023
:notes: Minimalist websocket framework for Go
:notes: Minimalist websocket framework for Go

melody ?? Minimalist websocket framework for Go. Melody is websocket framework based on github.com/gorilla/websocket that abstracts away the tedious p

Dec 23, 2022
Comet - Minimalist websocket framework for Go

Comet : fork Melody ?? Minimalist websocket framework for Go. Comet is websocket

Feb 8, 2022
API that upgrades connection to use websocket. Contains server and client and testing how they communicate

Websocket Test API How to execute First run server using: make run-server. Then run many client instances with: make run-client. Then start typing in

Dec 25, 2021
Websocket server. Get data from provider API, clean data and send to websoket, when it's changed.

Описание Сервис получает данные по киберспортивным матчам CS:GO от провайдера, структурирует, очищает от лишнего и отправляет всем активным вебсокет к

Apr 6, 2022
WebSocket Command Line Client written in Go

ws-cli WebSocket Command Line Client written in Go Installation go get github.com/kseo/ws-cli Usage $ ws-cli -url ws://echo.websocket.org connected (

Nov 12, 2021
A tiny command line websocket client written in Go

wsc A simplistic tool for sending and receiving websocket messages from a command line. Mainly useful to test websocket servers. Getting started: $ go

Jan 12, 2022
A websocket powered discord wrapper for Sugaroid written in golang

sg-discord A thin discord wrapper built on top of Sugaroid Websocket implementation. Build go build . Run export DISCORD_BOT_TOKEN="supersecrettoken"

Dec 30, 2021
A websocket powered telegram wrapper for Sugaroid written in golang

sg-telegram A thin telegram wrapper built on top of Sugaroid Websocket

Nov 4, 2021
Websocket market data capture utility for coinbase (written in Go)

mdcapture Websocket market data capture utility for coinbase (written in Go) Features Live subscription and capture of Coinbase market data Intended f

Jan 6, 2022
Websocket API Gateway that allows to subscribe on notifications about price changes of financial instruments

websocket-api-gateway Websocket API Gateway that allows to subscribe on notifications about price changes of financial instruments To test connection

Dec 5, 2021
Minimal and idiomatic WebSocket library for Go

websocket websocket is a minimal and idiomatic WebSocket library for Go. Install go get nhooyr.io/websocket Highlights Minimal and idiomatic API First

Dec 31, 2022
Go-distributed-websocket - Distributed Web Socket with Golang and Redis
Go-distributed-websocket - Distributed Web Socket with Golang and Redis

go-distributed-websocket Distributed Web Socket with Golang and Redis Dependenci

Oct 13, 2022
Turn any program that uses STDIN/STDOUT into a WebSocket server. Like inetd, but for WebSockets.

websocketd websocketd is a small command-line tool that will wrap an existing command-line interface program, and allow it to be accessed via a WebSoc

Dec 31, 2022
proxy your traffic through CDN using websocket

go-cdn2proxy proxy your traffic through CDN using websocket what does it do example server client thanks what does it do you can use this as a library

Dec 7, 2022
Chat bots (& more) for Zoom by figuring out their websocket protocol
Chat bots (& more) for Zoom by figuring out their websocket protocol

zoomer - Bot library for Zoom meetings Good bot support is part of what makes Discord so nice to use. Unfortunately, the official Zoom API is basicall

Dec 14, 2022
Tiny WebSocket library for Go.

RFC6455 WebSocket implementation in Go.

Dec 28, 2022