Maison >développement back-end >Golang >Discutez en tête-à-tête avec la prise Golang
J'ai une application d'achat où les utilisateurs peuvent publier leur disponibilité et d'autres utilisateurs peuvent les trouver et ajouter leur disponibilité.
Je dispose désormais d'un service de chat, essentiellement pour discuter. Autrement dit, les clients peuvent discuter avec l'acheteur pour confirmer des détails ou d'autres choses. Cette discussion devrait être en tête-à-tête. Il peut donc y avoir 5 clients qui posent des questions sur une publication d'achat et je souhaite que la discussion soit unique, car la discussion du client A sur les achats doit être distincte de la discussion du client B sur les mêmes achats. Les acheteurs devraient pouvoir voir le chat et répondre.
C'est ce que j'ai actuellement, mais cela semble diffuser un message à tout le monde dans la référence. Je souhaite uniquement que les acheteurs reçoivent des messages d'un expéditeur spécifique sans que d'autres aient accès au chat.
"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"` }
La principale raison pour laquelle votre code diffuse un message à toutes les personnes présentes dans la pièce avec la même référence est que vous le faites selon la méthode hub
的 broadcast
频道中处理消息的方式。在当前的实现中,当发送消息时,它会被转发到同一房间中的每个客户端(即具有相同的引用)。这是在 hub
的 run
:
case m := <-h.broadcast: if _, ok := h.rooms[m.reference]; ok { for _, cl := range h.rooms[m.reference].clients { cl.message <- m ...
J'espère que le score est de 1-1. La citation est postid
Si reference
是 postid
et que vous souhaitez une communication individuelle entre l'acheteur (la personne publiant la publication de disponibilité) et chaque client, vous devez vous assurer que chaque discussion est identifiable de manière unique. p>
La clé unique pour chaque session de chat doit être une combinaison de postid
(reference
) 和客户 id (sender
). Cela garantit que chaque client dispose d'une session de discussion unique avec l'acheteur dans chaque publication.
Vous pouvez ensuite mettre à jour la combinaison de client
结构,使其具有 chatid
,它是 reference
和 sender
.
type client struct { ... chatid string `json:"chat_id"` }
Vous pouvez mettre à jour le logo hub
来管理聊天会话地图(由 chatid
) à la place de la pièce.
type hub struct { chats map[string]*chat ... }
La structure de chacun chat
est la suivante :
type chat struct { shopper *client customer *client }
Pour gérer les messages, lorsqu'un client envoie un message, le message est envoyé à l'acheteur, et lorsque l'acheteur répond, le message est envoyé au client. Le routage peut être effectué en utilisant chatid
.
Par exemple, dans votre broadcast
logique :
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 } }La variable
m
est de type *message
et elle n'a pas de champ m
变量的类型为 *message
,它没有 chatid
.
Pour résoudre ce problème, vous devriez envisager d'ajouter le champ chatid
字段添加到 message
à la structure
message
Tout d'abord, nous modifions la
type message struct { content string `json:"content"` chatid string `json:"chat_id"` sender string `json:"sender"` }
client
的 readmessage
方法中构造一个新的 message
Ensuite, lorsque vous construisez un nouveau dans la méthode readmessage
du client
:
msg := &message{ content: string(m), chatid: c.chatid, sender: c.sender, }Lors de l'initialisation du chat :
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 } }Avertissement : il ne s'agit que d'un squelette de base de la fonctionnalité, mais il ne prend pas en compte des complexités supplémentaires, telles que la gestion des situations dans lesquelles les clients ou les acheteurs peuvent disposer de plusieurs appareils, la garantie d'une gestion robuste des erreurs, et bien plus encore. 🎜
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!