antoniodipinto / ikisocket

🧬 WebSocket wrapper with event management for Fiber https://github.com/gofiber/fiber. Based on Fiber WebSocket and inspired by Socket.io
MIT License
123 stars 21 forks source link

Getting a "message cannot be delivered invalid/gone connection" error. #35

Closed Anan7Codes closed 10 months ago

Anan7Codes commented 10 months ago

Describe the bug I have copy pasted the code from the custom event example. I connected to the websocket server using postman and I sent the test message and I did receive the response which is the same message that I am passing but I also get an error on my console that says "message cannot be delivered invalid/gone connection" despite getting the response.

antoniodipinto commented 10 months ago

This error can show up only when the connection is closed or you're trying to emit to a specific socket but that socket connection is closed. I've experienced some issues like that in the past with Postman, but when moved to javascript directly, the problem disappears.

My suggestion is to try with https://websocketking.com/, they have a clean javascript implementation.

In my experience, Postman had some issues with WS connections in the past, closing connection randomly.

If you still experience the issue, please add more details here

Anan7Codes commented 10 months ago

Hey thanks for the response. Kinda makes sense will try it thanks!

Anan7Codes commented 10 months ago

I'm still getting an error while doing through https://websocketking.com. Think it is an issue with my code?

package main

import (
    "github.com/gofiber/fiber/v2"
    "github.com/gofiber/fiber/v2/middleware/cors"
    "github.com/joho/godotenv"
    "log"
    "github.com/antoniodipinto/ikisocket"
    "github.com/gofiber/contrib/websocket"
    "fmt"
    "encoding/json"
)

type MessageObject struct {
    Data  string `json:"data"`
    From  string `json:"from"`
    Event string `json:"event"`
    To    string `json:"to"`
}

func setupSocketListeners(clients map[string]string) {
    ikisocket.On(ikisocket.EventConnect, func(ep *ikisocket.EventPayload) {
        fmt.Println(fmt.Sprintf("Connection event 1 - User: %s", ep.Kws.GetStringAttribute("user_id")))
    })

    ikisocket.On(ikisocket.EventMessage, func(ep *ikisocket.EventPayload) {

        fmt.Println(fmt.Sprintf("Message event - User: %s - Message: %s", ep.Kws.GetStringAttribute("user_id"), string(ep.Data)))

        message := MessageObject{}

        // Unmarshal the json message
        // {
        //  "from": "<user-id>",
        //  "to": "<recipient-user-id>",
        //  "event": "CUSTOM_EVENT",
        //  "data": "hello"
        //}
        err := json.Unmarshal(ep.Data, &message)
        if err != nil {
            fmt.Println(err)
            return
        }

        log.Print("Runs 1")

        // Fire custom event based on some
        // business logic
        if message.Event != "" {
            ep.Kws.Fire(message.Event, []byte(message.Data))
        }

        log.Print("Runs 2")

        // Emit the message directly to specified user
        err = ep.Kws.EmitTo(clients[message.To], ep.Data, ikisocket.TextMessage)
        if err != nil {
            fmt.Println(err)
        }

        log.Print("Runs 3")
    })

    // On disconnect event
    ikisocket.On(ikisocket.EventDisconnect, func(ep *ikisocket.EventPayload) {
        // Remove the user from the local clients
        delete(clients, ep.Kws.GetStringAttribute("user_id"))
        fmt.Println(fmt.Sprintf("Disconnection event - User: %s", ep.Kws.GetStringAttribute("user_id")))
    })

    // On close event
    // This event is called when the server disconnects the user actively with .Close() method
    ikisocket.On(ikisocket.EventClose, func(ep *ikisocket.EventPayload) {
        // Remove the user from the local clients
        delete(clients, ep.Kws.GetStringAttribute("user_id"))
        fmt.Println(fmt.Sprintf("Close event - User: %s", ep.Kws.GetStringAttribute("user_id")))
    })

    // On error event
    ikisocket.On(ikisocket.EventError, func(ep *ikisocket.EventPayload) {
        fmt.Println(fmt.Sprintf("Error event - User: %s", ep.Kws.GetStringAttribute("user_id")))
    })
}

func main() {
    if err := godotenv.Load(".env"); err != nil {
        panic("Error loading .env file")
    }

    clients := make(map[string]string)

    app := fiber.New()
    app.Use(cors.New())

    app.Use(func(c *fiber.Ctx) error {
        // IsWebSocketUpgrade returns true if the client
        // requested upgrade to the WebSocket protocol.
        if websocket.IsWebSocketUpgrade(c) {
            c.Locals("allowed", true)
            return c.Next()
        }
        return fiber.ErrUpgradeRequired
    })

    setupSocketListeners(clients)

    app.Get("/ws/:id", ikisocket.New(func(kws *ikisocket.Websocket) {

        // Retrieve the user id from endpoint
        userId := kws.Params("id")
        // Add the connection to the list of the connected clients
        // The UUID is generated randomly and is the key that allow
        // ikisocket to manage Emit/EmitTo/Broadcast
        clients[userId] = kws.UUID

        // Every websocket connection has an optional session key => value storage
        kws.SetAttribute("user_id", userId)

        //Write welcome message
        kws.Emit([]byte(fmt.Sprintf("Hello user: %s with UUID: %s", userId, kws.UUID)), ikisocket.TextMessage)
    }))

    log.Println("Running on port: ", config.Config("PORT"))
    app.Listen(":" + config.Config("PORT"))
}

Logs Screenshot 2023-11-06 at 10 06 04 AM

Anan7Codes commented 10 months ago

I'm testing it out locally as btw fyi.

Anan7Codes commented 10 months ago

Tried connecting it with a react app. Still getting error actually even though it is working. Not sure why the Error event is being triggered.

antoniodipinto commented 10 months ago

Thanks for all these details. I'll look into it!

Anan7Codes commented 10 months ago

Most welcome!

antoniodipinto commented 10 months ago

Hi @Anan7Codes I have a question. What kind of "to" field are you sending in this structure?

{
    "from": "<user-id>",
    "to": "<recipient-user-id>",
    "event": "CUSTOM_EVENT",
    "data": "hello"
}

Is the recipient connected?

Anan7Codes commented 10 months ago

Ah that could be it. I only changed "from" values during the test. Such a braindead moment.

antoniodipinto commented 10 months ago

Just to be sure, do a full test with "real/connected" at least 2 different ones

Anan7Codes commented 10 months ago

Hey, how can I disconnect a particular connection? The disconnect function doesn't take any parameters 🤔

antoniodipinto commented 10 months ago

Please check https://github.com/antoniodipinto/ikisocket/blob/master/ikisocket.go#L415

The kws.Close() doesn't need params, because it's part of the socket struct (kws) and basically will close itself.