@@ -154,6 +154,7 @@ namespace Discord.Net.WebSockets | |||||
while (!cancelToken.IsCancellationRequested) | while (!cancelToken.IsCancellationRequested) | ||||
{ | { | ||||
WebSocketReceiveResult socketResult = await _client.ReceiveAsync(buffer, cancelToken).ConfigureAwait(false); | WebSocketReceiveResult socketResult = await _client.ReceiveAsync(buffer, cancelToken).ConfigureAwait(false); | ||||
System.Diagnostics.Debug.WriteLine("Got " + socketResult.Count); | |||||
byte[] result; | byte[] result; | ||||
int resultCount; | int resultCount; | ||||
@@ -193,6 +194,7 @@ namespace Discord.Net.WebSockets | |||||
result = buffer.Array; | result = buffer.Array; | ||||
} | } | ||||
System.Diagnostics.Debug.WriteLine("Start"); | |||||
if (socketResult.MessageType == WebSocketMessageType.Text) | if (socketResult.MessageType == WebSocketMessageType.Text) | ||||
{ | { | ||||
string text = Encoding.UTF8.GetString(result, 0, resultCount); | string text = Encoding.UTF8.GetString(result, 0, resultCount); | ||||
@@ -200,6 +202,7 @@ namespace Discord.Net.WebSockets | |||||
} | } | ||||
else | else | ||||
await BinaryMessage(result, 0, resultCount).ConfigureAwait(false); | await BinaryMessage(result, 0, resultCount).ConfigureAwait(false); | ||||
System.Diagnostics.Debug.WriteLine("Stop"); | |||||
} | } | ||||
} | } | ||||
catch (Win32Exception ex) when (ex.HResult == HR_TIMEOUT) | catch (Win32Exception ex) when (ex.HResult == HR_TIMEOUT) | ||||
@@ -269,14 +269,14 @@ namespace Discord.API | |||||
options = RequestOptions.CreateOrClone(options); | options = RequestOptions.CreateOrClone(options); | ||||
return await SendRpcAsync<GetGuildsResponse>("GET_GUILDS", null, options: options).ConfigureAwait(false); | 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); | options = RequestOptions.CreateOrClone(options); | ||||
var msg = new GetGuildParams | var msg = new GetGuildParams | ||||
{ | { | ||||
GuildId = guildId | 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) | 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); | 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); | options = RequestOptions.CreateOrClone(options); | ||||
var msg = new GetChannelParams | var msg = new GetChannelParams | ||||
{ | { | ||||
ChannelId = channelId | 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); | 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); | 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) | public async Task<SubscriptionResponse> SendGlobalSubscribeAsync(string evt, RequestOptions options = null) | ||||
@@ -370,10 +371,16 @@ namespace Discord.API | |||||
options = RequestOptions.CreateOrClone(options); | options = RequestOptions.CreateOrClone(options); | ||||
return await SendRpcAsync<API.Rpc.VoiceSettings>("GET_VOICE_SETTINGS", null, options: options).ConfigureAwait(false); | 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); | 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) | 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 | namespace Discord.API.Rpc | ||||
{ | { | ||||
public class ChannelCreatedEvent | |||||
public class ChannelSummary | |||||
{ | { | ||||
[JsonProperty("id")] | [JsonProperty("id")] | ||||
public ulong Id { get; set; } | public ulong Id { get; set; } |
@@ -3,7 +3,7 @@ using Newtonsoft.Json; | |||||
namespace Discord.API.Rpc | namespace Discord.API.Rpc | ||||
{ | { | ||||
public class VoiceStateEvent | |||||
public class ExtendedVoiceState | |||||
{ | { | ||||
[JsonProperty("user")] | [JsonProperty("user")] | ||||
public User User { get; set; } | public User User { get; set; } |
@@ -1,11 +1,12 @@ | |||||
#pragma warning disable CS1591 | #pragma warning disable CS1591 | ||||
using Newtonsoft.Json; | using Newtonsoft.Json; | ||||
using System.Collections.Generic; | |||||
namespace Discord.API.Rpc | namespace Discord.API.Rpc | ||||
{ | { | ||||
public class GetChannelsResponse | public class GetChannelsResponse | ||||
{ | { | ||||
[JsonProperty("channels")] | [JsonProperty("channels")] | ||||
public RpcChannel[] Channels { get; set; } | |||||
public IReadOnlyCollection<ChannelSummary> Channels { get; set; } | |||||
} | } | ||||
} | } |
@@ -1,4 +1,5 @@ | |||||
#pragma warning disable CS1591 | #pragma warning disable CS1591 | ||||
namespace Discord.API.Rpc | namespace Discord.API.Rpc | ||||
{ | { | ||||
public class GetGuildsParams | public class GetGuildsParams | ||||
@@ -6,6 +6,6 @@ namespace Discord.API.Rpc | |||||
public class GetGuildsResponse | public class GetGuildsResponse | ||||
{ | { | ||||
[JsonProperty("guilds")] | [JsonProperty("guilds")] | ||||
public RpcUserGuild[] Guilds { get; set; } | |||||
public GuildSummary[] Guilds { get; set; } | |||||
} | } | ||||
} | } |
@@ -1,13 +1,18 @@ | |||||
#pragma warning disable CS1591 | #pragma warning disable CS1591 | ||||
using Newtonsoft.Json; | using Newtonsoft.Json; | ||||
using System.Collections.Generic; | |||||
namespace Discord.API.Rpc | namespace Discord.API.Rpc | ||||
{ | { | ||||
public class RpcUserGuild | |||||
public class Guild | |||||
{ | { | ||||
[JsonProperty("id")] | [JsonProperty("id")] | ||||
public ulong Id { get; set; } | public ulong Id { get; set; } | ||||
[JsonProperty("name")] | [JsonProperty("name")] | ||||
public string Name { get; set; } | 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 | namespace Discord.API.Rpc | ||||
{ | { | ||||
public class GuildCreatedEvent | |||||
public class GuildSummary | |||||
{ | { | ||||
[JsonProperty("id")] | [JsonProperty("id")] | ||||
public ulong Id { get; set; } | public ulong Id { get; set; } |
@@ -2,7 +2,7 @@ | |||||
namespace Discord.API.Rpc | namespace Discord.API.Rpc | ||||
{ | { | ||||
public class RpcMessage : Message | |||||
public class Message : Discord.API.Message | |||||
{ | { | ||||
[JsonProperty("blocked")] | [JsonProperty("blocked")] | ||||
public Optional<bool> IsBlocked { get; } | public Optional<bool> IsBlocked { get; } |
@@ -7,6 +7,6 @@ namespace Discord.API.Rpc | |||||
[JsonProperty("channel_id")] | [JsonProperty("channel_id")] | ||||
public ulong ChannelId { get; set; } | public ulong ChannelId { get; set; } | ||||
[JsonProperty("message")] | [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 | namespace Discord.API.Rpc | ||||
{ | { | ||||
public class SelectVoiceChannelParams | |||||
public class SelectChannelParams | |||||
{ | { | ||||
[JsonProperty("channel_id")] | [JsonProperty("channel_id")] | ||||
public ulong? ChannelId { get; set; } | 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>>(); | private readonly AsyncEvent<Func<Task>> _readyEvent = new AsyncEvent<Func<Task>>(); | ||||
//Channel | //Channel | ||||
public event Func<RpcChannel, Task> ChannelCreated | |||||
public event Func<RpcChannelSummary, Task> ChannelCreated | |||||
{ | { | ||||
add { _channelCreatedEvent.Add(value); } | add { _channelCreatedEvent.Add(value); } | ||||
remove { _channelCreatedEvent.Remove(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 | //Guild | ||||
public event Func<RpcGuild, Task> GuildCreated | |||||
public event Func<RpcGuildSummary, Task> GuildCreated | |||||
{ | { | ||||
add { _guildCreatedEvent.Add(value); } | add { _guildCreatedEvent.Add(value); } | ||||
remove { _guildCreatedEvent.Remove(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 | public event Func<RpcGuildStatus, Task> GuildStatusUpdated | ||||
{ | { | ||||
add { _guildStatusUpdatedEvent.Add(value); } | add { _guildStatusUpdatedEvent.Add(value); } | ||||
@@ -8,6 +8,7 @@ using Newtonsoft.Json.Linq; | |||||
using System; | using System; | ||||
using System.Collections.Generic; | using System.Collections.Generic; | ||||
using System.Collections.Immutable; | using System.Collections.Immutable; | ||||
using System.Linq; | |||||
using System.Threading; | using System.Threading; | ||||
using System.Threading.Tasks; | using System.Threading.Tasks; | ||||
@@ -265,6 +266,59 @@ namespace Discord.Rpc | |||||
await ApiClient.SendChannelUnsubscribeAsync(GetEventName(events[i]), channelId); | 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() | public async Task<VoiceSettings> GetVoiceSettingsAsync() | ||||
{ | { | ||||
var model = await ApiClient.GetVoiceSettingsAsync().ConfigureAwait(false); | var model = await ApiClient.GetVoiceSettingsAsync().ConfigureAwait(false); | ||||
@@ -279,6 +333,12 @@ namespace Discord.Rpc | |||||
func(settings); | func(settings); | ||||
await ApiClient.SetVoiceSettingsAsync(settings).ConfigureAwait(false); | 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) | private static string GetEventName(RpcGlobalEvent rpcEvent) | ||||
{ | { | ||||
@@ -363,8 +423,8 @@ namespace Discord.Rpc | |||||
case "CHANNEL_CREATE": | case "CHANNEL_CREATE": | ||||
{ | { | ||||
await _rpcLogger.DebugAsync("Received Dispatch (CHANNEL_CREATE)").ConfigureAwait(false); | 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); | await _channelCreatedEvent.InvokeAsync(channel).ConfigureAwait(false); | ||||
} | } | ||||
@@ -374,8 +434,8 @@ namespace Discord.Rpc | |||||
case "GUILD_CREATE": | case "GUILD_CREATE": | ||||
{ | { | ||||
await _rpcLogger.DebugAsync("Received Dispatch (GUILD_CREATE)").ConfigureAwait(false); | 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); | await _guildCreatedEvent.InvokeAsync(guild).ConfigureAwait(false); | ||||
} | } | ||||
@@ -394,7 +454,7 @@ namespace Discord.Rpc | |||||
case "VOICE_STATE_CREATE": | case "VOICE_STATE_CREATE": | ||||
{ | { | ||||
await _rpcLogger.DebugAsync("Received Dispatch (VOICE_STATE_CREATE)").ConfigureAwait(false); | 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); | var voiceState = RpcVoiceState.Create(this, data); | ||||
await _voiceStateCreatedEvent.InvokeAsync(voiceState).ConfigureAwait(false); | await _voiceStateCreatedEvent.InvokeAsync(voiceState).ConfigureAwait(false); | ||||
@@ -403,7 +463,7 @@ namespace Discord.Rpc | |||||
case "VOICE_STATE_UPDATE": | case "VOICE_STATE_UPDATE": | ||||
{ | { | ||||
await _rpcLogger.DebugAsync("Received Dispatch (VOICE_STATE_UPDATE)").ConfigureAwait(false); | 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); | var voiceState = RpcVoiceState.Create(this, data); | ||||
await _voiceStateUpdatedEvent.InvokeAsync(voiceState).ConfigureAwait(false); | await _voiceStateUpdatedEvent.InvokeAsync(voiceState).ConfigureAwait(false); | ||||
@@ -412,7 +472,7 @@ namespace Discord.Rpc | |||||
case "VOICE_STATE_DELETE": | case "VOICE_STATE_DELETE": | ||||
{ | { | ||||
await _rpcLogger.DebugAsync("Received Dispatch (VOICE_STATE_DELETE)").ConfigureAwait(false); | 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); | var voiceState = RpcVoiceState.Create(this, data); | ||||
await _voiceStateDeletedEvent.InvokeAsync(voiceState).ConfigureAwait(false); | 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 | 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 | namespace Discord.Rpc | ||||
{ | { | ||||
[DebuggerDisplay(@"{DebuggerDisplay,nq}")] | [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); | entity.Update(model); | ||||
return entity; | return entity; | ||||
} | } | ||||
internal void Update(Model model) | internal void Update(Model model) | ||||
{ | { | ||||
Name = model.Name; | Name = model.Name; | ||||
IconUrl = model.IconUrl; | |||||
Users = model.Members.Select(x => RpcGuildUser.Create(Discord, x)).ToImmutableArray(); | |||||
} | } | ||||
public override string ToString() => Name; | public override string ToString() => Name; | ||||
@@ -6,12 +6,12 @@ namespace Discord.Rpc | |||||
[DebuggerDisplay(@"{DebuggerDisplay,nq}")] | [DebuggerDisplay(@"{DebuggerDisplay,nq}")] | ||||
public class RpcGuildStatus | public class RpcGuildStatus | ||||
{ | { | ||||
public RpcGuild Guild { get; } | |||||
public RpcGuildSummary Guild { get; } | |||||
public int Online { get; private set; } | public int Online { get; private set; } | ||||
internal RpcGuildStatus(ulong guildId) | internal RpcGuildStatus(ulong guildId) | ||||
{ | { | ||||
Guild = new RpcGuild(guildId); | |||||
Guild = new RpcGuildSummary(guildId); | |||||
} | } | ||||
internal static RpcGuildStatus Create(Model model) | 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; | ||||
using System.Collections.Generic; | using System.Collections.Generic; | ||||
using System.Collections.Immutable; | using System.Collections.Immutable; | ||||
using Model = Discord.API.Rpc.RpcMessage; | |||||
using Model = Discord.API.Rpc.Message; | |||||
namespace Discord.Rpc | namespace Discord.Rpc | ||||
{ | { | ||||
@@ -1,6 +1,6 @@ | |||||
using Discord.Rest; | using Discord.Rest; | ||||
using System.Diagnostics; | using System.Diagnostics; | ||||
using Model = Discord.API.Rpc.RpcMessage; | |||||
using Model = Discord.API.Rpc.Message; | |||||
namespace Discord.Rpc | namespace Discord.Rpc | ||||
{ | { | ||||
@@ -5,7 +5,7 @@ using System.Collections.Generic; | |||||
using System.Collections.Immutable; | using System.Collections.Immutable; | ||||
using System.Diagnostics; | using System.Diagnostics; | ||||
using System.Threading.Tasks; | using System.Threading.Tasks; | ||||
using Model = Discord.API.Rpc.RpcMessage; | |||||
using Model = Discord.API.Rpc.Message; | |||||
namespace Discord.Rpc | 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 | namespace Discord.Rpc | ||||
{ | { | ||||
[DebuggerDisplay(@"{DebuggerDisplay,nq}")] | [DebuggerDisplay(@"{DebuggerDisplay,nq}")] | ||||
public class RpcUser : RpcEntity<ulong>, IUser, IUpdateable | |||||
public class RpcUser : RpcEntity<ulong>, IUser | |||||
{ | { | ||||
public bool IsBot { get; private set; } | public bool IsBot { get; private set; } | ||||
public string Username { get; private set; } | public string Username { get; private set; } | ||||
@@ -40,12 +40,6 @@ namespace Discord.Rpc | |||||
if (model.Username.IsSpecified) | if (model.Username.IsSpecified) | ||||
Username = model.Username.Value; | 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) | public Task<RestDMChannel> CreateDMChannelAsync(RequestOptions options = null) | ||||
=> UserHelper.CreateDMChannelAsync(this, Discord, options); | => UserHelper.CreateDMChannelAsync(this, Discord, options); | ||||
@@ -1,6 +1,6 @@ | |||||
using System; | using System; | ||||
using System.Diagnostics; | using System.Diagnostics; | ||||
using Model = Discord.API.Rpc.VoiceStateEvent; | |||||
using Model = Discord.API.Rpc.ExtendedVoiceState; | |||||
namespace Discord.Rpc | namespace Discord.Rpc | ||||
{ | { | ||||
@@ -1,6 +1,5 @@ | |||||
using System; | using System; | ||||
using System.Collections.Generic; | using System.Collections.Generic; | ||||
using System.Collections.Immutable; | |||||
using System.Diagnostics; | using System.Diagnostics; | ||||
using System.Linq; | using System.Linq; | ||||
using System.Threading.Tasks; | using System.Threading.Tasks; | ||||