package wshandler import ( "context" "encoding/json" "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 } // 만약 destroyChan가 nil이면 room이 비어도 파괴되지 않는다. 영구 유지되는 room func makeRoom(name string, destroyChan chan<- string) *room { return &room{ inChan: make(chan *wsconn, 10), outChan: make(chan *wsconn, 10), messageChan: make(chan *UpstreamMessage, 100), name: name, destroyChan: destroyChan, } } 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: (*conns)[conn.sender.Accid.Hex()] = conn case conn := <-r.outChan: 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), } bt, _ := json.Marshal(ds) for _, conn := range *conns { conn.Conn.WriteMessage(websocket.TextMessage, bt) } } } }