package application import ( "context" "log" "sync" "sync/atomic" "git.ali33.ru/fcg-xvii/rest" ) type StreamStore struct { mu sync.RWMutex items []rest.IStream } /////////////////////////////////////////// func NewStreamStore(stream rest.IStream) *StreamStore { items := []rest.IStream{} if stream != nil { items = append(items, stream) } return &StreamStore{ items: items, } } func (s *StreamStore) add(item rest.IStream) { s.mu.Lock() s.items = append(s.items, item) s.mu.Unlock() } func (s *StreamStore) remove(item rest.IStream) int { s.mu.Lock() for i, val := range s.items { if val == item { s.items = append(s.items[:i], s.items[i+1:]...) break } } res := len(s.items) s.mu.Unlock() return res } func (s *StreamStore) get(index int) (res rest.IStream) { s.mu.RLock() if index >= 0 && index < len(s.items) { res = s.items[index] } s.mu.RUnlock() return res } func (s *StreamStore) Size() int { s.mu.RLock() res := len(s.items) s.mu.RUnlock() return res } func (s *StreamStore) SendMessage(message rest.IRequestOut) { s.mu.RLock() for _, val := range s.items { val.SendMessage(message) } s.mu.RUnlock() } //////////////////////////////////////////////////////////// func NewSockets() *Sockets { res := &Sockets{ counter: &atomic.Int64{}, chConnect: make(chan rest.IStream, 5), clients: &sync.Map{}, } go res.work() return res } type Sockets struct { ctx context.Context cancel context.CancelFunc counter *atomic.Int64 chConnect chan rest.IStream clients *sync.Map } func (s *Sockets) work() { s.ctx, s.cancel = context.WithCancel(context.Background()) for { select { case <-s.ctx.Done(): return case stream := <-s.chConnect: log.Println("CONNECT-------", s.counter.Add(1)) go func() { <-stream.Context().Done() log.Println("DISCONNECT-------", s.counter.Add(-1)) // auth auth := stream.Auth() if auth != nil { id := auth.Int32("id", 0) iStore, ok := s.clients.Load(id) if ok { store := iStore.(*StreamStore) if store.remove(stream) == 0 { s.clients.Delete(id) } } } }() } } } func (s *Sockets) Connect() chan<- rest.IStream { return s.chConnect } func (s *Sockets) OnlineCount() int64 { return s.counter.Load() } func (s *Sockets) ClientAuth(id any, stream rest.IStream) { store, exists := s.clients.LoadOrStore(id, NewStreamStore(stream)) if exists { store.(*StreamStore).add(stream) } } func (s *Sockets) ClientExists(id any) bool { _, exists := s.clients.Load(id) return exists } func (s *Sockets) SendMessage(id any, message rest.IRequestOut) { store, exists := s.clients.Load(id) if exists { store.(*StreamStore).SendMessage(message) } }