Ich habe eine Shopping-App, in der Benutzer Verfügbarkeiten posten können und andere Benutzer sie finden und ihre Verfügbarkeit hinzufügen können.
Ich habe jetzt einen Chat-Dienst, hauptsächlich zum Chatten. Das heißt, Kunden können mit dem Käufer chatten, um Details oder andere Dinge zu bestätigen. Dieser Chat sollte ein Einzelgespräch sein. Es können also fünf Kunden sein, die nach einem Einkaufsbeitrag fragen, und ich möchte, dass der Chat einzigartig ist, da der Chat von Kunde A über den Kauf vom Chat von Kunde B über denselben Kauf getrennt sein sollte. Käufer sollten den Chat sehen und antworten können.
Das ist es, was ich derzeit habe, aber dies scheint eine Botschaft an alle in der Referenz zu senden. Ich möchte, dass Käufer nur Nachrichten von einem bestimmten Absender erhalten, ohne dass andere Zugriff auf den Chat haben.
"client.go"
type client struct { conn *websocket.conn chatrepository chat.chatrepository message chan *message id string `json:"id"` reference string `json:"reference"` username string `json:"username"` sender string `json:"sender"` recipient string `json:"recipient"` } type message struct { content string `json:"content"` reference string `json:"reference"` // username string `json:"username"` sender string `json:"sender"` } func (c *client) writemessage() { defer func() { c.conn.close() }() for { message, ok := <-c.message if !ok { return } uuid, err := uuid.newv4() if err != nil { log.fatalf("failed to generate uuid: %v", err) } chatmessage := chat.chatmessage{ id: uuid.string(), sender: message.sender, // recipient: recipient, timestamp: time.now(), content: message.content, } if c.sender == message.sender { _, errx := c.chatrepository.addmessage(message.reference, chatmessage) if err != nil { log.fatalf("failed to generate uuid: %v", errx) } } c.conn.writejson(chatmessage) } } func (c *client) readmessage(hub *hub) { defer func() { hub.unregister <- c c.conn.close() }() for { _, m, err := c.conn.readmessage() if err != nil { if websocket.isunexpectedcloseerror(err, websocket.closegoingaway, websocket.closeabnormalclosure) { log.printf("error: %v", err) } break } msg := &message{ content: string(m), reference: c.reference, sender: c.sender, // username: c.username, } hub.broadcast <- msg } }
"hub.go"
type room struct { id string `json:"id"` name string `json:"name"` clients map[string]*client `json:"clients"` } type hub struct { rooms map[string]*room register chan *client unregister chan *client broadcast chan *message emmiter events.emitter } func newhub(emmiter events.emitter) *hub { return &hub{ rooms: make(map[string]*room), register: make(chan *client), unregister: make(chan *client), broadcast: make(chan *message, 5), emmiter: emmiter, } } func (h *hub) run() { for { select { case cl := <-h.register: if _, ok := h.rooms[cl.reference]; ok { r := h.rooms[cl.reference] if _, ok := r.clients[cl.id]; !ok { r.clients[cl.id] = cl } } case cl := <-h.unregister: if _, ok := h.rooms[cl.reference]; ok { if _, ok := h.rooms[cl.reference].clients[cl.id]; ok { // if len(h.rooms[cl.reference].clients) != 0 { // h.broadcast <- &message{ // content: "user left the chat", // reference: cl.reference, // username: cl.username, // } // } delete(h.rooms[cl.reference].clients, cl.id) close(cl.message) } } case m := <-h.broadcast: if _, ok := h.rooms[m.reference]; ok { for _, cl := range h.rooms[m.reference].clients { cl.message <- m if m.sender != cl.recipient { notifications.sendpush(h.emmiter, cl.recipient, fmt.sprintf("new message from %v", cl.username), m.content) } } } } } }
"handler.go"
type handler struct { hub *hub chatrepository chat.chatrepository } func newhandler(h *hub, chatrepository chat.chatrepository) *handler { return &handler{ hub: h, chatrepository: chatrepository, } } var upgrader = websocket.upgrader{ readbuffersize: 1024, writebuffersize: 1024, checkorigin: func(r *http.request) bool { return true }, } func (h *handler) joinroom(c *gin.context) { conn, err := upgrader.upgrade(c.writer, c.request, nil) if err != nil { utils.handleerror(c, nil, "error creating chat connection", http.statusbadgateway) return } reference := c.param("reference") sender := c.query("sender") username := c.query("username") recipient := c.query("recipient") if reference == "" || sender == "" || username == "" || recipient == "" { utils.handleerror(c, nil, "required parameters missing", http.statusbadgateway) return } if _, ok := h.hub.rooms[reference]; !ok { // room doesn't exist, handle accordingly _, err1 := h.chatrepository.getchathistory(reference) if err1 != nil { log.printf("failed to retrieve chat history: %s", err1) errx := h.chatrepository.createchat(reference) if errx != nil { utils.handleerror(c, nil, "error storing connection", http.statusbadgateway) return } } h.hub.rooms[reference] = &room{ id: reference, name: sender, clients: make(map[string]*client), } } cl := &client{ conn: conn, chatrepository: h.chatrepository, message: make(chan *message, 10), id: sender, reference: reference, sender: sender, username: username, recipient: recipient, } h.hub.register <- cl go cl.writemessage() cl.readmessage(h.hub) }
"route.go"
hub := ws.newhub(events.neweventemitter(conn)) wshandler := ws.newhandler(hub, pr.newchatrepository(db, client)) go hub.run() v1.get("/chat/ws/:reference", g.guard([]string{"user", "admin", "dispatcher"}, nil), wshandler.joinroom)
"chat.model.go" type Chat struct { ID string `json:"id,omitempty" bson:"_id,omitempty"` Reference string `json:"reference" bson:"reference"` Messages []ChatMessage `json:"messages" bson:"messages"` } type ChatMessage struct { ID string `json:"id,omitempty" bson:"_id,omitempty"` Sender string `json:"sender" bson:"sender,omitempty"` Timestamp time.Time `json:"timestamp" bson:"timestamp,omitempty"` Content string `json:"content" bson:"content,omitempty"` }
Der Hauptgrund, warum Ihr Code eine Nachricht mit derselben Referenz an alle im Raum sendet, ist, dass Sie es in derhub
的broadcast
频道中处理消息的方式。在当前的实现中,当发送消息时,它会被转发到同一房间中的每个客户端(即具有相同的引用)。这是在hub
的run
-Methode tun:
case m := <-h.broadcast: if _, ok := h.rooms[m.reference]; ok { for _, cl := range h.rooms[m.reference].clients { cl.message <- m ...
Ich hoffe, dass es 1:1 steht. Das Zitat ist gepostet
Wennreference
是postid
Sie eine persönliche Kommunikation zwischen dem Käufer (der Person, die den Verfügbarkeitsbeitrag veröffentlicht) und jedem Kunden wünschen, müssen Sie sicherstellen, dass jeder Chat eindeutig identifizierbar ist.
Der eindeutige Schlüssel für jede Chat-Sitzung sollte eine Kombination auspostid
(reference
) 和客户 id (sender
sein. Dadurch wird sichergestellt, dass jeder Kunde in jedem Beitrag eine einzigartige Chat-Sitzung mit dem Käufer hat.
Sie können dann die Kombination vonclient
结构,使其具有chatid
,它是reference
和sender
aktualisieren.
type client struct { ... chatid string `json:"chat_id"` }
Sie können dashub
来管理聊天会话地图(由chatid
-Logo anstelle des Raums aktualisieren.
type hub struct { chats map[string]*chat ... }
Die Struktur jedeschat
ist wie folgt:
type chat struct { shopper *client customer *client }
Um Nachrichten zu verarbeiten: Wenn ein Kunde eine Nachricht sendet, wird die Nachricht an den Käufer gesendet, und wenn der Käufer antwortet, wird die Nachricht an den Kunden gesendet. Das Routing kann mitchatid
erfolgen.
Zum Beispiel in deinerbroadcast
Logik:
case m := <-h.broadcast: chat, ok := h.chats[m.chatid] if ok { if m.sender == chat.customer.id { // message is from customer to shopper chat.shopper.message <- m } else if m.sender == chat.shopper.id { // message is from shopper to customer chat.customer.message <- m } }
m
ist vom Typ*message
und hat keinm
变量的类型为*message
,它没有chatid
-Feld.
Um dieses Problem zu lösen, sollten Sie erwägen, daschatid
字段添加到message
-Feld zur
message
Zuerst modifizieren wir die
type message struct { content string `json:"content"` chatid string `json:"chat_id"` sender string `json:"sender"` }
client
的
readmessage
方法中构造一个新的
message
Dann, wenn Sie ein neues
in der
readmessage
-Methode des
Clients
erstellen:
msg := &message{ content: string(m), chatid: c.chatid, sender: c.sender, }
chatID := reference + "_" + sender cl := &Client{ ... ChatID: chatID, } // If the chat session does not exist, create it. if _, ok := h.hub.Chats[chatID]; !ok { h.hub.Chats[chatID] = &Chat{ Customer: cl, Shopper: nil, // That will be set when the shopper joins. } } else { // That assumes only the customer or the shopper can join, not both at the same time. if h.hub.Chats[chatID].Shopper == nil { h.hub.Chats[chatID].Shopper = cl } else { h.hub.Chats[chatID].Customer = cl } }
Das obige ist der detaillierte Inhalt vonChatten Sie eins zu eins mit Golang Socket. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!