Last active
January 7, 2025 02:18
-
-
Save crosstyan/47e7d3fa1b9e4716c0d6c76760a4a70c to your computer and use it in GitHub Desktop.
A websocket based multiroom chat using golang and gin
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"log" | |
"net/http" | |
"net/url" | |
"github.com/gin-gonic/gin" | |
"github.com/google/uuid" | |
//"github.com/gorilla/mux" | |
//The name mux stands for "HTTP request multiplexer". | |
"github.com/gorilla/websocket" | |
) | |
var sessionGroupMap = make(map[string]map[uuid.UUID]*websocket.Conn) | |
func main() { | |
app := gin.Default() | |
app.Any("thread", wsHandler) //callback | |
app.Run("localhost:8081") | |
} | |
var upgrader = websocket.Upgrader{ | |
//Solve "request origin not allowed by Upgrader.CheckOrigin" | |
CheckOrigin: func(r *http.Request) bool { | |
return true | |
}, | |
} | |
//w http.ResponseWriter, r *http.Request | |
func wsHandler(ginContext *gin.Context) { //Usually use c *gin.Context | |
wsSession, err := upgrader.Upgrade(ginContext.Writer, ginContext.Request, nil) | |
if err != nil { | |
log.Fatal(err) | |
} | |
uid := uuid.New() | |
wsURL := ginContext.Request.URL | |
wsURLParam, err := url.ParseQuery(wsURL.RawQuery) | |
if err != nil { | |
wsSession.Close() | |
log.Println(err) | |
} | |
if _, ok := wsURLParam["name"]; ok { | |
threadName := wsURLParam["name"][0] | |
log.Printf("A client connect to %s", threadName) | |
if _, ok := sessionGroupMap[threadName]; ok { //Maybe needn't this if? | |
sessionGroupMap[threadName][uid] = wsSession | |
} else { | |
sessionGroupMap[threadName] = make(map[uuid.UUID]*websocket.Conn) | |
sessionGroupMap[threadName][uid] = wsSession | |
} | |
defer wsSession.Close() | |
echo(wsSession, threadName, uid) | |
} else { | |
wsSession.Close() | |
} | |
} | |
func echo(wsSession *websocket.Conn, threadName string, uid uuid.UUID) { | |
//Message Type: | |
//Details in | |
//https://godoc.org/github.com/gorilla/websocket#pkg-constants | |
//TextMessage=1 | |
//BinaryMessage=2 | |
for { //An endlessloop | |
messageType, messageContent, err := wsSession.ReadMessage() | |
if messageType == 1 { | |
log.Printf("Recv:%s from %s", messageContent, threadName) | |
broadcast(threadName, messageContent) | |
} | |
if err != nil { | |
wsSession.Close() | |
delete(sessionGroupMap[threadName], uid) | |
//I don't think it's recommended to deal with connection closing like this, but it's the easiest way. | |
//Or you have to maintain a hashmap to indicate if a session is open or closed? No idea. | |
if websocket.IsCloseError(err, websocket.CloseGoingAway) { | |
log.Printf("Client disconnected in %s", threadName) | |
} else { | |
log.Printf("Reading Error in %s. %s", threadName, err) | |
} | |
break //To escape from the endless loop | |
} | |
} | |
} | |
func broadcast(threadName string, messageContent []byte) { | |
for _, wsSession := range sessionGroupMap[threadName] { | |
err := wsSession.WriteMessage(1, messageContent) | |
if err != nil { | |
log.Println(err) | |
} | |
} | |
} |
[GIN] 2023/10/20 - 17:14:20 | 404 | 0s | 127.0.0.1 | GET "/socket.io/?EIO=4&transport=polling&t=OjCb2cH"
[GIN] 2023/10/20 - 17:14:20 | 404 | 0s | 127.0.0.1 | GET "/socket.io/?EIO=4&transport=polling&t=OjCb2cV"
when i run your code, it repeats this, could you have me fix it ?
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Thanks. Save me a lot of time!