Vom Golang-Server an jeden Benutzer gesendete Ereignisse

PHPz
Freigeben: 2024-02-06 11:39:14
nach vorne
1075 Leute haben es durchsucht

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

Frageninhalt

Ich benutze Go schon seit einiger Zeit, habe SSE aber noch nie zuvor verwendet. Ich habe ein Problem. Kann jemand ein funktionierendes Beispiel für ein vom Server gesendetes Ereignis bereitstellen, das nur an einen bestimmten Benutzer (Verbindung) gesendet wird?

Ich verwende die Gorilla-Sitzung zur Authentifizierung und möchte die Benutzer-ID verwenden, um die Verbindungen zu trennen.

Oder sollte ich eine 5-Sekunden-Abfrage über Ajax verwenden?

Vielen Dank

Das habe ich gefunden und ausprobiert:

  1. https://gist.github.com/ismasan/3fb75381cd2deb6bfa9c Es wird nicht an einzelne Benutzer gesendet und die Go-Funktion wird nicht beendet, wenn die Verbindung geschlossen wird

  2. https://github.com/striversity/gotr/blob/master/010-server-sent-event-part-2/main.go Das ist genau das, was ich brauche, aber sobald die Verbindung gelöscht wird. Wenn Sie nun den Browser schließen und in einem privaten Fenster öffnen, funktioniert es überhaupt nicht mehr. Außerdem wird, wie oben erwähnt, die Go-Routine fortgesetzt.


Richtige Antwort


Erstellen Sie einen „Broker“, um Nachrichten an verbundene Benutzer zu verteilen:

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
        }
    }
}
Nach dem Login kopieren

Variablen auf Paketebene mithilfe von Proxys deklarieren:

var broker = newbroker()
Nach dem Login kopieren

SSE-Endpunkt mit Proxy schreiben:

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()
        }
    }
}
Nach dem Login kopieren

Fügen Sie Code zu Ihrer Anwendung hinzu, um Broker.sendtouser aufzurufen.

Das obige ist der detaillierte Inhalt vonVom Golang-Server an jeden Benutzer gesendete Ereignisse. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Quelle:stackoverflow.com
Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage