njones / socketio

A Modern SocketIO library for go
MIT License
64 stars 9 forks source link

v0.1.1 doesn't allow to connect to a specific namespace while using socket.io JS library #61

Closed tavancini-tc closed 1 year ago

tavancini-tc commented 1 year ago

v0.1.1 doesn't allow to connect to a specific namespace while using socket.io JS library.

  1. Install socket.io-client npm install socket.io-client@2.3.1
  2. Test script (test.js):
    
    const io = require("socket.io-client");

const socket = io("http://localhost:8003/channel", { transports: ["websocket"], reconnection: true, autoConnect: true, pingInterval: 8000, pingTimeout: 10000, connectTimeout: 10000, });

socket.on("connect", () => { console.log("Connected."); });

socket.on("message", (msg) => { console.log("Message: ", msg) })

socket.on("error", (error) => { console.log("Error: ", error); });

socket.on("disconnect", (error) => { console.log("Disconnected: ", error); });

socket.on("connect_error", (error) => { console.log("connect_error: ", error); });

socket.connect();

4. Execute running `node test.js`
3. Socket.io server (Go):
```go
package main

import (
    "log"
    "net/http"
    "time"

    sio "github.com/njones/socketio"
    eio "github.com/njones/socketio/engineio"
    eiot "github.com/njones/socketio/engineio/transport"
)

func main() {
    port := "localhost:8003"

    server := sio.NewServerV2(
        eio.WithSessionShave(1*time.Millisecond),
        eio.WithPingInterval(5*time.Second),
        eio.WithPingTimeout(1*time.Minute),
        eio.WithMaxPayload(1000000),
        eio.WithTransportOption(eiot.WithGovernor(1500*time.Microsecond, 500*time.Microsecond)),
    )

    // Root namespace
    server.OnConnect(func(socket *sio.SocketV2) error {
        log.Printf("/ %s connected.", socket.ID().String())
        return nil
    })

    // Channel namespace
    channel := server.Of("/channel")
    channel.OnConnect(func(socket *sio.SocketV2) error {
        log.Printf("/channel %s connected.", socket.ID().String())
        return nil
    })

    log.Printf("Serving port %s...\n", port)
    log.Fatal(http.ListenAndServe(port, server))
}
njones commented 1 year ago

Okay, I've found where the issue is. I should have a test and the fix out in about a day.

tavancini-tc commented 1 year ago

Hi Nika, the example in NodeJS above is not working when running v0.1.2. It doesn't allow to connect to a namespace by using a URL like "http://localhost:8003/channel" -- where the namespace is "channel".

njones commented 1 year ago

Can you tell me what the issue is when you run v0.1.2? I don't see anything immediately. I've run your test code, and it shows the two namespaces connecting as expected.

Is your issue beyond the connection stage?

tavancini-tc commented 1 year ago

The NodeJS app is not triggering the socket.on("connect" callback. And I also notice that the namespace connection doesn't happen when passing a query param:

NodeJS:

const io = require("socket.io-client");

const socket = io("http://localhost:8003/channel", {
    transports: ["websocket"],
    reconnection: true,
    autoConnect: true,
    pingInterval: 8000,
    pingTimeout: 10000,
    connectTimeout: 10000,
    query: {
        token: "token!",
    },
});

socket.on("connect", () => {
    console.log("Connected.");
});

socket.on("message", (msg) => {
    console.log("Message: ", msg)
})

socket.on("error", (error) => {
    console.log("Error: ", error);
});

socket.on("disconnect", (error) => {
    console.log("Disconnected: ", error);
});

socket.on("connect_error", (error) => {
    console.log("connect_error: ", error);
});

socket.connect();

Go:

package main

import (
    "log"
    "net/http"
    "time"

    sio "github.com/njones/socketio"
    eio "github.com/njones/socketio/engineio"
    eiot "github.com/njones/socketio/engineio/transport"
)

func main() {
    port := "localhost:8003"

    server := sio.NewServerV2(
        eio.WithSessionShave(1*time.Millisecond),
        eio.WithPingInterval(5*time.Second),
        eio.WithPingTimeout(1*time.Minute),
        eio.WithMaxPayload(1000000),
        eio.WithTransportOption(eiot.WithGovernor(1500*time.Microsecond, 500*time.Microsecond)),
    )

    //////////////////////////////////////////////////
    //////////////////////////////////////////////////
    // ROOT
    server.OnConnect(func(socket *sio.SocketV2) error {
        log.Printf("/ %s connected.", socket.ID().String())
        log.Printf("/ token: %s", socket.Request().URL.Query().Get("token"))
        return nil
    })

    //////////////////////////////////////////////////
    //////////////////////////////////////////////////
    // CHANNEL
    channel := server.Of("/channel")
    channel.OnConnect(func(socket *sio.SocketV2) error {
        log.Printf("/channel %s connected.", socket.ID().String())
        log.Printf("/channel token: %s", socket.Request().URL.Query().Get("token"))
        return nil
    })

    //////////////////////////////////////////////////
    //////////////////////////////////////////////////
    log.Printf("Serving port %s...\n", port)
    log.Fatal(http.ListenAndServe(port, server))
}
njones commented 1 year ago

This is working with the code that you supplied... but I will be putting more tests in place with JavaScript and Python clients. As well as increasing my test coverage (in go). Thanks for the bug report!

tavancini-tc commented 1 year ago

Ok, I'll run some tests tomorrow and let you know if I find anything else. Thanks!

tavancini-tc commented 1 year ago

Hi Nika, I'm still having issues with the NodeJs example. I'm using the v0.1.3 and the js example above and got: Error: { message: 'socket: invalid onconnect' }. Also, I'm not receiving a confirmation, using the python client I've built, that the channel namespace is connected.

To help you on the debugging process, see below a very simple server that I've built using a very known Socket.io python library.

requirements.txt

python-socketio
python-socketio[client]==4.6.1
tornado
asyncio

main.py

import tornado.ioloop
import tornado.web
import socketio
import urllib.parse

sio = socketio.AsyncServer(async_mode='tornado')

@sio.event
async def connect(sid, env):
    token = getToken(env)
    print("Client connected @ /:", sid, "with token:", token)

@sio.event
def disconnect(sid):
    print("Client disconnected @ /:", sid)

@sio.event(namespace="/channel")
async def connect(sid, env):
    token = getToken(env)
    print("Client connected @ /channel:", sid, "with token:", token)

@sio.event(namespace="/channel")
def disconnect(sid):
    print("Client disconnected @ /channel:", sid)

def main():
    app = tornado.web.Application(
        [
            (r"/socket.io/", socketio.get_tornado_handler(sio)),
        ],
        debug=True,
    )
    app.listen(8003)
    tornado.ioloop.IOLoop.current().start()

def getToken(env):
    if "QUERY_STRING" not in env:
        return ""
    params = dict(urllib.parse.parse_qsl(env["QUERY_STRING"]))
    if "token" in params:
        return params["token"]
    return ""

if __name__ == "__main__":
    main()

I hope that helps. Thanks!

njones commented 1 year ago

Just giving a little update. I'm getting this code fixed, and I'm adding more tests around it. So it's taking some time to put together. I'm also fixing another long standing issue, so there's some additional code changes going in that should make things easier to manage in the future.

Thanks for your patience.

tavancini-tc commented 1 year ago

Np, thanks!

tavancini-tc commented 1 year ago

Hi Nika, do you have any updates?