A simple chat server/client implemented with gRPC in Go sample
All clients are stored in the map[string]chan *chat.StreamResponse
type server struct {
Host, Password string
Broadcast chan *chat.StreamResponse
ClientNames map[string]string
ClientStreams map[string]chan *chat.StreamResponse
namesMtx, streamsMtx sync.RWMutex
}
And broadcast messages to all clients
func (s *server) broadcast(_ context.Context) {
for res := range s.Broadcast {
s.streamsMtx.RLock()
for _, stream := range s.ClientStreams {
select {
case stream <- res:
// noop
default:
ServerLogf(time.Now(), "client stream full, dropping message")
}
}
s.streamsMtx.RUnlock()
}
}
// send messages in individual client
func (s *server) sendBroadcasts(srv chat.Chat_StreamServer, tkn string) {
stream := s.openStream(tkn)
defer s.closeStream(tkn)
for {
select {
case <-srv.Context().Done():
return
case res := <-stream:
if s, ok := status.FromError(srv.Send(res)); ok {
switch s.Code() {
case codes.OK:
// noop
case codes.Unavailable, codes.Canceled, codes.DeadlineExceeded:
DebugLogf("client (%s) terminated connection", tkn)
return
default:
ClientLogf(time.Now(), "failed to send to client (%s): %v", tkn, s.Err())
return
}
}
}
}
}