示例#1
0
        private void ParseMessage(string message)
        {
            var type = JObject.Parse(message).SelectToken("type")?.ToString();

            switch (type?.ToLower())
            {
            case "response":
                var resp = new Models.Responses.Response(message);
                if (_previousRequests.Count != 0)
                {
                    foreach (var request in _previousRequests)
                    {
                        if (string.Equals(request.Nonce, resp.Nonce, StringComparison.CurrentCultureIgnoreCase))
                        {
                            OnListenResponse?.Invoke(this, new OnListenResponseArgs {
                                Response = resp, Topic = request.Topic, Successful = resp.Successful
                            });
                        }
                    }
                    return;
                }
                break;

            case "message":
                var msg = new Models.Responses.Message(message);
                switch (msg.Topic.Split('.')[0])
                {
                case "channel-subscribe-events-v1":
                    var subscription = msg.MessageData as ChannelSubscription;
                    OnChannelSubscription?.Invoke(this, new OnChannelSubscriptionArgs {
                        Subscription = subscription
                    });
                    return;

                case "whispers":
                    var whisper = (Whisper)msg.MessageData;
                    OnWhisper?.Invoke(this, new OnWhisperArgs {
                        Whisper = whisper
                    });
                    return;

                case "chat_moderator_actions":
                    var cma    = msg.MessageData as ChatModeratorActions;
                    var reason = "";
                    switch (cma?.ModerationAction.ToLower())
                    {
                    case "timeout":
                        if (cma.Args.Count > 2)
                        {
                            reason = cma.Args[2];
                        }
                        OnTimeout?.Invoke(this, new OnTimeoutArgs
                        {
                            TimedoutBy      = cma.CreatedBy,
                            TimedoutById    = cma.CreatedByUserId,
                            TimedoutUserId  = cma.TargetUserId,
                            TimeoutDuration = TimeSpan.FromSeconds(int.Parse(cma.Args[1])),
                            TimeoutReason   = reason,
                            TimedoutUser    = cma.Args[0]
                        });
                        return;

                    case "ban":
                        if (cma.Args.Count > 1)
                        {
                            reason = cma.Args[1];
                        }
                        OnBan?.Invoke(this, new OnBanArgs {
                            BannedBy = cma.CreatedBy, BannedByUserId = cma.CreatedByUserId, BannedUserId = cma.TargetUserId, BanReason = reason, BannedUser = cma.Args[0]
                        });
                        return;

                    case "unban":
                        OnUnban?.Invoke(this, new OnUnbanArgs {
                            UnbannedBy = cma.CreatedBy, UnbannedByUserId = cma.CreatedByUserId, UnbannedUserId = cma.TargetUserId
                        });
                        return;

                    case "untimeout":
                        OnUntimeout?.Invoke(this, new OnUntimeoutArgs {
                            UntimeoutedBy = cma.CreatedBy, UntimeoutedByUserId = cma.CreatedByUserId, UntimeoutedUserId = cma.TargetUserId
                        });
                        return;

                    case "host":
                        OnHost?.Invoke(this, new OnHostArgs {
                            HostedChannel = cma.Args[0], Moderator = cma.CreatedBy
                        });
                        return;

                    case "subscribers":
                        OnSubscribersOnly?.Invoke(this, new OnSubscribersOnlyArgs {
                            Moderator = cma.CreatedBy
                        });
                        return;

                    case "subscribersoff":
                        OnSubscribersOnlyOff?.Invoke(this, new OnSubscribersOnlyOffArgs {
                            Moderator = cma.CreatedBy
                        });
                        return;

                    case "clear":
                        OnClear?.Invoke(this, new OnClearArgs {
                            Moderator = cma.CreatedBy
                        });
                        return;

                    case "emoteonly":
                        OnEmoteOnly?.Invoke(this, new OnEmoteOnlyArgs {
                            Moderator = cma.CreatedBy
                        });
                        return;

                    case "emoteonlyoff":
                        OnEmoteOnlyOff?.Invoke(this, new OnEmoteOnlyOffArgs {
                            Moderator = cma.CreatedBy
                        });
                        return;

                    case "r9kbeta":
                        OnR9kBeta?.Invoke(this, new OnR9kBetaArgs {
                            Moderator = cma.CreatedBy
                        });
                        return;

                    case "r9kbetaoff":
                        OnR9kBetaOff?.Invoke(this, new OnR9kBetaOffArgs {
                            Moderator = cma.CreatedBy
                        });
                        return;
                    }
                    break;

                case "channel-bits-events-v1":
                    if (msg.MessageData is ChannelBitsEvents cbe)
                    {
                        OnBitsReceived?.Invoke(this, new OnBitsReceivedArgs
                        {
                            BitsUsed      = cbe.BitsUsed,
                            ChannelId     = cbe.ChannelId,
                            ChannelName   = cbe.ChannelName,
                            ChatMessage   = cbe.ChatMessage,
                            Context       = cbe.Context,
                            Time          = cbe.Time,
                            TotalBitsUsed = cbe.TotalBitsUsed,
                            UserId        = cbe.UserId,
                            Username      = cbe.Username
                        });
                    }
                    return;

                case "channel-commerce-events-v1":
                    if (msg.MessageData is ChannelCommerceEvents cce)
                    {
                        OnChannelCommerceReceived?.Invoke(this, new OnChannelCommerceReceivedArgs
                        {
                            Username        = cce.Username,
                            DisplayName     = cce.DisplayName,
                            ChannelName     = cce.ChannelName,
                            UserId          = cce.UserId,
                            ChannelId       = cce.ChannelId,
                            Time            = cce.Time,
                            ItemImageURL    = cce.ItemImageURL,
                            ItemDescription = cce.ItemDescription,
                            SupportsChannel = cce.SupportsChannel,
                            PurchaseMessage = cce.PurchaseMessage
                        });
                    }
                    return;

                case "video-playback":
                    var vP = msg.MessageData as VideoPlayback;
                    switch (vP?.Type)
                    {
                    case VideoPlaybackType.StreamDown:
                        OnStreamDown?.Invoke(this, new OnStreamDownArgs {
                            ServerTime = vP.ServerTime
                        });
                        return;

                    case VideoPlaybackType.StreamUp:
                        OnStreamUp?.Invoke(this, new OnStreamUpArgs {
                            PlayDelay = vP.PlayDelay, ServerTime = vP.ServerTime
                        });
                        return;

                    case VideoPlaybackType.ViewCount:
                        OnViewCount?.Invoke(this, new OnViewCountArgs {
                            ServerTime = vP.ServerTime, Viewers = vP.Viewers
                        });
                        return;
                    }
                    break;
                }
                break;
            }
            UnaccountedFor(message);
        }
示例#2
0
        /// <summary>
        /// Parses the message.
        /// </summary>
        /// <param name="message">The message.</param>
        private void ParseMessage(string message)
        {
            var type = JObject.Parse(message).SelectToken("type")?.ToString();

            switch (type?.ToLower())
            {
            case "response":
                var resp = new Models.Responses.Response(message);
                if (_previousRequests.Count != 0)
                {
                    bool handled = false;
                    _previousRequestsSemaphore.WaitOne();
                    try
                    {
                        for (int i = 0; i < _previousRequests.Count;)
                        {
                            var request = _previousRequests[i];
                            if (string.Equals(request.Nonce, resp.Nonce, StringComparison.CurrentCulture))
                            {
                                //Remove the request.
                                _previousRequests.RemoveAt(i);
                                _topicToChannelId.TryGetValue(request.Topic, out var requestChannelId);
                                OnListenResponse?.Invoke(this, new OnListenResponseArgs {
                                    Response = resp, Topic = request.Topic, Successful = resp.Successful, ChannelId = requestChannelId
                                });
                                handled = true;
                            }
                            else
                            {
                                i++;
                            }
                        }
                    }
                    finally
                    {
                        _previousRequestsSemaphore.Release();
                    }
                    if (handled)
                    {
                        return;
                    }
                }
                break;

            case "message":
                var msg = new Models.Responses.Message(message);
                _topicToChannelId.TryGetValue(msg.Topic, out var channelId);
                channelId = channelId ?? "";
                switch (msg.Topic.Split('.')[0])
                {
                case "user-moderation-notifications":
                    var userModerationNotifications = msg.MessageData as UserModerationNotifications;
                    switch (userModerationNotifications.Type)
                    {
                    case UserModerationNotificationsType.AutomodCaughtMessage:
                        var automodCaughtMessage = userModerationNotifications.Data as Models.Responses.Messages.UserModerationNotificationsTypes.AutomodCaughtMessage;
                        OnAutomodCaughtUserMessage?.Invoke(this, new OnAutomodCaughtUserMessage {
                            ChannelId = channelId, UserId = msg.Topic.Split('.')[2], AutomodCaughtMessage = automodCaughtMessage
                        });
                        break;

                    case UserModerationNotificationsType.Unknown:
                        break;
                    }
                    return;

                case "automod-queue":
                    var automodQueue = msg.MessageData as AutomodQueue;
                    switch (automodQueue.Type)
                    {
                    case AutomodQueueType.CaughtMessage:
                        var caughtMessage = automodQueue.Data as AutomodCaughtMessage;
                        OnAutomodCaughtMessage?.Invoke(this, new OnAutomodCaughtMessageArgs {
                            ChannelId = channelId, AutomodCaughtMessage = caughtMessage
                        });
                        break;

                    case AutomodQueueType.Unknown:
                        UnaccountedFor($"Unknown automod queue type. Msg: {automodQueue.RawData}");
                        break;
                    }
                    return;

                case "channel-subscribe-events-v1":
                    var subscription = msg.MessageData as ChannelSubscription;
                    OnChannelSubscription?.Invoke(this, new OnChannelSubscriptionArgs {
                        Subscription = subscription, ChannelId = channelId
                    });
                    return;

                case "whispers":
                    var whisper = (Whisper)msg.MessageData;
                    OnWhisper?.Invoke(this, new OnWhisperArgs {
                        Whisper = whisper, ChannelId = channelId
                    });
                    return;

                case "chat_moderator_actions":
                    var cma    = msg.MessageData as ChatModeratorActions;
                    var reason = "";
                    switch (cma?.ModerationAction.ToLower())
                    {
                    case "timeout":
                        if (cma.Args.Count > 2)
                        {
                            reason = cma.Args[2];
                        }
                        OnTimeout?.Invoke(this, new OnTimeoutArgs
                        {
                            TimedoutBy      = cma.CreatedBy,
                            TimedoutById    = cma.CreatedByUserId,
                            TimedoutUserId  = cma.TargetUserId,
                            TimeoutDuration = TimeSpan.FromSeconds(int.Parse(cma.Args[1])),
                            TimeoutReason   = reason,
                            TimedoutUser    = cma.Args[0],
                            ChannelId       = channelId
                        });
                        return;

                    case "ban":
                        if (cma.Args.Count > 1)
                        {
                            reason = cma.Args[1];
                        }
                        OnBan?.Invoke(this, new OnBanArgs {
                            BannedBy = cma.CreatedBy, BannedByUserId = cma.CreatedByUserId, BannedUserId = cma.TargetUserId, BanReason = reason, BannedUser = cma.Args[0], ChannelId = channelId
                        });
                        return;

                    case "delete":
                        OnMessageDeleted?.Invoke(this, new OnMessageDeletedArgs {
                            DeletedBy = cma.CreatedBy, DeletedByUserId = cma.CreatedByUserId, TargetUserId = cma.TargetUserId, TargetUser = cma.Args[0], Message = cma.Args[1], MessageId = cma.Args[2], ChannelId = channelId
                        });
                        return;

                    case "unban":
                        OnUnban?.Invoke(this, new OnUnbanArgs {
                            UnbannedBy = cma.CreatedBy, UnbannedByUserId = cma.CreatedByUserId, UnbannedUserId = cma.TargetUserId, UnbannedUser = cma.Args[0], ChannelId = channelId
                        });
                        return;

                    case "untimeout":
                        OnUntimeout?.Invoke(this, new OnUntimeoutArgs {
                            UntimeoutedBy = cma.CreatedBy, UntimeoutedByUserId = cma.CreatedByUserId, UntimeoutedUserId = cma.TargetUserId, UntimeoutedUser = cma.Args[0], ChannelId = channelId
                        });
                        return;

                    case "host":
                        OnHost?.Invoke(this, new OnHostArgs {
                            HostedChannel = cma.Args[0], Moderator = cma.CreatedBy, ChannelId = channelId
                        });
                        return;

                    case "subscribers":
                        OnSubscribersOnly?.Invoke(this, new OnSubscribersOnlyArgs {
                            Moderator = cma.CreatedBy, ChannelId = channelId
                        });
                        return;

                    case "subscribersoff":
                        OnSubscribersOnlyOff?.Invoke(this, new OnSubscribersOnlyOffArgs {
                            Moderator = cma.CreatedBy, ChannelId = channelId
                        });
                        return;

                    case "clear":
                        OnClear?.Invoke(this, new OnClearArgs {
                            Moderator = cma.CreatedBy, ChannelId = channelId
                        });
                        return;

                    case "emoteonly":
                        OnEmoteOnly?.Invoke(this, new OnEmoteOnlyArgs {
                            Moderator = cma.CreatedBy, ChannelId = channelId
                        });
                        return;

                    case "emoteonlyoff":
                        OnEmoteOnlyOff?.Invoke(this, new OnEmoteOnlyOffArgs {
                            Moderator = cma.CreatedBy, ChannelId = channelId
                        });
                        return;

                    case "r9kbeta":
                        OnR9kBeta?.Invoke(this, new OnR9kBetaArgs {
                            Moderator = cma.CreatedBy, ChannelId = channelId
                        });
                        return;

                    case "r9kbetaoff":
                        OnR9kBetaOff?.Invoke(this, new OnR9kBetaOffArgs {
                            Moderator = cma.CreatedBy, ChannelId = channelId
                        });
                        return;
                    }
                    break;

                case "channel-bits-events-v1":
                    if (msg.MessageData is ChannelBitsEvents cbe)
                    {
                        OnBitsReceived?.Invoke(this, new OnBitsReceivedArgs
                        {
                            BitsUsed      = cbe.BitsUsed,
                            ChannelId     = cbe.ChannelId,
                            ChannelName   = cbe.ChannelName,
                            ChatMessage   = cbe.ChatMessage,
                            Context       = cbe.Context,
                            Time          = cbe.Time,
                            TotalBitsUsed = cbe.TotalBitsUsed,
                            UserId        = cbe.UserId,
                            Username      = cbe.Username
                        });
                        return;
                    }
                    break;

                case "channel-bits-events-v2":
                    if (msg.MessageData is ChannelBitsEventsV2 cbev2)
                    {
                        OnBitsReceivedV2?.Invoke(this, new OnBitsReceivedV2Args
                        {
                            IsAnonymous   = cbev2.IsAnonymous,
                            BitsUsed      = cbev2.BitsUsed,
                            ChannelId     = cbev2.ChannelId,
                            ChannelName   = cbev2.ChannelName,
                            ChatMessage   = cbev2.ChatMessage,
                            Context       = cbev2.Context,
                            Time          = cbev2.Time,
                            TotalBitsUsed = cbev2.TotalBitsUsed,
                            UserId        = cbev2.UserId,
                            UserName      = cbev2.UserName
                        });
                        return;
                    }
                    break;

                case "channel-commerce-events-v1":
                    if (msg.MessageData is ChannelCommerceEvents cce)
                    {
                        OnChannelCommerceReceived?.Invoke(this, new OnChannelCommerceReceivedArgs
                        {
                            Username        = cce.Username,
                            DisplayName     = cce.DisplayName,
                            ChannelName     = cce.ChannelName,
                            UserId          = cce.UserId,
                            ChannelId       = cce.ChannelId,
                            Time            = cce.Time,
                            ItemImageURL    = cce.ItemImageURL,
                            ItemDescription = cce.ItemDescription,
                            SupportsChannel = cce.SupportsChannel,
                            PurchaseMessage = cce.PurchaseMessage
                        });
                        return;
                    }
                    break;

                case "channel-ext-v1":
                    var cEB = msg.MessageData as ChannelExtensionBroadcast;
                    OnChannelExtensionBroadcast?.Invoke(this, new OnChannelExtensionBroadcastArgs {
                        Messages = cEB.Messages, ChannelId = channelId
                    });
                    return;

                case "video-playback-by-id":
                    var vP = msg.MessageData as VideoPlayback;
                    switch (vP?.Type)
                    {
                    case VideoPlaybackType.StreamDown:
                        OnStreamDown?.Invoke(this, new OnStreamDownArgs {
                            ServerTime = vP.ServerTime, ChannelId = channelId
                        });
                        return;

                    case VideoPlaybackType.StreamUp:
                        OnStreamUp?.Invoke(this, new OnStreamUpArgs {
                            PlayDelay = vP.PlayDelay, ServerTime = vP.ServerTime, ChannelId = channelId
                        });
                        return;

                    case VideoPlaybackType.ViewCount:
                        OnViewCount?.Invoke(this, new OnViewCountArgs {
                            ServerTime = vP.ServerTime, Viewers = vP.Viewers, ChannelId = channelId
                        });
                        return;

                    case VideoPlaybackType.Commercial:
                        OnCommercial?.Invoke(this, new OnCommercialArgs {
                            ServerTime = vP.ServerTime, Length = vP.Length, ChannelId = channelId
                        });
                        return;
                    }
                    break;

                case "following":
                    var f = (Following)msg.MessageData;
                    f.FollowedChannelId = msg.Topic.Split('.')[1];
                    OnFollow?.Invoke(this, new OnFollowArgs {
                        FollowedChannelId = f.FollowedChannelId, DisplayName = f.DisplayName, UserId = f.UserId, Username = f.Username
                    });
                    return;

                case "community-points-channel-v1":
                    var cpc = msg.MessageData as CommunityPointsChannel;
                    switch (cpc?.Type)
                    {
                    case CommunityPointsChannelType.RewardRedeemed:
                        OnRewardRedeemed?.Invoke(this, new OnRewardRedeemedArgs {
                            TimeStamp = cpc.TimeStamp, ChannelId = cpc.ChannelId, Login = cpc.Login, DisplayName = cpc.DisplayName, Message = cpc.Message, RewardId = cpc.RewardId, RewardTitle = cpc.RewardTitle, RewardPrompt = cpc.RewardPrompt, RewardCost = cpc.RewardCost, Status = cpc.Status, RedemptionId = cpc.RedemptionId
                        });
                        return;

                    case CommunityPointsChannelType.CustomRewardUpdated:
                        OnCustomRewardUpdated?.Invoke(this, new OnCustomRewardUpdatedArgs {
                            TimeStamp = cpc.TimeStamp, ChannelId = cpc.ChannelId, RewardId = cpc.RewardId, RewardTitle = cpc.RewardTitle, RewardPrompt = cpc.RewardPrompt, RewardCost = cpc.RewardCost
                        });
                        return;

                    case CommunityPointsChannelType.CustomRewardCreated:
                        OnCustomRewardCreated?.Invoke(this, new OnCustomRewardCreatedArgs {
                            TimeStamp = cpc.TimeStamp, ChannelId = cpc.ChannelId, RewardId = cpc.RewardId, RewardTitle = cpc.RewardTitle, RewardPrompt = cpc.RewardPrompt, RewardCost = cpc.RewardCost
                        });
                        return;

                    case CommunityPointsChannelType.CustomRewardDeleted:
                        OnCustomRewardDeleted?.Invoke(this, new OnCustomRewardDeletedArgs {
                            TimeStamp = cpc.TimeStamp, ChannelId = cpc.ChannelId, RewardId = cpc.RewardId, RewardTitle = cpc.RewardTitle, RewardPrompt = cpc.RewardPrompt
                        });
                        return;
                    }
                    return;

                case "channel-points-channel-v1":
                    var channelPointsChannel = msg.MessageData as ChannelPointsChannel;
                    switch (channelPointsChannel.Type)
                    {
                    case ChannelPointsChannelType.RewardRedeemed:
                        var rewardRedeemed = channelPointsChannel.Data as RewardRedeemed;
                        OnChannelPointsRewardRedeemed?.Invoke(this, new OnChannelPointsRewardRedeemedArgs {
                            ChannelId = rewardRedeemed.Redemption.ChannelId, RewardRedeemed = rewardRedeemed
                        });
                        break;

                    case ChannelPointsChannelType.Unknown:
                        UnaccountedFor($"Unknown channel points type. Msg: {channelPointsChannel.RawData}");
                        break;
                    }
                    return;

                case "leaderboard-events-v1":
                    var lbe = msg.MessageData as LeaderboardEvents;
                    switch (lbe?.Type)
                    {
                    case LeaderBoardType.BitsUsageByChannel:
                        OnLeaderboardBits?.Invoke(this, new OnLeaderboardEventArgs {
                            ChannelId = lbe.ChannelId, TopList = lbe.Top
                        });
                        return;

                    case LeaderBoardType.SubGiftSent:
                        OnLeaderboardSubs?.Invoke(this, new OnLeaderboardEventArgs {
                            ChannelId = lbe.ChannelId, TopList = lbe.Top
                        });
                        return;
                    }
                    return;

                case "raid":
                    var r = msg.MessageData as RaidEvents;
                    switch (r?.Type)
                    {
                    case RaidType.RaidUpdate:
                        OnRaidUpdate?.Invoke(this, new OnRaidUpdateArgs {
                            Id = r.Id, ChannelId = r.ChannelId, TargetChannelId = r.TargetChannelId, AnnounceTime = r.AnnounceTime, RaidTime = r.RaidTime, RemainingDurationSeconds = r.RemainigDurationSeconds, ViewerCount = r.ViewerCount
                        });
                        return;

                    case RaidType.RaidUpdateV2:
                        OnRaidUpdateV2?.Invoke(this, new OnRaidUpdateV2Args {
                            Id = r.Id, ChannelId = r.ChannelId, TargetChannelId = r.TargetChannelId, TargetLogin = r.TargetLogin, TargetDisplayName = r.TargetDisplayName, TargetProfileImage = r.TargetProfileImage, ViewerCount = r.ViewerCount
                        });
                        return;

                    case RaidType.RaidGo:
                        OnRaidGo?.Invoke(this, new OnRaidGoArgs {
                            Id = r.Id, ChannelId = r.ChannelId, TargetChannelId = r.TargetChannelId, TargetLogin = r.TargetLogin, TargetDisplayName = r.TargetDisplayName, TargetProfileImage = r.TargetProfileImage, ViewerCount = r.ViewerCount
                        });
                        return;
                    }
                    return;

                case "predictions-channel-v1":
                    var pred = msg.MessageData as PredictionEvents;
                    switch (pred?.Type)
                    {
                    case PredictionType.EventCreated:
                        OnPrediction?.Invoke(this, new OnPredictionArgs {
                            CreatedAt = pred.CreatedAt, Title = pred.Title, ChannelId = pred.ChannelId, EndedAt = pred.EndedAt, Id = pred.Id, Outcomes = pred.Outcomes, LockedAt = pred.LockedAt, PredictionTime = pred.PredictionTime, Status = pred.Status, WinningOutcomeId = pred.WinningOutcomeId, Type = pred.Type
                        });
                        return;

                    case PredictionType.EventUpdated:
                        OnPrediction?.Invoke(this, new OnPredictionArgs {
                            CreatedAt = pred.CreatedAt, Title = pred.Title, ChannelId = pred.ChannelId, EndedAt = pred.EndedAt, Id = pred.Id, Outcomes = pred.Outcomes, LockedAt = pred.LockedAt, PredictionTime = pred.PredictionTime, Status = pred.Status, WinningOutcomeId = pred.WinningOutcomeId, Type = pred.Type
                        });
                        return;

                    case null:
                        UnaccountedFor("Prediction Type: null");
                        break;

                    default:
                        UnaccountedFor($"Prediction Type: {pred.Type}");
                        break;
                    }
                    return;
                }
                break;

            case "pong":
                _pongReceived = true;
                return;

            case "reconnect": _socket.Close(); break;
            }
            UnaccountedFor(message);
        }
示例#3
0
        /// <summary>
        /// Parses the message.
        /// </summary>
        /// <param name="message">The message.</param>
        private void ParseMessage(string message)
        {
            var type = JObject.Parse(message).SelectToken("type")?.ToString();

            switch (type?.ToLower())
            {
            case "response":
                var resp = new Models.Responses.Response(message);
                if (_previousRequests.Count != 0)
                {
                    bool handled = false;
                    foreach (var request in _previousRequests)
                    {
                        if (string.Equals(request.Nonce, resp.Nonce, StringComparison.CurrentCulture))
                        {
                            OnListenResponse?.Invoke(this, new OnListenResponseArgs {
                                Response = resp, Topic = request.Topic, Successful = resp.Successful
                            });
                            handled = true;
                        }
                    }
                    if (handled)
                    {
                        return;
                    }
                }
                break;

            case "message":
                var msg = new Models.Responses.Message(message);
                _topicToChannelId.TryGetValue(msg.Topic, out var channelId);
                channelId = channelId ?? "";
                switch (msg.Topic.Split('.')[0])
                {
                case "channel-subscribe-events-v1":
                    var subscription = msg.MessageData as ChannelSubscription;
                    OnChannelSubscription?.Invoke(this, new OnChannelSubscriptionArgs {
                        Subscription = subscription, ChannelId = channelId
                    });
                    return;

                case "whispers":
                    var whisper = (Whisper)msg.MessageData;
                    OnWhisper?.Invoke(this, new OnWhisperArgs {
                        Whisper = whisper, ChannelId = channelId
                    });
                    return;

                case "chat_moderator_actions":
                    var cma             = msg.MessageData as ChatModeratorActions;
                    var reason          = "";
                    var targetChannelId = msg.Topic.Split('.')[2];
                    switch (cma?.ModerationAction.ToLower())
                    {
                    case "timeout":
                        if (cma.Args.Count > 2)
                        {
                            reason = cma.Args[2];
                        }
                        OnTimeout?.Invoke(this, new OnTimeoutArgs
                        {
                            TimedoutBy      = cma.CreatedBy,
                            TimedoutById    = cma.CreatedByUserId,
                            TimedoutUserId  = cma.TargetUserId,
                            TimeoutDuration = TimeSpan.FromSeconds(int.Parse(cma.Args[1])),
                            TimeoutReason   = reason,
                            TimedoutUser    = cma.Args[0],
                            ChannelId       = channelId
                        });
                        return;

                    case "ban":
                        if (cma.Args.Count > 1)
                        {
                            reason = cma.Args[1];
                        }
                        OnBan?.Invoke(this, new OnBanArgs {
                            BannedBy = cma.CreatedBy, BannedByUserId = cma.CreatedByUserId, BannedUserId = cma.TargetUserId, BanReason = reason, BannedUser = cma.Args[0], ChannelId = channelId
                        });
                        return;

                    case "delete":
                        OnMessageDeleted?.Invoke(this, new OnMessageDeletedArgs {
                            DeletedBy = cma.CreatedBy, DeletedByUserId = cma.CreatedByUserId, TargetUserId = cma.TargetUserId, TargetUser = cma.Args[0], Message = cma.Args[1], MessageId = cma.Args[2], ChannelId = channelId
                        });
                        return;

                    case "unban":
                        OnUnban?.Invoke(this, new OnUnbanArgs {
                            UnbannedBy = cma.CreatedBy, UnbannedByUserId = cma.CreatedByUserId, UnbannedUserId = cma.TargetUserId, UnbannedUser = cma.Args[0], ChannelId = channelId
                        });
                        return;

                    case "untimeout":
                        OnUntimeout?.Invoke(this, new OnUntimeoutArgs {
                            UntimeoutedBy = cma.CreatedBy, UntimeoutedByUserId = cma.CreatedByUserId, UntimeoutedUserId = cma.TargetUserId, UntimeoutedUser = cma.Args[0], ChannelId = channelId
                        });
                        return;

                    case "host":
                        OnHost?.Invoke(this, new OnHostArgs {
                            HostedChannel = cma.Args[0], Moderator = cma.CreatedBy, ChannelId = channelId
                        });
                        return;

                    case "subscribers":
                        OnSubscribersOnly?.Invoke(this, new OnSubscribersOnlyArgs {
                            Moderator = cma.CreatedBy, ChannelId = channelId
                        });
                        return;

                    case "subscribersoff":
                        OnSubscribersOnlyOff?.Invoke(this, new OnSubscribersOnlyOffArgs {
                            Moderator = cma.CreatedBy, ChannelId = channelId
                        });
                        return;

                    case "clear":
                        OnClear?.Invoke(this, new OnClearArgs {
                            Moderator = cma.CreatedBy, ChannelId = channelId
                        });
                        return;

                    case "emoteonly":
                        OnEmoteOnly?.Invoke(this, new OnEmoteOnlyArgs {
                            Moderator = cma.CreatedBy, ChannelId = channelId
                        });
                        return;

                    case "emoteonlyoff":
                        OnEmoteOnlyOff?.Invoke(this, new OnEmoteOnlyOffArgs {
                            Moderator = cma.CreatedBy, ChannelId = channelId
                        });
                        return;

                    case "r9kbeta":
                        OnR9kBeta?.Invoke(this, new OnR9kBetaArgs {
                            Moderator = cma.CreatedBy, ChannelId = channelId
                        });
                        return;

                    case "r9kbetaoff":
                        OnR9kBetaOff?.Invoke(this, new OnR9kBetaOffArgs {
                            Moderator = cma.CreatedBy, ChannelId = channelId
                        });
                        return;
                    }
                    break;

                case "channel-bits-events-v1":
                    if (msg.MessageData is ChannelBitsEvents cbe)
                    {
                        OnBitsReceived?.Invoke(this, new OnBitsReceivedArgs
                        {
                            BitsUsed      = cbe.BitsUsed,
                            ChannelId     = cbe.ChannelId,
                            ChannelName   = cbe.ChannelName,
                            ChatMessage   = cbe.ChatMessage,
                            Context       = cbe.Context,
                            Time          = cbe.Time,
                            TotalBitsUsed = cbe.TotalBitsUsed,
                            UserId        = cbe.UserId,
                            Username      = cbe.Username
                        });
                        return;
                    }
                    break;

                case "channel-commerce-events-v1":
                    if (msg.MessageData is ChannelCommerceEvents cce)
                    {
                        OnChannelCommerceReceived?.Invoke(this, new OnChannelCommerceReceivedArgs
                        {
                            Username        = cce.Username,
                            DisplayName     = cce.DisplayName,
                            ChannelName     = cce.ChannelName,
                            UserId          = cce.UserId,
                            ChannelId       = cce.ChannelId,
                            Time            = cce.Time,
                            ItemImageURL    = cce.ItemImageURL,
                            ItemDescription = cce.ItemDescription,
                            SupportsChannel = cce.SupportsChannel,
                            PurchaseMessage = cce.PurchaseMessage
                        });
                        return;
                    }
                    break;

                case "channel-ext-v1":
                    var cEB = msg.MessageData as ChannelExtensionBroadcast;
                    OnChannelExtensionBroadcast?.Invoke(this, new OnChannelExtensionBroadcastArgs {
                        Messages = cEB.Messages, ChannelId = channelId
                    });
                    return;

                case "video-playback":
                case "video-playback-by-id":
                    var vP = msg.MessageData as VideoPlayback;
                    switch (vP?.Type)
                    {
                    case VideoPlaybackType.StreamDown:
                        OnStreamDown?.Invoke(this, new OnStreamDownArgs {
                            ChannelId = channelId, ServerTime = vP.ServerTime
                        });
                        return;

                    case VideoPlaybackType.StreamUp:
                        OnStreamUp?.Invoke(this, new OnStreamUpArgs {
                            ChannelId = channelId, PlayDelay = vP.PlayDelay, ServerTime = vP.ServerTime
                        });
                        return;

                    case VideoPlaybackType.ViewCount:
                        OnViewCount?.Invoke(this, new OnViewCountArgs {
                            ChannelId = channelId, ServerTime = vP.ServerTime, Viewers = vP.Viewers
                        });
                        return;

                    case VideoPlaybackType.Commercial:
                        OnCommercial?.Invoke(this, new OnCommercialArgs {
                            ChannelId = channelId, ServerTime = vP.ServerTime, Length = vP.Length
                        });
                        return;

                    case VideoPlaybackType.WatchPartyVod:
                        OnWatchPartyVod?.Invoke(this, new OnWatchPartyVodArgs {
                            ChannelId = channelId, WpId = vP.WpId, WpType = vP.WpType, IncrementUrl = vP.IncrementUrl, VodId = vP.VodId, Title = vP.Title, BroadcastType = vP.BroadcastType, Viewable = vP.Viewable
                        });
                        return;
                    }
                    break;

                case "broadcast-settings-update":
                    var bsu = msg.MessageData as BroadcastSettingsUpdate;
                    switch (bsu?.Type)
                    {
                    case BroadcastSettingsUpdateType.BroadcastSettingsUpdate:
                        OnBroadcastSettingsUpdate?.Invoke(this, new OnBroadcastSettingsUpdateArgs {
                            ChannelId = channelId, Channel = bsu.Channel, Game = bsu.Game, GameId = bsu.GameId, OldGame = bsu.OldGame, OldGameId = bsu.OldGameId, OldStatus = bsu.OldStatus, Status = bsu.Status
                        });
                        return;
                    }
                    break;

                case "following":
                    var f = (Following)msg.MessageData;
                    f.FollowedChannelId = msg.Topic.Split('.')[1];
                    OnFollow?.Invoke(this, new OnFollowArgs {
                        FollowedChannelId = f.FollowedChannelId, DisplayName = f.DisplayName, UserId = f.UserId, Username = f.Username
                    });
                    return;

                case "community-points-channel-v1":
                    var cpc = msg.MessageData as CommunityPointsChannel;
                    switch (cpc?.Type)
                    {
                    case CommunityPointsChannelType.RewardRedeemed:
                        OnRewardRedeemed?.Invoke(this, new OnRewardRedeemedArgs {
                            TimeStamp = cpc.TimeStamp, ChannelId = cpc.ChannelId, Login = cpc.Login, DisplayName = cpc.DisplayName, Message = cpc.Message, RewardId = cpc.RewardId, RewardTitle = cpc.RewardTitle, RewardPrompt = cpc.RewardPrompt, RewardCost = cpc.RewardCost, Status = cpc.Status
                        });
                        return;

                    case CommunityPointsChannelType.CustomRewardUpdated:
                        OnCustomRewardUpdated?.Invoke(this, new OnCustomRewardUpdatedArgs {
                            TimeStamp = cpc.TimeStamp, ChannelId = cpc.ChannelId, RewardId = cpc.RewardId, RewardTitle = cpc.RewardTitle, RewardPrompt = cpc.RewardPrompt, RewardCost = cpc.RewardCost
                        });
                        return;

                    case CommunityPointsChannelType.CustomRewardCreated:
                        OnCustomRewardCreated?.Invoke(this, new OnCustomRewardCreatedArgs {
                            TimeStamp = cpc.TimeStamp, ChannelId = cpc.ChannelId, RewardId = cpc.RewardId, RewardTitle = cpc.RewardTitle, RewardPrompt = cpc.RewardPrompt, RewardCost = cpc.RewardCost
                        });
                        return;

                    case CommunityPointsChannelType.CustomRewardDeleted:
                        OnCustomRewardDeleted?.Invoke(this, new OnCustomRewardDeletedArgs {
                            TimeStamp = cpc.TimeStamp, ChannelId = cpc.ChannelId, RewardId = cpc.RewardId, RewardTitle = cpc.RewardTitle, RewardPrompt = cpc.RewardPrompt
                        });
                        return;
                    }
                    return;

                case "leaderboard-events-v1":
                    var lbe = msg.MessageData as LeaderboardEvents;
                    switch (lbe?.Type)
                    {
                    case LeaderBoardType.BitsUsageByChannel:
                        OnLeaderboardBits?.Invoke(this, new OnLeaderboardEventArgs {
                            ChannelId = lbe.ChannelId, TopList = lbe.Top
                        });
                        return;

                    case LeaderBoardType.SubGiftSent:
                        OnLeaderboardSubs?.Invoke(this, new OnLeaderboardEventArgs {
                            ChannelId = lbe.ChannelId, TopList = lbe.Top
                        });
                        return;
                    }
                    return;

                case "raid":
                    var r = msg.MessageData as RaidEvents;
                    switch (r?.Type)
                    {
                    case RaidType.RaidUpdate:
                        OnRaidUpdate?.Invoke(this, new OnRaidUpdateArgs {
                            Id = r.Id, ChannelId = r.ChannelId, TargetChannelId = r.TargetChannelId, AnnounceTime = r.AnnounceTime, RaidTime = r.RaidTime, RemainingDurationSeconds = r.RemainigDurationSeconds, ViewerCount = r.ViewerCount
                        });
                        return;

                    case RaidType.RaidUpdateV2:
                        OnRaidUpdateV2?.Invoke(this, new OnRaidUpdateV2Args {
                            Id = r.Id, ChannelId = r.ChannelId, TargetChannelId = r.TargetChannelId, TargetLogin = r.TargetLogin, TargetDisplayName = r.TargetDisplayName, TargetProfileImage = r.TargetProfileImage, ViewerCount = r.ViewerCount
                        });
                        return;

                    case RaidType.RaidGo:
                        OnRaidGo?.Invoke(this, new OnRaidGoArgs {
                            Id = r.Id, ChannelId = r.ChannelId, TargetChannelId = r.TargetChannelId, TargetLogin = r.TargetLogin, TargetDisplayName = r.TargetDisplayName, TargetProfileImage = r.TargetProfileImage, ViewerCount = r.ViewerCount
                        });
                        return;
                    }
                    return;
                }
                break;
            }
            UnaccountedFor(message);
        }