package sse import ( "fmt" ) type ConnectionDispatcher struct { buffer *SSEConnectionRingBuffer } // bufferSize размер кольца минимум 2 func NewConnectionDispatcher(bufferSize int) *ConnectionDispatcher { return &ConnectionDispatcher{ buffer: NewSSEConnectionRingBuffer(bufferSize), } } func (r *ConnectionDispatcher) AddConnection(userID, deviceID string) *SSEConnection { conn := NewSSEConnection(userID, deviceID) currentMap := r.buffer.GetCurrent() // тут текущие данные откуда читают воркеры nextMap := r.buffer.GetNext() // следующая поидее должна быть пустой for key, value := range currentMap { nextMap[key] = value } // покомментарию Миши копируем слайсы отдельно existingConnections := nextMap[userID] newConnections := make([]*SSEConnection, len(existingConnections)+1) copy(newConnections, existingConnections) newConnections[len(existingConnections)] = conn nextMap[userID] = newConnections r.buffer.Rotate() return conn } func (r *ConnectionDispatcher) RemoveConnection(userID, deviceID string) { currentMap := r.buffer.GetCurrent() // тут текущие данные откуда читают воркеры nextMap := r.buffer.GetNext() // следующая на которую переключимся for key, value := range currentMap { nextMap[key] = value } existingConnections := nextMap[userID] afterDropConnections := make([]*SSEConnection, 0, len(existingConnections)) for _, conn := range existingConnections { if conn.DeviceID != deviceID { afterDropConnections = append(afterDropConnections, conn) } else { close(conn.Channel) } } // если есть коннекты то складываем оставшиеся после удаления, если == 0 то дропаем этого пользователя из мэпки if len(afterDropConnections) > 0 { nextMap[userID] = afterDropConnections } else { delete(nextMap, userID) } r.buffer.Rotate() } func (r *ConnectionDispatcher) SendToUser(userID string, event SSEEvent) error { currentMap := r.buffer.GetCurrent() connections := currentMap[userID] if len(connections) == 0 { return fmt.Errorf("no active connections for user %s", userID) } for _, conn := range connections { conn.Channel <- event } return nil }