Added support for more events, added benchmark
This commit is contained in:
@@ -14,8 +14,8 @@ namespace Discord.API
|
||||
[JsonProperty("joined_at")]
|
||||
public DateTime?JoinedAt { get; set; }
|
||||
[JsonProperty("deaf")]
|
||||
public bool Deaf { get; set; }
|
||||
public bool? Deaf { get; set; }
|
||||
[JsonProperty("mute")]
|
||||
public bool Mute { get; set; }
|
||||
public bool? Mute { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ namespace Discord.API
|
||||
public Attachment[] Attachments { get; set; }
|
||||
[JsonProperty("embeds")]
|
||||
public Embed[] Embeds { get; set; }
|
||||
[JsonProperty("nonce")]
|
||||
public uint? Nonce { get; set; }
|
||||
/*[JsonProperty("nonce")]
|
||||
public object Nonce { get; set; }*/
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,8 @@ namespace Discord.API
|
||||
{
|
||||
[JsonProperty("user")]
|
||||
public User User { get; set; }
|
||||
[JsonProperty("guild_id")]
|
||||
public ulong? GuildId { get; set; }
|
||||
[JsonProperty("status")]
|
||||
public UserStatus Status { get; set; }
|
||||
[JsonProperty("game")]
|
||||
|
||||
@@ -4,8 +4,10 @@ namespace Discord.API
|
||||
{
|
||||
public class VoiceState
|
||||
{
|
||||
[JsonProperty("guild_id")]
|
||||
public ulong? GuildId { get; set; }
|
||||
[JsonProperty("channel_id")]
|
||||
public ulong ChannelId { get; set; }
|
||||
public ulong? ChannelId { get; set; }
|
||||
[JsonProperty("user_id")]
|
||||
public ulong UserId { get; set; }
|
||||
[JsonProperty("session_id")]
|
||||
|
||||
10
src/Discord.Net/API/Gateway/GuildMemberAddEvent.cs
Normal file
10
src/Discord.Net/API/Gateway/GuildMemberAddEvent.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Discord.API.Gateway
|
||||
{
|
||||
public class GuildMemberAddEvent : GuildMember
|
||||
{
|
||||
[JsonProperty("guild_id")]
|
||||
public ulong GuildId { get; set; }
|
||||
}
|
||||
}
|
||||
12
src/Discord.Net/API/Gateway/GuildMemberRemoveEvent.cs
Normal file
12
src/Discord.Net/API/Gateway/GuildMemberRemoveEvent.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Discord.API.Gateway
|
||||
{
|
||||
public class GuildMemberRemoveEvent
|
||||
{
|
||||
[JsonProperty("guild_id")]
|
||||
public ulong GuildId { get; set; }
|
||||
[JsonProperty("user")]
|
||||
public User User { get; set; }
|
||||
}
|
||||
}
|
||||
10
src/Discord.Net/API/Gateway/GuildMemberUpdateEvent.cs
Normal file
10
src/Discord.Net/API/Gateway/GuildMemberUpdateEvent.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Discord.API.Gateway
|
||||
{
|
||||
public class GuildMemberUpdateEvent : GuildMember
|
||||
{
|
||||
[JsonProperty("guild_id")]
|
||||
public ulong GuildId { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,6 @@ namespace Discord.API.Gateway
|
||||
[JsonProperty("guild_id")]
|
||||
public ulong GuildId { get; set; }
|
||||
[JsonProperty("role")]
|
||||
public Role Data { get; set; }
|
||||
public Role Role { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,6 @@ namespace Discord.API.Gateway
|
||||
[JsonProperty("guild_id")]
|
||||
public ulong GuildId { get; set; }
|
||||
[JsonProperty("role")]
|
||||
public Role Data { get; set; }
|
||||
public Role Role { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,6 +41,9 @@ namespace Discord
|
||||
|
||||
private readonly ConcurrentQueue<ulong> _largeGuilds;
|
||||
private readonly Logger _gatewayLogger;
|
||||
#if BENCHMARK
|
||||
private readonly Logger _benchmarkLogger;
|
||||
#endif
|
||||
private readonly DataStoreProvider _dataStoreProvider;
|
||||
private readonly JsonSerializer _serializer;
|
||||
private readonly int _connectionTimeout, _reconnectDelay, _failedReconnectDelay;
|
||||
@@ -106,7 +109,10 @@ namespace Discord
|
||||
_largeThreshold = config.LargeThreshold;
|
||||
|
||||
_gatewayLogger = _log.CreateLogger("Gateway");
|
||||
|
||||
#if BENCHMARK
|
||||
_benchmarkLogger = _log.CreateLogger("Benchmark");
|
||||
#endif
|
||||
|
||||
_serializer = new JsonSerializer { ContractResolver = new DiscordContractResolver() };
|
||||
|
||||
ApiClient.SentGatewayMessage += async opCode => await _gatewayLogger.Debug($"Sent {(GatewayOpCode)opCode}");
|
||||
@@ -207,7 +213,7 @@ namespace Discord
|
||||
{
|
||||
dataStore = dataStore ?? DataStore;
|
||||
|
||||
var guild = new CachedGuild(this, model);
|
||||
var guild = new CachedGuild(this, model, dataStore);
|
||||
if (model.Unavailable != true)
|
||||
{
|
||||
for (int i = 0; i < model.Channels.Length; i++)
|
||||
@@ -247,7 +253,7 @@ namespace Discord
|
||||
{
|
||||
dataStore = dataStore ?? DataStore;
|
||||
|
||||
var recipient = AddCachedUser(model.Recipient, dataStore);
|
||||
var recipient = GetOrAddCachedUser(model.Recipient, dataStore);
|
||||
var channel = recipient.AddDMChannel(model);
|
||||
dataStore.AddChannel(channel);
|
||||
return channel;
|
||||
@@ -287,7 +293,7 @@ namespace Discord
|
||||
{
|
||||
return Task.FromResult<IUser>(DataStore.Users.Where(x => x.Discriminator == discriminator && x.Username == username).FirstOrDefault());
|
||||
}
|
||||
internal CachedPublicUser AddCachedUser(API.User model, DataStore dataStore = null)
|
||||
internal CachedPublicUser GetOrAddCachedUser(API.User model, DataStore dataStore = null)
|
||||
{
|
||||
dataStore = dataStore ?? DataStore;
|
||||
|
||||
@@ -299,8 +305,7 @@ namespace Discord
|
||||
{
|
||||
dataStore = dataStore ?? DataStore;
|
||||
|
||||
var user = dataStore.GetUser(id);
|
||||
user.RemoveRef();
|
||||
var user = dataStore.RemoveUser(id);
|
||||
return user;
|
||||
}
|
||||
|
||||
@@ -336,7 +341,7 @@ namespace Discord
|
||||
batchTasks[j] = guild.DownloaderPromise;
|
||||
}
|
||||
|
||||
ApiClient.SendRequestMembers(batchIds);
|
||||
await ApiClient.SendRequestMembers(batchIds).ConfigureAwait(false);
|
||||
|
||||
if (isLast && batchCount > 1)
|
||||
await Task.WhenAll(batchTasks.Take(count)).ConfigureAwait(false);
|
||||
@@ -347,474 +352,511 @@ namespace Discord
|
||||
|
||||
private async Task ProcessMessage(GatewayOpCode opCode, int? seq, string type, object payload)
|
||||
{
|
||||
if (seq != null)
|
||||
_lastSeq = seq.Value;
|
||||
#if BENCHMARK
|
||||
Stopwatch stopwatch = Stopwatch.StartNew();
|
||||
try
|
||||
{
|
||||
switch (opCode)
|
||||
#endif
|
||||
if (seq != null)
|
||||
_lastSeq = seq.Value;
|
||||
try
|
||||
{
|
||||
case GatewayOpCode.Hello:
|
||||
{
|
||||
var data = (payload as JToken).ToObject<HelloEvent>(_serializer);
|
||||
switch (opCode)
|
||||
{
|
||||
case GatewayOpCode.Hello:
|
||||
{
|
||||
await _gatewayLogger.Debug($"Received Hello").ConfigureAwait(false);
|
||||
var data = (payload as JToken).ToObject<HelloEvent>(_serializer);
|
||||
|
||||
await ApiClient.SendIdentify().ConfigureAwait(false);
|
||||
_heartbeatTask = RunHeartbeat(data.HeartbeatInterval, _heartbeatCancelToken.Token);
|
||||
}
|
||||
break;
|
||||
case GatewayOpCode.HeartbeatAck:
|
||||
{
|
||||
var latency = (int)(Environment.TickCount - _heartbeatTime);
|
||||
await _gatewayLogger.Debug($"Latency: {latency} ms").ConfigureAwait(false);
|
||||
Latency = latency;
|
||||
await ApiClient.SendIdentify().ConfigureAwait(false);
|
||||
_heartbeatTask = RunHeartbeat(data.HeartbeatInterval, _heartbeatCancelToken.Token);
|
||||
}
|
||||
break;
|
||||
case GatewayOpCode.HeartbeatAck:
|
||||
{
|
||||
await _gatewayLogger.Debug($"Received HeartbeatAck").ConfigureAwait(false);
|
||||
|
||||
await LatencyUpdated.Raise(latency).ConfigureAwait(false);
|
||||
}
|
||||
break;
|
||||
case GatewayOpCode.Dispatch:
|
||||
switch (type)
|
||||
{
|
||||
//Global
|
||||
case "READY":
|
||||
{
|
||||
//TODO: Make downloading large guilds optional
|
||||
var data = (payload as JToken).ToObject<ReadyEvent>(_serializer);
|
||||
var dataStore = _dataStoreProvider(ShardId, _totalShards, data.Guilds.Length, data.PrivateChannels.Length);
|
||||
var latency = (int)(Environment.TickCount - _heartbeatTime);
|
||||
await _gatewayLogger.Debug($"Latency = {latency} ms").ConfigureAwait(false);
|
||||
Latency = latency;
|
||||
|
||||
_currentUser = new CachedSelfUser(this, data.User);
|
||||
|
||||
for (int i = 0; i < data.Guilds.Length; i++)
|
||||
AddCachedGuild(data.Guilds[i], dataStore);
|
||||
for (int i = 0; i < data.PrivateChannels.Length; i++)
|
||||
AddCachedDMChannel(data.PrivateChannels[i], dataStore);
|
||||
|
||||
_sessionId = data.SessionId;
|
||||
DataStore = dataStore;
|
||||
|
||||
await Ready.Raise().ConfigureAwait(false);
|
||||
|
||||
_connectTask.TrySetResult(true); //Signal the .Connect() call to complete
|
||||
}
|
||||
break;
|
||||
|
||||
//Guilds
|
||||
case "GUILD_CREATE":
|
||||
{
|
||||
var data = (payload as JToken).ToObject<ExtendedGuild>(_serializer);
|
||||
var guild = new CachedGuild(this, data);
|
||||
DataStore.AddGuild(guild);
|
||||
|
||||
if (data.Unavailable == false)
|
||||
type = "GUILD_AVAILABLE";
|
||||
else
|
||||
await JoinedGuild.Raise(guild).ConfigureAwait(false);
|
||||
|
||||
await GuildAvailable.Raise(guild);
|
||||
}
|
||||
break;
|
||||
case "GUILD_UPDATE":
|
||||
{
|
||||
var data = (payload as JToken).ToObject<API.Guild>(_serializer);
|
||||
var guild = DataStore.GetGuild(data.Id);
|
||||
if (guild != null)
|
||||
await LatencyUpdated.Raise(latency).ConfigureAwait(false);
|
||||
}
|
||||
break;
|
||||
case GatewayOpCode.Dispatch:
|
||||
switch (type)
|
||||
{
|
||||
//Global
|
||||
case "READY":
|
||||
{
|
||||
var before = _enablePreUpdateEvents ? guild.Clone() : null;
|
||||
guild.Update(data, UpdateSource.WebSocket);
|
||||
await GuildUpdated.Raise(before, guild);
|
||||
await _gatewayLogger.Debug($"Received Dispatch (READY)").ConfigureAwait(false);
|
||||
|
||||
//TODO: Make downloading large guilds optional
|
||||
var data = (payload as JToken).ToObject<ReadyEvent>(_serializer);
|
||||
var dataStore = _dataStoreProvider(ShardId, _totalShards, data.Guilds.Length, data.PrivateChannels.Length);
|
||||
|
||||
_currentUser = new CachedSelfUser(this, data.User);
|
||||
|
||||
for (int i = 0; i < data.Guilds.Length; i++)
|
||||
AddCachedGuild(data.Guilds[i], dataStore);
|
||||
for (int i = 0; i < data.PrivateChannels.Length; i++)
|
||||
AddCachedDMChannel(data.PrivateChannels[i], dataStore);
|
||||
|
||||
_sessionId = data.SessionId;
|
||||
DataStore = dataStore;
|
||||
|
||||
await Ready.Raise().ConfigureAwait(false);
|
||||
|
||||
_connectTask.TrySetResult(true); //Signal the .Connect() call to complete
|
||||
}
|
||||
else
|
||||
await _gatewayLogger.Warning("GUILD_UPDATE referenced an unknown guild.");
|
||||
}
|
||||
break;
|
||||
case "GUILD_DELETE":
|
||||
{
|
||||
var data = (payload as JToken).ToObject<ExtendedGuild>(_serializer);
|
||||
var guild = DataStore.RemoveGuild(data.Id);
|
||||
if (guild != null)
|
||||
{
|
||||
if (data.Unavailable == true)
|
||||
type = "GUILD_UNAVAILABLE";
|
||||
break;
|
||||
|
||||
await GuildUnavailable.Raise(guild);
|
||||
if (data.Unavailable != true)
|
||||
await LeftGuild.Raise(guild);
|
||||
//Guilds
|
||||
case "GUILD_CREATE":
|
||||
{
|
||||
var data = (payload as JToken).ToObject<ExtendedGuild>(_serializer);
|
||||
var guild = new CachedGuild(this, data, DataStore);
|
||||
DataStore.AddGuild(guild);
|
||||
|
||||
if (data.Unavailable == false)
|
||||
type = "GUILD_AVAILABLE";
|
||||
await _gatewayLogger.Debug($"Received Dispatch ({type})").ConfigureAwait(false);
|
||||
|
||||
if (data.Unavailable != false)
|
||||
await JoinedGuild.Raise(guild).ConfigureAwait(false);
|
||||
|
||||
await GuildAvailable.Raise(guild).ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
await _gatewayLogger.Warning("GUILD_DELETE referenced an unknown guild.");
|
||||
}
|
||||
break;
|
||||
|
||||
//Channels
|
||||
case "CHANNEL_CREATE":
|
||||
{
|
||||
var data = (payload as JToken).ToObject<API.Channel>(_serializer);
|
||||
|
||||
ICachedChannel channel = null;
|
||||
if (data.GuildId != null)
|
||||
break;
|
||||
case "GUILD_UPDATE":
|
||||
{
|
||||
var guild = DataStore.GetGuild(data.GuildId.Value);
|
||||
await _gatewayLogger.Debug($"Received Dispatch (GUILD_UPDATE)").ConfigureAwait(false);
|
||||
|
||||
var data = (payload as JToken).ToObject<API.Guild>(_serializer);
|
||||
var guild = DataStore.GetGuild(data.Id);
|
||||
if (guild != null)
|
||||
{
|
||||
channel = guild.AddCachedChannel(data);
|
||||
DataStore.AddChannel(channel);
|
||||
var before = _enablePreUpdateEvents ? guild.Clone() : null;
|
||||
guild.Update(data, UpdateSource.WebSocket);
|
||||
await GuildUpdated.Raise(before, guild).ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
await _gatewayLogger.Warning("CHANNEL_CREATE referenced an unknown guild.");
|
||||
await _gatewayLogger.Warning("GUILD_UPDATE referenced an unknown guild.");
|
||||
}
|
||||
else
|
||||
channel = AddCachedDMChannel(data);
|
||||
if (channel != null)
|
||||
await ChannelCreated.Raise(channel);
|
||||
}
|
||||
break;
|
||||
case "CHANNEL_UPDATE":
|
||||
{
|
||||
var data = (payload as JToken).ToObject<API.Channel>(_serializer);
|
||||
var channel = DataStore.GetChannel(data.Id);
|
||||
if (channel != null)
|
||||
break;
|
||||
case "GUILD_DELETE":
|
||||
{
|
||||
var before = _enablePreUpdateEvents ? channel.Clone() : null;
|
||||
channel.Update(data, UpdateSource.WebSocket);
|
||||
await ChannelUpdated.Raise(before, channel);
|
||||
}
|
||||
else
|
||||
await _gatewayLogger.Warning("CHANNEL_UPDATE referenced an unknown channel.");
|
||||
}
|
||||
break;
|
||||
case "CHANNEL_DELETE":
|
||||
{
|
||||
var data = (payload as JToken).ToObject<API.Channel>(_serializer);
|
||||
var channel = RemoveCachedChannel(data.Id);
|
||||
if (channel != null)
|
||||
await ChannelDestroyed.Raise(channel);
|
||||
else
|
||||
await _gatewayLogger.Warning("CHANNEL_DELETE referenced an unknown channel.");
|
||||
}
|
||||
break;
|
||||
var data = (payload as JToken).ToObject<ExtendedGuild>(_serializer);
|
||||
if (data.Unavailable == true)
|
||||
type = "GUILD_UNAVAILABLE";
|
||||
await _gatewayLogger.Debug($"Received Dispatch ({type})").ConfigureAwait(false);
|
||||
|
||||
//Members
|
||||
/*case "GUILD_MEMBER_ADD":
|
||||
{
|
||||
var data = (payload as JToken).ToObject<API.GuildMember>(_serializer);
|
||||
var guild = GetGuild(data.GuildId.Value);
|
||||
if (guild != null)
|
||||
{
|
||||
var user = guild.AddCachedUser(data.User.Id, true, true);
|
||||
user.Update(data);
|
||||
user.UpdateActivity();
|
||||
UserJoined.Raise(user);
|
||||
}
|
||||
else
|
||||
await _gatewayLogger.Warning("GUILD_MEMBER_ADD referenced an unknown guild.");
|
||||
}
|
||||
break;
|
||||
case "GUILD_MEMBER_UPDATE":
|
||||
{
|
||||
var data = (payload as JToken).ToObject<API.GuildMember>(_serializer);
|
||||
var guild = GetGuild(data.GuildId.Value);
|
||||
if (guild != null)
|
||||
{
|
||||
var user = guild.GetCachedUser(data.User.Id);
|
||||
if (user != null)
|
||||
var guild = DataStore.RemoveGuild(data.Id);
|
||||
if (guild != null)
|
||||
{
|
||||
var before = _enablePreUpdateEvents ? user.Clone() : null;
|
||||
user.Update(data);
|
||||
await UserUpdated.Raise(before, user);
|
||||
await GuildUnavailable.Raise(guild).ConfigureAwait(false);
|
||||
if (data.Unavailable != true)
|
||||
await LeftGuild.Raise(guild).ConfigureAwait(false);
|
||||
foreach (var member in guild.Members)
|
||||
member.User.RemoveRef();
|
||||
}
|
||||
else
|
||||
await _gatewayLogger.Warning("GUILD_MEMBER_UPDATE referenced an unknown user.");
|
||||
await _gatewayLogger.Warning($"{type} referenced an unknown guild.").ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
await _gatewayLogger.Warning("GUILD_MEMBER_UPDATE referenced an unknown guild.");
|
||||
}
|
||||
break;
|
||||
case "GUILD_MEMBER_REMOVE":
|
||||
{
|
||||
var data = (payload as JToken).ToObject<API.GuildMember>(_serializer);
|
||||
var guild = GetGuild(data.GuildId.Value);
|
||||
if (guild != null)
|
||||
break;
|
||||
|
||||
//Channels
|
||||
case "CHANNEL_CREATE":
|
||||
{
|
||||
var user = guild.RemoveCachedUser(data.User.Id);
|
||||
if (user != null)
|
||||
await _gatewayLogger.Debug($"Received Dispatch (CHANNEL_CREATE)").ConfigureAwait(false);
|
||||
|
||||
var data = (payload as JToken).ToObject<API.Channel>(_serializer);
|
||||
ICachedChannel channel = null;
|
||||
if (data.GuildId != null)
|
||||
{
|
||||
user.GlobalUser.RemoveGuild();
|
||||
if (user.GuildCount == 0 && user.DMChannel == null)
|
||||
DataStore.RemoveUser(user.Id);
|
||||
await UserLeft.Raise(user);
|
||||
var guild = DataStore.GetGuild(data.GuildId.Value);
|
||||
if (guild != null)
|
||||
{
|
||||
channel = guild.AddCachedChannel(data);
|
||||
DataStore.AddChannel(channel);
|
||||
}
|
||||
else
|
||||
await _gatewayLogger.Warning("CHANNEL_CREATE referenced an unknown guild.");
|
||||
}
|
||||
else
|
||||
await _gatewayLogger.Warning("GUILD_MEMBER_REMOVE referenced an unknown user.");
|
||||
channel = AddCachedDMChannel(data);
|
||||
if (channel != null)
|
||||
await ChannelCreated.Raise(channel);
|
||||
}
|
||||
else
|
||||
await _gatewayLogger.Warning("GUILD_MEMBER_REMOVE referenced an unknown guild.");
|
||||
}
|
||||
break;
|
||||
case "GUILD_MEMBERS_CHUNK":
|
||||
{
|
||||
var data = (payload as JToken).ToObject<GuildMembersChunkEvent>(_serializer);
|
||||
var guild = GetCachedGuild(data.GuildId);
|
||||
if (guild != null)
|
||||
break;
|
||||
case "CHANNEL_UPDATE":
|
||||
{
|
||||
foreach (var memberData in data.Members)
|
||||
{
|
||||
var user = guild.AddCachedUser(memberData.User.Id, true, false);
|
||||
user.Update(memberData);
|
||||
}
|
||||
await _gatewayLogger.Debug($"Received Dispatch (CHANNEL_UPDATE)").ConfigureAwait(false);
|
||||
|
||||
if (guild.CurrentUserCount >= guild.UserCount) //Finished downloading for there
|
||||
await GuildAvailable.Raise(guild);
|
||||
}
|
||||
else
|
||||
await _gatewayLogger.Warning("GUILD_MEMBERS_CHUNK referenced an unknown guild.");
|
||||
}
|
||||
break;
|
||||
|
||||
//Roles
|
||||
/*case "GUILD_ROLE_CREATE":
|
||||
{
|
||||
var data = (payload as JToken).ToObject<GuildRoleCreateEvent>(_serializer);
|
||||
var guild = GetCachedGuild(data.GuildId);
|
||||
if (guild != null)
|
||||
{
|
||||
var role = guild.AddCachedRole(data.Data.Id);
|
||||
role.Update(data.Data, false);
|
||||
RoleCreated.Raise(role);
|
||||
}
|
||||
else
|
||||
await _gatewayLogger.Warning("GUILD_ROLE_CREATE referenced an unknown guild.");
|
||||
}
|
||||
break;
|
||||
case "GUILD_ROLE_UPDATE":
|
||||
{
|
||||
var data = (payload as JToken).ToObject<GuildRoleUpdateEvent>(_serializer);
|
||||
var guild = GetCachedGuild(data.GuildId);
|
||||
if (guild != null)
|
||||
{
|
||||
var role = guild.GetRole(data.Data.Id);
|
||||
if (role != null)
|
||||
var data = (payload as JToken).ToObject<API.Channel>(_serializer);
|
||||
var channel = DataStore.GetChannel(data.Id);
|
||||
if (channel != null)
|
||||
{
|
||||
var before = _enablePreUpdateEvents ? role.Clone() : null;
|
||||
role.Update(data.Data, true);
|
||||
RoleUpdated.Raise(before, role);
|
||||
var before = _enablePreUpdateEvents ? channel.Clone() : null;
|
||||
channel.Update(data, UpdateSource.WebSocket);
|
||||
await ChannelUpdated.Raise(before, channel);
|
||||
}
|
||||
else
|
||||
await _gatewayLogger.Warning("GUILD_ROLE_UPDATE referenced an unknown role.");
|
||||
await _gatewayLogger.Warning("CHANNEL_UPDATE referenced an unknown channel.");
|
||||
}
|
||||
else
|
||||
await _gatewayLogger.Warning("GUILD_ROLE_UPDATE referenced an unknown guild.");
|
||||
}
|
||||
break;
|
||||
case "GUILD_ROLE_DELETE":
|
||||
{
|
||||
var data = (payload as JToken).ToObject<GuildRoleDeleteEvent>(_serializer);
|
||||
var guild = DataStore.GetGuild(data.GuildId);
|
||||
if (guild != null)
|
||||
break;
|
||||
case "CHANNEL_DELETE":
|
||||
{
|
||||
var role = guild.RemoveRole(data.RoleId);
|
||||
if (role != null)
|
||||
RoleDeleted.Raise(role);
|
||||
await _gatewayLogger.Debug($"Received Dispatch (CHANNEL_DELETE)").ConfigureAwait(false);
|
||||
|
||||
var data = (payload as JToken).ToObject<API.Channel>(_serializer);
|
||||
var channel = RemoveCachedChannel(data.Id);
|
||||
if (channel != null)
|
||||
await ChannelDestroyed.Raise(channel);
|
||||
else
|
||||
await _gatewayLogger.Warning("GUILD_ROLE_DELETE referenced an unknown role.");
|
||||
await _gatewayLogger.Warning("CHANNEL_DELETE referenced an unknown channel.");
|
||||
}
|
||||
else
|
||||
await _gatewayLogger.Warning("GUILD_ROLE_DELETE referenced an unknown guild.");
|
||||
}
|
||||
break;
|
||||
break;
|
||||
|
||||
//Bans
|
||||
case "GUILD_BAN_ADD":
|
||||
{
|
||||
var data = (payload as JToken).ToObject<GuildBanEvent>(_serializer);
|
||||
var guild = GetCachedGuild(data.GuildId);
|
||||
if (guild != null)
|
||||
await UserBanned.Raise(new User(this, data));
|
||||
else
|
||||
await _gatewayLogger.Warning("GUILD_BAN_ADD referenced an unknown guild.");
|
||||
}
|
||||
break;
|
||||
case "GUILD_BAN_REMOVE":
|
||||
{
|
||||
var data = payload.ToObject<GuildBanEvent>(_serializer);
|
||||
var guild = GetCachedGuild(data.GuildId);
|
||||
if (guild != null)
|
||||
await UserUnbanned.Raise(new User(this, data));
|
||||
else
|
||||
await _gatewayLogger.Warning("GUILD_BAN_REMOVE referenced an unknown guild.");
|
||||
}
|
||||
break;
|
||||
|
||||
//Messages
|
||||
case "MESSAGE_CREATE":
|
||||
{
|
||||
var data = (payload as JToken).ToObject<API.Message>(_serializer);
|
||||
var channel = DataStore.GetChannel(data.ChannelId);
|
||||
if (channel != null)
|
||||
//Members
|
||||
case "GUILD_MEMBER_ADD":
|
||||
{
|
||||
var user = channel.GetUser(data.Author.Id);
|
||||
await _gatewayLogger.Debug($"Received Dispatch (GUILD_MEMBER_ADD)").ConfigureAwait(false);
|
||||
|
||||
if (user != null)
|
||||
var data = (payload as JToken).ToObject<GuildMemberAddEvent>(_serializer);
|
||||
var guild = DataStore.GetGuild(data.GuildId);
|
||||
if (guild != null)
|
||||
{
|
||||
bool isAuthor = data.Author.Id == CurrentUser.Id;
|
||||
var msg = channel.AddMessage(data.Id, user, data.Timestamp.Value);
|
||||
|
||||
msg.Update(data);
|
||||
|
||||
MessageReceived.Raise(msg);
|
||||
var user = guild.AddCachedUser(data);
|
||||
await UserJoined.Raise(user).ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
await _gatewayLogger.Warning("MESSAGE_CREATE referenced an unknown user.");
|
||||
await _gatewayLogger.Warning("GUILD_MEMBER_ADD referenced an unknown guild.");
|
||||
}
|
||||
else
|
||||
await _gatewayLogger.Warning("MESSAGE_CREATE referenced an unknown channel.");
|
||||
}
|
||||
break;
|
||||
case "MESSAGE_UPDATE":
|
||||
{
|
||||
var data = (payload as JToken).ToObject<API.Message>(_serializer);
|
||||
var channel = GetCachedChannel(data.ChannelId);
|
||||
if (channel != null)
|
||||
break;
|
||||
case "GUILD_MEMBER_UPDATE":
|
||||
{
|
||||
var msg = channel.GetMessage(data.Id, data.Author?.Id);
|
||||
var before = _enablePreUpdateEvents ? msg.Clone() : null;
|
||||
msg.Update(data);
|
||||
MessageUpdated.Raise(before, msg);
|
||||
}
|
||||
else
|
||||
await _gatewayLogger.Warning("MESSAGE_UPDATE referenced an unknown channel.");
|
||||
}
|
||||
break;
|
||||
case "MESSAGE_DELETE":
|
||||
{
|
||||
var data = (payload as JToken).ToObject<API.Message>(_serializer);
|
||||
var channel = GetCachedChannel(data.ChannelId);
|
||||
if (channel != null)
|
||||
{
|
||||
var msg = channel.RemoveMessage(data.Id);
|
||||
MessageDeleted.Raise(msg);
|
||||
}
|
||||
else
|
||||
await _gatewayLogger.Warning("MESSAGE_DELETE referenced an unknown channel.");
|
||||
}
|
||||
break;
|
||||
await _gatewayLogger.Debug($"Received Dispatch (GUILD_MEMBER_UPDATE)").ConfigureAwait(false);
|
||||
|
||||
//Statuses
|
||||
case "PRESENCE_UPDATE":
|
||||
{
|
||||
var data = (payload as JToken).ToObject<API.Presence>(_serializer);
|
||||
User user;
|
||||
Guild guild;
|
||||
if (data.GuildId == null)
|
||||
{
|
||||
guild = null;
|
||||
user = GetPrivateChannel(data.User.Id)?.Recipient;
|
||||
}
|
||||
else
|
||||
{
|
||||
guild = GetGuild(data.GuildId.Value);
|
||||
if (guild == null)
|
||||
var data = (payload as JToken).ToObject<GuildMemberUpdateEvent>(_serializer);
|
||||
var guild = DataStore.GetGuild(data.GuildId);
|
||||
if (guild != null)
|
||||
{
|
||||
await _gatewayLogger.Warning("PRESENCE_UPDATE referenced an unknown guild.");
|
||||
break;
|
||||
var user = guild.GetCachedUser(data.User.Id);
|
||||
if (user != null)
|
||||
{
|
||||
var before = _enablePreUpdateEvents ? user.Clone() : null;
|
||||
user.Update(data, UpdateSource.WebSocket);
|
||||
await UserUpdated.Raise(before, user);
|
||||
}
|
||||
else
|
||||
await _gatewayLogger.Warning("GUILD_MEMBER_UPDATE referenced an unknown user.");
|
||||
}
|
||||
else
|
||||
user = guild.GetUser(data.User.Id);
|
||||
await _gatewayLogger.Warning("GUILD_MEMBER_UPDATE referenced an unknown guild.");
|
||||
}
|
||||
break;
|
||||
case "GUILD_MEMBER_REMOVE":
|
||||
{
|
||||
await _gatewayLogger.Debug($"Received Dispatch (GUILD_MEMBER_REMOVE)").ConfigureAwait(false);
|
||||
|
||||
if (user != null)
|
||||
{
|
||||
var before = _enablePreUpdateEvents ? user.Clone() : null;
|
||||
user.Update(data);
|
||||
UserUpdated.Raise(before, user);
|
||||
}
|
||||
else
|
||||
{
|
||||
//Occurs when a user leaves a guild
|
||||
//await _gatewayLogger.Warning("PRESENCE_UPDATE referenced an unknown user.");
|
||||
}
|
||||
}
|
||||
break;
|
||||
case "TYPING_START":
|
||||
{
|
||||
var data = (payload as JToken).ToObject<TypingStartEvent>(_serializer);
|
||||
var channel = GetCachedChannel(data.ChannelId);
|
||||
if (channel != null)
|
||||
{
|
||||
var user = channel.GetUser(data.UserId);
|
||||
if (user != null)
|
||||
var data = (payload as JToken).ToObject<GuildMemberRemoveEvent>(_serializer);
|
||||
var guild = DataStore.GetGuild(data.GuildId);
|
||||
if (guild != null)
|
||||
{
|
||||
await UserIsTyping.Raise(channel, user);
|
||||
user.UpdateActivity();
|
||||
var user = guild.RemoveCachedUser(data.User.Id);
|
||||
if (user != null)
|
||||
{
|
||||
user.User.RemoveRef();
|
||||
await UserLeft.Raise(user);
|
||||
}
|
||||
else
|
||||
await _gatewayLogger.Warning("GUILD_MEMBER_REMOVE referenced an unknown user.");
|
||||
}
|
||||
else
|
||||
await _gatewayLogger.Warning("GUILD_MEMBER_REMOVE referenced an unknown guild.");
|
||||
}
|
||||
else
|
||||
await _gatewayLogger.Warning("TYPING_START referenced an unknown channel.");
|
||||
}
|
||||
break;
|
||||
|
||||
//Voice
|
||||
case "VOICE_STATE_UPDATE":
|
||||
{
|
||||
var data = (payload as JToken).ToObject<API.VoiceState>(_serializer);
|
||||
var guild = GetGuild(data.GuildId);
|
||||
if (guild != null)
|
||||
break;
|
||||
case "GUILD_MEMBERS_CHUNK":
|
||||
{
|
||||
var user = guild.GetUser(data.UserId);
|
||||
if (user != null)
|
||||
await _gatewayLogger.Debug($"Received Dispatch (GUILD_MEMBERS_CHUNK)").ConfigureAwait(false);
|
||||
|
||||
var data = (payload as JToken).ToObject<GuildMembersChunkEvent>(_serializer);
|
||||
var guild = DataStore.GetGuild(data.GuildId);
|
||||
if (guild != null)
|
||||
{
|
||||
var before = _enablePreUpdateEvents ? user.Clone() : null;
|
||||
user.Update(data);
|
||||
UserUpdated.Raise(before, user);
|
||||
foreach (var memberModel in data.Members)
|
||||
guild.AddCachedUser(memberModel);
|
||||
|
||||
if (guild.DownloadedMemberCount >= guild.MemberCount) //Finished downloading for there
|
||||
{
|
||||
guild.CompleteDownloadMembers();
|
||||
await GuildDownloadedMembers.Raise(guild).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
else
|
||||
await _gatewayLogger.Warning("GUILD_MEMBERS_CHUNK referenced an unknown guild.");
|
||||
}
|
||||
break;
|
||||
|
||||
//Roles
|
||||
case "GUILD_ROLE_CREATE":
|
||||
{
|
||||
await _gatewayLogger.Debug($"Received Dispatch (GUILD_ROLE_CREATE)").ConfigureAwait(false);
|
||||
|
||||
var data = (payload as JToken).ToObject<GuildRoleCreateEvent>(_serializer);
|
||||
var guild = DataStore.GetGuild(data.GuildId);
|
||||
if (guild != null)
|
||||
{
|
||||
var role = guild.AddCachedRole(data.Role);
|
||||
await RoleCreated.Raise(role).ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
await _gatewayLogger.Warning("GUILD_ROLE_CREATE referenced an unknown guild.");
|
||||
}
|
||||
break;
|
||||
case "GUILD_ROLE_UPDATE":
|
||||
{
|
||||
await _gatewayLogger.Debug($"Received Dispatch (GUILD_ROLE_UPDATE)").ConfigureAwait(false);
|
||||
|
||||
var data = (payload as JToken).ToObject<GuildRoleUpdateEvent>(_serializer);
|
||||
var guild = DataStore.GetGuild(data.GuildId);
|
||||
if (guild != null)
|
||||
{
|
||||
var role = guild.GetRole(data.Role.Id);
|
||||
if (role != null)
|
||||
{
|
||||
var before = _enablePreUpdateEvents ? role.Clone() : null;
|
||||
role.Update(data.Role, UpdateSource.WebSocket);
|
||||
await RoleUpdated.Raise(before, role).ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
await _gatewayLogger.Warning("GUILD_ROLE_UPDATE referenced an unknown role.");
|
||||
}
|
||||
else
|
||||
await _gatewayLogger.Warning("GUILD_ROLE_UPDATE referenced an unknown guild.");
|
||||
}
|
||||
break;
|
||||
case "GUILD_ROLE_DELETE":
|
||||
{
|
||||
await _gatewayLogger.Debug($"Received Dispatch (GUILD_ROLE_DELETE)").ConfigureAwait(false);
|
||||
|
||||
var data = (payload as JToken).ToObject<GuildRoleDeleteEvent>(_serializer);
|
||||
var guild = DataStore.GetGuild(data.GuildId);
|
||||
if (guild != null)
|
||||
{
|
||||
var role = guild.RemoveCachedRole(data.RoleId);
|
||||
if (role != null)
|
||||
await RoleDeleted.Raise(role).ConfigureAwait(false);
|
||||
else
|
||||
await _gatewayLogger.Warning("GUILD_ROLE_DELETE referenced an unknown role.");
|
||||
}
|
||||
else
|
||||
await _gatewayLogger.Warning("GUILD_ROLE_DELETE referenced an unknown guild.");
|
||||
}
|
||||
break;
|
||||
|
||||
//Bans
|
||||
case "GUILD_BAN_ADD":
|
||||
{
|
||||
await _gatewayLogger.Debug($"Received Dispatch (GUILD_BAN_ADD)").ConfigureAwait(false);
|
||||
|
||||
var data = (payload as JToken).ToObject<GuildBanEvent>(_serializer);
|
||||
var guild = DataStore.GetGuild(data.GuildId);
|
||||
if (guild != null)
|
||||
await UserBanned.Raise(new User(this, data));
|
||||
else
|
||||
await _gatewayLogger.Warning("GUILD_BAN_ADD referenced an unknown guild.");
|
||||
}
|
||||
break;
|
||||
case "GUILD_BAN_REMOVE":
|
||||
{
|
||||
await _gatewayLogger.Debug($"Received Dispatch (GUILD_BAN_REMOVE)").ConfigureAwait(false);
|
||||
|
||||
var data = (payload as JToken).ToObject<GuildBanEvent>(_serializer);
|
||||
var guild = DataStore.GetGuild(data.GuildId);
|
||||
if (guild != null)
|
||||
await UserUnbanned.Raise(new User(this, data));
|
||||
else
|
||||
await _gatewayLogger.Warning("GUILD_BAN_REMOVE referenced an unknown guild.");
|
||||
}
|
||||
break;
|
||||
|
||||
//Messages
|
||||
case "MESSAGE_CREATE":
|
||||
{
|
||||
await _gatewayLogger.Debug($"Received Dispatch (MESSAGE_CREATE)").ConfigureAwait(false);
|
||||
|
||||
var data = (payload as JToken).ToObject<API.Message>(_serializer);
|
||||
var channel = DataStore.GetChannel(data.ChannelId) as ICachedMessageChannel;
|
||||
if (channel != null)
|
||||
{
|
||||
var author = channel.GetCachedUser(data.Author.Id);
|
||||
|
||||
if (author != null)
|
||||
{
|
||||
var msg = channel.AddCachedMessage(author, data);
|
||||
await MessageReceived.Raise(msg).ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
await _gatewayLogger.Warning("MESSAGE_CREATE referenced an unknown user.");
|
||||
}
|
||||
else
|
||||
await _gatewayLogger.Warning("MESSAGE_CREATE referenced an unknown channel.");
|
||||
}
|
||||
break;
|
||||
case "MESSAGE_UPDATE":
|
||||
{
|
||||
await _gatewayLogger.Debug($"Received Dispatch (MESSAGE_UPDATE)").ConfigureAwait(false);
|
||||
|
||||
var data = (payload as JToken).ToObject<API.Message>(_serializer);
|
||||
var channel = DataStore.GetChannel(data.ChannelId) as ICachedMessageChannel;
|
||||
if (channel != null)
|
||||
{
|
||||
var msg = channel.GetCachedMessage(data.Id);
|
||||
var before = _enablePreUpdateEvents ? msg.Clone() : null;
|
||||
msg.Update(data, UpdateSource.WebSocket);
|
||||
await MessageUpdated.Raise(before, msg).ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
await _gatewayLogger.Warning("MESSAGE_UPDATE referenced an unknown channel.");
|
||||
}
|
||||
break;
|
||||
case "MESSAGE_DELETE":
|
||||
{
|
||||
await _gatewayLogger.Debug($"Received Dispatch (MESSAGE_DELETE)").ConfigureAwait(false);
|
||||
|
||||
var data = (payload as JToken).ToObject<API.Message>(_serializer);
|
||||
var channel = DataStore.GetChannel(data.ChannelId) as ICachedMessageChannel;
|
||||
if (channel != null)
|
||||
{
|
||||
var msg = channel.RemoveCachedMessage(data.Id);
|
||||
await MessageDeleted.Raise(msg).ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
await _gatewayLogger.Warning("MESSAGE_DELETE referenced an unknown channel.");
|
||||
}
|
||||
break;
|
||||
|
||||
//Statuses
|
||||
case "PRESENCE_UPDATE":
|
||||
{
|
||||
await _gatewayLogger.Debug($"Received Dispatch (PRESENCE_UPDATE)").ConfigureAwait(false);
|
||||
|
||||
var data = (payload as JToken).ToObject<API.Presence>(_serializer);
|
||||
if (data.GuildId == null)
|
||||
{
|
||||
var user = DataStore.GetUser(data.User.Id);
|
||||
if (user == null)
|
||||
user.Update(data, UpdateSource.WebSocket);
|
||||
}
|
||||
else
|
||||
{
|
||||
//Occurs when a user leaves a guild
|
||||
//await _gatewayLogger.Warning("VOICE_STATE_UPDATE referenced an unknown user.");
|
||||
var guild = DataStore.GetGuild(data.GuildId.Value);
|
||||
if (guild == null)
|
||||
{
|
||||
await _gatewayLogger.Warning("PRESENCE_UPDATE referenced an unknown guild.");
|
||||
break;
|
||||
}
|
||||
if (data.Status == UserStatus.Offline)
|
||||
guild.RemoveCachedPresence(data.User.Id);
|
||||
else
|
||||
guild.AddOrUpdateCachedPresence(data);
|
||||
}
|
||||
}
|
||||
else
|
||||
await _gatewayLogger.Warning("VOICE_STATE_UPDATE referenced an unknown guild.");
|
||||
}
|
||||
break;
|
||||
|
||||
//Settings
|
||||
case "USER_UPDATE":
|
||||
{
|
||||
var data = (payload as JToken).ToObject<SelfUser>(_serializer);
|
||||
if (data.Id == CurrentUser.Id)
|
||||
break;
|
||||
case "TYPING_START":
|
||||
{
|
||||
var before = _enablePreUpdateEvents ? CurrentUser.Clone() : null;
|
||||
CurrentUser.Update(data);
|
||||
await CurrentUserUpdated.Raise(before, CurrentUser).ConfigureAwait(false);
|
||||
await _gatewayLogger.Debug($"Received Dispatch (TYPING_START)").ConfigureAwait(false);
|
||||
|
||||
var data = (payload as JToken).ToObject<TypingStartEvent>(_serializer);
|
||||
var channel = DataStore.GetChannel(data.ChannelId) as ICachedMessageChannel;
|
||||
if (channel != null)
|
||||
{
|
||||
var user = channel.GetCachedUser(data.UserId);
|
||||
if (user != null)
|
||||
await UserIsTyping.Raise(channel, user).ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
await _gatewayLogger.Warning("TYPING_START referenced an unknown channel.").ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
break;*/
|
||||
break;
|
||||
|
||||
//Ignored
|
||||
case "USER_SETTINGS_UPDATE":
|
||||
case "MESSAGE_ACK": //TODO: Add (User only)
|
||||
case "GUILD_EMOJIS_UPDATE": //TODO: Add
|
||||
case "GUILD_INTEGRATIONS_UPDATE": //TODO: Add
|
||||
case "VOICE_SERVER_UPDATE": //TODO: Add
|
||||
case "RESUMED": //TODO: Add
|
||||
await _gatewayLogger.Debug($"Ignored Dispatch ({type})").ConfigureAwait(false);
|
||||
return;
|
||||
//Voice
|
||||
case "VOICE_STATE_UPDATE":
|
||||
{
|
||||
await _gatewayLogger.Debug($"Received Dispatch (VOICE_STATE_UPDATE)").ConfigureAwait(false);
|
||||
|
||||
//Others
|
||||
default:
|
||||
await _gatewayLogger.Warning($"Unknown Dispatch ({type})").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
await _gatewayLogger.Warning($"Unknown OpCode ({opCode})").ConfigureAwait(false);
|
||||
return;
|
||||
var data = (payload as JToken).ToObject<API.VoiceState>(_serializer);
|
||||
if (data.GuildId.HasValue)
|
||||
{
|
||||
var guild = DataStore.GetGuild(data.GuildId.Value);
|
||||
if (guild != null)
|
||||
{
|
||||
if (data.ChannelId == null)
|
||||
guild.RemoveCachedVoiceState(data.UserId);
|
||||
else
|
||||
guild.AddOrUpdateCachedVoiceState(data);
|
||||
|
||||
var user = guild.GetCachedUser(data.UserId);
|
||||
user.Update(data, UpdateSource.WebSocket);
|
||||
}
|
||||
else
|
||||
await _gatewayLogger.Warning("VOICE_STATE_UPDATE referenced an unknown guild.").ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
//Settings
|
||||
case "USER_UPDATE":
|
||||
{
|
||||
await _gatewayLogger.Debug($"Received Dispatch (USER_UPDATE)").ConfigureAwait(false);
|
||||
|
||||
var data = (payload as JToken).ToObject<API.User>(_serializer);
|
||||
if (data.Id == CurrentUser.Id)
|
||||
{
|
||||
var before = _enablePreUpdateEvents ? CurrentUser.Clone() : null;
|
||||
CurrentUser.Update(data, UpdateSource.WebSocket);
|
||||
await CurrentUserUpdated.Raise(before, CurrentUser).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
//Ignored
|
||||
case "USER_SETTINGS_UPDATE":
|
||||
case "MESSAGE_ACK": //TODO: Add (User only)
|
||||
case "GUILD_EMOJIS_UPDATE": //TODO: Add
|
||||
case "GUILD_INTEGRATIONS_UPDATE": //TODO: Add
|
||||
case "VOICE_SERVER_UPDATE": //TODO: Add
|
||||
case "RESUMED": //TODO: Add
|
||||
await _gatewayLogger.Debug($"Ignored Dispatch ({type})").ConfigureAwait(false);
|
||||
return;
|
||||
|
||||
//Others
|
||||
default:
|
||||
await _gatewayLogger.Warning($"Unknown Dispatch ({type})").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
await _gatewayLogger.Warning($"Unknown OpCode ({opCode})").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await _gatewayLogger.Error($"Error handling {opCode}{(type != null ? $" ({type})" : "")}", ex).ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
#if BENCHMARK
|
||||
}
|
||||
catch (Exception ex)
|
||||
finally
|
||||
{
|
||||
await _gatewayLogger.Error($"Error handling {opCode}{(type != null ? $" ({type})" : "")}", ex).ConfigureAwait(false);
|
||||
return;
|
||||
stopwatch.Stop();
|
||||
double millis = Math.Round(stopwatch.ElapsedTicks / (double)Stopwatch.Frequency * 1000.0, 2);
|
||||
await _benchmarkLogger.Debug($"{millis} ms").ConfigureAwait(false);
|
||||
}
|
||||
await _gatewayLogger.Debug($"Received {opCode}{(type != null ? $" ({type})" : "")}").ConfigureAwait(false);
|
||||
#endif
|
||||
}
|
||||
private async Task RunHeartbeat(int intervalMillis, CancellationToken cancelToken)
|
||||
{
|
||||
|
||||
@@ -57,6 +57,8 @@ namespace Discord
|
||||
{
|
||||
await Discord.ApiClient.DeleteGuildRole(Guild.Id, Id).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public Role Clone() => MemberwiseClone() as Role;
|
||||
|
||||
public override string ToString() => Name;
|
||||
private string DebuggerDisplay => $"{Name} ({Id})";
|
||||
|
||||
@@ -5,6 +5,7 @@ using System.Collections.Immutable;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Model = Discord.API.GuildMember;
|
||||
using VoiceStateModel = Discord.API.VoiceState;
|
||||
|
||||
namespace Discord
|
||||
{
|
||||
@@ -24,12 +25,12 @@ namespace Discord
|
||||
public string AvatarUrl => User.AvatarUrl;
|
||||
public DateTime CreatedAt => User.CreatedAt;
|
||||
public string Discriminator => User.Discriminator;
|
||||
public Game? Game => User.Game;
|
||||
public bool IsAttached => User.IsAttached;
|
||||
public bool IsBot => User.IsBot;
|
||||
public string Mention => User.Mention;
|
||||
public UserStatus Status => User.Status;
|
||||
public string Username => User.Username;
|
||||
public virtual UserStatus Status => User.Status;
|
||||
public virtual Game? Game => User.Game;
|
||||
|
||||
public DiscordClient Discord => Guild.Discord;
|
||||
|
||||
@@ -43,8 +44,10 @@ namespace Discord
|
||||
{
|
||||
if (source == UpdateSource.Rest && IsAttached) return;
|
||||
|
||||
IsDeaf = model.Deaf;
|
||||
IsMute = model.Mute;
|
||||
if (model.Deaf.HasValue)
|
||||
IsDeaf = model.Deaf.Value;
|
||||
if (model.Mute.HasValue)
|
||||
IsMute = model.Mute.Value;
|
||||
JoinedAt = model.JoinedAt.Value;
|
||||
Nickname = model.Nick;
|
||||
|
||||
@@ -56,6 +59,13 @@ namespace Discord
|
||||
|
||||
GuildPermissions = new GuildPermissions(Permissions.ResolveGuild(this));
|
||||
}
|
||||
public void Update(VoiceStateModel model, UpdateSource source)
|
||||
{
|
||||
if (source == UpdateSource.Rest && IsAttached) return;
|
||||
|
||||
IsDeaf = model.Deaf;
|
||||
IsMute = model.Mute;
|
||||
}
|
||||
|
||||
public async Task Update()
|
||||
{
|
||||
@@ -107,6 +117,10 @@ namespace Discord
|
||||
|
||||
IGuild IGuildUser.Guild => Guild;
|
||||
IReadOnlyCollection<IRole> IGuildUser.Roles => Roles;
|
||||
IVoiceChannel IGuildUser.VoiceChannel => null;
|
||||
bool IVoiceState.IsSelfDeafened => false;
|
||||
bool IVoiceState.IsSelfMuted => false;
|
||||
bool IVoiceState.IsSuppressed => false;
|
||||
IVoiceChannel IVoiceState.VoiceChannel => null;
|
||||
string IVoiceState.VoiceSessionId => null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ using Discord.API.Rest;
|
||||
namespace Discord
|
||||
{
|
||||
/// <summary> A Guild-User pairing. </summary>
|
||||
public interface IGuildUser : IUpdateable, IUser
|
||||
public interface IGuildUser : IUpdateable, IUser, IVoiceState
|
||||
{
|
||||
/// <summary> Returns true if the guild has deafened this user. </summary>
|
||||
bool IsDeaf { get; }
|
||||
@@ -23,8 +23,6 @@ namespace Discord
|
||||
IGuild Guild { get; }
|
||||
/// <summary> Returns a collection of the roles this user is a member of in this guild, including the guild's @everyone role. </summary>
|
||||
IReadOnlyCollection<IRole> Roles { get; }
|
||||
/// <summary> Gets the voice channel this user is currently in, if any. </summary>
|
||||
IVoiceChannel VoiceChannel { get; }
|
||||
|
||||
/// <summary> Gets the channel-level permissions granted to this user for a given channel. </summary>
|
||||
ChannelPermissions GetPermissions(IGuildChannel channel);
|
||||
|
||||
16
src/Discord.Net/Entities/Users/IVoiceState.cs
Normal file
16
src/Discord.Net/Entities/Users/IVoiceState.cs
Normal file
@@ -0,0 +1,16 @@
|
||||
namespace Discord
|
||||
{
|
||||
public interface IVoiceState
|
||||
{
|
||||
/// <summary> Returns true if this user has marked themselves as deafened. </summary>
|
||||
bool IsSelfDeafened { get; }
|
||||
/// <summary> Returns true if this user has marked themselves as muted. </summary>
|
||||
bool IsSelfMuted { get; }
|
||||
/// <summary> Returns true if the guild is temporarily blocking audio to/from this user. </summary>
|
||||
bool IsSuppressed { get; }
|
||||
/// <summary> Gets the voice channel this user is currently in, if any. </summary>
|
||||
IVoiceChannel VoiceChannel { get; }
|
||||
/// <summary> Gets the unique identifier for this user's voice session. </summary>
|
||||
string VoiceSessionId { get; }
|
||||
}
|
||||
}
|
||||
@@ -30,7 +30,7 @@ namespace Discord
|
||||
|
||||
var model = await Discord.ApiClient.GetCurrentUser().ConfigureAwait(false);
|
||||
Update(model, UpdateSource.Rest);
|
||||
}
|
||||
}
|
||||
public async Task Modify(Action<ModifyCurrentUserParams> func)
|
||||
{
|
||||
if (func != null) throw new NullReferenceException(nameof(func));
|
||||
|
||||
@@ -17,9 +17,9 @@ namespace Discord
|
||||
public override DiscordClient Discord { get; }
|
||||
|
||||
public string AvatarUrl => API.CDN.GetUserAvatarUrl(Id, _avatarId);
|
||||
public virtual Game? Game => null;
|
||||
public string Mention => MentionUtils.Mention(this, false);
|
||||
public string NicknameMention => MentionUtils.Mention(this, true);
|
||||
public virtual Game? Game => null;
|
||||
public virtual UserStatus Status => UserStatus.Unknown;
|
||||
|
||||
public User(DiscordClient discord, Model model)
|
||||
|
||||
@@ -13,7 +13,7 @@ namespace Discord
|
||||
|
||||
public new DiscordSocketClient Discord => base.Discord as DiscordSocketClient;
|
||||
public new CachedPublicUser Recipient => base.Recipient as CachedPublicUser;
|
||||
public IReadOnlyCollection<IUser> Members => ImmutableArray.Create<IUser>(Discord.CurrentUser, Recipient);
|
||||
public IReadOnlyCollection<ICachedUser> Members => ImmutableArray.Create<ICachedUser>(Discord.CurrentUser, Recipient);
|
||||
|
||||
public CachedDMChannel(DiscordSocketClient discord, CachedPublicUser recipient, Model model)
|
||||
: base(discord, recipient, model)
|
||||
@@ -21,11 +21,11 @@ namespace Discord
|
||||
_messages = new MessageCache(Discord, this);
|
||||
}
|
||||
|
||||
public override Task<IUser> GetUser(ulong id) => Task.FromResult(GetCachedUser(id));
|
||||
public override Task<IReadOnlyCollection<IUser>> GetUsers() => Task.FromResult(Members);
|
||||
public override Task<IUser> GetUser(ulong id) => Task.FromResult<IUser>(GetCachedUser(id));
|
||||
public override Task<IReadOnlyCollection<IUser>> GetUsers() => Task.FromResult<IReadOnlyCollection<IUser>>(Members);
|
||||
public override Task<IReadOnlyCollection<IUser>> GetUsers(int limit, int offset)
|
||||
=> Task.FromResult<IReadOnlyCollection<IUser>>(Members.Skip(offset).Take(limit).ToImmutableArray());
|
||||
public IUser GetCachedUser(ulong id)
|
||||
public ICachedUser GetCachedUser(ulong id)
|
||||
{
|
||||
var currentUser = Discord.CurrentUser;
|
||||
if (id == Recipient.Id)
|
||||
@@ -48,7 +48,7 @@ namespace Discord
|
||||
{
|
||||
return await _messages.Download(fromMessageId, dir, limit).ConfigureAwait(false);
|
||||
}
|
||||
public CachedMessage AddCachedMessage(IUser author, MessageModel model)
|
||||
public CachedMessage AddCachedMessage(ICachedUser author, MessageModel model)
|
||||
{
|
||||
var msg = new CachedMessage(this, author, model);
|
||||
_messages.Add(msg);
|
||||
|
||||
@@ -11,6 +11,8 @@ using ExtendedModel = Discord.API.Gateway.ExtendedGuild;
|
||||
using MemberModel = Discord.API.GuildMember;
|
||||
using Model = Discord.API.Guild;
|
||||
using PresenceModel = Discord.API.Presence;
|
||||
using RoleModel = Discord.API.Role;
|
||||
using VoiceStateModel = Discord.API.VoiceState;
|
||||
|
||||
namespace Discord
|
||||
{
|
||||
@@ -20,9 +22,11 @@ namespace Discord
|
||||
private ConcurrentHashSet<ulong> _channels;
|
||||
private ConcurrentDictionary<ulong, CachedGuildUser> _members;
|
||||
private ConcurrentDictionary<ulong, Presence> _presences;
|
||||
private int _userCount;
|
||||
private ConcurrentDictionary<ulong, VoiceState> _voiceStates;
|
||||
|
||||
public bool Available { get; private set; } //TODO: Add to IGuild
|
||||
public int MemberCount { get; private set; }
|
||||
public int DownloadedMemberCount { get; private set; }
|
||||
|
||||
public bool HasAllMembers => _downloaderPromise.Task.IsCompleted;
|
||||
public Task DownloaderPromise => _downloaderPromise.Task;
|
||||
@@ -32,9 +36,10 @@ namespace Discord
|
||||
public IReadOnlyCollection<ICachedGuildChannel> Channels => _channels.Select(x => GetCachedChannel(x)).ToReadOnlyCollection(_channels);
|
||||
public IReadOnlyCollection<CachedGuildUser> Members => _members.ToReadOnlyCollection();
|
||||
|
||||
public CachedGuild(DiscordSocketClient discord, Model model) : base(discord, model)
|
||||
public CachedGuild(DiscordSocketClient discord, ExtendedModel model, DataStore dataStore) : base(discord, model)
|
||||
{
|
||||
_downloaderPromise = new TaskCompletionSource<bool>();
|
||||
Update(model, UpdateSource.Creation, dataStore);
|
||||
}
|
||||
|
||||
public void Update(ExtendedModel model, UpdateSource source, DataStore dataStore)
|
||||
@@ -52,6 +57,8 @@ namespace Discord
|
||||
_presences = new ConcurrentDictionary<ulong, Presence>();
|
||||
if (_roles == null)
|
||||
_roles = new ConcurrentDictionary<ulong, Role>();
|
||||
if (_voiceStates == null)
|
||||
_voiceStates = new ConcurrentDictionary<ulong, VoiceState>();
|
||||
if (Emojis == null)
|
||||
Emojis = ImmutableArray.Create<Emoji>();
|
||||
if (Features == null)
|
||||
@@ -61,7 +68,7 @@ namespace Discord
|
||||
|
||||
base.Update(model as Model, source);
|
||||
|
||||
_userCount = model.MemberCount;
|
||||
MemberCount = model.MemberCount;
|
||||
|
||||
var channels = new ConcurrentHashSet<ulong>();
|
||||
if (model.Channels != null)
|
||||
@@ -75,7 +82,7 @@ namespace Discord
|
||||
if (model.Presences != null)
|
||||
{
|
||||
for (int i = 0; i < model.Presences.Length; i++)
|
||||
AddCachedPresence(model.Presences[i], presences);
|
||||
AddOrUpdateCachedPresence(model.Presences[i], presences);
|
||||
}
|
||||
_presences = presences;
|
||||
|
||||
@@ -85,10 +92,19 @@ namespace Discord
|
||||
for (int i = 0; i < model.Members.Length; i++)
|
||||
AddCachedUser(model.Members[i], members, dataStore);
|
||||
_downloaderPromise = new TaskCompletionSource<bool>();
|
||||
DownloadedMemberCount = model.Members.Length;
|
||||
if (!model.Large)
|
||||
_downloaderPromise.SetResult(true);
|
||||
}
|
||||
_members = members;
|
||||
|
||||
var voiceStates = new ConcurrentDictionary<ulong, VoiceState>();
|
||||
if (model.VoiceStates != null)
|
||||
{
|
||||
for (int i = 0; i < model.VoiceStates.Length; i++)
|
||||
AddOrUpdateCachedVoiceState(model.VoiceStates[i], _voiceStates);
|
||||
}
|
||||
_voiceStates = voiceStates;
|
||||
}
|
||||
|
||||
public override Task<IGuildChannel> GetChannel(ulong id) => Task.FromResult<IGuildChannel>(GetCachedChannel(id));
|
||||
@@ -108,7 +124,7 @@ namespace Discord
|
||||
(channels ?? _channels).TryRemove(id);
|
||||
}
|
||||
|
||||
public Presence AddCachedPresence(PresenceModel model, ConcurrentDictionary<ulong, Presence> presences = null)
|
||||
public Presence AddOrUpdateCachedPresence(PresenceModel model, ConcurrentDictionary<ulong, Presence> presences = null)
|
||||
{
|
||||
var game = model.Game != null ? new Game(model.Game) : (Game?)null;
|
||||
var presence = new Presence(model.Status, game);
|
||||
@@ -130,6 +146,42 @@ namespace Discord
|
||||
return null;
|
||||
}
|
||||
|
||||
public Role AddCachedRole(RoleModel model, ConcurrentDictionary<ulong, Role> roles = null)
|
||||
{
|
||||
var role = new Role(this, model);
|
||||
(roles ?? _roles)[model.Id] = role;
|
||||
return role;
|
||||
}
|
||||
public Role RemoveCachedRole(ulong id)
|
||||
{
|
||||
Role role;
|
||||
if (_roles.TryRemove(id, out role))
|
||||
return role;
|
||||
return null;
|
||||
}
|
||||
|
||||
public VoiceState AddOrUpdateCachedVoiceState(VoiceStateModel model, ConcurrentDictionary<ulong, VoiceState> voiceStates = null)
|
||||
{
|
||||
var voiceChannel = GetCachedChannel(model.ChannelId.Value) as CachedVoiceChannel;
|
||||
var voiceState = new VoiceState(voiceChannel, model.SessionId, model.SelfMute, model.SelfDeaf, model.Suppress);
|
||||
(voiceStates ?? _voiceStates)[model.UserId] = voiceState;
|
||||
return voiceState;
|
||||
}
|
||||
public VoiceState? GetCachedVoiceState(ulong id)
|
||||
{
|
||||
VoiceState voiceState;
|
||||
if (_voiceStates.TryGetValue(id, out voiceState))
|
||||
return voiceState;
|
||||
return null;
|
||||
}
|
||||
public VoiceState? RemoveCachedVoiceState(ulong id)
|
||||
{
|
||||
VoiceState voiceState;
|
||||
if (_voiceStates.TryRemove(id, out voiceState))
|
||||
return voiceState;
|
||||
return null;
|
||||
}
|
||||
|
||||
public override Task<IGuildUser> GetUser(ulong id) => Task.FromResult<IGuildUser>(GetCachedUser(id));
|
||||
public override Task<IGuildUser> GetCurrentUser()
|
||||
=> Task.FromResult<IGuildUser>(CurrentUser);
|
||||
@@ -140,10 +192,11 @@ namespace Discord
|
||||
=> Task.FromResult<IReadOnlyCollection<IGuildUser>>(Members.OrderBy(x => x.Id).Skip(offset).Take(limit).ToImmutableArray());
|
||||
public CachedGuildUser AddCachedUser(MemberModel model, ConcurrentDictionary<ulong, CachedGuildUser> members = null, DataStore dataStore = null)
|
||||
{
|
||||
var user = Discord.AddCachedUser(model.User);
|
||||
var user = Discord.GetOrAddCachedUser(model.User);
|
||||
var member = new CachedGuildUser(this, user, model);
|
||||
(members ?? _members)[user.Id] = member;
|
||||
user.AddRef();
|
||||
DownloadedMemberCount++;
|
||||
return member;
|
||||
}
|
||||
public CachedGuildUser GetCachedUser(ulong id)
|
||||
@@ -160,7 +213,6 @@ namespace Discord
|
||||
return member;
|
||||
return null;
|
||||
}
|
||||
|
||||
public async Task DownloadMembers()
|
||||
{
|
||||
if (!HasAllMembers)
|
||||
@@ -169,7 +221,7 @@ namespace Discord
|
||||
}
|
||||
public void CompleteDownloadMembers()
|
||||
{
|
||||
_downloaderPromise.SetResult(true);
|
||||
_downloaderPromise.TrySetResult(true);
|
||||
}
|
||||
|
||||
public CachedGuild Clone() => MemberwiseClone() as CachedGuild;
|
||||
|
||||
@@ -2,11 +2,21 @@
|
||||
|
||||
namespace Discord
|
||||
{
|
||||
internal class CachedGuildUser : GuildUser, ICachedEntity<ulong>
|
||||
internal class CachedGuildUser : GuildUser, ICachedUser
|
||||
{
|
||||
public VoiceChannel VoiceChannel { get; private set; }
|
||||
|
||||
public new DiscordSocketClient Discord => base.Discord as DiscordSocketClient;
|
||||
public new CachedGuild Guild => base.Guild as CachedGuild;
|
||||
public new CachedPublicUser User => base.User as CachedPublicUser;
|
||||
|
||||
public Presence? Presence => Guild.GetCachedPresence(Id);
|
||||
public override Game? Game => Presence?.Game;
|
||||
public override UserStatus Status => Presence?.Status ?? UserStatus.Offline;
|
||||
|
||||
public VoiceState? VoiceState => Guild.GetCachedVoiceState(Id);
|
||||
public bool IsSelfDeafened => VoiceState?.IsSelfDeafened ?? false;
|
||||
public bool IsSelfMuted => VoiceState?.IsSelfMuted ?? false;
|
||||
public bool IsSuppressed => VoiceState?.IsSuppressed ?? false;
|
||||
public CachedVoiceChannel VoiceChannel => VoiceState?.VoiceChannel;
|
||||
|
||||
public CachedGuildUser(CachedGuild guild, CachedPublicUser user, Model model)
|
||||
: base(guild, user, model)
|
||||
@@ -14,5 +24,6 @@ namespace Discord
|
||||
}
|
||||
|
||||
public CachedGuildUser Clone() => MemberwiseClone() as CachedGuildUser;
|
||||
ICachedUser ICachedUser.Clone() => Clone();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,15 +1,20 @@
|
||||
using ChannelModel = Discord.API.Channel;
|
||||
using Model = Discord.API.User;
|
||||
using PresenceModel = Discord.API.Presence;
|
||||
|
||||
namespace Discord
|
||||
{
|
||||
internal class CachedPublicUser : User, ICachedEntity<ulong>
|
||||
internal class CachedPublicUser : User, ICachedUser
|
||||
{
|
||||
private int _references;
|
||||
private Game? _game;
|
||||
private UserStatus _status;
|
||||
|
||||
public CachedDMChannel DMChannel { get; private set; }
|
||||
|
||||
public new DiscordSocketClient Discord => base.Discord as DiscordSocketClient;
|
||||
public override UserStatus Status => _status;
|
||||
public override Game? Game => _game;
|
||||
|
||||
public CachedPublicUser(DiscordSocketClient discord, Model model)
|
||||
: base(discord, model)
|
||||
@@ -39,6 +44,16 @@ namespace Discord
|
||||
}
|
||||
}
|
||||
|
||||
public void Update(PresenceModel model, UpdateSource source)
|
||||
{
|
||||
if (source == UpdateSource.Rest) return;
|
||||
|
||||
var game = model.Game != null ? new Game(model.Game) : (Game?)null;
|
||||
|
||||
_status = model.Status;
|
||||
_game = game;
|
||||
}
|
||||
|
||||
public void AddRef()
|
||||
{
|
||||
lock (this)
|
||||
@@ -54,5 +69,6 @@ namespace Discord
|
||||
}
|
||||
|
||||
public CachedPublicUser Clone() => MemberwiseClone() as CachedPublicUser;
|
||||
ICachedUser ICachedUser.Clone() => Clone();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace Discord
|
||||
{
|
||||
internal class CachedSelfUser : SelfUser, ICachedEntity<ulong>
|
||||
internal class CachedSelfUser : SelfUser, ICachedUser
|
||||
{
|
||||
public new DiscordSocketClient Discord => base.Discord as DiscordSocketClient;
|
||||
|
||||
@@ -12,5 +12,6 @@ namespace Discord
|
||||
}
|
||||
|
||||
public CachedSelfUser Clone() => MemberwiseClone() as CachedSelfUser;
|
||||
ICachedUser ICachedUser.Clone() => Clone();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ namespace Discord
|
||||
public new DiscordSocketClient Discord => base.Discord as DiscordSocketClient;
|
||||
public new CachedGuild Guild => base.Guild as CachedGuild;
|
||||
|
||||
public IReadOnlyCollection<IGuildUser> Members
|
||||
public IReadOnlyCollection<CachedGuildUser> Members
|
||||
=> Guild.Members.Where(x => Permissions.GetValue(Permissions.ResolveChannel(x, this, x.GuildPermissions.RawValue), ChannelPermission.ReadMessages)).ToImmutableArray();
|
||||
|
||||
public CachedTextChannel(CachedGuild guild, Model model)
|
||||
@@ -23,11 +23,11 @@ namespace Discord
|
||||
_messages = new MessageCache(Discord, this);
|
||||
}
|
||||
|
||||
public override Task<IGuildUser> GetUser(ulong id) => Task.FromResult(GetCachedUser(id));
|
||||
public override Task<IReadOnlyCollection<IGuildUser>> GetUsers() => Task.FromResult(Members);
|
||||
public override Task<IGuildUser> GetUser(ulong id) => Task.FromResult<IGuildUser>(GetCachedUser(id));
|
||||
public override Task<IReadOnlyCollection<IGuildUser>> GetUsers() => Task.FromResult<IReadOnlyCollection<IGuildUser>>(Members);
|
||||
public override Task<IReadOnlyCollection<IGuildUser>> GetUsers(int limit, int offset)
|
||||
=> Task.FromResult<IReadOnlyCollection<IGuildUser>>(Members.Skip(offset).Take(limit).ToImmutableArray());
|
||||
public IGuildUser GetCachedUser(ulong id)
|
||||
public CachedGuildUser GetCachedUser(ulong id)
|
||||
{
|
||||
var user = Guild.GetCachedUser(id);
|
||||
if (user != null && Permissions.GetValue(Permissions.ResolveChannel(user, this, user.GuildPermissions.RawValue), ChannelPermission.ReadMessages))
|
||||
@@ -48,7 +48,7 @@ namespace Discord
|
||||
return await _messages.Download(fromMessageId, dir, limit).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public CachedMessage AddCachedMessage(IUser author, MessageModel model)
|
||||
public CachedMessage AddCachedMessage(ICachedUser author, MessageModel model)
|
||||
{
|
||||
var msg = new CachedMessage(this, author, model);
|
||||
_messages.Add(msg);
|
||||
@@ -65,10 +65,10 @@ namespace Discord
|
||||
|
||||
public CachedTextChannel Clone() => MemberwiseClone() as CachedTextChannel;
|
||||
|
||||
IReadOnlyCollection<IUser> ICachedMessageChannel.Members => Members;
|
||||
IReadOnlyCollection<ICachedUser> ICachedMessageChannel.Members => Members;
|
||||
|
||||
IMessage IMessageChannel.GetCachedMessage(ulong id) => GetCachedMessage(id);
|
||||
IUser ICachedMessageChannel.GetCachedUser(ulong id) => GetCachedUser(id);
|
||||
ICachedUser ICachedMessageChannel.GetCachedUser(ulong id) => GetCachedUser(id);
|
||||
ICachedChannel ICachedChannel.Clone() => Clone();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,12 +5,12 @@ namespace Discord
|
||||
{
|
||||
internal interface ICachedMessageChannel : ICachedChannel, IMessageChannel
|
||||
{
|
||||
IReadOnlyCollection<IUser> Members { get; }
|
||||
IReadOnlyCollection<ICachedUser> Members { get; }
|
||||
|
||||
CachedMessage AddCachedMessage(IUser author, MessageModel model);
|
||||
CachedMessage AddCachedMessage(ICachedUser author, MessageModel model);
|
||||
new CachedMessage GetCachedMessage(ulong id);
|
||||
CachedMessage RemoveCachedMessage(ulong id);
|
||||
|
||||
IUser GetCachedUser(ulong id);
|
||||
ICachedUser GetCachedUser(ulong id);
|
||||
}
|
||||
}
|
||||
|
||||
7
src/Discord.Net/Entities/WebSocket/ICachedUser.cs
Normal file
7
src/Discord.Net/Entities/WebSocket/ICachedUser.cs
Normal file
@@ -0,0 +1,7 @@
|
||||
namespace Discord
|
||||
{
|
||||
internal interface ICachedUser : IUser, ICachedEntity<ulong>
|
||||
{
|
||||
ICachedUser Clone();
|
||||
}
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
/*using System;
|
||||
using Model = Discord.API.MemberVoiceState;
|
||||
|
||||
namespace Discord.WebSocket
|
||||
{
|
||||
internal class VoiceState : IVoiceState
|
||||
{
|
||||
[Flags]
|
||||
private enum VoiceStates : byte
|
||||
{
|
||||
None = 0x0,
|
||||
Muted = 0x01,
|
||||
Deafened = 0x02,
|
||||
Suppressed = 0x4,
|
||||
SelfMuted = 0x10,
|
||||
SelfDeafened = 0x20,
|
||||
}
|
||||
|
||||
private VoiceStates _voiceStates;
|
||||
|
||||
public Guild Guild { get; }
|
||||
public ulong UserId { get; }
|
||||
|
||||
/// <summary> Gets this user's current voice channel. </summary>
|
||||
public VoiceChannel VoiceChannel { get; set; }
|
||||
|
||||
/// <summary> Returns true if this user has marked themselves as muted. </summary>
|
||||
public bool IsSelfMuted => (_voiceStates & VoiceStates.SelfMuted) != 0;
|
||||
/// <summary> Returns true if this user has marked themselves as deafened. </summary>
|
||||
public bool IsSelfDeafened => (_voiceStates & VoiceStates.SelfDeafened) != 0;
|
||||
/// <summary> Returns true if the guild is blocking audio from this user. </summary>
|
||||
public bool IsMuted => (_voiceStates & VoiceStates.Muted) != 0;
|
||||
/// <summary> Returns true if the guild is blocking audio to this user. </summary>
|
||||
public bool IsDeafened => (_voiceStates & VoiceStates.Deafened) != 0;
|
||||
/// <summary> Returns true if the guild is temporarily blocking audio to/from this user. </summary>
|
||||
public bool IsSuppressed => (_voiceStates & VoiceStates.Suppressed) != 0;
|
||||
|
||||
public VoiceState(ulong userId, Guild guild)
|
||||
{
|
||||
UserId = userId;
|
||||
Guild = guild;
|
||||
}
|
||||
|
||||
private void Update(Model model, UpdateSource source)
|
||||
{
|
||||
if (model.IsMuted == true)
|
||||
_voiceStates |= VoiceStates.Muted;
|
||||
else if (model.IsMuted == false)
|
||||
_voiceStates &= ~VoiceStates.Muted;
|
||||
|
||||
if (model.IsDeafened == true)
|
||||
_voiceStates |= VoiceStates.Deafened;
|
||||
else if (model.IsDeafened == false)
|
||||
_voiceStates &= ~VoiceStates.Deafened;
|
||||
|
||||
if (model.IsSuppressed == true)
|
||||
_voiceStates |= VoiceStates.Suppressed;
|
||||
else if (model.IsSuppressed == false)
|
||||
_voiceStates &= ~VoiceStates.Suppressed;
|
||||
}
|
||||
}
|
||||
}*/
|
||||
42
src/Discord.Net/Entities/WebSocket/VoiceState.cs
Normal file
42
src/Discord.Net/Entities/WebSocket/VoiceState.cs
Normal file
@@ -0,0 +1,42 @@
|
||||
using System;
|
||||
|
||||
namespace Discord
|
||||
{
|
||||
internal struct VoiceState : IVoiceState
|
||||
{
|
||||
[Flags]
|
||||
private enum Flags : byte
|
||||
{
|
||||
None = 0x0,
|
||||
Suppressed = 0x1,
|
||||
SelfMuted = 0x2,
|
||||
SelfDeafened = 0x4,
|
||||
}
|
||||
|
||||
private readonly Flags _voiceStates;
|
||||
|
||||
public CachedVoiceChannel VoiceChannel { get; }
|
||||
public string VoiceSessionId { get; }
|
||||
|
||||
public bool IsSelfMuted => (_voiceStates & Flags.SelfMuted) != 0;
|
||||
public bool IsSelfDeafened => (_voiceStates & Flags.SelfDeafened) != 0;
|
||||
public bool IsSuppressed => (_voiceStates & Flags.Suppressed) != 0;
|
||||
|
||||
public VoiceState(CachedVoiceChannel voiceChannel, string sessionId, bool isSelfMuted, bool isSelfDeafened, bool isSuppressed)
|
||||
{
|
||||
VoiceChannel = voiceChannel;
|
||||
VoiceSessionId = sessionId;
|
||||
|
||||
Flags voiceStates = Flags.None;
|
||||
if (isSelfMuted)
|
||||
voiceStates |= Flags.SelfMuted;
|
||||
if (isSelfDeafened)
|
||||
voiceStates |= Flags.SelfDeafened;
|
||||
if (isSuppressed)
|
||||
voiceStates |= Flags.Suppressed;
|
||||
_voiceStates = voiceStates;
|
||||
}
|
||||
|
||||
IVoiceChannel IVoiceState.VoiceChannel => VoiceChannel;
|
||||
}
|
||||
}
|
||||
@@ -15,6 +15,7 @@
|
||||
|
||||
"buildOptions": {
|
||||
"allowUnsafe": true,
|
||||
"define": [ "BENCHMARK" ],
|
||||
"warningsAsErrors": false
|
||||
},
|
||||
|
||||
|
||||
Reference in New Issue
Block a user