Я работаю с Go некоторое время, но никогда раньше не занимался SSE. У меня проблема, может кто-нибудь, ПОЖАЛУЙСТА, предоставить рабочий пример событий, отправленных сервером, которые будут отправляться только определенному пользователю (подключению).
Я использую сеансы гориллы для аутентификации, и я хотел бы использовать UserID для разделения соединений.
Или я должен использовать 5-секундный опрос через Ajax?
Большое спасибо
Вот что я нашел и попробовал:
https://gist.github.com/ismasan/3fb75381cd2deb6bfa9c он не отправляет отдельному пользователю, и функция go не остановится, если соединение закрыто
https://github.com/striversity/gotr/blob/master/010-server-sent-event-part-2/main.go это то, что мне нужно, но оно не отслеживает после удаления соединения . Итак, теперь, когда вы закрываете и открываете браузер в приватном окне, он вообще не работает. Кроме того, как и выше, процедура go продолжает выполняться.
Создайте «брокера» для рассылки сообщений подключенным пользователям:
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
}
}
}
Объявите переменную с брокером на уровне пакета:
var broker = newBroker()
Напишите конечную точку SSE с помощью брокера:
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()
}
}
}
Добавьте в приложение код для вызова Broker.sendToUser.