package wshandler import ( "bytes" "context" "encoding/json" "github.com/go-redis/redis/v8" "github.com/gorilla/websocket" "repositories.action2quare.com/ayo/gocommon/logger" ) type room struct { inChan chan *wsconn outChan chan *wsconn messageChan chan *UpstreamMessage name string destroyChan chan<- string sendMsgChan chan<- send_msg_queue_elem redisClient *redis.Client } // 만약 destroyChan가 nil이면 room이 비어도 파괴되지 않는다. 영구 유지되는 room func makeRoom(name string, redisClient *redis.Client, destroyChan chan<- string, sendMsgChan chan<- send_msg_queue_elem) *room { return &room{ inChan: make(chan *wsconn, 10), outChan: make(chan *wsconn, 10), messageChan: make(chan *UpstreamMessage, 100), name: name, destroyChan: destroyChan, sendMsgChan: sendMsgChan, redisClient: redisClient, } } func (r *room) broadcast(msg *UpstreamMessage) { r.messageChan <- msg } func (r *room) in(conn *wsconn) *room { r.inChan <- conn return r } func (r *room) out(conn *wsconn) *room { r.outChan <- conn return r } func (r *room) start(ctx context.Context) { go func(ctx context.Context) { conns := make(map[string]*wsconn) normal := false for !normal { normal = r.loop(ctx, &conns) } }(ctx) } func (r *room) loop(ctx context.Context, conns *map[string]*wsconn) (normalEnd bool) { defer func() { s := recover() if s != nil { logger.Error(s) normalEnd = false } }() tag := "#" + r.name for { select { case <-ctx.Done(): return true case conn := <-r.inChan: r.redisClient.HIncrBy(ctx, r.name, "count", 1).Result() (*conns)[conn.sender.Accid.Hex()] = conn case conn := <-r.outChan: r.redisClient.HIncrBy(ctx, r.name, "count", -1).Result() delete((*conns), conn.sender.Accid.Hex()) if len(*conns) == 0 && r.destroyChan != nil { r.destroyChan <- r.name return true } case msg := <-r.messageChan: ds := DownstreamMessage{ Alias: msg.Alias, Body: msg.Body, Tag: append(msg.Tag, tag), } buff := new(bytes.Buffer) enc := json.NewEncoder(buff) enc.SetEscapeHTML(false) enc.Encode(ds) for _, conn := range *conns { r.sendMsgChan <- send_msg_queue_elem{ to: conn, mt: websocket.TextMessage, msg: buff.Bytes(), } } } } }