// Check if the type of the channel is presence func (c *channel) IsPresence() bool { return utils.IsPresenceChannel(c.ChannelID) }
// Handle messages // // If there is an unrecoverable error then break the loop, // otherwise just keep going. func onMessage(conn *websocket.Conn, w http.ResponseWriter, r *http.Request, sessionID string, app *app) { var event struct { Event string `json:"event"` } for { _, message, err := conn.ReadMessage() if err != nil { log.Errorf("%+v", err) switch err { case io.EOF: onClose(sessionID, app) default: emitWSError(newGenericReconnectImmediatelyError(), conn) } break } if err := json.Unmarshal(message, &event); err != nil { emitWSError(newGenericReconnectImmediatelyError(), conn) break } log.Infof("websockets: Handling %s event", event.Event) switch event.Event { case "pusher:ping": if err := conn.WriteJSON(newPongEvent()); err != nil { emitWSError(newGenericReconnectImmediatelyError(), conn) } case "pusher:subscribe": subscribeEvent := subscribeEvent{} if err := json.Unmarshal(message, &subscribeEvent); err != nil { emitWSError(newGenericReconnectImmediatelyError(), conn) break } connection, err := app.FindConnection(sessionID) if err != nil { emitWSError(newGenericReconnectImmediatelyError(), conn) break } channelName := strings.TrimSpace(subscribeEvent.Data.Channel) if !utils.IsChannelNameValid(channelName) { emitWSError(newGenericError(fmt.Sprintf("This channel name is not valid")), conn) break } isPresence := utils.IsPresenceChannel(channelName) isPrivate := utils.IsPrivateChannel(channelName) if isPresence || isPrivate { toSign := []string{connection.SocketID, channelName} if isPresence { toSign = append(toSign, subscribeEvent.Data.ChannelData) } expectedAuthKey := fmt.Sprintf("%s:%s", app.Key, utils.HashMAC([]byte(strings.Join(toSign, ":")), []byte(app.Secret))) if subscribeEvent.Data.Auth != expectedAuthKey { emitWSError(newGenericError(fmt.Sprintf("Auth value for subscription to %s is invalid", channelName)), conn) continue } } channel := app.FindOrCreateChannelByChannelID(channelName) log.Info(subscribeEvent.Data.ChannelData) if err := app.Subscribe(channel, connection, subscribeEvent.Data.ChannelData); err != nil { emitWSError(newGenericReconnectImmediatelyError(), conn) } case "pusher:unsubscribe": unsubscribeEvent := unsubscribeEvent{} if err := json.Unmarshal(message, &unsubscribeEvent); err != nil { emitWSError(newGenericReconnectImmediatelyError(), conn) } connection, err := app.FindConnection(sessionID) if err != nil { emitWSError(newGenericError(fmt.Sprintf("Could not find a connection with the id %s", sessionID)), conn) } channel, err := app.FindChannelByChannelID(unsubscribeEvent.Data.Channel) if err != nil { emitWSError(newGenericError(fmt.Sprintf("Could not find a channel with the id %s", unsubscribeEvent.Data.Channel)), conn) } if err := app.Unsubscribe(channel, connection); err != nil { emitWSError(newGenericReconnectImmediatelyError(), conn) break } default: // CLient Events ?? // see http://pusher.com/docs/client_api_guide/client_events#trigger-events if strings.HasPrefix(event.Event, "client-") { if !app.UserEvents { emitWSError(newGenericError("To send client events, you must enable this feature in the Settings."), conn) } clientEvent := rawEvent{} if err := json.Unmarshal(message, &clientEvent); err != nil { log.Error(err) emitWSError(newGenericReconnectImmediatelyError(), conn) break } channel, err := app.FindChannelByChannelID(clientEvent.Channel) if err != nil { emitWSError(newGenericError(fmt.Sprintf("Could not find a channel with the id %s", clientEvent.Channel)), conn) } if !channel.IsPresenceOrPrivate() { emitWSError(newGenericError("Client event rejected - only supported on private and presence channels"), conn) break } if err := app.Publish(channel, clientEvent, sessionID); err != nil { log.Error(err) emitWSError(newGenericReconnectImmediatelyError(), conn) break } } } // switch } // For }