Maison > développement back-end > Golang > Événements envoyés par le serveur Golang à chaque utilisateur

Événements envoyés par le serveur Golang à chaque utilisateur

PHPz
Libérer: 2024-02-06 11:39:14
avant
1144 Les gens l'ont consulté

Golang 服务器向每个用户发送的事件

Contenu de la question

J'utilise Go depuis un certain temps mais je n'ai jamais utilisé SSE auparavant. J'ai un problème, quelqu'un peut-il fournir un exemple fonctionnel d'un événement envoyé par le serveur qui n'est envoyé qu'à un utilisateur spécifique (connexion) ?

J'utilise gorilla - session pour l'authentification et je souhaite utiliser UserID pour séparer les connexions.

Ou dois-je utiliser un sondage de 5 secondes via Ajax ?

Merci beaucoup

Voici ce que j'ai trouvé et essayé :

  1. https://gist.github.com/ismasan/3fb75381cd2deb6bfa9c Il ne sera pas envoyé aux utilisateurs individuels et la fonction go ne s'arrêtera pas si la connexion est fermée

  2. https://github.com/striversity/gotr/blob/master/010-server-sent-event-part-2/main.go C'est exactement ce dont j'ai besoin, mais une fois la connexion supprimée. Alors maintenant, une fois que vous fermez et ouvrez le navigateur dans une fenêtre privée, cela ne fonctionne plus du tout. De plus, comme mentionné ci-dessus, la routine Go continue.


Bonne réponse


Créez un "broker" pour distribuer les messages aux utilisateurs connectés :

type broker struct {
    // users is a map where the key is the user id
    // and the value is a slice of channels to connections
    // for that user id
    users map[string][]chan []byte

    // actions is a channel of functions to call
    // in the broker's goroutine. the broker executes
    // everything in that single goroutine to avoid
    // data races.
    actions chan func()
}

// run executes in a goroutine. it simply gets and 
// calls functions.
func (b *broker) run() {
    for a := range b.actions {
        a()
    }
}

func newbroker() *broker {
    b := &broker{
        users:   make(map[string][]chan []byte),
        actions: make(chan func()),
    }
    go b.run()
    return b
}

// adduserchan adds a channel for user with given id.
func (b *broker) adduserchan(id string, ch chan []byte) {
    b.actions <- func() {
        b.users[id] = append(b.users[id], ch)
    }
}

// removeuserchan removes a channel for a user with the given id.
func (b *broker) removeuserchan(id string, ch chan []byte) {
    // the broker may be trying to send to 
    // ch, but nothing is receiving. pump ch
    // to prevent broker from getting stuck.
    go func() { for range ch {} }()

    b.actions <- func() {
        chs := b.users[id]
        i := 0
        for _, c := range chs {
            if c != ch {
                chs[i] = c
                i = i + 1
            }
        }
        if i == 0 {
            delete(b.users, id)
        } else {
            b.users[id] = chs[:i]
        }
        // close channel to break loop at beginning
        // of removeuserchan.
        // this must be done in broker goroutine
        // to ensure that broker does not send to
        // closed goroutine.
        close(ch)
    }
}

// sendtouser sends a message to all channels for the given user id.
func (b *broker) sendtouser(id string, data []byte) {
    b.actions <- func() {
        for _, ch := range b.users[id] {
            ch <- data
        }
    }
}
Copier après la connexion

Déclarez les variables au niveau du package à l'aide de proxys :

var broker = newbroker()
Copier après la connexion

Écrivez le point de terminaison sse à l'aide d'un proxy :

func sseEndpoint(w http.ResponseWriter, r *http.Request) {
    // I assume that user id is in query string for this example,
    // You should use your authentication code to get the id.
    id := r.FormValue("id")

    // Do the usual SSE setup.
    flusher := w.(http.Flusher)
    w.Header().Set("Content-Type", "text/event-stream")
    w.Header().Set("Cache-Control", "no-cache")
    w.Header().Set("Connection", "keep-alive")

    // Create channel to receive messages for this connection.  
    // Register that channel with the broker.
    // On return from the function, remove the channel
    // from the broker.
    ch := make(chan []byte)
    broker.addUserChan(id, ch)
    defer broker.removeUserChan(id, ch)
    for {
        select {
        case <-r.Context().Done():
            // User closed the connection. We are out of here.
            return
        case m := <-ch:
            // We got a message. Do the usual SSE stuff.
            fmt.Fprintf(w, "data: %s\n\n", m)
            flusher.Flush()
        }
    }
}
Copier après la connexion

Ajoutez du code à votre application pour appeler broker.sendtouser.

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!

Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal