lxzan / gws

simple, fast, reliable websocket server & client, supports running over tcp/kcp/unix domain socket. keywords: ws, proxy, chat, go, golang...
https://pkg.go.dev/github.com/lxzan/gws
Apache License 2.0
1.34k stars 84 forks source link

Broadcaster.Broadcast() then con.WriteClose() #90

Closed prawnsalad closed 2 months ago

prawnsalad commented 3 months ago

I'm trying to broadcast a message and then close several connections at once. Eg:

    broadcaster := gws.NewBroadcaster(payloadType, payload)
    defer broadcaster.Close()

    for _, con := range conns {
        broadcaster.Broadcast(con.Socket)
    }

    for _, con := range conns {
        con.Socket.WriteClose(1000, reason)
    }

Broadcaster.Broadcast() adds the message to a sockets writeQueue, but Conn.WriteClose() > emitError bypasses the queue and closes instantly, causing the final message from the Broadcaster to not be sent yet.

What is the correct way to wait until the broadcaster has finished?

lxzan commented 3 months ago

use WriteAsync to replace WriteClose

socket.WriteAsync(gws.OpcodeCloseConnection, nil, func(err error) {
    _ = socket.NetConn().Close()
})
prawnsalad commented 3 months ago

Thanks.. that does send the close. But it doesn't allow a custom close status and reason?

$ ws ws://localhost:5000/connect
< last text message
websocket: close 1005 (no status)

And secondly - where does it actually close the socket connection when sending OpcodeCloseConnection? I don't see that in the code.

lxzan commented 3 months ago

The coding of code and reason makes little sense.

And secondly - where does it actually close the socket connection when sending OpcodeCloseConnection? I don't see that in the code.

I updated the code above

prawnsalad commented 3 months ago

Ah.. the callback function was in a newer version than I had. I've updated and now that makes more sense, awesome.

WriteClose() supports the code and reason which I see is encoded in Conn.emitError(). Do we need to manually encode the status and reason to use it in WriteAsync()?

prawnsalad commented 3 months ago

For reference I now have this function which looks to do what I need, but I was expecting a gws function that handles the code and reason encoding for me. No problem if not though - I'm just looking for the correct way

func closeConnections(conns []*connectionlookup.Connection, code int16, reason []byte) {
    closeCode := []byte{uint8(code >> 8), uint8(code << 8 >> 8)}
    payload :=  append(closeCode, reason...)

    for _, con := range conns {
        con.Socket.WriteAsync(gws.OpcodeCloseConnection, payload, func(err error) {
            con.Socket.NetConn().Close()
        })
    }
}
lxzan commented 3 months ago

Consider adding a new WriteCloseAsync method