From f30272deae514d761da384b1e6fc1d542c6beb04 Mon Sep 17 00:00:00 2001 From: Antonio Di Pinto Date: Sun, 10 Mar 2024 07:47:55 +0200 Subject: [PATCH 1/3] Added example for socket io chat --- socketio/go.mod | 26 +++++++++++ socketio/go.sum | 48 +++++++++++++++++++ socketio/main.go | 119 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 193 insertions(+) create mode 100644 socketio/go.mod create mode 100644 socketio/go.sum create mode 100644 socketio/main.go diff --git a/socketio/go.mod b/socketio/go.mod new file mode 100644 index 0000000000..2349c2a6ef --- /dev/null +++ b/socketio/go.mod @@ -0,0 +1,26 @@ +module main + +go 1.22.0 + +require ( + github.com/gofiber/contrib/socketio v1.0.0 + github.com/gofiber/contrib/websocket v1.3.0 + github.com/gofiber/fiber/v2 v2.52.2 +) + +require ( + github.com/andybalholm/brotli v1.0.5 // indirect + github.com/fasthttp/websocket v1.5.7 // indirect + github.com/google/uuid v1.5.0 // indirect + github.com/klauspost/compress v1.17.3 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + github.com/mattn/go-runewidth v0.0.15 // indirect + github.com/rivo/uniseg v0.4.4 // indirect + github.com/savsgio/gotils v0.0.0-20230208104028-c358bd845dee // indirect + github.com/valyala/bytebufferpool v1.0.0 // indirect + github.com/valyala/fasthttp v1.51.0 // indirect + github.com/valyala/tcplisten v1.0.0 // indirect + golang.org/x/net v0.18.0 // indirect + golang.org/x/sys v0.15.0 // indirect +) diff --git a/socketio/go.sum b/socketio/go.sum new file mode 100644 index 0000000000..4f43246128 --- /dev/null +++ b/socketio/go.sum @@ -0,0 +1,48 @@ +github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs= +github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/fasthttp/websocket v1.5.7 h1:0a6o2OfeATvtGgoMKleURhLT6JqWPg7fYfWnH4KHau4= +github.com/fasthttp/websocket v1.5.7/go.mod h1:bC4fxSono9czeXHQUVKxsC0sNjbm7lPJR04GDFqClfU= +github.com/gofiber/contrib/socketio v1.0.0 h1:Wanb9hsiuBg69IIDkes0mmKv23TsW+PxZQ/gBBqFwko= +github.com/gofiber/contrib/socketio v1.0.0/go.mod h1:I8TtbDgnvysM+VJckHbuMAZGFO8qDokuHysXgcx/JzI= +github.com/gofiber/contrib/websocket v1.3.0 h1:XADFAGorer1VJ1bqC4UkCjqS37kwRTV0415+050NrMk= +github.com/gofiber/contrib/websocket v1.3.0/go.mod h1:xguaOzn2ZZ759LavtosEP+rcxIgBEE/rdumPINhR+Xo= +github.com/gofiber/fiber/v2 v2.52.2 h1:b0rYH6b06Df+4NyrbdptQL8ifuxw/Tf2DgfkZkDaxEo= +github.com/gofiber/fiber/v2 v2.52.2/go.mod h1:KEOE+cXMhXG0zHc9d8+E38hoX+ZN7bhOtgeF2oT6jrQ= +github.com/google/uuid v1.5.0 h1:1p67kYwdtXjb0gL0BPiP1Av9wiZPo5A8z2cWkTZ+eyU= +github.com/google/uuid v1.5.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/klauspost/compress v1.17.3 h1:qkRjuerhUU1EmXLYGkSH6EZL+vPSxIrYjLNAK4slzwA= +github.com/klauspost/compress v1.17.3/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U= +github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= +github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis= +github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= +github.com/savsgio/gotils v0.0.0-20230208104028-c358bd845dee h1:8Iv5m6xEo1NR1AvpV+7XmhI4r39LGNzwUL4YpMuL5vk= +github.com/savsgio/gotils v0.0.0-20230208104028-c358bd845dee/go.mod h1:qwtSXrKuJh/zsFQ12yEE89xfCrGKK63Rr7ctU/uCo4g= +github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= +github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= +github.com/valyala/fasthttp v1.51.0 h1:8b30A5JlZ6C7AS81RsWjYMQmrZG6feChmgAolCl1SqA= +github.com/valyala/fasthttp v1.51.0/go.mod h1:oI2XroL+lI7vdXyYoQk03bXBThfFl2cVdIA3Xl7cH8g= +github.com/valyala/tcplisten v1.0.0 h1:rBHj/Xf+E1tRGZyWIWwJDiRY0zc1Js+CV5DqwacVSA8= +github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc= +golang.org/x/net v0.18.0 h1:mIYleuAkSbHh0tCv7RvjL3F6ZVbLjq4+R7zbOn3Kokg= +golang.org/x/net v0.18.0/go.mod h1:/czyP5RqHAH4odGYxBJ1qz0+CE5WZ+2j1YgoEo8F2jQ= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= +golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/socketio/main.go b/socketio/main.go new file mode 100644 index 0000000000..a18161616c --- /dev/null +++ b/socketio/main.go @@ -0,0 +1,119 @@ +// 🚀 Fiber is an Express inspired web framework written in Go with 💖 +// 📌 API Documentation: https://docs.gofiber.io +// 📝 Github Repository: https://github.com/gofiber/fiber + +// SocketIO Chat Example + +package main + +import ( + "encoding/json" + "fmt" + "github.com/gofiber/contrib/socketio" + "github.com/gofiber/contrib/websocket" + "github.com/gofiber/fiber/v2" + "log" +) + +// MessageObject Basic chat message object +type MessageObject struct { + Data string `json:"data"` + From string `json:"from"` + To string `json:"to"` +} + +func main() { + + // The key for the map is message.to + clients := make(map[string]string) + + // Start a new Fiber application + app := fiber.New() + + // Setup the middleware to retrieve the data sent in first GET request + 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 + }) + + // Multiple event handling supported + socketio.On(socketio.EventConnect, func(ep *socketio.EventPayload) { + fmt.Println(fmt.Sprintf("Connection event 1 - User: %s", ep.Kws.GetStringAttribute("user_id"))) + }) + socketio.On(socketio.EventConnect, func(ep *socketio.EventPayload) { + fmt.Println(fmt.Sprintf("Connection event 2 - User: %s", ep.Kws.GetStringAttribute("user_id"))) + }) + + // On message event + socketio.On(socketio.EventMessage, func(ep *socketio.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": "", + // "to": "", + // "data": "hello" + //} + err := json.Unmarshal(ep.Data, &message) + if err != nil { + fmt.Println(err) + return + } + + // Emit the message directly to specified user + err = ep.Kws.EmitTo(clients[message.To], ep.Data) + if err != nil { + fmt.Println(err) + } + }) + + // On disconnect event + socketio.On(socketio.EventDisconnect, func(ep *socketio.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 + socketio.On(socketio.EventClose, func(ep *socketio.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 + socketio.On(socketio.EventError, func(ep *socketio.EventPayload) { + fmt.Println(fmt.Sprintf("Error event - User: %s", ep.Kws.GetStringAttribute("user_id"))) + }) + + app.Get("/ws/:id", socketio.New(func(kws *socketio.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 + // socketio to manage Emit/EmitTo/Broadcast + clients[userId] = kws.UUID + + // Every websocket connection has an optional session key => value storage + kws.SetAttribute("user_id", userId) + + //Broadcast to all the connected users the newcomer + kws.Broadcast([]byte(fmt.Sprintf("New user connected: %s and UUID: %s", userId, kws.UUID)), true) + //Write welcome message + kws.Emit([]byte(fmt.Sprintf("Hello user: %s with UUID: %s", userId, kws.UUID))) + })) + + log.Fatal(app.Listen(":3000")) + +} From 0e90c36af09d8cb1df9ae54917911dad557dc81b Mon Sep 17 00:00:00 2001 From: Antonio Di Pinto Date: Sun, 10 Mar 2024 07:48:50 +0200 Subject: [PATCH 2/3] Added socketio in README --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 6c6872d1c4..ba6ff178ce 100644 --- a/README.md +++ b/README.md @@ -54,6 +54,7 @@ Here you can find the most **delicious** recipes to cook delicious meals using o - [Server-Sent Events](/sse) - [Sessions-SQLite3](/sessions-sqlite3) - [Single Page Application Example](/spa) +- [Socket.io](/socketio) - [Sqlboiler](/sqlboiler) - [Sqlc](/sqlc) - [Streaming of the Request Body](/stream-request-body) From 82e4e929998f29a8c9fabb7863ba858c70601c7b Mon Sep 17 00:00:00 2001 From: Antonio Di Pinto Date: Tue, 12 Mar 2024 15:51:50 +0200 Subject: [PATCH 3/3] Added README.md for socket.io --- socketio/README.md | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 socketio/README.md diff --git a/socketio/README.md b/socketio/README.md new file mode 100644 index 0000000000..21fbaf320c --- /dev/null +++ b/socketio/README.md @@ -0,0 +1,20 @@ +### Disclaimer: +__This an example of a basic chat, connecting multiple sockets.__ + +## Websocket Chat Example +With this example, you can create a simple chatroom using Websockets. This example supports multiple users and allows them to send messages to each other. + +### Connect to the websocket +``` +ws://localhost:3000/ws/ +``` +### Message object example + +``` +{ +"from": "", +"to": "", +"data": "hello" +} +``` +