private async Task ProcessMessageAsync(string cmd, Optional <string> evnt, Optional <object> payload)
        {
            try
            {
                switch (cmd)
                {
                case "DISPATCH":
                    switch (evnt.Value)
                    {
                    //Connection
                    case "READY":
                    {
                        await _rpcLogger.DebugAsync("Received Dispatch (READY)").ConfigureAwait(false);

                        var data = (payload.Value as JToken).ToObject <ReadyEvent>(_serializer);

                        RequestOptions options = new RequestOptions
                        {
                            //CancellationToken = _cancelToken //TODO: Implement
                        };

                        if (ApiClient.LoginState == LoginState.LoggedIn)
                        {
                            var _ = Task.Run(async() =>
                                {
                                    try
                                    {
                                        var response            = await ApiClient.SendAuthenticateAsync(options).ConfigureAwait(false);
                                        CurrentUser             = RestSelfUser.Create(this, response.User);
                                        ApiClient.CurrentUserId = CurrentUser.Id;
                                        ApplicationInfo         = RestApplication.Create(this, response.Application);
                                        Scopes         = response.Scopes;
                                        TokenExpiresAt = response.Expires;

                                        var __ = _connectTask.TrySetResultAsync(true);         //Signal the .Connect() call to complete
                                        await _rpcLogger.InfoAsync("Ready").ConfigureAwait(false);
                                    }
                                    catch (Exception ex)
                                    {
                                        await _rpcLogger.ErrorAsync($"Error handling {cmd}{(evnt.IsSpecified ? $" ({evnt})" : "")}", ex).ConfigureAwait(false);
                                        return;
                                    }
                                });
                        }
                        else
                        {
                            var _ = _connectTask.TrySetResultAsync(true);             //Signal the .Connect() call to complete
                            await _rpcLogger.InfoAsync("Ready").ConfigureAwait(false);
                        }
                    }
                    break;

                    //Channels
                    case "CHANNEL_CREATE":
                    {
                        await _rpcLogger.DebugAsync("Received Dispatch (CHANNEL_CREATE)").ConfigureAwait(false);

                        var data    = (payload.Value as JToken).ToObject <ChannelSummary>(_serializer);
                        var channel = RpcChannelSummary.Create(data);

                        await _channelCreatedEvent.InvokeAsync(channel).ConfigureAwait(false);
                    }
                    break;

                    //Guilds
                    case "GUILD_CREATE":
                    {
                        await _rpcLogger.DebugAsync("Received Dispatch (GUILD_CREATE)").ConfigureAwait(false);

                        var data  = (payload.Value as JToken).ToObject <GuildSummary>(_serializer);
                        var guild = RpcGuildSummary.Create(data);

                        await _guildCreatedEvent.InvokeAsync(guild).ConfigureAwait(false);
                    }
                    break;

                    case "GUILD_STATUS":
                    {
                        await _rpcLogger.DebugAsync("Received Dispatch (GUILD_STATUS)").ConfigureAwait(false);

                        var data        = (payload.Value as JToken).ToObject <GuildStatusEvent>(_serializer);
                        var guildStatus = RpcGuildStatus.Create(data);

                        await _guildStatusUpdatedEvent.InvokeAsync(guildStatus).ConfigureAwait(false);
                    }
                    break;

                    //Voice
                    case "VOICE_STATE_CREATE":
                    {
                        await _rpcLogger.DebugAsync("Received Dispatch (VOICE_STATE_CREATE)").ConfigureAwait(false);

                        var data       = (payload.Value as JToken).ToObject <ExtendedVoiceState>(_serializer);
                        var voiceState = RpcVoiceState.Create(this, data);

                        await _voiceStateCreatedEvent.InvokeAsync(voiceState).ConfigureAwait(false);
                    }
                    break;

                    case "VOICE_STATE_UPDATE":
                    {
                        await _rpcLogger.DebugAsync("Received Dispatch (VOICE_STATE_UPDATE)").ConfigureAwait(false);

                        var data       = (payload.Value as JToken).ToObject <ExtendedVoiceState>(_serializer);
                        var voiceState = RpcVoiceState.Create(this, data);

                        await _voiceStateUpdatedEvent.InvokeAsync(voiceState).ConfigureAwait(false);
                    }
                    break;

                    case "VOICE_STATE_DELETE":
                    {
                        await _rpcLogger.DebugAsync("Received Dispatch (VOICE_STATE_DELETE)").ConfigureAwait(false);

                        var data       = (payload.Value as JToken).ToObject <ExtendedVoiceState>(_serializer);
                        var voiceState = RpcVoiceState.Create(this, data);

                        await _voiceStateDeletedEvent.InvokeAsync(voiceState).ConfigureAwait(false);
                    }
                    break;

                    case "SPEAKING_START":
                    {
                        await _rpcLogger.DebugAsync("Received Dispatch (SPEAKING_START)").ConfigureAwait(false);

                        var data = (payload.Value as JToken).ToObject <SpeakingEvent>(_serializer);

                        await _speakingStartedEvent.InvokeAsync(data.UserId).ConfigureAwait(false);
                    }
                    break;

                    case "SPEAKING_STOP":
                    {
                        await _rpcLogger.DebugAsync("Received Dispatch (SPEAKING_STOP)").ConfigureAwait(false);

                        var data = (payload.Value as JToken).ToObject <SpeakingEvent>(_serializer);

                        await _speakingStoppedEvent.InvokeAsync(data.UserId).ConfigureAwait(false);
                    }
                    break;

                    case "VOICE_SETTINGS_UPDATE":
                    {
                        await _rpcLogger.DebugAsync("Received Dispatch (VOICE_SETTINGS_UPDATE)").ConfigureAwait(false);

                        var data     = (payload.Value as JToken).ToObject <API.Rpc.VoiceSettings>(_serializer);
                        var settings = VoiceSettings.Create(data);

                        await _voiceSettingsUpdated.InvokeAsync(settings).ConfigureAwait(false);
                    }
                    break;

                    //Messages
                    case "MESSAGE_CREATE":
                    {
                        await _rpcLogger.DebugAsync("Received Dispatch (MESSAGE_CREATE)").ConfigureAwait(false);

                        var data = (payload.Value as JToken).ToObject <MessageEvent>(_serializer);
                        var msg  = RpcMessage.Create(this, data.ChannelId, data.Message);

                        await _messageReceivedEvent.InvokeAsync(msg).ConfigureAwait(false);
                    }
                    break;

                    case "MESSAGE_UPDATE":
                    {
                        await _rpcLogger.DebugAsync("Received Dispatch (MESSAGE_UPDATE)").ConfigureAwait(false);

                        var data = (payload.Value as JToken).ToObject <MessageEvent>(_serializer);
                        var msg  = RpcMessage.Create(this, data.ChannelId, data.Message);

                        await _messageUpdatedEvent.InvokeAsync(msg).ConfigureAwait(false);
                    }
                    break;

                    case "MESSAGE_DELETE":
                    {
                        await _rpcLogger.DebugAsync("Received Dispatch (MESSAGE_DELETE)").ConfigureAwait(false);

                        var data = (payload.Value as JToken).ToObject <MessageEvent>(_serializer);

                        await _messageDeletedEvent.InvokeAsync(data.ChannelId, data.Message.Id).ConfigureAwait(false);
                    }
                    break;

                    //Others
                    default:
                        await _rpcLogger.WarningAsync($"Unknown Dispatch ({evnt})").ConfigureAwait(false);

                        return;
                    }
                    break;

                    /*default: //Other opcodes are used for command responses
                     *  await _rpcLogger.WarningAsync($"Unknown OpCode ({cmd})").ConfigureAwait(false);
                     *  return;*/
                }
            }
            catch (Exception ex)
            {
                await _rpcLogger.ErrorAsync($"Error handling {cmd}{(evnt.IsSpecified ? $" ({evnt})" : "")}", ex).ConfigureAwait(false);

                return;
            }
        }
        public async Task <IReadOnlyCollection <RpcChannelSummary> > GetRpcChannelsAsync(ulong guildId, RequestOptions options = null)
        {
            var models = await ApiClient.SendGetChannelsAsync(guildId, options).ConfigureAwait(false);

            return(models.Channels.Select(x => RpcChannelSummary.Create(x)).ToImmutableArray());
        }