internal async Task SendAsync(DiscordFrameType type, object payload)
        {
            if (this.Pipe == null || !this.Pipe.IsConnected)
            {
                return;
            }

            var result = new DiscordFrame()
                         .WithType(type)
                         .WithPayload(payload)
                         .GetBytes();

            await this.RequireConnectedAsync().ConfigureAwait(false);

            await this.Pipe.WriteAsync(result, 0, result.Length).ConfigureAwait(false);
        }
        public async Task SetActivityAsync(DiscordActivity activity, int?pid = null)
        {
            var command = new DiscordCommand()
            {
                Command   = DiscordCommandType.SetActivity,
                Arguments = JObject.FromObject(new
                {
                    pid = pid.GetValueOrDefault(Process.GetCurrentProcess().Id),
                    activity
                })
            };

            var result = new DiscordFrame()
                         .WithType(DiscordFrameType.Frame)
                         .WithPayload(command)
                         .GetBytes();

            await this.RequireConnectedAsync().ConfigureAwait(false);

            await this.Pipe.WriteAsync(result, 0, result.Length).ConfigureAwait(false);
        }
        internal async Task HandleFrameAsync(DiscordFrame frame)
        {
            var payload = frame.Payload.ToObject <DiscordCommand>();

            if (!string.IsNullOrEmpty(payload.Nonce))
            {
                if (this.Callbacks.TryRemove(payload.Nonce, out var callback))
                {
                    _ = Task.Run(() => callback(this, payload).ConfigureAwait(false));
                    return;
                }
            }

            switch (payload.Command)
            {
            case DiscordCommandType.Dispatch:
                await this.HandleEventAsync(frame, payload).ConfigureAwait(false);

                break;
            }
        }
        internal async Task SendCommandAsync(DiscordFrameType type, DiscordCommand command, DiscordCommandCallback callback = null)
        {
            if (this.Pipe == null || !this.Pipe.IsConnected)
            {
                return;
            }

            var result = new DiscordFrame()
                         .WithType(type)
                         .WithPayload(command)
                         .GetBytes();

            if (callback != null)
            {
                this.Callbacks.AddOrUpdate(command.Nonce, callback, (key, old) => callback);
            }

            await this.RequireConnectedAsync().ConfigureAwait(false);

            await this.Pipe.WriteAsync(result, 0, result.Length).ConfigureAwait(false);
        }
        async Task ReadPipeAsync()
        {
            while (this.Pipe != null && this.Pipe.IsConnected)
            {
                try
                {
                    var raw = new byte[this.Pipe.InBufferSize];

                    if (await this.Pipe.ReadAsync(raw, 0, raw.Length).ConfigureAwait(false) > 0)
                    {
                        var frame = new DiscordFrame(raw);

                        Debug.WriteLine("[DISCORD-IPC] ReadPipeAsync(): <<: {0}", args: frame.GetJson());

                        switch (frame.Type)
                        {
                        case DiscordFrameType.Frame:
                            await this.HandleFrameAsync(frame);

                            break;

                        case DiscordFrameType.Close:
                            await this.DisconnectAsync();

                            break;
                        }
                    }

                    await Task.Delay(1);
                }
                catch (Exception ex)
                {
                    await this.Errored?.Invoke(ex);

                    await this.DisconnectAsync().ConfigureAwait(false);
                }
            }

            await this.DisconnectAsync().ConfigureAwait(false);
        }
        protected async Task HandleEventAsync(DiscordFrame frame, DiscordCommand command)
        {
            switch (command.Event)
            {
            case DiscordEventType.Ready:
            {
                var e = command.Data.ToObject <ReadyEventArgs>();
                e.Client = this;

                this.Environment = e.Configuration;
                this.RpcVersion  = e.Version;
                this.CurrentUser = e.User;

                var handler = this.Ready;

                if (handler != null)
                {
                    await handler.Invoke(e).ConfigureAwait(false);
                }
            }
            break;
            }
        }