// run receives pubsub messages from Redis after establishing a connection. // When a valid message is received it is broadcast to all connected websockets func (rr *redisReceiver) run() { conn := rr.pool.Get() defer conn.Close() psc := redis.PubSubConn{conn} psc.Subscribe(CHANNEL) for { switch v := psc.Receive().(type) { case redis.Message: log.WithFields(log.Fields{ "channel": v.Channel, "message": string(v.Data), }).Println("Redis Message Received") msg, err := validateMessage(v.Data) if err != nil { log.WithFields(log.Fields{ "err": err, "data": v.Data, "msg": msg, }).Error("Error unmarshalling message from Redis") continue } rr.broadcast(v.Data) case redis.Subscription: log.WithFields(log.Fields{ "channel": v.Channel, "kind": v.Kind, "count": v.Count, }).Println("Redis Subscription Received") case error: log.WithField("err", v).Errorf("Error while subscribed to Redis channel %s", CHANNEL) default: log.WithField("v", v).Println("Unknown Redis receive during subscription") } } }
// run the main redisWriter loop that publishes incoming messages to Redis. func (rw *redisWriter) run() { conn := rw.pool.Get() defer conn.Close() for data := range rw.messages { ctx := log.Fields{"data": data} if err := conn.Send("PUBLISH", CHANNEL, data); err != nil { ctx["err"] = err log.WithFields(ctx).Fatalf("Unable to publish message to Redis") } if err := conn.Flush(); err != nil { ctx["err"] = err log.WithFields(ctx).Fatalf("Unable to flush published message to Redis") } } }
// handleWebsocket connection. Update to func handleWebsocket(w http.ResponseWriter, r *http.Request) { if r.Method != "GET" { http.Error(w, "Method not allowed", 405) return } ws, err := upgrader.Upgrade(w, r, nil) if err != nil { log.WithField("err", err).Println("Upgrading to websockets") http.Error(w, "Error Upgrading to websockets", 400) return } id := rr.register(ws) for { mt, data, err := ws.ReadMessage() ctx := log.Fields{"mt": mt, "data": data, "err": err} if err != nil { if err == io.EOF { log.WithFields(ctx).Info("Websocket closed!") } else { log.WithFields(ctx).Error("Error reading websocket message") } break } switch mt { case websocket.TextMessage: msg, err := validateMessage(data) if err != nil { ctx["msg"] = msg ctx["err"] = err log.WithFields(ctx).Error("Invalid Message") break } rw.publish(data) default: log.WithFields(ctx).Warning("Unknown Message!") } } rr.deRegister(id) ws.WriteMessage(websocket.CloseMessage, []byte{}) }
// broadcast the provided message to all connected websocket connections. // If an error occurs while writting a message to a websocket connection it is // closed and deregistered. func (rr *redisReceiver) broadcast(data []byte) { rr.Mutex.Lock() defer rr.Mutex.Unlock() for id, conn := range rr.conns { if err := conn.WriteMessage(websocket.TextMessage, data); err != nil { log.WithFields(log.Fields{ "id": id, "data": data, "err": err, "conn": conn, }).Error("Error writting data to connection! Closing and removing Connection") rr.deRegister(id) } } }