public PubSub(EndPoint proxy = null) : base(null) { ThreadDispatcher.EnsureCreated(); base.OnPubSubServiceConnected += ((object sender, EventArgs e) => { ThreadDispatcher.Enqueue(() => OnPubSubServiceConnected?.Invoke(sender, e)); }); base.OnPubSubServiceError += ((object sender, OnPubSubServiceErrorArgs e) => { ThreadDispatcher.Enqueue(() => OnPubSubServiceError?.Invoke(sender, e)); }); base.OnPubSubServiceClosed += ((object sender, EventArgs e) => { ThreadDispatcher.Enqueue(() => OnPubSubServiceClosed?.Invoke(sender, e)); }); base.OnListenResponse += ((object sender, OnListenResponseArgs e) => { ThreadDispatcher.Enqueue(() => OnListenResponse?.Invoke(sender, e)); }); base.OnTimeout += ((object sender, OnTimeoutArgs e) => { ThreadDispatcher.Enqueue(() => OnTimeout?.Invoke(sender, e)); }); base.OnBan += ((object sender, OnBanArgs e) => { ThreadDispatcher.Enqueue(() => OnBan?.Invoke(sender, e)); }); base.OnUnban += ((object sender, OnUnbanArgs e) => { ThreadDispatcher.Enqueue(() => OnUnban?.Invoke(sender, e)); }); base.OnUntimeout += ((object sender, OnUntimeoutArgs e) => { ThreadDispatcher.Enqueue(() => OnUntimeout?.Invoke(sender, e)); }); base.OnHost += ((object sender, OnHostArgs e) => { ThreadDispatcher.Enqueue(() => OnHost?.Invoke(sender, e)); }); base.OnSubscribersOnly += ((object sender, OnSubscribersOnlyArgs e) => { ThreadDispatcher.Enqueue(() => OnSubscribersOnly?.Invoke(sender, e)); }); base.OnSubscribersOnlyOff += ((object sender, OnSubscribersOnlyOffArgs e) => { ThreadDispatcher.Enqueue(() => OnSubscribersOnlyOff?.Invoke(sender, e)); }); base.OnClear += ((object sender, OnClearArgs e) => { ThreadDispatcher.Enqueue(() => OnClear?.Invoke(sender, e)); }); base.OnEmoteOnly += ((object sender, OnEmoteOnlyArgs e) => { ThreadDispatcher.Enqueue(() => OnEmoteOnly?.Invoke(sender, e)); }); base.OnEmoteOnlyOff += ((object sender, OnEmoteOnlyOffArgs e) => { ThreadDispatcher.Enqueue(() => OnEmoteOnlyOff?.Invoke(sender, e)); }); base.OnR9kBeta += ((object sender, OnR9kBetaArgs e) => { ThreadDispatcher.Enqueue(() => OnR9kBeta?.Invoke(sender, e)); }); base.OnR9kBetaOff += ((object sender, OnR9kBetaOffArgs e) => { ThreadDispatcher.Enqueue(() => OnR9kBetaOff?.Invoke(sender, e)); }); base.OnBitsReceived += ((object sender, OnBitsReceivedArgs e) => { ThreadDispatcher.Enqueue(() => OnBitsReceived?.Invoke(sender, e)); }); base.OnStreamUp += ((object sender, OnStreamUpArgs arg) => { ThreadDispatcher.Enqueue(() => OnStreamUp(sender, arg)); }); base.OnStreamDown += ((object sender, OnStreamDownArgs e) => { ThreadDispatcher.Enqueue(() => OnStreamDown?.Invoke(sender, e)); }); base.OnViewCount += ((object sender, OnViewCountArgs e) => { ThreadDispatcher.Enqueue(() => OnViewCount?.Invoke(sender, e)); }); base.OnWhisper += ((object sender, OnWhisperArgs e) => { ThreadDispatcher.Enqueue(() => OnWhisper?.Invoke(sender, e)); }); base.OnChannelSubscription += ((object sender, OnChannelSubscriptionArgs e) => { ThreadDispatcher.Enqueue(() => OnChannelSubscription?.Invoke(sender, e)); }); base.OnChannelCommerceReceived += ((object sender, OnChannelCommerceReceivedArgs e) => { ThreadDispatcher.Enqueue(() => OnChannelCommerceReceived?.Invoke(sender, e)); }); base.OnChannelExtensionBroadcast += ((object sender, OnChannelExtensionBroadcastArgs e) => { ThreadDispatcher.Enqueue(() => OnChannelExtensionBroadcast?.Invoke(sender, e)); }); base.OnFollow += ((object sender, OnFollowArgs e) => { ThreadDispatcher.Enqueue(() => OnFollow?.Invoke(sender, e)); }); base.OnCustomRewardCreated += ((object sender, OnCustomRewardCreatedArgs e) => { ThreadDispatcher.Enqueue(() => OnCustomRewardCreated?.Invoke(sender, e)); }); base.OnCustomRewardUpdated += ((object sender, OnCustomRewardUpdatedArgs e) => { ThreadDispatcher.Enqueue(() => OnCustomRewardUpdated?.Invoke(sender, e)); }); base.OnCustomRewardDeleted += ((object sender, OnCustomRewardDeletedArgs e) => { ThreadDispatcher.Enqueue(() => OnCustomRewardDeleted?.Invoke(sender, e)); }); base.OnRewardRedeemed += ((object sender, OnRewardRedeemedArgs e) => { ThreadDispatcher.Enqueue(() => OnRewardRedeemed?.Invoke(sender, e)); }); base.OnBitsReceivedV2 += ((object sender, OnBitsReceivedV2Args e) => { ThreadDispatcher.Enqueue(() => OnBitsReceivedV2?.Invoke(sender, e)); }); base.OnLeaderboardSubs += ((object sender, OnLeaderboardEventArgs e) => { ThreadDispatcher.Enqueue(() => OnLeaderboardSubs?.Invoke(sender, e)); }); base.OnLeaderboardBits += ((object sender, OnLeaderboardEventArgs e) => { ThreadDispatcher.Enqueue(() => OnLeaderboardBits?.Invoke(sender, e)); }); base.OnRaidUpdate += ((object sender, OnRaidUpdateArgs e) => { ThreadDispatcher.Enqueue(() => OnRaidUpdate?.Invoke(sender, e)); }); base.OnRaidUpdateV2 += ((object sender, OnRaidUpdateV2Args e) => { ThreadDispatcher.Enqueue(() => OnRaidUpdateV2?.Invoke(sender, e)); }); base.OnRaidGo += ((object sender, OnRaidGoArgs e) => { ThreadDispatcher.Enqueue(() => OnRaidGo?.Invoke(sender, e)); }); base.OnMessageDeleted += ((object sender, OnMessageDeletedArgs e) => { ThreadDispatcher.Enqueue(() => OnMessageDeleted?.Invoke(sender, e)); }); base.OnLog += ((object sender, OnLogArgs e) => { ThreadDispatcher.Enqueue(() => OnLog?.Invoke(sender, e)); }); base.OnCommercial += ((object sender, OnCommercialArgs e) => { ThreadDispatcher.Enqueue(() => OnCommercial?.Invoke(sender, e)); }); base.OnPrediction += ((object sender, OnPredictionArgs e) => { ThreadDispatcher.Enqueue(() => OnPrediction?.Invoke(sender, e)); }); }
/// <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); }
/// <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); }