| @@ -154,6 +154,7 @@ namespace Discord.Net.WebSockets | |||
| while (!cancelToken.IsCancellationRequested) | |||
| { | |||
| WebSocketReceiveResult socketResult = await _client.ReceiveAsync(buffer, cancelToken).ConfigureAwait(false); | |||
| System.Diagnostics.Debug.WriteLine("Got " + socketResult.Count); | |||
| byte[] result; | |||
| int resultCount; | |||
| @@ -193,6 +194,7 @@ namespace Discord.Net.WebSockets | |||
| result = buffer.Array; | |||
| } | |||
| System.Diagnostics.Debug.WriteLine("Start"); | |||
| if (socketResult.MessageType == WebSocketMessageType.Text) | |||
| { | |||
| string text = Encoding.UTF8.GetString(result, 0, resultCount); | |||
| @@ -200,6 +202,7 @@ namespace Discord.Net.WebSockets | |||
| } | |||
| else | |||
| await BinaryMessage(result, 0, resultCount).ConfigureAwait(false); | |||
| System.Diagnostics.Debug.WriteLine("Stop"); | |||
| } | |||
| } | |||
| catch (Win32Exception ex) when (ex.HResult == HR_TIMEOUT) | |||
| @@ -269,14 +269,14 @@ namespace Discord.API | |||
| options = RequestOptions.CreateOrClone(options); | |||
| return await SendRpcAsync<GetGuildsResponse>("GET_GUILDS", null, options: options).ConfigureAwait(false); | |||
| } | |||
| public async Task<Rpc.RpcGuild> SendGetGuildAsync(ulong guildId, RequestOptions options = null) | |||
| public async Task<Rpc.Guild> SendGetGuildAsync(ulong guildId, RequestOptions options = null) | |||
| { | |||
| options = RequestOptions.CreateOrClone(options); | |||
| var msg = new GetGuildParams | |||
| { | |||
| GuildId = guildId | |||
| }; | |||
| return await SendRpcAsync<Rpc.RpcGuild>("GET_GUILD", msg, options: options).ConfigureAwait(false); | |||
| return await SendRpcAsync<Rpc.Guild>("GET_GUILD", msg, options: options).ConfigureAwait(false); | |||
| } | |||
| public async Task<GetChannelsResponse> SendGetChannelsAsync(ulong guildId, RequestOptions options = null) | |||
| { | |||
| @@ -287,33 +287,34 @@ namespace Discord.API | |||
| }; | |||
| return await SendRpcAsync<GetChannelsResponse>("GET_CHANNELS", msg, options: options).ConfigureAwait(false); | |||
| } | |||
| public async Task<Rpc.RpcChannel> SendGetChannelAsync(ulong channelId, RequestOptions options = null) | |||
| public async Task<Rpc.Channel> SendGetChannelAsync(ulong channelId, RequestOptions options = null) | |||
| { | |||
| options = RequestOptions.CreateOrClone(options); | |||
| var msg = new GetChannelParams | |||
| { | |||
| ChannelId = channelId | |||
| }; | |||
| return await SendRpcAsync<Rpc.RpcChannel>("GET_CHANNEL", msg, options: options).ConfigureAwait(false); | |||
| return await SendRpcAsync<Rpc.Channel>("GET_CHANNEL", msg, options: options).ConfigureAwait(false); | |||
| } | |||
| public async Task<SetLocalVolumeResponse> SendSetLocalVolumeAsync(int volume, RequestOptions options = null) | |||
| public async Task<Rpc.Channel> SendSelectTextChannelAsync(ulong channelId, RequestOptions options = null) | |||
| { | |||
| options = RequestOptions.CreateOrClone(options); | |||
| var msg = new SetLocalVolumeParams | |||
| var msg = new SelectChannelParams | |||
| { | |||
| Volume = volume | |||
| ChannelId = channelId | |||
| }; | |||
| return await SendRpcAsync<SetLocalVolumeResponse>("SET_LOCAL_VOLUME", msg, options: options).ConfigureAwait(false); | |||
| return await SendRpcAsync<Rpc.Channel>("SELECT_TEXT_CHANNEL", msg, options: options).ConfigureAwait(false); | |||
| } | |||
| public async Task<Rpc.RpcChannel> SendSelectVoiceChannelAsync(ulong channelId, RequestOptions options = null) | |||
| public async Task<Rpc.Channel> SendSelectVoiceChannelAsync(ulong channelId, bool force = false, RequestOptions options = null) | |||
| { | |||
| options = RequestOptions.CreateOrClone(options); | |||
| var msg = new SelectVoiceChannelParams | |||
| var msg = new SelectChannelParams | |||
| { | |||
| ChannelId = channelId | |||
| ChannelId = channelId, | |||
| Force = force | |||
| }; | |||
| return await SendRpcAsync<Rpc.RpcChannel>("SELECT_VOICE_CHANNEL", msg, options: options).ConfigureAwait(false); | |||
| return await SendRpcAsync<Rpc.Channel>("SELECT_VOICE_CHANNEL", msg, options: options).ConfigureAwait(false); | |||
| } | |||
| public async Task<SubscriptionResponse> SendGlobalSubscribeAsync(string evt, RequestOptions options = null) | |||
| @@ -370,10 +371,16 @@ namespace Discord.API | |||
| options = RequestOptions.CreateOrClone(options); | |||
| return await SendRpcAsync<API.Rpc.VoiceSettings>("GET_VOICE_SETTINGS", null, options: options).ConfigureAwait(false); | |||
| } | |||
| public async Task<API.Rpc.VoiceSettings> SetVoiceSettingsAsync(API.Rpc.VoiceSettings settings, RequestOptions options = null) | |||
| public async Task SetVoiceSettingsAsync(API.Rpc.VoiceSettings settings, RequestOptions options = null) | |||
| { | |||
| options = RequestOptions.CreateOrClone(options); | |||
| await SendRpcAsync<API.Rpc.VoiceSettings>("SET_VOICE_SETTINGS", settings, options: options).ConfigureAwait(false); | |||
| } | |||
| public async Task SetUserVoiceSettingsAsync(ulong userId, API.Rpc.UserVoiceSettings settings, RequestOptions options = null) | |||
| { | |||
| options = RequestOptions.CreateOrClone(options); | |||
| return await SendRpcAsync<API.Rpc.VoiceSettings>("SET_VOICE_SETTINGS", settings, options: options).ConfigureAwait(false); | |||
| settings.UserId = userId; | |||
| await SendRpcAsync<API.Rpc.UserVoiceSettings>("SET_USER_VOICE_SETTINGS", settings, options: options).ConfigureAwait(false); | |||
| } | |||
| private bool ProcessMessage(API.Rpc.RpcFrame msg) | |||
| @@ -0,0 +1,34 @@ | |||
| #pragma warning disable CS1591 | |||
| using Newtonsoft.Json; | |||
| namespace Discord.API.Rpc | |||
| { | |||
| public class Channel | |||
| { | |||
| //Shared | |||
| [JsonProperty("id")] | |||
| public ulong Id { get; set; } | |||
| [JsonProperty("type")] | |||
| public ChannelType Type { get; set; } | |||
| //GuildChannel | |||
| [JsonProperty("guild_id")] | |||
| public Optional<ulong> GuildId { get; set; } | |||
| [JsonProperty("name")] | |||
| public Optional<string> Name { get; set; } | |||
| [JsonProperty("position")] | |||
| public Optional<int> Position { get; set; } | |||
| //IMessageChannel | |||
| [JsonProperty("messages")] | |||
| public Message[] Messages { get; set; } | |||
| //VoiceChannel | |||
| [JsonProperty("bitrate")] | |||
| public Optional<int> Bitrate { get; set; } | |||
| [JsonProperty("user_limit")] | |||
| public Optional<int> UserLimit { get; set; } | |||
| [JsonProperty("voice_states")] | |||
| public ExtendedVoiceState[] VoiceStates { get; set; } | |||
| } | |||
| } | |||
| @@ -2,7 +2,7 @@ | |||
| namespace Discord.API.Rpc | |||
| { | |||
| public class ChannelCreatedEvent | |||
| public class ChannelSummary | |||
| { | |||
| [JsonProperty("id")] | |||
| public ulong Id { get; set; } | |||
| @@ -3,7 +3,7 @@ using Newtonsoft.Json; | |||
| namespace Discord.API.Rpc | |||
| { | |||
| public class VoiceStateEvent | |||
| public class ExtendedVoiceState | |||
| { | |||
| [JsonProperty("user")] | |||
| public User User { get; set; } | |||
| @@ -1,11 +1,12 @@ | |||
| #pragma warning disable CS1591 | |||
| using Newtonsoft.Json; | |||
| using System.Collections.Generic; | |||
| namespace Discord.API.Rpc | |||
| { | |||
| public class GetChannelsResponse | |||
| { | |||
| [JsonProperty("channels")] | |||
| public RpcChannel[] Channels { get; set; } | |||
| public IReadOnlyCollection<ChannelSummary> Channels { get; set; } | |||
| } | |||
| } | |||
| @@ -1,4 +1,5 @@ | |||
| #pragma warning disable CS1591 | |||
| namespace Discord.API.Rpc | |||
| { | |||
| public class GetGuildsParams | |||
| @@ -6,6 +6,6 @@ namespace Discord.API.Rpc | |||
| public class GetGuildsResponse | |||
| { | |||
| [JsonProperty("guilds")] | |||
| public RpcUserGuild[] Guilds { get; set; } | |||
| public GuildSummary[] Guilds { get; set; } | |||
| } | |||
| } | |||
| @@ -1,13 +1,18 @@ | |||
| #pragma warning disable CS1591 | |||
| using Newtonsoft.Json; | |||
| using System.Collections.Generic; | |||
| namespace Discord.API.Rpc | |||
| { | |||
| public class RpcUserGuild | |||
| public class Guild | |||
| { | |||
| [JsonProperty("id")] | |||
| public ulong Id { get; set; } | |||
| [JsonProperty("name")] | |||
| public string Name { get; set; } | |||
| [JsonProperty("icon_url")] | |||
| public string IconUrl { get; set; } | |||
| [JsonProperty("members")] | |||
| public IEnumerable<GuildMember> Members { get; set; } | |||
| } | |||
| } | |||
| @@ -0,0 +1,15 @@ | |||
| #pragma warning disable CS1591 | |||
| using Newtonsoft.Json; | |||
| namespace Discord.API.Rpc | |||
| { | |||
| public class GuildMember | |||
| { | |||
| [JsonProperty("user")] | |||
| public User User { get; set; } | |||
| [JsonProperty("status")] | |||
| public UserStatus Status { get; set; } | |||
| /*[JsonProperty("activity")] | |||
| public object Activity { get; set; }*/ | |||
| } | |||
| } | |||
| @@ -2,7 +2,7 @@ | |||
| namespace Discord.API.Rpc | |||
| { | |||
| public class GuildCreatedEvent | |||
| public class GuildSummary | |||
| { | |||
| [JsonProperty("id")] | |||
| public ulong Id { get; set; } | |||
| @@ -2,7 +2,7 @@ | |||
| namespace Discord.API.Rpc | |||
| { | |||
| public class RpcMessage : Message | |||
| public class Message : Discord.API.Message | |||
| { | |||
| [JsonProperty("blocked")] | |||
| public Optional<bool> IsBlocked { get; } | |||
| @@ -7,6 +7,6 @@ namespace Discord.API.Rpc | |||
| [JsonProperty("channel_id")] | |||
| public ulong ChannelId { get; set; } | |||
| [JsonProperty("message")] | |||
| public RpcMessage Message { get; set; } | |||
| public Message Message { get; set; } | |||
| } | |||
| } | |||
| @@ -1,11 +0,0 @@ | |||
| #pragma warning disable CS1591 | |||
| using Newtonsoft.Json; | |||
| namespace Discord.API.Rpc | |||
| { | |||
| public class RpcChannel : Channel | |||
| { | |||
| [JsonProperty("voice_states")] | |||
| public VoiceState[] VoiceStates { get; set; } | |||
| } | |||
| } | |||
| @@ -1,13 +0,0 @@ | |||
| #pragma warning disable CS1591 | |||
| using Newtonsoft.Json; | |||
| namespace Discord.API.Rpc | |||
| { | |||
| public class RpcGuild : Guild | |||
| { | |||
| [JsonProperty("online")] | |||
| public int Online { get; set; } | |||
| [JsonProperty("members")] | |||
| public GuildMember[] Members { get; set; } | |||
| } | |||
| } | |||
| @@ -3,9 +3,11 @@ using Newtonsoft.Json; | |||
| namespace Discord.API.Rpc | |||
| { | |||
| public class SelectVoiceChannelParams | |||
| public class SelectChannelParams | |||
| { | |||
| [JsonProperty("channel_id")] | |||
| public ulong? ChannelId { get; set; } | |||
| [JsonProperty("force")] | |||
| public Optional<bool> Force { get; set; } | |||
| } | |||
| } | |||
| @@ -0,0 +1,18 @@ | |||
| #pragma warning disable CS1591 | |||
| using Newtonsoft.Json; | |||
| namespace Discord.API.Rpc | |||
| { | |||
| public class UserVoiceSettings | |||
| { | |||
| [JsonProperty("userId")] | |||
| internal ulong UserId { get; set; } | |||
| [JsonProperty("pan")] | |||
| public Optional<Pan> Pan { get; set; } | |||
| [JsonProperty("volume")] | |||
| public Optional<int> Volume { get; set; } | |||
| [JsonProperty("mute")] | |||
| public Optional<bool> Mute { get; set; } | |||
| } | |||
| } | |||
| @@ -26,20 +26,20 @@ namespace Discord.Rpc | |||
| private readonly AsyncEvent<Func<Task>> _readyEvent = new AsyncEvent<Func<Task>>(); | |||
| //Channel | |||
| public event Func<RpcChannel, Task> ChannelCreated | |||
| public event Func<RpcChannelSummary, Task> ChannelCreated | |||
| { | |||
| add { _channelCreatedEvent.Add(value); } | |||
| remove { _channelCreatedEvent.Remove(value); } | |||
| } | |||
| private readonly AsyncEvent<Func<RpcChannel, Task>> _channelCreatedEvent = new AsyncEvent<Func<RpcChannel, Task>>(); | |||
| private readonly AsyncEvent<Func<RpcChannelSummary, Task>> _channelCreatedEvent = new AsyncEvent<Func<RpcChannelSummary, Task>>(); | |||
| //Guild | |||
| public event Func<RpcGuild, Task> GuildCreated | |||
| public event Func<RpcGuildSummary, Task> GuildCreated | |||
| { | |||
| add { _guildCreatedEvent.Add(value); } | |||
| remove { _guildCreatedEvent.Remove(value); } | |||
| } | |||
| private readonly AsyncEvent<Func<RpcGuild, Task>> _guildCreatedEvent = new AsyncEvent<Func<RpcGuild, Task>>(); | |||
| private readonly AsyncEvent<Func<RpcGuildSummary, Task>> _guildCreatedEvent = new AsyncEvent<Func<RpcGuildSummary, Task>>(); | |||
| public event Func<RpcGuildStatus, Task> GuildStatusUpdated | |||
| { | |||
| add { _guildStatusUpdatedEvent.Add(value); } | |||
| @@ -8,6 +8,7 @@ using Newtonsoft.Json.Linq; | |||
| using System; | |||
| using System.Collections.Generic; | |||
| using System.Collections.Immutable; | |||
| using System.Linq; | |||
| using System.Threading; | |||
| using System.Threading.Tasks; | |||
| @@ -265,6 +266,59 @@ namespace Discord.Rpc | |||
| await ApiClient.SendChannelUnsubscribeAsync(GetEventName(events[i]), channelId); | |||
| } | |||
| public async Task<RpcGuild> GetRpcGuildAsync(ulong id) | |||
| { | |||
| var model = await ApiClient.SendGetGuildAsync(id).ConfigureAwait(false); | |||
| return RpcGuild.Create(this, model); | |||
| } | |||
| public async Task<IReadOnlyCollection<RpcGuildSummary>> GetRpcGuildsAsync() | |||
| { | |||
| var models = await ApiClient.SendGetGuildsAsync().ConfigureAwait(false); | |||
| return models.Guilds.Select(x => RpcGuildSummary.Create(x)).ToImmutableArray(); | |||
| } | |||
| public async Task<RpcChannel> GetRpcChannelAsync(ulong id) | |||
| { | |||
| var model = await ApiClient.SendGetChannelAsync(id).ConfigureAwait(false); | |||
| return RpcChannel.Create(this, model); | |||
| } | |||
| public async Task<IReadOnlyCollection<RpcChannelSummary>> GetRpcChannelsAsync(ulong guildId) | |||
| { | |||
| var models = await ApiClient.SendGetChannelsAsync(guildId).ConfigureAwait(false); | |||
| return models.Channels.Select(x => RpcChannelSummary.Create(x)).ToImmutableArray(); | |||
| } | |||
| public async Task<IMessageChannel> SelectTextChannelAsync(IChannel channel) | |||
| { | |||
| var model = await ApiClient.SendSelectTextChannelAsync(channel.Id).ConfigureAwait(false); | |||
| return RpcChannel.Create(this, model) as IMessageChannel; | |||
| } | |||
| public async Task<IMessageChannel> SelectTextChannelAsync(RpcChannelSummary channel) | |||
| { | |||
| var model = await ApiClient.SendSelectTextChannelAsync(channel.Id).ConfigureAwait(false); | |||
| return RpcChannel.Create(this, model) as IMessageChannel; | |||
| } | |||
| public async Task<IMessageChannel> SelectTextChannelAsync(ulong channelId) | |||
| { | |||
| var model = await ApiClient.SendSelectTextChannelAsync(channelId).ConfigureAwait(false); | |||
| return RpcChannel.Create(this, model) as IMessageChannel; | |||
| } | |||
| public async Task<IRpcAudioChannel> SelectVoiceChannelAsync(IChannel channel, bool force = false) | |||
| { | |||
| var model = await ApiClient.SendSelectVoiceChannelAsync(channel.Id, force).ConfigureAwait(false); | |||
| return RpcChannel.Create(this, model) as IRpcAudioChannel; | |||
| } | |||
| public async Task<IRpcAudioChannel> SelectVoiceChannelAsync(RpcChannelSummary channel, bool force = false) | |||
| { | |||
| var model = await ApiClient.SendSelectVoiceChannelAsync(channel.Id, force).ConfigureAwait(false); | |||
| return RpcChannel.Create(this, model) as IRpcAudioChannel; | |||
| } | |||
| public async Task<IRpcAudioChannel> SelectVoiceChannelAsync(ulong channelId, bool force = false) | |||
| { | |||
| var model = await ApiClient.SendSelectVoiceChannelAsync(channelId, force).ConfigureAwait(false); | |||
| return RpcChannel.Create(this, model) as IRpcAudioChannel; | |||
| } | |||
| public async Task<VoiceSettings> GetVoiceSettingsAsync() | |||
| { | |||
| var model = await ApiClient.GetVoiceSettingsAsync().ConfigureAwait(false); | |||
| @@ -279,6 +333,12 @@ namespace Discord.Rpc | |||
| func(settings); | |||
| await ApiClient.SetVoiceSettingsAsync(settings).ConfigureAwait(false); | |||
| } | |||
| public async Task SetUserVoiceSettingsAsync(ulong userId, Action<API.Rpc.UserVoiceSettings> func) | |||
| { | |||
| var settings = new API.Rpc.UserVoiceSettings(); | |||
| func(settings); | |||
| await ApiClient.SetUserVoiceSettingsAsync(userId, settings).ConfigureAwait(false); | |||
| } | |||
| private static string GetEventName(RpcGlobalEvent rpcEvent) | |||
| { | |||
| @@ -363,8 +423,8 @@ namespace Discord.Rpc | |||
| case "CHANNEL_CREATE": | |||
| { | |||
| await _rpcLogger.DebugAsync("Received Dispatch (CHANNEL_CREATE)").ConfigureAwait(false); | |||
| var data = (payload.Value as JToken).ToObject<ChannelCreatedEvent>(_serializer); | |||
| var channel = RpcChannel.Create(data); | |||
| var data = (payload.Value as JToken).ToObject<ChannelSummary>(_serializer); | |||
| var channel = RpcChannelSummary.Create(data); | |||
| await _channelCreatedEvent.InvokeAsync(channel).ConfigureAwait(false); | |||
| } | |||
| @@ -374,8 +434,8 @@ namespace Discord.Rpc | |||
| case "GUILD_CREATE": | |||
| { | |||
| await _rpcLogger.DebugAsync("Received Dispatch (GUILD_CREATE)").ConfigureAwait(false); | |||
| var data = (payload.Value as JToken).ToObject<GuildCreatedEvent>(_serializer); | |||
| var guild = RpcGuild.Create(data); | |||
| var data = (payload.Value as JToken).ToObject<GuildSummary>(_serializer); | |||
| var guild = RpcGuildSummary.Create(data); | |||
| await _guildCreatedEvent.InvokeAsync(guild).ConfigureAwait(false); | |||
| } | |||
| @@ -394,7 +454,7 @@ namespace Discord.Rpc | |||
| case "VOICE_STATE_CREATE": | |||
| { | |||
| await _rpcLogger.DebugAsync("Received Dispatch (VOICE_STATE_CREATE)").ConfigureAwait(false); | |||
| var data = (payload.Value as JToken).ToObject<VoiceStateEvent>(_serializer); | |||
| var data = (payload.Value as JToken).ToObject<ExtendedVoiceState>(_serializer); | |||
| var voiceState = RpcVoiceState.Create(this, data); | |||
| await _voiceStateCreatedEvent.InvokeAsync(voiceState).ConfigureAwait(false); | |||
| @@ -403,7 +463,7 @@ namespace Discord.Rpc | |||
| case "VOICE_STATE_UPDATE": | |||
| { | |||
| await _rpcLogger.DebugAsync("Received Dispatch (VOICE_STATE_UPDATE)").ConfigureAwait(false); | |||
| var data = (payload.Value as JToken).ToObject<VoiceStateEvent>(_serializer); | |||
| var data = (payload.Value as JToken).ToObject<ExtendedVoiceState>(_serializer); | |||
| var voiceState = RpcVoiceState.Create(this, data); | |||
| await _voiceStateUpdatedEvent.InvokeAsync(voiceState).ConfigureAwait(false); | |||
| @@ -412,7 +472,7 @@ namespace Discord.Rpc | |||
| case "VOICE_STATE_DELETE": | |||
| { | |||
| await _rpcLogger.DebugAsync("Received Dispatch (VOICE_STATE_DELETE)").ConfigureAwait(false); | |||
| var data = (payload.Value as JToken).ToObject<VoiceStateEvent>(_serializer); | |||
| var data = (payload.Value as JToken).ToObject<ExtendedVoiceState>(_serializer); | |||
| var voiceState = RpcVoiceState.Create(this, data); | |||
| await _voiceStateDeletedEvent.InvokeAsync(voiceState).ConfigureAwait(false); | |||
| @@ -0,0 +1,9 @@ | |||
| using System.Collections.Generic; | |||
| namespace Discord.Rpc | |||
| { | |||
| public interface IRpcAudioChannel : IAudioChannel | |||
| { | |||
| IReadOnlyCollection<RpcVoiceState> VoiceStates { get; } | |||
| } | |||
| } | |||
| @@ -0,0 +1,9 @@ | |||
| using System.Collections.Generic; | |||
| namespace Discord.Rpc | |||
| { | |||
| public interface IRpcMessageChannel : IMessageChannel | |||
| { | |||
| IReadOnlyCollection<RpcMessage> CachedMessages { get; } | |||
| } | |||
| } | |||
| @@ -0,0 +1,6 @@ | |||
| namespace Discord.Rpc | |||
| { | |||
| public interface IRpcPrivateChannel | |||
| { | |||
| } | |||
| } | |||
| @@ -1,32 +1,40 @@ | |||
| using System.Diagnostics; | |||
| using Model = Discord.API.Rpc.ChannelCreatedEvent; | |||
| using System; | |||
| using Model = Discord.API.Rpc.Channel; | |||
| namespace Discord.Rpc | |||
| { | |||
| [DebuggerDisplay(@"{DebuggerDisplay,nq}")] | |||
| public class RpcChannel | |||
| public class RpcChannel : RpcEntity<ulong> | |||
| { | |||
| public ulong Id { get; } | |||
| public string Name { get; set; } | |||
| public ChannelType Type { get; set; } | |||
| public string Name { get; private set; } | |||
| internal RpcChannel(ulong id) | |||
| internal RpcChannel(DiscordRpcClient discord, ulong id) | |||
| : base(discord, id) | |||
| { | |||
| Id = id; | |||
| } | |||
| internal static RpcChannel Create(Model model) | |||
| internal static RpcChannel Create(DiscordRpcClient discord, Model model) | |||
| { | |||
| var entity = new RpcChannel(model.Id); | |||
| entity.Update(model); | |||
| return entity; | |||
| if (model.GuildId.IsSpecified) | |||
| return RpcGuildChannel.Create(discord, model); | |||
| else | |||
| return CreatePrivate(discord, model); | |||
| } | |||
| internal void Update(Model model) | |||
| internal static RpcChannel CreatePrivate(DiscordRpcClient discord, Model model) | |||
| { | |||
| Name = model.Name; | |||
| Type = model.Type; | |||
| switch (model.Type) | |||
| { | |||
| case ChannelType.DM: | |||
| return RpcDMChannel.Create(discord, model); | |||
| case ChannelType.Group: | |||
| return RpcGroupChannel.Create(discord, model); | |||
| default: | |||
| throw new InvalidOperationException($"Unexpected channel type: {model.Type}"); | |||
| } | |||
| } | |||
| internal virtual void Update(Model model) | |||
| { | |||
| if (model.Name.IsSpecified) | |||
| Name = model.Name.Value; | |||
| } | |||
| public override string ToString() => Name; | |||
| private string DebuggerDisplay => $"{Name} ({Id}, {Type})"; | |||
| } | |||
| } | |||
| @@ -0,0 +1,32 @@ | |||
| using System.Diagnostics; | |||
| using Model = Discord.API.Rpc.ChannelSummary; | |||
| namespace Discord.Rpc | |||
| { | |||
| [DebuggerDisplay(@"{DebuggerDisplay,nq}")] | |||
| public class RpcChannelSummary | |||
| { | |||
| public ulong Id { get; } | |||
| public string Name { get; set; } | |||
| public ChannelType Type { get; set; } | |||
| internal RpcChannelSummary(ulong id) | |||
| { | |||
| Id = id; | |||
| } | |||
| internal static RpcChannelSummary Create(Model model) | |||
| { | |||
| var entity = new RpcChannelSummary(model.Id); | |||
| entity.Update(model); | |||
| return entity; | |||
| } | |||
| internal void Update(Model model) | |||
| { | |||
| Name = model.Name; | |||
| Type = model.Type; | |||
| } | |||
| public override string ToString() => Name; | |||
| private string DebuggerDisplay => $"{Name} ({Id}, {Type})"; | |||
| } | |||
| } | |||
| @@ -0,0 +1,124 @@ | |||
| using Discord.Rest; | |||
| using System; | |||
| using System.Collections.Generic; | |||
| using System.Collections.Immutable; | |||
| using System.IO; | |||
| using System.Linq; | |||
| using System.Threading.Tasks; | |||
| using Model = Discord.API.Rpc.Channel; | |||
| namespace Discord.Rpc | |||
| { | |||
| public class RpcDMChannel : RpcChannel, IRpcMessageChannel, IRpcPrivateChannel, IDMChannel | |||
| { | |||
| public IReadOnlyCollection<RpcMessage> CachedMessages { get; private set; } | |||
| internal RpcDMChannel(DiscordRpcClient discord, ulong id) | |||
| : base(discord, id) | |||
| { | |||
| } | |||
| internal static new RpcDMChannel Create(DiscordRpcClient discord, Model model) | |||
| { | |||
| var entity = new RpcDMChannel(discord, model.Id); | |||
| entity.Update(model); | |||
| return entity; | |||
| } | |||
| internal override void Update(Model model) | |||
| { | |||
| base.Update(model); | |||
| CachedMessages = model.Messages.Select(x => RpcMessage.Create(Discord, Id, x)).ToImmutableArray(); | |||
| } | |||
| public Task CloseAsync(RequestOptions options = null) | |||
| => ChannelHelper.DeleteAsync(this, Discord, options); | |||
| //TODO: Use RPC cache | |||
| public Task<RestMessage> GetMessageAsync(ulong id, RequestOptions options = null) | |||
| => ChannelHelper.GetMessageAsync(this, Discord, id, null, options); | |||
| public IAsyncEnumerable<IReadOnlyCollection<RestMessage>> GetMessagesAsync(int limit = DiscordConfig.MaxMessagesPerBatch, RequestOptions options = null) | |||
| => ChannelHelper.GetMessagesAsync(this, Discord, null, Direction.Before, limit, null, options); | |||
| public IAsyncEnumerable<IReadOnlyCollection<RestMessage>> GetMessagesAsync(ulong fromMessageId, Direction dir, int limit = DiscordConfig.MaxMessagesPerBatch, RequestOptions options = null) | |||
| => ChannelHelper.GetMessagesAsync(this, Discord, fromMessageId, dir, limit, null, options); | |||
| public IAsyncEnumerable<IReadOnlyCollection<RestMessage>> GetMessagesAsync(IMessage fromMessage, Direction dir, int limit = DiscordConfig.MaxMessagesPerBatch, RequestOptions options = null) | |||
| => ChannelHelper.GetMessagesAsync(this, Discord, fromMessage.Id, dir, limit, null, options); | |||
| public Task<IReadOnlyCollection<RestMessage>> GetPinnedMessagesAsync(RequestOptions options = null) | |||
| => ChannelHelper.GetPinnedMessagesAsync(this, Discord, null, options); | |||
| public Task<RestUserMessage> SendMessageAsync(string text, bool isTTS, RequestOptions options = null) | |||
| => ChannelHelper.SendMessageAsync(this, Discord, text, isTTS, null, options); | |||
| public Task<RestUserMessage> SendFileAsync(string filePath, string text, bool isTTS, RequestOptions options = null) | |||
| => ChannelHelper.SendFileAsync(this, Discord, filePath, text, isTTS, null, options); | |||
| public Task<RestUserMessage> SendFileAsync(Stream stream, string filename, string text, bool isTTS, RequestOptions options = null) | |||
| => ChannelHelper.SendFileAsync(this, Discord, stream, filename, text, isTTS, null, options); | |||
| public Task DeleteMessagesAsync(IEnumerable<IMessage> messages, RequestOptions options = null) | |||
| => ChannelHelper.DeleteMessagesAsync(this, Discord, messages, options); | |||
| public Task TriggerTypingAsync(RequestOptions options = null) | |||
| => ChannelHelper.TriggerTypingAsync(this, Discord, options); | |||
| public IDisposable EnterTypingState(RequestOptions options = null) | |||
| => ChannelHelper.EnterTypingState(this, Discord, options); | |||
| public override string ToString() => Id.ToString(); | |||
| private string DebuggerDisplay => $"({Id}, DM)"; | |||
| //IDMChannel | |||
| IUser IDMChannel.Recipient { get { throw new NotSupportedException(); } } | |||
| //IPrivateChannel | |||
| IReadOnlyCollection<IUser> IPrivateChannel.Recipients { get { throw new NotSupportedException(); } } | |||
| //IMessageChannel | |||
| async Task<IMessage> IMessageChannel.GetMessageAsync(ulong id, CacheMode mode, RequestOptions options) | |||
| { | |||
| if (mode == CacheMode.AllowDownload) | |||
| return await GetMessageAsync(id, options); | |||
| else | |||
| return null; | |||
| } | |||
| IAsyncEnumerable<IReadOnlyCollection<IMessage>> IMessageChannel.GetMessagesAsync(int limit, CacheMode mode, RequestOptions options) | |||
| { | |||
| if (mode == CacheMode.AllowDownload) | |||
| return GetMessagesAsync(limit, options); | |||
| else | |||
| return AsyncEnumerable.Empty<IReadOnlyCollection<IMessage>>(); | |||
| } | |||
| IAsyncEnumerable<IReadOnlyCollection<IMessage>> IMessageChannel.GetMessagesAsync(ulong fromMessageId, Direction dir, int limit, CacheMode mode, RequestOptions options) | |||
| { | |||
| if (mode == CacheMode.AllowDownload) | |||
| return GetMessagesAsync(fromMessageId, dir, limit, options); | |||
| else | |||
| return AsyncEnumerable.Empty<IReadOnlyCollection<IMessage>>(); | |||
| } | |||
| IAsyncEnumerable<IReadOnlyCollection<IMessage>> IMessageChannel.GetMessagesAsync(IMessage fromMessage, Direction dir, int limit, CacheMode mode, RequestOptions options) | |||
| { | |||
| if (mode == CacheMode.AllowDownload) | |||
| return GetMessagesAsync(fromMessage, dir, limit, options); | |||
| else | |||
| return AsyncEnumerable.Empty<IReadOnlyCollection<IMessage>>(); | |||
| } | |||
| async Task<IReadOnlyCollection<IMessage>> IMessageChannel.GetPinnedMessagesAsync(RequestOptions options) | |||
| => await GetPinnedMessagesAsync(options); | |||
| async Task<IUserMessage> IMessageChannel.SendFileAsync(string filePath, string text, bool isTTS, RequestOptions options) | |||
| => await SendFileAsync(filePath, text, isTTS, options); | |||
| async Task<IUserMessage> IMessageChannel.SendFileAsync(Stream stream, string filename, string text, bool isTTS, RequestOptions options) | |||
| => await SendFileAsync(stream, filename, text, isTTS, options); | |||
| async Task<IUserMessage> IMessageChannel.SendMessageAsync(string text, bool isTTS, RequestOptions options) | |||
| => await SendMessageAsync(text, isTTS, options); | |||
| IDisposable IMessageChannel.EnterTypingState(RequestOptions options) | |||
| => EnterTypingState(options); | |||
| //IChannel | |||
| string IChannel.Name { get { throw new NotSupportedException(); } } | |||
| Task<IUser> IChannel.GetUserAsync(ulong id, CacheMode mode, RequestOptions options) | |||
| { | |||
| throw new NotSupportedException(); | |||
| } | |||
| IAsyncEnumerable<IReadOnlyCollection<IUser>> IChannel.GetUsersAsync(CacheMode mode, RequestOptions options) | |||
| { | |||
| throw new NotSupportedException(); | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,123 @@ | |||
| using Discord.Rest; | |||
| using System; | |||
| using System.Collections.Generic; | |||
| using System.Collections.Immutable; | |||
| using System.IO; | |||
| using System.Linq; | |||
| using System.Threading.Tasks; | |||
| using Model = Discord.API.Rpc.Channel; | |||
| namespace Discord.Rpc | |||
| { | |||
| public class RpcGroupChannel : RpcChannel, IRpcMessageChannel, IRpcAudioChannel, IRpcPrivateChannel, IGroupChannel | |||
| { | |||
| public IReadOnlyCollection<RpcMessage> CachedMessages { get; private set; } | |||
| public IReadOnlyCollection<RpcVoiceState> VoiceStates { get; private set; } | |||
| internal RpcGroupChannel(DiscordRpcClient discord, ulong id) | |||
| : base(discord, id) | |||
| { | |||
| } | |||
| internal new static RpcGroupChannel Create(DiscordRpcClient discord, Model model) | |||
| { | |||
| var entity = new RpcGroupChannel(discord, model.Id); | |||
| entity.Update(model); | |||
| return entity; | |||
| } | |||
| internal override void Update(Model model) | |||
| { | |||
| base.Update(model); | |||
| CachedMessages = model.Messages.Select(x => RpcMessage.Create(Discord, Id, x)).ToImmutableArray(); | |||
| VoiceStates = model.VoiceStates.Select(x => RpcVoiceState.Create(Discord, x)).ToImmutableArray(); | |||
| } | |||
| public Task LeaveAsync(RequestOptions options = null) | |||
| => ChannelHelper.DeleteAsync(this, Discord, options); | |||
| //TODO: Use RPC cache | |||
| public Task<RestMessage> GetMessageAsync(ulong id, RequestOptions options = null) | |||
| => ChannelHelper.GetMessageAsync(this, Discord, id, null, options); | |||
| public IAsyncEnumerable<IReadOnlyCollection<RestMessage>> GetMessagesAsync(int limit = DiscordConfig.MaxMessagesPerBatch, RequestOptions options = null) | |||
| => ChannelHelper.GetMessagesAsync(this, Discord, null, Direction.Before, limit, null, options); | |||
| public IAsyncEnumerable<IReadOnlyCollection<RestMessage>> GetMessagesAsync(ulong fromMessageId, Direction dir, int limit = DiscordConfig.MaxMessagesPerBatch, RequestOptions options = null) | |||
| => ChannelHelper.GetMessagesAsync(this, Discord, fromMessageId, dir, limit, null, options); | |||
| public IAsyncEnumerable<IReadOnlyCollection<RestMessage>> GetMessagesAsync(IMessage fromMessage, Direction dir, int limit = DiscordConfig.MaxMessagesPerBatch, RequestOptions options = null) | |||
| => ChannelHelper.GetMessagesAsync(this, Discord, fromMessage.Id, dir, limit, null, options); | |||
| public Task<IReadOnlyCollection<RestMessage>> GetPinnedMessagesAsync(RequestOptions options = null) | |||
| => ChannelHelper.GetPinnedMessagesAsync(this, Discord, null, options); | |||
| public Task<RestUserMessage> SendMessageAsync(string text, bool isTTS, RequestOptions options = null) | |||
| => ChannelHelper.SendMessageAsync(this, Discord, text, isTTS, null, options); | |||
| public Task<RestUserMessage> SendFileAsync(string filePath, string text, bool isTTS, RequestOptions options = null) | |||
| => ChannelHelper.SendFileAsync(this, Discord, filePath, text, isTTS, null, options); | |||
| public Task<RestUserMessage> SendFileAsync(Stream stream, string filename, string text, bool isTTS, RequestOptions options = null) | |||
| => ChannelHelper.SendFileAsync(this, Discord, stream, filename, text, isTTS, null, options); | |||
| public Task DeleteMessagesAsync(IEnumerable<IMessage> messages, RequestOptions options = null) | |||
| => ChannelHelper.DeleteMessagesAsync(this, Discord, messages, options); | |||
| public Task TriggerTypingAsync(RequestOptions options = null) | |||
| => ChannelHelper.TriggerTypingAsync(this, Discord, options); | |||
| public IDisposable EnterTypingState(RequestOptions options = null) | |||
| => ChannelHelper.EnterTypingState(this, Discord, options); | |||
| public override string ToString() => Id.ToString(); | |||
| private string DebuggerDisplay => $"({Id}, Group)"; | |||
| //IPrivateChannel | |||
| IReadOnlyCollection<IUser> IPrivateChannel.Recipients { get { throw new NotSupportedException(); } } | |||
| //IMessageChannel | |||
| async Task<IMessage> IMessageChannel.GetMessageAsync(ulong id, CacheMode mode, RequestOptions options) | |||
| { | |||
| if (mode == CacheMode.AllowDownload) | |||
| return await GetMessageAsync(id, options); | |||
| else | |||
| return null; | |||
| } | |||
| IAsyncEnumerable<IReadOnlyCollection<IMessage>> IMessageChannel.GetMessagesAsync(int limit, CacheMode mode, RequestOptions options) | |||
| { | |||
| if (mode == CacheMode.AllowDownload) | |||
| return GetMessagesAsync(limit, options); | |||
| else | |||
| return AsyncEnumerable.Empty<IReadOnlyCollection<IMessage>>(); | |||
| } | |||
| IAsyncEnumerable<IReadOnlyCollection<IMessage>> IMessageChannel.GetMessagesAsync(ulong fromMessageId, Direction dir, int limit, CacheMode mode, RequestOptions options) | |||
| { | |||
| if (mode == CacheMode.AllowDownload) | |||
| return GetMessagesAsync(fromMessageId, dir, limit, options); | |||
| else | |||
| return AsyncEnumerable.Empty<IReadOnlyCollection<IMessage>>(); | |||
| } | |||
| IAsyncEnumerable<IReadOnlyCollection<IMessage>> IMessageChannel.GetMessagesAsync(IMessage fromMessage, Direction dir, int limit, CacheMode mode, RequestOptions options) | |||
| { | |||
| if (mode == CacheMode.AllowDownload) | |||
| return GetMessagesAsync(fromMessage, dir, limit, options); | |||
| else | |||
| return AsyncEnumerable.Empty<IReadOnlyCollection<IMessage>>(); | |||
| } | |||
| async Task<IReadOnlyCollection<IMessage>> IMessageChannel.GetPinnedMessagesAsync(RequestOptions options) | |||
| => await GetPinnedMessagesAsync(options); | |||
| async Task<IUserMessage> IMessageChannel.SendFileAsync(string filePath, string text, bool isTTS, RequestOptions options) | |||
| => await SendFileAsync(filePath, text, isTTS, options); | |||
| async Task<IUserMessage> IMessageChannel.SendFileAsync(Stream stream, string filename, string text, bool isTTS, RequestOptions options) | |||
| => await SendFileAsync(stream, filename, text, isTTS, options); | |||
| async Task<IUserMessage> IMessageChannel.SendMessageAsync(string text, bool isTTS, RequestOptions options) | |||
| => await SendMessageAsync(text, isTTS, options); | |||
| IDisposable IMessageChannel.EnterTypingState(RequestOptions options) | |||
| => EnterTypingState(options); | |||
| //IChannel | |||
| string IChannel.Name { get { throw new NotSupportedException(); } } | |||
| Task<IUser> IChannel.GetUserAsync(ulong id, CacheMode mode, RequestOptions options) | |||
| { | |||
| throw new NotSupportedException(); | |||
| } | |||
| IAsyncEnumerable<IReadOnlyCollection<IUser>> IChannel.GetUsersAsync(CacheMode mode, RequestOptions options) | |||
| { | |||
| throw new NotSupportedException(); | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,94 @@ | |||
| using System; | |||
| using System.Collections.Generic; | |||
| using System.Threading.Tasks; | |||
| using Discord.API.Rest; | |||
| using Model = Discord.API.Rpc.Channel; | |||
| using Discord.Rest; | |||
| namespace Discord.Rpc | |||
| { | |||
| public class RpcGuildChannel : RpcChannel, IGuildChannel | |||
| { | |||
| public ulong GuildId { get; } | |||
| public int Position { get; private set; } | |||
| internal RpcGuildChannel(DiscordRpcClient discord, ulong id, ulong guildId) | |||
| : base(discord, id) | |||
| { | |||
| GuildId = guildId; | |||
| } | |||
| internal new static RpcGuildChannel Create(DiscordRpcClient discord, Model model) | |||
| { | |||
| switch (model.Type) | |||
| { | |||
| case ChannelType.Text: | |||
| return RpcTextChannel.Create(discord, model); | |||
| case ChannelType.Voice: | |||
| return RpcVoiceChannel.Create(discord, model); | |||
| default: | |||
| throw new InvalidOperationException("Unknown guild channel type"); | |||
| } | |||
| } | |||
| internal override void Update(Model model) | |||
| { | |||
| base.Update(model); | |||
| if (model.Position.IsSpecified) | |||
| Position = model.Position.Value; | |||
| } | |||
| public Task ModifyAsync(Action<ModifyGuildChannelParams> func, RequestOptions options = null) | |||
| => ChannelHelper.ModifyAsync(this, Discord, func, options); | |||
| public Task DeleteAsync(RequestOptions options = null) | |||
| => ChannelHelper.DeleteAsync(this, Discord, options); | |||
| public Task AddPermissionOverwriteAsync(IUser user, OverwritePermissions perms, RequestOptions options = null) | |||
| => ChannelHelper.AddPermissionOverwriteAsync(this, Discord, user, perms, options); | |||
| public Task AddPermissionOverwriteAsync(IRole role, OverwritePermissions perms, RequestOptions options = null) | |||
| => ChannelHelper.AddPermissionOverwriteAsync(this, Discord, role, perms, options); | |||
| public Task RemovePermissionOverwriteAsync(IUser user, RequestOptions options = null) | |||
| => ChannelHelper.RemovePermissionOverwriteAsync(this, Discord, user, options); | |||
| public Task RemovePermissionOverwriteAsync(IRole role, RequestOptions options = null) | |||
| => ChannelHelper.RemovePermissionOverwriteAsync(this, Discord, role, options); | |||
| public async Task<IReadOnlyCollection<RestInviteMetadata>> GetInvitesAsync(RequestOptions options = null) | |||
| => await ChannelHelper.GetInvitesAsync(this, Discord, options); | |||
| public async Task<RestInviteMetadata> CreateInviteAsync(int? maxAge = 3600, int? maxUses = null, bool isTemporary = true, RequestOptions options = null) | |||
| => await ChannelHelper.CreateInviteAsync(this, Discord, maxAge, maxUses, isTemporary, options); | |||
| public override string ToString() => Name; | |||
| //IGuildChannel | |||
| async Task<IReadOnlyCollection<IInviteMetadata>> IGuildChannel.GetInvitesAsync(RequestOptions options) | |||
| => await GetInvitesAsync(options); | |||
| async Task<IInviteMetadata> IGuildChannel.CreateInviteAsync(int? maxAge, int? maxUses, bool isTemporary, RequestOptions options) | |||
| => await CreateInviteAsync(maxAge, maxUses, isTemporary, options); | |||
| IReadOnlyCollection<Overwrite> IGuildChannel.PermissionOverwrites { get { throw new NotSupportedException(); } } | |||
| OverwritePermissions? IGuildChannel.GetPermissionOverwrite(IUser user) | |||
| { | |||
| throw new NotSupportedException(); | |||
| } | |||
| OverwritePermissions? IGuildChannel.GetPermissionOverwrite(IRole role) | |||
| { | |||
| throw new NotSupportedException(); | |||
| } | |||
| IAsyncEnumerable<IReadOnlyCollection<IGuildUser>> IGuildChannel.GetUsersAsync(CacheMode mode, RequestOptions options) | |||
| { | |||
| throw new NotSupportedException(); | |||
| } | |||
| Task<IGuildUser> IGuildChannel.GetUserAsync(ulong id, CacheMode mode, RequestOptions options) | |||
| { | |||
| throw new NotSupportedException(); | |||
| } | |||
| //IChannel | |||
| IAsyncEnumerable<IReadOnlyCollection<IUser>> IChannel.GetUsersAsync(CacheMode mode, RequestOptions options) | |||
| { | |||
| throw new NotSupportedException(); | |||
| } | |||
| Task<IUser> IChannel.GetUserAsync(ulong id, CacheMode mode, RequestOptions options) | |||
| { | |||
| throw new NotSupportedException(); | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,113 @@ | |||
| using Discord.API.Rest; | |||
| using Discord.Rest; | |||
| using System; | |||
| using System.Collections.Generic; | |||
| using System.Collections.Immutable; | |||
| using System.Diagnostics; | |||
| using System.IO; | |||
| using System.Linq; | |||
| using System.Threading.Tasks; | |||
| using Model = Discord.API.Rpc.Channel; | |||
| namespace Discord.Rpc | |||
| { | |||
| [DebuggerDisplay(@"{DebuggerDisplay,nq}")] | |||
| public class RpcTextChannel : RpcGuildChannel, IRpcMessageChannel, ITextChannel | |||
| { | |||
| public IReadOnlyCollection<RpcMessage> CachedMessages { get; private set; } | |||
| public string Mention => MentionUtils.MentionChannel(Id); | |||
| internal RpcTextChannel(DiscordRpcClient discord, ulong id, ulong guildId) | |||
| : base(discord, id, guildId) | |||
| { | |||
| } | |||
| internal new static RpcVoiceChannel Create(DiscordRpcClient discord, Model model) | |||
| { | |||
| var entity = new RpcVoiceChannel(discord, model.Id, model.GuildId.Value); | |||
| entity.Update(model); | |||
| return entity; | |||
| } | |||
| internal override void Update(Model model) | |||
| { | |||
| base.Update(model); | |||
| CachedMessages = model.Messages.Select(x => RpcMessage.Create(Discord, Id, x)).ToImmutableArray(); | |||
| } | |||
| public Task ModifyAsync(Action<ModifyTextChannelParams> func, RequestOptions options = null) | |||
| => ChannelHelper.ModifyAsync(this, Discord, func, options); | |||
| //TODO: Use RPC cache | |||
| public Task<RestMessage> GetMessageAsync(ulong id, RequestOptions options = null) | |||
| => ChannelHelper.GetMessageAsync(this, Discord, id, null, options); | |||
| public IAsyncEnumerable<IReadOnlyCollection<RestMessage>> GetMessagesAsync(int limit = DiscordConfig.MaxMessagesPerBatch, RequestOptions options = null) | |||
| => ChannelHelper.GetMessagesAsync(this, Discord, null, Direction.Before, limit, null, options); | |||
| public IAsyncEnumerable<IReadOnlyCollection<RestMessage>> GetMessagesAsync(ulong fromMessageId, Direction dir, int limit = DiscordConfig.MaxMessagesPerBatch, RequestOptions options = null) | |||
| => ChannelHelper.GetMessagesAsync(this, Discord, fromMessageId, dir, limit, null, options); | |||
| public IAsyncEnumerable<IReadOnlyCollection<RestMessage>> GetMessagesAsync(IMessage fromMessage, Direction dir, int limit = DiscordConfig.MaxMessagesPerBatch, RequestOptions options = null) | |||
| => ChannelHelper.GetMessagesAsync(this, Discord, fromMessage.Id, dir, limit, null, options); | |||
| public Task<IReadOnlyCollection<RestMessage>> GetPinnedMessagesAsync(RequestOptions options = null) | |||
| => ChannelHelper.GetPinnedMessagesAsync(this, Discord, null, options); | |||
| public Task<RestUserMessage> SendMessageAsync(string text, bool isTTS, RequestOptions options = null) | |||
| => ChannelHelper.SendMessageAsync(this, Discord, text, isTTS, null, options); | |||
| public Task<RestUserMessage> SendFileAsync(string filePath, string text, bool isTTS, RequestOptions options = null) | |||
| => ChannelHelper.SendFileAsync(this, Discord, filePath, text, isTTS, null, options); | |||
| public Task<RestUserMessage> SendFileAsync(Stream stream, string filename, string text, bool isTTS, RequestOptions options = null) | |||
| => ChannelHelper.SendFileAsync(this, Discord, stream, filename, text, isTTS, null, options); | |||
| public Task DeleteMessagesAsync(IEnumerable<IMessage> messages, RequestOptions options = null) | |||
| => ChannelHelper.DeleteMessagesAsync(this, Discord, messages, options); | |||
| public Task TriggerTypingAsync(RequestOptions options = null) | |||
| => ChannelHelper.TriggerTypingAsync(this, Discord, options); | |||
| public IDisposable EnterTypingState(RequestOptions options = null) | |||
| => ChannelHelper.EnterTypingState(this, Discord, options); | |||
| private string DebuggerDisplay => $"{Name} ({Id}, Text)"; | |||
| //ITextChannel | |||
| string ITextChannel.Topic { get { throw new NotSupportedException(); } } | |||
| //IMessageChannel | |||
| async Task<IMessage> IMessageChannel.GetMessageAsync(ulong id, CacheMode mode, RequestOptions options) | |||
| { | |||
| if (mode == CacheMode.AllowDownload) | |||
| return await GetMessageAsync(id, options); | |||
| else | |||
| return null; | |||
| } | |||
| IAsyncEnumerable<IReadOnlyCollection<IMessage>> IMessageChannel.GetMessagesAsync(int limit, CacheMode mode, RequestOptions options) | |||
| { | |||
| if (mode == CacheMode.AllowDownload) | |||
| return GetMessagesAsync(limit, options); | |||
| else | |||
| return AsyncEnumerable.Empty<IReadOnlyCollection<IMessage>>(); | |||
| } | |||
| IAsyncEnumerable<IReadOnlyCollection<IMessage>> IMessageChannel.GetMessagesAsync(ulong fromMessageId, Direction dir, int limit, CacheMode mode, RequestOptions options) | |||
| { | |||
| if (mode == CacheMode.AllowDownload) | |||
| return GetMessagesAsync(fromMessageId, dir, limit, options); | |||
| else | |||
| return AsyncEnumerable.Empty<IReadOnlyCollection<IMessage>>(); | |||
| } | |||
| IAsyncEnumerable<IReadOnlyCollection<IMessage>> IMessageChannel.GetMessagesAsync(IMessage fromMessage, Direction dir, int limit, CacheMode mode, RequestOptions options) | |||
| { | |||
| if (mode == CacheMode.AllowDownload) | |||
| return GetMessagesAsync(fromMessage, dir, limit, options); | |||
| else | |||
| return AsyncEnumerable.Empty<IReadOnlyCollection<IMessage>>(); | |||
| } | |||
| async Task<IReadOnlyCollection<IMessage>> IMessageChannel.GetPinnedMessagesAsync(RequestOptions options) | |||
| => await GetPinnedMessagesAsync(options); | |||
| async Task<IUserMessage> IMessageChannel.SendFileAsync(string filePath, string text, bool isTTS, RequestOptions options) | |||
| => await SendFileAsync(filePath, text, isTTS, options); | |||
| async Task<IUserMessage> IMessageChannel.SendFileAsync(Stream stream, string filename, string text, bool isTTS, RequestOptions options) | |||
| => await SendFileAsync(stream, filename, text, isTTS, options); | |||
| async Task<IUserMessage> IMessageChannel.SendMessageAsync(string text, bool isTTS, RequestOptions options) | |||
| => await SendMessageAsync(text, isTTS, options); | |||
| IDisposable IMessageChannel.EnterTypingState(RequestOptions options) | |||
| => EnterTypingState(options); | |||
| } | |||
| } | |||
| @@ -0,0 +1,49 @@ | |||
| using Discord.API.Rest; | |||
| using Discord.Audio; | |||
| using Discord.Rest; | |||
| using System; | |||
| using System.Collections.Generic; | |||
| using System.Collections.Immutable; | |||
| using System.Diagnostics; | |||
| using System.Linq; | |||
| using System.Threading.Tasks; | |||
| using Model = Discord.API.Rpc.Channel; | |||
| namespace Discord.Rpc | |||
| { | |||
| [DebuggerDisplay(@"{DebuggerDisplay,nq}")] | |||
| public class RpcVoiceChannel : RpcGuildChannel, IRpcAudioChannel, IVoiceChannel | |||
| { | |||
| public int UserLimit { get; private set; } | |||
| public int Bitrate { get; private set; } | |||
| public IReadOnlyCollection<RpcVoiceState> VoiceStates { get; private set; } | |||
| internal RpcVoiceChannel(DiscordRpcClient discord, ulong id, ulong guildId) | |||
| : base(discord, id, guildId) | |||
| { | |||
| } | |||
| internal new static RpcVoiceChannel Create(DiscordRpcClient discord, Model model) | |||
| { | |||
| var entity = new RpcVoiceChannel(discord, model.Id, model.GuildId.Value); | |||
| entity.Update(model); | |||
| return entity; | |||
| } | |||
| internal override void Update(Model model) | |||
| { | |||
| base.Update(model); | |||
| if (model.UserLimit.IsSpecified) | |||
| UserLimit = model.UserLimit.Value; | |||
| if (model.Bitrate.IsSpecified) | |||
| Bitrate = model.Bitrate.Value; | |||
| VoiceStates = model.VoiceStates.Select(x => RpcVoiceState.Create(Discord, x)).ToImmutableArray(); | |||
| } | |||
| public Task ModifyAsync(Action<ModifyVoiceChannelParams> func, RequestOptions options = null) | |||
| => ChannelHelper.ModifyAsync(this, Discord, func, options); | |||
| private string DebuggerDisplay => $"{Name} ({Id}, Voice)"; | |||
| //IVoiceChannel | |||
| Task<IAudioClient> IVoiceChannel.ConnectAsync() { throw new NotSupportedException(); } | |||
| } | |||
| } | |||
| @@ -1,27 +1,33 @@ | |||
| using System.Diagnostics; | |||
| using Model = Discord.API.Rpc.GuildCreatedEvent; | |||
| using System.Collections.Generic; | |||
| using System.Collections.Immutable; | |||
| using System.Diagnostics; | |||
| using System.Linq; | |||
| using Model = Discord.API.Rpc.Guild; | |||
| namespace Discord.Rpc | |||
| { | |||
| [DebuggerDisplay(@"{DebuggerDisplay,nq}")] | |||
| public class RpcGuild | |||
| public class RpcGuild : RpcEntity<ulong> | |||
| { | |||
| public ulong Id { get; } | |||
| public string Name { get; set; } | |||
| public string Name { get; private set; } | |||
| public string IconUrl { get; private set; } | |||
| public IReadOnlyCollection<RpcGuildUser> Users { get; private set; } | |||
| internal RpcGuild(ulong id) | |||
| internal RpcGuild(DiscordRpcClient discord, ulong id) | |||
| : base(discord, id) | |||
| { | |||
| Id = id; | |||
| } | |||
| internal static RpcGuild Create(Model model) | |||
| internal static RpcGuild Create(DiscordRpcClient discord, Model model) | |||
| { | |||
| var entity = new RpcGuild(model.Id); | |||
| var entity = new RpcGuild(discord, model.Id); | |||
| entity.Update(model); | |||
| return entity; | |||
| } | |||
| internal void Update(Model model) | |||
| { | |||
| Name = model.Name; | |||
| IconUrl = model.IconUrl; | |||
| Users = model.Members.Select(x => RpcGuildUser.Create(Discord, x)).ToImmutableArray(); | |||
| } | |||
| public override string ToString() => Name; | |||
| @@ -6,12 +6,12 @@ namespace Discord.Rpc | |||
| [DebuggerDisplay(@"{DebuggerDisplay,nq}")] | |||
| public class RpcGuildStatus | |||
| { | |||
| public RpcGuild Guild { get; } | |||
| public RpcGuildSummary Guild { get; } | |||
| public int Online { get; private set; } | |||
| internal RpcGuildStatus(ulong guildId) | |||
| { | |||
| Guild = new RpcGuild(guildId); | |||
| Guild = new RpcGuildSummary(guildId); | |||
| } | |||
| internal static RpcGuildStatus Create(Model model) | |||
| { | |||
| @@ -0,0 +1,30 @@ | |||
| using System.Diagnostics; | |||
| using Model = Discord.API.Rpc.GuildSummary; | |||
| namespace Discord.Rpc | |||
| { | |||
| [DebuggerDisplay(@"{DebuggerDisplay,nq}")] | |||
| public class RpcGuildSummary | |||
| { | |||
| public ulong Id { get; } | |||
| public string Name { get; private set; } | |||
| internal RpcGuildSummary(ulong id) | |||
| { | |||
| Id = id; | |||
| } | |||
| internal static RpcGuildSummary Create(Model model) | |||
| { | |||
| var entity = new RpcGuildSummary(model.Id); | |||
| entity.Update(model); | |||
| return entity; | |||
| } | |||
| internal void Update(Model model) | |||
| { | |||
| Name = model.Name; | |||
| } | |||
| public override string ToString() => Name; | |||
| private string DebuggerDisplay => $"{Name} ({Id})"; | |||
| } | |||
| } | |||
| @@ -1,7 +1,7 @@ | |||
| using System; | |||
| using System.Collections.Generic; | |||
| using System.Collections.Immutable; | |||
| using Model = Discord.API.Rpc.RpcMessage; | |||
| using Model = Discord.API.Rpc.Message; | |||
| namespace Discord.Rpc | |||
| { | |||
| @@ -1,6 +1,6 @@ | |||
| using Discord.Rest; | |||
| using System.Diagnostics; | |||
| using Model = Discord.API.Rpc.RpcMessage; | |||
| using Model = Discord.API.Rpc.Message; | |||
| namespace Discord.Rpc | |||
| { | |||
| @@ -5,7 +5,7 @@ using System.Collections.Generic; | |||
| using System.Collections.Immutable; | |||
| using System.Diagnostics; | |||
| using System.Threading.Tasks; | |||
| using Model = Discord.API.Rpc.RpcMessage; | |||
| using Model = Discord.API.Rpc.Message; | |||
| namespace Discord.Rpc | |||
| { | |||
| @@ -0,0 +1,29 @@ | |||
| using Model = Discord.API.Rpc.GuildMember; | |||
| namespace Discord.Rpc | |||
| { | |||
| public class RpcGuildUser : RpcUser | |||
| { | |||
| private UserStatus _status; | |||
| public override UserStatus Status => _status; | |||
| //public object Acitivity { get; private set; } | |||
| internal RpcGuildUser(DiscordRpcClient discord, ulong id) | |||
| : base(discord, id) | |||
| { | |||
| } | |||
| internal static RpcGuildUser Create(DiscordRpcClient discord, Model model) | |||
| { | |||
| var entity = new RpcGuildUser(discord, model.User.Id); | |||
| entity.Update(model); | |||
| return entity; | |||
| } | |||
| internal void Update(Model model) | |||
| { | |||
| base.Update(model.User); | |||
| _status = model.Status; | |||
| //Activity = model.Activity; | |||
| } | |||
| } | |||
| } | |||
| @@ -6,7 +6,7 @@ using Model = Discord.API.User; | |||
| namespace Discord.Rpc | |||
| { | |||
| [DebuggerDisplay(@"{DebuggerDisplay,nq}")] | |||
| public class RpcUser : RpcEntity<ulong>, IUser, IUpdateable | |||
| public class RpcUser : RpcEntity<ulong>, IUser | |||
| { | |||
| public bool IsBot { get; private set; } | |||
| public string Username { get; private set; } | |||
| @@ -40,12 +40,6 @@ namespace Discord.Rpc | |||
| if (model.Username.IsSpecified) | |||
| Username = model.Username.Value; | |||
| } | |||
| public virtual async Task UpdateAsync(RequestOptions options = null) | |||
| { | |||
| var model = await Discord.ApiClient.GetUserAsync(Id, options); | |||
| Update(model); | |||
| } | |||
| public Task<RestDMChannel> CreateDMChannelAsync(RequestOptions options = null) | |||
| => UserHelper.CreateDMChannelAsync(this, Discord, options); | |||
| @@ -1,6 +1,6 @@ | |||
| using System; | |||
| using System.Diagnostics; | |||
| using Model = Discord.API.Rpc.VoiceStateEvent; | |||
| using Model = Discord.API.Rpc.ExtendedVoiceState; | |||
| namespace Discord.Rpc | |||
| { | |||
| @@ -1,6 +1,5 @@ | |||
| using System; | |||
| using System.Collections.Generic; | |||
| using System.Collections.Immutable; | |||
| using System.Diagnostics; | |||
| using System.Linq; | |||
| using System.Threading.Tasks; | |||