From 28ea31ed27f6ca289feb9fb4df423073161f20d9 Mon Sep 17 00:00:00 2001
From: Suiram1701 <110390261+Suiram1701@users.noreply.github.com>
Date: Wed, 23 Apr 2025 21:31:28 +0200
Subject: [PATCH 01/12] Added a basic otel instrumentation project and the
classes for WebSocket
---
Discord.Net.sln | 15 ++++++++++++
.../Discord.Net.OpenTelemetry.csproj | 22 ++++++++++++++++++
src/Discord.Net.OpenTelemetry/Extensions.cs | 23 +++++++++++++++++++
.../Diagnostics/SocketActivitySource.cs | 20 ++++++++++++++++
.../Diagnostics/SocketMeter.cs | 16 +++++++++++++
5 files changed, 96 insertions(+)
create mode 100644 src/Discord.Net.OpenTelemetry/Discord.Net.OpenTelemetry.csproj
create mode 100644 src/Discord.Net.OpenTelemetry/Extensions.cs
create mode 100644 src/Discord.Net.WebSocket/Diagnostics/SocketActivitySource.cs
create mode 100644 src/Discord.Net.WebSocket/Diagnostics/SocketMeter.cs
diff --git a/Discord.Net.sln b/Discord.Net.sln
index 48c80d54fe..80b92bee7d 100644
--- a/Discord.Net.sln
+++ b/Discord.Net.sln
@@ -42,6 +42,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Samples", "Samples", "{BB59
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Discord.Net.BuildOverrides", "experiment\Discord.Net.BuildOverrides\Discord.Net.BuildOverrides.csproj", "{115F4921-B44D-4F69-996B-69796959C99D}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Discord.Net.OpenTelemetry", "src\Discord.Net.OpenTelemetry\Discord.Net.OpenTelemetry.csproj", "{88D77C2C-547E-41B8-8AFC-D1C089652767}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -244,6 +246,18 @@ Global
{115F4921-B44D-4F69-996B-69796959C99D}.Release|x64.Build.0 = Release|Any CPU
{115F4921-B44D-4F69-996B-69796959C99D}.Release|x86.ActiveCfg = Release|Any CPU
{115F4921-B44D-4F69-996B-69796959C99D}.Release|x86.Build.0 = Release|Any CPU
+ {88D77C2C-547E-41B8-8AFC-D1C089652767}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {88D77C2C-547E-41B8-8AFC-D1C089652767}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {88D77C2C-547E-41B8-8AFC-D1C089652767}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {88D77C2C-547E-41B8-8AFC-D1C089652767}.Debug|x64.Build.0 = Debug|Any CPU
+ {88D77C2C-547E-41B8-8AFC-D1C089652767}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {88D77C2C-547E-41B8-8AFC-D1C089652767}.Debug|x86.Build.0 = Debug|Any CPU
+ {88D77C2C-547E-41B8-8AFC-D1C089652767}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {88D77C2C-547E-41B8-8AFC-D1C089652767}.Release|Any CPU.Build.0 = Release|Any CPU
+ {88D77C2C-547E-41B8-8AFC-D1C089652767}.Release|x64.ActiveCfg = Release|Any CPU
+ {88D77C2C-547E-41B8-8AFC-D1C089652767}.Release|x64.Build.0 = Release|Any CPU
+ {88D77C2C-547E-41B8-8AFC-D1C089652767}.Release|x86.ActiveCfg = Release|Any CPU
+ {88D77C2C-547E-41B8-8AFC-D1C089652767}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -264,6 +278,7 @@ Global
{B61AAE66-15CC-40E4-873A-C23E697C3411} = {BB59D5B5-E7B0-4BF4-8F82-D14431B2799B}
{4A03840B-9EBE-47E3-89AB-E0914DF21AFB} = {BB59D5B5-E7B0-4BF4-8F82-D14431B2799B}
{115F4921-B44D-4F69-996B-69796959C99D} = {CC3D4B1C-9DE0-448B-8AE7-F3F1F3EC5C3A}
+ {88D77C2C-547E-41B8-8AFC-D1C089652767} = {CC3D4B1C-9DE0-448B-8AE7-F3F1F3EC5C3A}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {D2404771-EEC8-45F2-9D71-F3373F6C1495}
diff --git a/src/Discord.Net.OpenTelemetry/Discord.Net.OpenTelemetry.csproj b/src/Discord.Net.OpenTelemetry/Discord.Net.OpenTelemetry.csproj
new file mode 100644
index 0000000000..f417a0a045
--- /dev/null
+++ b/src/Discord.Net.OpenTelemetry/Discord.Net.OpenTelemetry.csproj
@@ -0,0 +1,22 @@
+
+
+
+
+ net9.0;net8.0;net6.0;net5.0;net461;netstandard2.0;netstandard2.1
+ Discord.OpenTelemetry
+ Discord.Net.OpenTelemetry
+ A Discord.Net extension adding support for the OpenTelemetry (otel) Sdk.
+ 5
+ True
+ true
+ snupkg
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Discord.Net.OpenTelemetry/Extensions.cs b/src/Discord.Net.OpenTelemetry/Extensions.cs
new file mode 100644
index 0000000000..26132a3d1c
--- /dev/null
+++ b/src/Discord.Net.OpenTelemetry/Extensions.cs
@@ -0,0 +1,23 @@
+using OpenTelemetry.Metrics;
+using OpenTelemetry.Trace;
+using System;
+
+namespace Discord.OpenTelemetry
+{
+ ///
+ /// An extension class which contains methods to added the Discord.Net OpenTelemetry instrumentations.
+ ///
+ public static class Extensions
+ {
+ public static TracerProviderBuilder AddDiscordNetInstrumentation(this TracerProviderBuilder builder)
+ {
+ throw new NotImplementedException();
+ }
+
+ public static MeterProviderBuilder AddDiscordNetInstrumentation(this MeterProviderBuilder builder)
+ {
+ throw new NotImplementedException();
+ }
+ }
+
+}
diff --git a/src/Discord.Net.WebSocket/Diagnostics/SocketActivitySource.cs b/src/Discord.Net.WebSocket/Diagnostics/SocketActivitySource.cs
new file mode 100644
index 0000000000..3f57a8563e
--- /dev/null
+++ b/src/Discord.Net.WebSocket/Diagnostics/SocketActivitySource.cs
@@ -0,0 +1,20 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Linq;
+using System.Reflection;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Discord.WebSocket.Diagnostics
+{
+ internal static class SocketActivitySource
+ {
+#if NET5_0_OR_GREATER
+ private static readonly ActivitySource _source = new(
+ name: "Discord.Net.WebSocket",
+ version: typeof(DiscordSocketClient).Assembly.GetName().Version.ToString());
+#else
+#endif
+ }
+}
diff --git a/src/Discord.Net.WebSocket/Diagnostics/SocketMeter.cs b/src/Discord.Net.WebSocket/Diagnostics/SocketMeter.cs
new file mode 100644
index 0000000000..bfddf8dfe6
--- /dev/null
+++ b/src/Discord.Net.WebSocket/Diagnostics/SocketMeter.cs
@@ -0,0 +1,16 @@
+#if NET6_0_OR_GREATER
+using System.Diagnostics.Metrics;
+#endif
+
+namespace Discord.WebSocket.Diagnostics
+{
+ internal static class SocketMeter
+ {
+#if NET6_0_OR_GREATER
+ private readonly static Meter _meter = new(
+ name: "Discord.Net.WebSocket",
+ version: typeof(DiscordSocketClient).Assembly.GetName().Version.ToString());
+#else
+#endif
+ }
+}
From 05f597f7a395f5b14c1e1ef66248d5102d5801d3 Mon Sep 17 00:00:00 2001
From: Suiram1701 <110390261+Suiram1701@users.noreply.github.com>
Date: Thu, 24 Apr 2025 20:06:08 +0200
Subject: [PATCH 02/12] Added the source names to the extensions and added otel
project to the Github actions workflow
---
.github/workflows/dotnet.yml | 1 +
src/Discord.Net.OpenTelemetry/Extensions.cs | 10 ++++++++--
2 files changed, 9 insertions(+), 2 deletions(-)
diff --git a/.github/workflows/dotnet.yml b/.github/workflows/dotnet.yml
index 65f0fe2e3e..e258b67279 100644
--- a/.github/workflows/dotnet.yml
+++ b/.github/workflows/dotnet.yml
@@ -65,6 +65,7 @@ jobs:
dotnet pack "src\Discord.Net.Commands\Discord.Net.Commands.csproj" --no-restore --no-build -v minimal -c Release -o ${{ env.ArtifactStagingDirectory }} /p:BuildNumber=${{ env.Suffix }} /p:IsTagBuild=${{ env.IsTagBuild }}
dotnet pack "src\Discord.Net.Webhook\Discord.Net.Webhook.csproj" --no-restore --no-build -v minimal -c Release -o ${{ env.ArtifactStagingDirectory }} /p:BuildNumber=${{ env.Suffix }} /p:IsTagBuild=${{ env.IsTagBuild }}
dotnet pack "src\Discord.Net.Interactions\Discord.Net.Interactions.csproj" --no-restore --no-build -v minimal -c Release -o ${{ env.ArtifactStagingDirectory }} /p:BuildNumber=${{ env.Suffix }} /p:IsTagBuild=${{ env.IsTagBuild }}
+ dotnet pack "src\Discord.Net.OpenTelemetry\Discord.Net.OpenTelemetry.csproj" --no-restore --no-build -v minimal -c Release -o ${{ env.ArtifactStagingDirectory }} /p:BuildNumber=${{ env.Suffix }} /p:IsTagBuild=${{ env.IsTagBuild }}
# dotnet pack "experiment\Discord.Net.BuildOverrides\Discord.Net.BuildOverrides.csproj" --no-restore --no-build -v minimal -c Release -o ${{ env.ArtifactStagingDirectory }} /p:BuildNumber=${{ env.Suffix }} /p:IsTagBuild=${{ env.IsTagBuild }}
- name: Publish Artifacts
diff --git a/src/Discord.Net.OpenTelemetry/Extensions.cs b/src/Discord.Net.OpenTelemetry/Extensions.cs
index 26132a3d1c..7ecfe403da 100644
--- a/src/Discord.Net.OpenTelemetry/Extensions.cs
+++ b/src/Discord.Net.OpenTelemetry/Extensions.cs
@@ -9,14 +9,20 @@ namespace Discord.OpenTelemetry
///
public static class Extensions
{
+ private const string SourceName = "Discord.Net.WebSocket";
+
public static TracerProviderBuilder AddDiscordNetInstrumentation(this TracerProviderBuilder builder)
{
- throw new NotImplementedException();
+ if (builder is null)
+ throw new ArgumentNullException(nameof(builder));
+ return builder.AddSource(SourceName);
}
public static MeterProviderBuilder AddDiscordNetInstrumentation(this MeterProviderBuilder builder)
{
- throw new NotImplementedException();
+ if (builder is null)
+ throw new ArgumentNullException(nameof(builder));
+ return builder.AddMeter(SourceName);
}
}
From a3f074c42ad282990dc52ec8d08e0bd816117382 Mon Sep 17 00:00:00 2001
From: Suiram1701 <110390261+Suiram1701@users.noreply.github.com>
Date: Thu, 24 Apr 2025 21:48:37 +0200
Subject: [PATCH 03/12] Added metrics and tracing for socket events
---
.../Diagnostics/Options.cs | 23 +
.../Diagnostics/SocketActivity.cs | 43 +
.../Diagnostics/SocketActivitySource.cs | 20 -
.../Diagnostics/SocketMeter.cs | 70 +-
.../DiscordSocketClient.EventHandling.cs | 3641 +++++++++--------
5 files changed, 1966 insertions(+), 1831 deletions(-)
create mode 100644 src/Discord.Net.WebSocket/Diagnostics/Options.cs
create mode 100644 src/Discord.Net.WebSocket/Diagnostics/SocketActivity.cs
delete mode 100644 src/Discord.Net.WebSocket/Diagnostics/SocketActivitySource.cs
diff --git a/src/Discord.Net.WebSocket/Diagnostics/Options.cs b/src/Discord.Net.WebSocket/Diagnostics/Options.cs
new file mode 100644
index 0000000000..060e6d307a
--- /dev/null
+++ b/src/Discord.Net.WebSocket/Diagnostics/Options.cs
@@ -0,0 +1,23 @@
+using Discord.API.Gateway;
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+
+namespace Discord.WebSocket.Diagnostics
+{
+ internal static class Options
+ {
+ internal const string SourceName = "Discord.Net.WebSocket";
+ internal static readonly string Version = typeof(Options).Assembly.GetName().Version.ToString();
+
+#if NET5_0_OR_GREATER
+ internal static IEnumerable> CreateTags(GatewayOpCode opCode, string type, DiscordSocketConfig config) => [
+ KeyValuePair.Create("client.gateway_host", config.GatewayHost ?? "/gateway"),
+ KeyValuePair.Create("client.shard_id", config.ShardId ?? 0),
+ KeyValuePair.Create("event.op_code", opCode),
+ KeyValuePair.Create("event.type", type)
+ ];
+#endif
+ }
+
+}
diff --git a/src/Discord.Net.WebSocket/Diagnostics/SocketActivity.cs b/src/Discord.Net.WebSocket/Diagnostics/SocketActivity.cs
new file mode 100644
index 0000000000..db1b2ee52b
--- /dev/null
+++ b/src/Discord.Net.WebSocket/Diagnostics/SocketActivity.cs
@@ -0,0 +1,43 @@
+using Discord.API.Gateway;
+using System;
+using System.Diagnostics;
+
+namespace Discord.WebSocket.Diagnostics
+{
+ internal static class SocketActivity
+ {
+#if NET5_0_OR_GREATER
+ private static readonly ActivitySource _source = new(Options.SourceName, Options.Version);
+
+ internal static Activity StartSocketDispatchActivity(string type, DiscordSocketConfig config)
+ {
+ return _source.StartActivity(
+ "dispatch socket event",
+ ActivityKind.Consumer,
+ null,
+ tags: Options.CreateTags(GatewayOpCode.Dispatch, type, config));
+ }
+
+ internal static void AddExceptionToActivity(this Activity activity, Exception ex)
+ {
+#if NET6_0_OR_GREATER
+ activity.SetStatus(ActivityStatusCode.Error, ex.Message);
+#endif
+#if NET9_0_OR_GREATER
+ activity.AddException(ex);
+#else
+ activity.AddEvent(new("exception", tags: new()
+ {
+ { "exception.type", ex.GetType().ToString() },
+ { "exception.message", ex.Message },
+ { "exception.stacktrace", ex.ToString() }
+ }));
+#endif
+ }
+#else
+ internal static IDisposable StartSocketDispatchActivity(string type, DiscordSocketConfig config) => null;
+
+ internal static void AddExceptionToActivity(this IDisposable activity, Exception ex) { }
+#endif
+ }
+}
diff --git a/src/Discord.Net.WebSocket/Diagnostics/SocketActivitySource.cs b/src/Discord.Net.WebSocket/Diagnostics/SocketActivitySource.cs
deleted file mode 100644
index 3f57a8563e..0000000000
--- a/src/Discord.Net.WebSocket/Diagnostics/SocketActivitySource.cs
+++ /dev/null
@@ -1,20 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Diagnostics;
-using System.Linq;
-using System.Reflection;
-using System.Text;
-using System.Threading.Tasks;
-
-namespace Discord.WebSocket.Diagnostics
-{
- internal static class SocketActivitySource
- {
-#if NET5_0_OR_GREATER
- private static readonly ActivitySource _source = new(
- name: "Discord.Net.WebSocket",
- version: typeof(DiscordSocketClient).Assembly.GetName().Version.ToString());
-#else
-#endif
- }
-}
diff --git a/src/Discord.Net.WebSocket/Diagnostics/SocketMeter.cs b/src/Discord.Net.WebSocket/Diagnostics/SocketMeter.cs
index bfddf8dfe6..0f8d9dbdda 100644
--- a/src/Discord.Net.WebSocket/Diagnostics/SocketMeter.cs
+++ b/src/Discord.Net.WebSocket/Diagnostics/SocketMeter.cs
@@ -1,3 +1,8 @@
+using Discord.API.Gateway;
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+
#if NET6_0_OR_GREATER
using System.Diagnostics.Metrics;
#endif
@@ -7,10 +12,69 @@ namespace Discord.WebSocket.Diagnostics
internal static class SocketMeter
{
#if NET6_0_OR_GREATER
- private readonly static Meter _meter = new(
- name: "Discord.Net.WebSocket",
- version: typeof(DiscordSocketClient).Assembly.GetName().Version.ToString());
+ private readonly static Meter _meter = new(Options.SourceName, Options.Version);
+
+ private readonly static Counter _socketEvents;
+ private readonly static Counter _socketEventExceptions;
+ private readonly static Counter _socketDispatches;
+ private readonly static Counter _socketDispatchesExceptions;
+ private readonly static Histogram _socketDispatchesDuration;
+
+ static SocketMeter()
+ {
+ _socketEvents = _meter.CreateCounter(
+ name: "socket.events_count",
+ unit: "Events",
+ description: "The total amount of events sent by the gateway since the application is running.");
+ _socketEventExceptions = _meter.CreateCounter(
+ name: "socket.events.exceptions_count",
+ unit: "Exceptions",
+ description: "The amount of exceptions occurred while event procession.");
+ _socketDispatches = _meter.CreateCounter(
+ name: "socket.dispatches_count",
+ unit: "Dispatches",
+ description: "The total amount of dispatches (like 'READY' or 'INTERACTION_CREATE') sent by the gateway since the application is running.");
+ _socketDispatchesExceptions = _meter.CreateCounter(
+ name: "socket.dispatches.exceptions_count",
+ unit: "Exceptions",
+ description: "The amount of exceptions occurred while handling dispatches (like 'READY' or 'INTERACTION_CREATE').");
+ _socketDispatchesDuration = _meter.CreateHistogram(
+ name: "socket.dispatches.duration",
+ unit: "Seconds",
+ description: "The handling duration of dispatches (like 'READY' or 'INTERACTION_CREATE') received from the gateway.");
+ }
+
+ internal static void RecordSocketEvent(GatewayOpCode opCode, string type, DiscordSocketConfig config)
+ {
+ _socketEvents.Add(1, [..Options.CreateTags(opCode, type, config)]);
+ }
+
+ internal static void RecordSocketEventException(Exception ex, GatewayOpCode opCode, string type, DiscordSocketConfig config)
+ {
+ TagList tags = [
+ .. Options.CreateTags(opCode, type, config),
+ KeyValuePair.Create("exception.type", ex.GetType().ToString()),
+ KeyValuePair.Create("exception.message", ex.Message),
+ KeyValuePair.Create("exception.stacktrace", ex.ToString()),
+ ];
+
+ _socketEventExceptions.Add(1, tags);
+ if (opCode == GatewayOpCode.Dispatch)
+ _socketDispatchesExceptions.Add(1, tags);
+ }
+
+ internal static void RecordSocketDispatch(TimeSpan duration, string type, DiscordSocketConfig config)
+ {
+ TagList tags = [..Options.CreateTags(GatewayOpCode.Dispatch, type, config)];
+ _socketDispatches.Add(1, tags);
+ _socketDispatchesDuration.Record(duration.TotalSeconds, tags);
+ }
#else
+ internal static void RecordSocketEvent(GatewayOpCode opCode, string type, DiscordSocketConfig config) { }
+
+ internal static void RecordSocketEventException(Exception ex, GatewayOpCode opCode, string type, DiscordSocketConfig config) { }
+
+ internal static void RecordSocketDispatch(TimeSpan duration, string type, DiscordSocketConfig config) { }
#endif
}
}
diff --git a/src/Discord.Net.WebSocket/DiscordSocketClient.EventHandling.cs b/src/Discord.Net.WebSocket/DiscordSocketClient.EventHandling.cs
index fdb57e7edd..d4c04ea986 100644
--- a/src/Discord.Net.WebSocket/DiscordSocketClient.EventHandling.cs
+++ b/src/Discord.Net.WebSocket/DiscordSocketClient.EventHandling.cs
@@ -2,14 +2,14 @@
using Discord.API.Gateway;
using Discord.Rest;
using Discord.Utils;
+using Discord.WebSocket.Diagnostics;
using Newtonsoft.Json.Linq;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Threading.Tasks;
using System;
-
-using GameModel = Discord.API.Game;
+using System.Diagnostics;
namespace Discord.WebSocket;
@@ -22,6 +22,7 @@ private async Task ProcessMessageAsync(GatewayOpCode opCode, int? seq, string ty
_lastSeq = seq.Value;
_lastMessageTime = Environment.TickCount;
+ SocketMeter.RecordSocketEvent(opCode, type, BaseConfig);
try
{
switch (opCode)
@@ -87,141 +88,165 @@ private async Task ProcessMessageAsync(GatewayOpCode opCode, int? seq, string ty
}
break;
case GatewayOpCode.Dispatch:
- switch (type)
+ var activity = SocketActivity.StartSocketDispatchActivity(type, BaseConfig);
+ var watch = activity is null ? Stopwatch.StartNew() : null;
+ try
{
- #region Connection
- case "READY":
+ switch (type)
{
- try
- {
- await _gatewayLogger.DebugAsync("Received Dispatch (READY)").ConfigureAwait(false);
-
- var data = (payload as JToken).ToObject(_serializer);
- var state = new ClientState(data.Guilds.Length, data.PrivateChannels.Length);
-
- var currentUser = SocketSelfUser.Create(this, state, data.User);
- Rest.CreateRestSelfUser(data.User);
- var activities = _activity.IsSpecified ? ImmutableList.Create(_activity.Value) : null;
- currentUser.Presence = new SocketPresence(Status, null, activities);
- ApiClient.CurrentUserId = currentUser.Id;
- ApiClient.CurrentApplicationId = data.Application?.Id;
- Rest.CurrentUser = RestSelfUser.Create(this, data.User);
- int unavailableGuilds = 0;
- for (int i = 0; i < data.Guilds.Length; i++)
- {
- var model = data.Guilds[i];
- var guild = AddGuild(model, state);
- if (!guild.IsAvailable)
- unavailableGuilds++;
- else
- await GuildAvailableAsync(guild).ConfigureAwait(false);
- }
- for (int i = 0; i < data.PrivateChannels.Length; i++)
- AddPrivateChannel(data.PrivateChannels[i], state);
-
- _sessionId = data.SessionId;
- ApiClient.ResumeGatewayUrl = data.ResumeGatewayUrl;
- _unavailableGuildCount = unavailableGuilds;
- CurrentUser = currentUser;
- _previousSessionUser = CurrentUser;
- State = state;
- }
- catch (Exception ex)
+ #region Connection
+ case "READY":
{
- _connection.CriticalError(new Exception("Processing READY failed", ex));
- return;
- }
-
- _lastGuildAvailableTime = Environment.TickCount;
- _guildDownloadTask = WaitForGuildsAsync(_connection.CancelToken, _gatewayLogger)
- .ContinueWith(async x =>
+ try
{
- if (x.IsFaulted)
+ await _gatewayLogger.DebugAsync("Received Dispatch (READY)").ConfigureAwait(false);
+
+ var data = (payload as JToken).ToObject(_serializer);
+ var state = new ClientState(data.Guilds.Length, data.PrivateChannels.Length);
+
+ var currentUser = SocketSelfUser.Create(this, state, data.User);
+ Rest.CreateRestSelfUser(data.User);
+ var activities = _activity.IsSpecified ? ImmutableList.Create(_activity.Value) : null;
+ currentUser.Presence = new SocketPresence(Status, null, activities);
+ ApiClient.CurrentUserId = currentUser.Id;
+ ApiClient.CurrentApplicationId = data.Application?.Id;
+ Rest.CurrentUser = RestSelfUser.Create(this, data.User);
+ int unavailableGuilds = 0;
+ for (int i = 0; i < data.Guilds.Length; i++)
{
- _connection.Error(x.Exception);
- return;
+ var model = data.Guilds[i];
+ var guild = AddGuild(model, state);
+ if (!guild.IsAvailable)
+ unavailableGuilds++;
+ else
+ await GuildAvailableAsync(guild).ConfigureAwait(false);
}
- else if (_connection.CancelToken.IsCancellationRequested)
- return;
+ for (int i = 0; i < data.PrivateChannels.Length; i++)
+ AddPrivateChannel(data.PrivateChannels[i], state);
- if (BaseConfig.AlwaysDownloadUsers)
- try
- {
- _ = DownloadUsersAsync(Guilds.Where(x => x.IsAvailable && !x.HasAllMembers));
- }
- catch (Exception ex)
+ _sessionId = data.SessionId;
+ ApiClient.ResumeGatewayUrl = data.ResumeGatewayUrl;
+ _unavailableGuildCount = unavailableGuilds;
+ CurrentUser = currentUser;
+ _previousSessionUser = CurrentUser;
+ State = state;
+ }
+ catch (Exception ex)
+ {
+ _connection.CriticalError(new Exception("Processing READY failed", ex));
+ return;
+ }
+
+ _lastGuildAvailableTime = Environment.TickCount;
+ _guildDownloadTask = WaitForGuildsAsync(_connection.CancelToken, _gatewayLogger)
+ .ContinueWith(async x =>
+ {
+ if (x.IsFaulted)
{
- await _gatewayLogger.WarningAsync(ex);
+ _connection.Error(x.Exception);
+ return;
}
+ else if (_connection.CancelToken.IsCancellationRequested)
+ return;
- await TimedInvokeAsync(_readyEvent, nameof(Ready)).ConfigureAwait(false);
- await _gatewayLogger.InfoAsync("Ready").ConfigureAwait(false);
- });
- _ = _connection.CompleteAsync();
- }
- break;
- case "RESUMED":
- {
- await _gatewayLogger.DebugAsync("Received Dispatch (RESUMED)").ConfigureAwait(false);
-
- _ = _connection.CompleteAsync();
+ if (BaseConfig.AlwaysDownloadUsers)
+ try
+ {
+ _ = DownloadUsersAsync(Guilds.Where(x => x.IsAvailable && !x.HasAllMembers));
+ }
+ catch (Exception ex)
+ {
+ await _gatewayLogger.WarningAsync(ex);
+ }
- //Notify the client that these guilds are available again
- foreach (var guild in State.Guilds)
- {
- if (guild.IsAvailable)
- await GuildAvailableAsync(guild).ConfigureAwait(false);
+ await TimedInvokeAsync(_readyEvent, nameof(Ready)).ConfigureAwait(false);
+ await _gatewayLogger.InfoAsync("Ready").ConfigureAwait(false);
+ });
+ _ = _connection.CompleteAsync();
}
+ break;
+ case "RESUMED":
+ {
+ await _gatewayLogger.DebugAsync("Received Dispatch (RESUMED)").ConfigureAwait(false);
- // Restore the previous sessions current user
- CurrentUser = _previousSessionUser;
+ _ = _connection.CompleteAsync();
- await _gatewayLogger.InfoAsync("Resumed previous session").ConfigureAwait(false);
- }
- break;
- #endregion
+ //Notify the client that these guilds are available again
+ foreach (var guild in State.Guilds)
+ {
+ if (guild.IsAvailable)
+ await GuildAvailableAsync(guild).ConfigureAwait(false);
+ }
- #region Guilds
- case "GUILD_CREATE":
- {
- var data = (payload as JToken).ToObject(_serializer);
+ // Restore the previous sessions current user
+ CurrentUser = _previousSessionUser;
+
+ await _gatewayLogger.InfoAsync("Resumed previous session").ConfigureAwait(false);
+ }
+ break;
+ #endregion
- if (data.Unavailable == false)
+ #region Guilds
+ case "GUILD_CREATE":
{
- type = "GUILD_AVAILABLE";
- _lastGuildAvailableTime = Environment.TickCount;
- await _gatewayLogger.DebugAsync("Received Dispatch (GUILD_AVAILABLE)").ConfigureAwait(false);
+ var data = (payload as JToken).ToObject(_serializer);
- var guild = State.GetGuild(data.Id);
- if (guild != null)
+ if (data.Unavailable == false)
{
- guild.Update(State, data);
+ type = "GUILD_AVAILABLE";
+ _lastGuildAvailableTime = Environment.TickCount;
+ await _gatewayLogger.DebugAsync("Received Dispatch (GUILD_AVAILABLE)").ConfigureAwait(false);
- if (_unavailableGuildCount != 0)
- _unavailableGuildCount--;
- await GuildAvailableAsync(guild).ConfigureAwait(false);
+ var guild = State.GetGuild(data.Id);
+ if (guild != null)
+ {
+ guild.Update(State, data);
- if (guild.DownloadedMemberCount >= guild.MemberCount && !guild.DownloaderPromise.IsCompleted)
+ if (_unavailableGuildCount != 0)
+ _unavailableGuildCount--;
+ await GuildAvailableAsync(guild).ConfigureAwait(false);
+
+ if (guild.DownloadedMemberCount >= guild.MemberCount && !guild.DownloaderPromise.IsCompleted)
+ {
+ guild.CompleteDownloadUsers();
+ await TimedInvokeAsync(_guildMembersDownloadedEvent, nameof(GuildMembersDownloaded), guild).ConfigureAwait(false);
+ }
+ }
+ else
{
- guild.CompleteDownloadUsers();
- await TimedInvokeAsync(_guildMembersDownloadedEvent, nameof(GuildMembersDownloaded), guild).ConfigureAwait(false);
+ await UnknownGuildAsync(type, data.Id).ConfigureAwait(false);
+ return;
}
}
else
{
- await UnknownGuildAsync(type, data.Id).ConfigureAwait(false);
- return;
+ await _gatewayLogger.DebugAsync("Received Dispatch (GUILD_CREATE)").ConfigureAwait(false);
+
+ var guild = AddGuild(data, State);
+ if (guild != null)
+ {
+ await TimedInvokeAsync(_joinedGuildEvent, nameof(JoinedGuild), guild).ConfigureAwait(false);
+ await GuildAvailableAsync(guild).ConfigureAwait(false);
+ }
+ else
+ {
+ await UnknownGuildAsync(type, data.Id).ConfigureAwait(false);
+ return;
+ }
}
}
- else
+ break;
+ case "GUILD_UPDATE":
{
- await _gatewayLogger.DebugAsync("Received Dispatch (GUILD_CREATE)").ConfigureAwait(false);
+ await _gatewayLogger.DebugAsync("Received Dispatch (GUILD_UPDATE)").ConfigureAwait(false);
- var guild = AddGuild(data, State);
+ var data = (payload as JToken).ToObject(_serializer);
+ var guild = State.GetGuild(data.Id);
if (guild != null)
{
- await TimedInvokeAsync(_joinedGuildEvent, nameof(JoinedGuild), guild).ConfigureAwait(false);
- await GuildAvailableAsync(guild).ConfigureAwait(false);
+ var before = guild.Clone();
+ guild.Update(State, data);
+ await TimedInvokeAsync(_guildUpdatedEvent, nameof(GuildUpdated), before, guild).ConfigureAwait(false);
}
else
{
@@ -229,2289 +254,2288 @@ private async Task ProcessMessageAsync(GatewayOpCode opCode, int? seq, string ty
return;
}
}
- }
- break;
- case "GUILD_UPDATE":
- {
- await _gatewayLogger.DebugAsync("Received Dispatch (GUILD_UPDATE)").ConfigureAwait(false);
-
- var data = (payload as JToken).ToObject(_serializer);
- var guild = State.GetGuild(data.Id);
- if (guild != null)
- {
- var before = guild.Clone();
- guild.Update(State, data);
- await TimedInvokeAsync(_guildUpdatedEvent, nameof(GuildUpdated), before, guild).ConfigureAwait(false);
- }
- else
- {
- await UnknownGuildAsync(type, data.Id).ConfigureAwait(false);
- return;
- }
- }
- break;
- case "GUILD_EMOJIS_UPDATE":
- {
- await _gatewayLogger.DebugAsync("Received Dispatch (GUILD_EMOJIS_UPDATE)").ConfigureAwait(false);
-
- var data = (payload as JToken).ToObject(_serializer);
- var guild = State.GetGuild(data.GuildId);
- if (guild != null)
- {
- var before = guild.Clone();
- guild.Update(State, data);
- await TimedInvokeAsync(_guildUpdatedEvent, nameof(GuildUpdated), before, guild).ConfigureAwait(false);
- }
- else
- {
- await UnknownGuildAsync(type, data.GuildId).ConfigureAwait(false);
- return;
- }
- }
- break;
- case "GUILD_SYNC":
- {
- await _gatewayLogger.DebugAsync("Ignored Dispatch (GUILD_SYNC)").ConfigureAwait(false);
- /*await _gatewayLogger.DebugAsync("Received Dispatch (GUILD_SYNC)").ConfigureAwait(false); //TODO remove? userbot related
- var data = (payload as JToken).ToObject(_serializer);
- var guild = State.GetGuild(data.Id);
- if (guild != null)
- {
- var before = guild.Clone();
- guild.Update(State, data);
- //This is treated as an extension of GUILD_AVAILABLE
- _unavailableGuildCount--;
- _lastGuildAvailableTime = Environment.TickCount;
- await GuildAvailableAsync(guild).ConfigureAwait(false);
- await TimedInvokeAsync(_guildUpdatedEvent, nameof(GuildUpdated), before, guild).ConfigureAwait(false);
- }
- else
- {
- await UnknownGuildAsync(type, data.Id).ConfigureAwait(false);
- return;
- }*/
- }
- break;
- case "GUILD_DELETE":
- {
- var data = (payload as JToken).ToObject(_serializer);
- if (data.Unavailable == true)
+ break;
+ case "GUILD_EMOJIS_UPDATE":
{
- type = "GUILD_UNAVAILABLE";
- await _gatewayLogger.DebugAsync("Received Dispatch (GUILD_UNAVAILABLE)").ConfigureAwait(false);
+ await _gatewayLogger.DebugAsync("Received Dispatch (GUILD_EMOJIS_UPDATE)").ConfigureAwait(false);
- var guild = State.GetGuild(data.Id);
+ var data = (payload as JToken).ToObject(_serializer);
+ var guild = State.GetGuild(data.GuildId);
if (guild != null)
{
- await GuildUnavailableAsync(guild).ConfigureAwait(false);
- _unavailableGuildCount++;
+ var before = guild.Clone();
+ guild.Update(State, data);
+ await TimedInvokeAsync(_guildUpdatedEvent, nameof(GuildUpdated), before, guild).ConfigureAwait(false);
}
else
{
- await UnknownGuildAsync(type, data.Id).ConfigureAwait(false);
+ await UnknownGuildAsync(type, data.GuildId).ConfigureAwait(false);
return;
}
}
- else
+ break;
+ case "GUILD_SYNC":
{
- await _gatewayLogger.DebugAsync("Received Dispatch (GUILD_DELETE)").ConfigureAwait(false);
-
- var guild = RemoveGuild(data.Id);
+ await _gatewayLogger.DebugAsync("Ignored Dispatch (GUILD_SYNC)").ConfigureAwait(false);
+ /*await _gatewayLogger.DebugAsync("Received Dispatch (GUILD_SYNC)").ConfigureAwait(false); //TODO remove? userbot related
+ var data = (payload as JToken).ToObject(_serializer);
+ var guild = State.GetGuild(data.Id);
if (guild != null)
{
- await GuildUnavailableAsync(guild).ConfigureAwait(false);
- await TimedInvokeAsync(_leftGuildEvent, nameof(LeftGuild), guild).ConfigureAwait(false);
- (guild as IDisposable).Dispose();
+ var before = guild.Clone();
+ guild.Update(State, data);
+ //This is treated as an extension of GUILD_AVAILABLE
+ _unavailableGuildCount--;
+ _lastGuildAvailableTime = Environment.TickCount;
+ await GuildAvailableAsync(guild).ConfigureAwait(false);
+ await TimedInvokeAsync(_guildUpdatedEvent, nameof(GuildUpdated), before, guild).ConfigureAwait(false);
}
else
{
await UnknownGuildAsync(type, data.Id).ConfigureAwait(false);
return;
- }
+ }*/
}
- }
- break;
- case "GUILD_STICKERS_UPDATE":
- {
- await _gatewayLogger.DebugAsync($"Received Dispatch (GUILD_STICKERS_UPDATE)").ConfigureAwait(false);
-
- var data = (payload as JToken).ToObject(_serializer);
-
- var guild = State.GetGuild(data.GuildId);
-
- if (guild == null)
- {
- await UnknownGuildAsync(type, data.GuildId).ConfigureAwait(false);
- return;
- }
-
- var newStickers = data.Stickers.Where(x => !guild.Stickers.Any(y => y.Id == x.Id));
- var deletedStickers = guild.Stickers.Where(x => !data.Stickers.Any(y => y.Id == x.Id));
- var updatedStickers = data.Stickers.Select(x =>
+ break;
+ case "GUILD_DELETE":
{
- var s = guild.Stickers.FirstOrDefault(y => y.Id == x.Id);
- if (s == null)
- return null;
-
- var e = s.Equals(x);
- if (!e)
+ var data = (payload as JToken).ToObject(_serializer);
+ if (data.Unavailable == true)
{
- return (s, x) as (SocketCustomSticker Entity, API.Sticker Model)?;
+ type = "GUILD_UNAVAILABLE";
+ await _gatewayLogger.DebugAsync("Received Dispatch (GUILD_UNAVAILABLE)").ConfigureAwait(false);
+
+ var guild = State.GetGuild(data.Id);
+ if (guild != null)
+ {
+ await GuildUnavailableAsync(guild).ConfigureAwait(false);
+ _unavailableGuildCount++;
+ }
+ else
+ {
+ await UnknownGuildAsync(type, data.Id).ConfigureAwait(false);
+ return;
+ }
}
else
{
- return null;
- }
- }).Where(x => x.HasValue).Select(x => x.Value).ToArray();
+ await _gatewayLogger.DebugAsync("Received Dispatch (GUILD_DELETE)").ConfigureAwait(false);
- foreach (var model in newStickers)
- {
- var entity = guild.AddSticker(model);
- await TimedInvokeAsync(_guildStickerCreated, nameof(GuildStickerCreated), entity);
- }
- foreach (var sticker in deletedStickers)
- {
- var entity = guild.RemoveSticker(sticker.Id);
- await TimedInvokeAsync(_guildStickerDeleted, nameof(GuildStickerDeleted), entity);
+ var guild = RemoveGuild(data.Id);
+ if (guild != null)
+ {
+ await GuildUnavailableAsync(guild).ConfigureAwait(false);
+ await TimedInvokeAsync(_leftGuildEvent, nameof(LeftGuild), guild).ConfigureAwait(false);
+ (guild as IDisposable).Dispose();
+ }
+ else
+ {
+ await UnknownGuildAsync(type, data.Id).ConfigureAwait(false);
+ return;
+ }
+ }
}
- foreach (var entityModelPair in updatedStickers)
+ break;
+ case "GUILD_STICKERS_UPDATE":
{
- var before = entityModelPair.Entity.Clone();
+ await _gatewayLogger.DebugAsync($"Received Dispatch (GUILD_STICKERS_UPDATE)").ConfigureAwait(false);
- entityModelPair.Entity.Update(entityModelPair.Model);
+ var data = (payload as JToken).ToObject(_serializer);
- await TimedInvokeAsync(_guildStickerUpdated, nameof(GuildStickerUpdated), before, entityModelPair.Entity);
- }
- }
- break;
- #endregion
+ var guild = State.GetGuild(data.GuildId);
- #region Channels
- case "CHANNEL_CREATE":
- {
- await _gatewayLogger.DebugAsync("Received Dispatch (CHANNEL_CREATE)").ConfigureAwait(false);
+ if (guild == null)
+ {
+ await UnknownGuildAsync(type, data.GuildId).ConfigureAwait(false);
+ return;
+ }
- var data = (payload as JToken).ToObject(_serializer);
- SocketChannel channel = null;
- if (data.GuildId.IsSpecified)
- {
- var guild = State.GetGuild(data.GuildId.Value);
- if (guild != null)
+ var newStickers = data.Stickers.Where(x => !guild.Stickers.Any(y => y.Id == x.Id));
+ var deletedStickers = guild.Stickers.Where(x => !data.Stickers.Any(y => y.Id == x.Id));
+ var updatedStickers = data.Stickers.Select(x =>
{
- channel = guild.AddChannel(State, data);
+ var s = guild.Stickers.FirstOrDefault(y => y.Id == x.Id);
+ if (s == null)
+ return null;
- if (!guild.IsSynced)
+ var e = s.Equals(x);
+ if (!e)
{
- await UnsyncedGuildAsync(type, guild.Id).ConfigureAwait(false);
- return;
+ return (s, x) as (SocketCustomSticker Entity, API.Sticker Model)?;
+ }
+ else
+ {
+ return null;
}
+ }).Where(x => x.HasValue).Select(x => x.Value).ToArray();
+
+ foreach (var model in newStickers)
+ {
+ var entity = guild.AddSticker(model);
+ await TimedInvokeAsync(_guildStickerCreated, nameof(GuildStickerCreated), entity);
}
- else
+ foreach (var sticker in deletedStickers)
{
- await UnknownGuildAsync(type, data.GuildId.Value).ConfigureAwait(false);
- return;
+ var entity = guild.RemoveSticker(sticker.Id);
+ await TimedInvokeAsync(_guildStickerDeleted, nameof(GuildStickerDeleted), entity);
}
- }
- else
- {
- channel = State.GetChannel(data.Id);
- if (channel != null)
- return; //Discord may send duplicate CHANNEL_CREATEs for DMs
- channel = AddPrivateChannel(data, State) as SocketChannel;
- }
+ foreach (var entityModelPair in updatedStickers)
+ {
+ var before = entityModelPair.Entity.Clone();
- if (channel != null)
- await TimedInvokeAsync(_channelCreatedEvent, nameof(ChannelCreated), channel).ConfigureAwait(false);
- }
- break;
- case "CHANNEL_UPDATE":
- {
- await _gatewayLogger.DebugAsync("Received Dispatch (CHANNEL_UPDATE)").ConfigureAwait(false);
+ entityModelPair.Entity.Update(entityModelPair.Model);
+
+ await TimedInvokeAsync(_guildStickerUpdated, nameof(GuildStickerUpdated), before, entityModelPair.Entity);
+ }
+ }
+ break;
+ #endregion
- var data = (payload as JToken).ToObject(_serializer);
- var channel = State.GetChannel(data.Id);
- if (channel != null)
+ #region Channels
+ case "CHANNEL_CREATE":
{
- var before = channel.Clone();
- channel.Update(State, data);
+ await _gatewayLogger.DebugAsync("Received Dispatch (CHANNEL_CREATE)").ConfigureAwait(false);
- var guild = (channel as SocketGuildChannel)?.Guild;
- if (!(guild?.IsSynced ?? true))
+ var data = (payload as JToken).ToObject(_serializer);
+ SocketChannel channel = null;
+ if (data.GuildId.IsSpecified)
{
- await UnsyncedGuildAsync(type, guild.Id).ConfigureAwait(false);
- return;
+ var guild = State.GetGuild(data.GuildId.Value);
+ if (guild != null)
+ {
+ channel = guild.AddChannel(State, data);
+
+ if (!guild.IsSynced)
+ {
+ await UnsyncedGuildAsync(type, guild.Id).ConfigureAwait(false);
+ return;
+ }
+ }
+ else
+ {
+ await UnknownGuildAsync(type, data.GuildId.Value).ConfigureAwait(false);
+ return;
+ }
+ }
+ else
+ {
+ channel = State.GetChannel(data.Id);
+ if (channel != null)
+ return; //Discord may send duplicate CHANNEL_CREATEs for DMs
+ channel = AddPrivateChannel(data, State) as SocketChannel;
}
- await TimedInvokeAsync(_channelUpdatedEvent, nameof(ChannelUpdated), before, channel).ConfigureAwait(false);
+ if (channel != null)
+ await TimedInvokeAsync(_channelCreatedEvent, nameof(ChannelCreated), channel).ConfigureAwait(false);
}
- else
+ break;
+ case "CHANNEL_UPDATE":
{
- await UnknownChannelAsync(type, data.Id).ConfigureAwait(false);
- return;
- }
- }
- break;
- case "CHANNEL_DELETE":
- {
- await _gatewayLogger.DebugAsync("Received Dispatch (CHANNEL_DELETE)").ConfigureAwait(false);
+ await _gatewayLogger.DebugAsync("Received Dispatch (CHANNEL_UPDATE)").ConfigureAwait(false);
- SocketChannel channel = null;
- var data = (payload as JToken).ToObject(_serializer);
- if (data.GuildId.IsSpecified)
- {
- var guild = State.GetGuild(data.GuildId.Value);
- if (guild != null)
+ var data = (payload as JToken).ToObject(_serializer);
+ var channel = State.GetChannel(data.Id);
+ if (channel != null)
{
- channel = guild.RemoveChannel(State, data.Id);
+ var before = channel.Clone();
+ channel.Update(State, data);
- if (!guild.IsSynced)
+ var guild = (channel as SocketGuildChannel)?.Guild;
+ if (!(guild?.IsSynced ?? true))
{
await UnsyncedGuildAsync(type, guild.Id).ConfigureAwait(false);
return;
}
+
+ await TimedInvokeAsync(_channelUpdatedEvent, nameof(ChannelUpdated), before, channel).ConfigureAwait(false);
}
else
{
- await UnknownGuildAsync(type, data.GuildId.Value).ConfigureAwait(false);
+ await UnknownChannelAsync(type, data.Id).ConfigureAwait(false);
return;
}
}
- else
- channel = RemovePrivateChannel(data.Id) as SocketChannel;
-
- if (channel != null)
- await TimedInvokeAsync(_channelDestroyedEvent, nameof(ChannelDestroyed), channel).ConfigureAwait(false);
- else
+ break;
+ case "CHANNEL_DELETE":
{
- await UnknownChannelAsync(type, data.Id, data.GuildId.GetValueOrDefault(0)).ConfigureAwait(false);
- return;
- }
- }
- break;
- #endregion
+ await _gatewayLogger.DebugAsync("Received Dispatch (CHANNEL_DELETE)").ConfigureAwait(false);
- #region Members
- case "GUILD_MEMBER_ADD":
- {
- await _gatewayLogger.DebugAsync("Received Dispatch (GUILD_MEMBER_ADD)").ConfigureAwait(false);
+ SocketChannel channel = null;
+ var data = (payload as JToken).ToObject(_serializer);
+ if (data.GuildId.IsSpecified)
+ {
+ var guild = State.GetGuild(data.GuildId.Value);
+ if (guild != null)
+ {
+ channel = guild.RemoveChannel(State, data.Id);
- var data = (payload as JToken).ToObject(_serializer);
- var guild = State.GetGuild(data.GuildId);
- if (guild != null)
- {
- var user = guild.AddOrUpdateUser(data);
- guild.MemberCount++;
+ if (!guild.IsSynced)
+ {
+ await UnsyncedGuildAsync(type, guild.Id).ConfigureAwait(false);
+ return;
+ }
+ }
+ else
+ {
+ await UnknownGuildAsync(type, data.GuildId.Value).ConfigureAwait(false);
+ return;
+ }
+ }
+ else
+ channel = RemovePrivateChannel(data.Id) as SocketChannel;
- if (!guild.IsSynced)
+ if (channel != null)
+ await TimedInvokeAsync(_channelDestroyedEvent, nameof(ChannelDestroyed), channel).ConfigureAwait(false);
+ else
{
- await UnsyncedGuildAsync(type, guild.Id).ConfigureAwait(false);
+ await UnknownChannelAsync(type, data.Id, data.GuildId.GetValueOrDefault(0)).ConfigureAwait(false);
return;
}
-
- await TimedInvokeAsync(_userJoinedEvent, nameof(UserJoined), user).ConfigureAwait(false);
}
- else
- {
- await UnknownGuildAsync(type, data.GuildId).ConfigureAwait(false);
- return;
- }
- }
- break;
- case "GUILD_MEMBER_UPDATE":
- {
- await _gatewayLogger.DebugAsync("Received Dispatch (GUILD_MEMBER_UPDATE)").ConfigureAwait(false);
+ break;
+ #endregion
- var data = (payload as JToken).ToObject(_serializer);
- var guild = State.GetGuild(data.GuildId);
- if (guild != null)
+ #region Members
+ case "GUILD_MEMBER_ADD":
{
- var user = guild.GetUser(data.User.Id);
+ await _gatewayLogger.DebugAsync("Received Dispatch (GUILD_MEMBER_ADD)").ConfigureAwait(false);
- if (!guild.IsSynced)
+ var data = (payload as JToken).ToObject(_serializer);
+ var guild = State.GetGuild(data.GuildId);
+ if (guild != null)
{
- await UnsyncedGuildAsync(type, guild.Id).ConfigureAwait(false);
- return;
- }
+ var user = guild.AddOrUpdateUser(data);
+ guild.MemberCount++;
- if (user != null)
- {
- var before = user.Clone();
- if (user.GlobalUser.Update(State, data.User))
+ if (!guild.IsSynced)
{
- //Global data was updated, trigger UserUpdated
- await TimedInvokeAsync(_userUpdatedEvent, nameof(UserUpdated), before.GlobalUser, user).ConfigureAwait(false);
+ await UnsyncedGuildAsync(type, guild.Id).ConfigureAwait(false);
+ return;
}
- user.Update(State, data);
-
- var cacheableBefore = new Cacheable(before, user.Id, true, () => Task.FromResult(null));
- await TimedInvokeAsync(_guildMemberUpdatedEvent, nameof(GuildMemberUpdated), cacheableBefore, user).ConfigureAwait(false);
+ await TimedInvokeAsync(_userJoinedEvent, nameof(UserJoined), user).ConfigureAwait(false);
}
else
{
- user = guild.AddOrUpdateUser(data);
- var cacheableBefore = new Cacheable(null, user.Id, false, () => Task.FromResult(null));
- await TimedInvokeAsync(_guildMemberUpdatedEvent, nameof(GuildMemberUpdated), cacheableBefore, user).ConfigureAwait(false);
+ await UnknownGuildAsync(type, data.GuildId).ConfigureAwait(false);
+ return;
}
}
- else
+ break;
+ case "GUILD_MEMBER_UPDATE":
{
- await UnknownGuildAsync(type, data.GuildId).ConfigureAwait(false);
- return;
- }
- }
- break;
- case "GUILD_MEMBER_REMOVE":
- {
- await _gatewayLogger.DebugAsync("Received Dispatch (GUILD_MEMBER_REMOVE)").ConfigureAwait(false);
+ await _gatewayLogger.DebugAsync("Received Dispatch (GUILD_MEMBER_UPDATE)").ConfigureAwait(false);
- var data = (payload as JToken).ToObject(_serializer);
- var guild = State.GetGuild(data.GuildId);
- if (guild != null)
- {
- SocketUser user = guild.RemoveUser(data.User.Id);
- guild.MemberCount--;
-
- if (!guild.IsSynced)
+ var data = (payload as JToken).ToObject(_serializer);
+ var guild = State.GetGuild(data.GuildId);
+ if (guild != null)
{
- await UnsyncedGuildAsync(type, guild.Id).ConfigureAwait(false);
- return;
- }
-
- user ??= State.GetUser(data.User.Id);
+ var user = guild.GetUser(data.User.Id);
- if (user != null)
- user.Update(State, data.User);
- else
- user = State.GetOrAddUser(data.User.Id, (x) => SocketGlobalUser.Create(this, State, data.User));
+ if (!guild.IsSynced)
+ {
+ await UnsyncedGuildAsync(type, guild.Id).ConfigureAwait(false);
+ return;
+ }
- await TimedInvokeAsync(_userLeftEvent, nameof(UserLeft), guild, user).ConfigureAwait(false);
- }
- else
- {
- await UnknownGuildAsync(type, data.GuildId).ConfigureAwait(false);
- return;
- }
- }
- break;
- case "GUILD_MEMBERS_CHUNK":
- {
- await _gatewayLogger.DebugAsync("Received Dispatch (GUILD_MEMBERS_CHUNK)").ConfigureAwait(false);
+ if (user != null)
+ {
+ var before = user.Clone();
+ if (user.GlobalUser.Update(State, data.User))
+ {
+ //Global data was updated, trigger UserUpdated
+ await TimedInvokeAsync(_userUpdatedEvent, nameof(UserUpdated), before.GlobalUser, user).ConfigureAwait(false);
+ }
- var data = (payload as JToken).ToObject(_serializer);
- var guild = State.GetGuild(data.GuildId);
- if (guild != null)
- {
- foreach (var memberModel in data.Members)
- guild.AddOrUpdateUser(memberModel);
+ user.Update(State, data);
- if (guild.DownloadedMemberCount >= guild.MemberCount && !guild.DownloaderPromise.IsCompleted)
+ var cacheableBefore = new Cacheable(before, user.Id, true, () => Task.FromResult(null));
+ await TimedInvokeAsync(_guildMemberUpdatedEvent, nameof(GuildMemberUpdated), cacheableBefore, user).ConfigureAwait(false);
+ }
+ else
+ {
+ user = guild.AddOrUpdateUser(data);
+ var cacheableBefore = new Cacheable(null, user.Id, false, () => Task.FromResult(null));
+ await TimedInvokeAsync(_guildMemberUpdatedEvent, nameof(GuildMemberUpdated), cacheableBefore, user).ConfigureAwait(false);
+ }
+ }
+ else
{
- guild.CompleteDownloadUsers();
- await TimedInvokeAsync(_guildMembersDownloadedEvent, nameof(GuildMembersDownloaded), guild).ConfigureAwait(false);
+ await UnknownGuildAsync(type, data.GuildId).ConfigureAwait(false);
+ return;
}
}
- else
- {
- await UnknownGuildAsync(type, data.GuildId).ConfigureAwait(false);
- return;
- }
- }
- break;
- case "GUILD_JOIN_REQUEST_DELETE":
- {
- await _gatewayLogger.DebugAsync("Received Dispatch (GUILD_JOIN_REQUEST_DELETE)").ConfigureAwait(false);
-
- var data = (payload as JToken).ToObject(_serializer);
-
- var guild = State.GetGuild(data.GuildId);
-
- if (guild == null)
+ break;
+ case "GUILD_MEMBER_REMOVE":
{
- await UnknownGuildAsync(type, data.GuildId).ConfigureAwait(false);
- return;
- }
-
- var user = guild.RemoveUser(data.UserId);
- guild.MemberCount--;
+ await _gatewayLogger.DebugAsync("Received Dispatch (GUILD_MEMBER_REMOVE)").ConfigureAwait(false);
- var cacheableUser = new Cacheable(user, data.UserId, user != null, () => Task.FromResult((SocketGuildUser)null));
+ var data = (payload as JToken).ToObject(_serializer);
+ var guild = State.GetGuild(data.GuildId);
+ if (guild != null)
+ {
+ SocketUser user = guild.RemoveUser(data.User.Id);
+ guild.MemberCount--;
- await TimedInvokeAsync(_guildJoinRequestDeletedEvent, nameof(GuildJoinRequestDeleted), cacheableUser, guild).ConfigureAwait(false);
- }
- break;
- #endregion
+ if (!guild.IsSynced)
+ {
+ await UnsyncedGuildAsync(type, guild.Id).ConfigureAwait(false);
+ return;
+ }
- #region DM Channels
+ user ??= State.GetUser(data.User.Id);
- case "CHANNEL_RECIPIENT_ADD":
- {
- await _gatewayLogger.DebugAsync("Received Dispatch (CHANNEL_RECIPIENT_ADD)").ConfigureAwait(false);
+ if (user != null)
+ user.Update(State, data.User);
+ else
+ user = State.GetOrAddUser(data.User.Id, (x) => SocketGlobalUser.Create(this, State, data.User));
- var data = (payload as JToken).ToObject(_serializer);
- if (State.GetChannel(data.ChannelId) is SocketGroupChannel channel)
- {
- var user = channel.GetOrAddUser(data.User);
- await TimedInvokeAsync(_recipientAddedEvent, nameof(RecipientAdded), user).ConfigureAwait(false);
+ await TimedInvokeAsync(_userLeftEvent, nameof(UserLeft), guild, user).ConfigureAwait(false);
+ }
+ else
+ {
+ await UnknownGuildAsync(type, data.GuildId).ConfigureAwait(false);
+ return;
+ }
}
- else
+ break;
+ case "GUILD_MEMBERS_CHUNK":
{
- await UnknownChannelAsync(type, data.ChannelId).ConfigureAwait(false);
- return;
- }
- }
- break;
- case "CHANNEL_RECIPIENT_REMOVE":
- {
- await _gatewayLogger.DebugAsync("Received Dispatch (CHANNEL_RECIPIENT_REMOVE)").ConfigureAwait(false);
+ await _gatewayLogger.DebugAsync("Received Dispatch (GUILD_MEMBERS_CHUNK)").ConfigureAwait(false);
- var data = (payload as JToken).ToObject(_serializer);
- if (State.GetChannel(data.ChannelId) is SocketGroupChannel channel)
- {
- var user = channel.RemoveUser(data.User.Id);
- if (user != null)
- await TimedInvokeAsync(_recipientRemovedEvent, nameof(RecipientRemoved), user).ConfigureAwait(false);
+ var data = (payload as JToken).ToObject(_serializer);
+ var guild = State.GetGuild(data.GuildId);
+ if (guild != null)
+ {
+ foreach (var memberModel in data.Members)
+ guild.AddOrUpdateUser(memberModel);
+
+ if (guild.DownloadedMemberCount >= guild.MemberCount && !guild.DownloaderPromise.IsCompleted)
+ {
+ guild.CompleteDownloadUsers();
+ await TimedInvokeAsync(_guildMembersDownloadedEvent, nameof(GuildMembersDownloaded), guild).ConfigureAwait(false);
+ }
+ }
else
{
- await UnknownChannelUserAsync(type, data.User.Id, data.ChannelId).ConfigureAwait(false);
+ await UnknownGuildAsync(type, data.GuildId).ConfigureAwait(false);
return;
}
}
- else
+ break;
+ case "GUILD_JOIN_REQUEST_DELETE":
{
- await UnknownChannelAsync(type, data.ChannelId).ConfigureAwait(false);
- return;
- }
- }
- break;
+ await _gatewayLogger.DebugAsync("Received Dispatch (GUILD_JOIN_REQUEST_DELETE)").ConfigureAwait(false);
- #endregion
+ var data = (payload as JToken).ToObject(_serializer);
- #region Roles
- case "GUILD_ROLE_CREATE":
- {
- await _gatewayLogger.DebugAsync("Received Dispatch (GUILD_ROLE_CREATE)").ConfigureAwait(false);
+ var guild = State.GetGuild(data.GuildId);
+
+ if (guild == null)
+ {
+ await UnknownGuildAsync(type, data.GuildId).ConfigureAwait(false);
+ return;
+ }
+
+ var user = guild.RemoveUser(data.UserId);
+ guild.MemberCount--;
+
+ var cacheableUser = new Cacheable(user, data.UserId, user != null, () => Task.FromResult((SocketGuildUser)null));
+
+ await TimedInvokeAsync(_guildJoinRequestDeletedEvent, nameof(GuildJoinRequestDeleted), cacheableUser, guild).ConfigureAwait(false);
+ }
+ break;
+ #endregion
+
+ #region DM Channels
- var data = (payload as JToken).ToObject(_serializer);
- var guild = State.GetGuild(data.GuildId);
- if (guild != null)
+ case "CHANNEL_RECIPIENT_ADD":
{
- var role = guild.AddRole(data.Role);
+ await _gatewayLogger.DebugAsync("Received Dispatch (CHANNEL_RECIPIENT_ADD)").ConfigureAwait(false);
- if (!guild.IsSynced)
+ var data = (payload as JToken).ToObject(_serializer);
+ if (State.GetChannel(data.ChannelId) is SocketGroupChannel channel)
{
- await UnsyncedGuildAsync(type, guild.Id).ConfigureAwait(false);
+ var user = channel.GetOrAddUser(data.User);
+ await TimedInvokeAsync(_recipientAddedEvent, nameof(RecipientAdded), user).ConfigureAwait(false);
+ }
+ else
+ {
+ await UnknownChannelAsync(type, data.ChannelId).ConfigureAwait(false);
return;
}
- await TimedInvokeAsync(_roleCreatedEvent, nameof(RoleCreated), role).ConfigureAwait(false);
}
- else
+ break;
+ case "CHANNEL_RECIPIENT_REMOVE":
{
- await UnknownGuildAsync(type, data.GuildId).ConfigureAwait(false);
- return;
- }
- }
- break;
- case "GUILD_ROLE_UPDATE":
- {
- await _gatewayLogger.DebugAsync("Received Dispatch (GUILD_ROLE_UPDATE)").ConfigureAwait(false);
+ await _gatewayLogger.DebugAsync("Received Dispatch (CHANNEL_RECIPIENT_REMOVE)").ConfigureAwait(false);
- var data = (payload as JToken).ToObject(_serializer);
- var guild = State.GetGuild(data.GuildId);
- if (guild != null)
- {
- var role = guild.GetRole(data.Role.Id);
- if (role != null)
+ var data = (payload as JToken).ToObject(_serializer);
+ if (State.GetChannel(data.ChannelId) is SocketGroupChannel channel)
{
- var before = role.Clone();
- role.Update(State, data.Role);
-
- if (!guild.IsSynced)
+ var user = channel.RemoveUser(data.User.Id);
+ if (user != null)
+ await TimedInvokeAsync(_recipientRemovedEvent, nameof(RecipientRemoved), user).ConfigureAwait(false);
+ else
{
- await UnsyncedGuildAsync(type, guild.Id).ConfigureAwait(false);
+ await UnknownChannelUserAsync(type, data.User.Id, data.ChannelId).ConfigureAwait(false);
return;
}
-
- await TimedInvokeAsync(_roleUpdatedEvent, nameof(RoleUpdated), before, role).ConfigureAwait(false);
}
else
{
- await UnknownRoleAsync(type, data.Role.Id, guild.Id).ConfigureAwait(false);
+ await UnknownChannelAsync(type, data.ChannelId).ConfigureAwait(false);
return;
}
}
- else
- {
- await UnknownGuildAsync(type, data.GuildId).ConfigureAwait(false);
- return;
- }
- }
- break;
- case "GUILD_ROLE_DELETE":
- {
- await _gatewayLogger.DebugAsync("Received Dispatch (GUILD_ROLE_DELETE)").ConfigureAwait(false);
+ break;
+
+ #endregion
- var data = (payload as JToken).ToObject(_serializer);
- var guild = State.GetGuild(data.GuildId);
- if (guild != null)
+ #region Roles
+ case "GUILD_ROLE_CREATE":
{
- var role = guild.RemoveRole(data.RoleId);
- if (role != null)
+ await _gatewayLogger.DebugAsync("Received Dispatch (GUILD_ROLE_CREATE)").ConfigureAwait(false);
+
+ var data = (payload as JToken).ToObject(_serializer);
+ var guild = State.GetGuild(data.GuildId);
+ if (guild != null)
{
+ var role = guild.AddRole(data.Role);
+
if (!guild.IsSynced)
{
await UnsyncedGuildAsync(type, guild.Id).ConfigureAwait(false);
return;
}
-
- await TimedInvokeAsync(_roleDeletedEvent, nameof(RoleDeleted), role).ConfigureAwait(false);
+ await TimedInvokeAsync(_roleCreatedEvent, nameof(RoleCreated), role).ConfigureAwait(false);
}
else
{
- await UnknownRoleAsync(type, data.RoleId, guild.Id).ConfigureAwait(false);
+ await UnknownGuildAsync(type, data.GuildId).ConfigureAwait(false);
return;
}
}
- else
+ break;
+ case "GUILD_ROLE_UPDATE":
{
- await UnknownGuildAsync(type, data.GuildId).ConfigureAwait(false);
- return;
- }
- }
- break;
- #endregion
+ await _gatewayLogger.DebugAsync("Received Dispatch (GUILD_ROLE_UPDATE)").ConfigureAwait(false);
- #region Bans
- case "GUILD_BAN_ADD":
- {
- await _gatewayLogger.DebugAsync("Received Dispatch (GUILD_BAN_ADD)").ConfigureAwait(false);
+ var data = (payload as JToken).ToObject(_serializer);
+ var guild = State.GetGuild(data.GuildId);
+ if (guild != null)
+ {
+ var role = guild.GetRole(data.Role.Id);
+ if (role != null)
+ {
+ var before = role.Clone();
+ role.Update(State, data.Role);
- var data = (payload as JToken).ToObject(_serializer);
- var guild = State.GetGuild(data.GuildId);
- if (guild != null)
- {
- if (!guild.IsSynced)
+ if (!guild.IsSynced)
+ {
+ await UnsyncedGuildAsync(type, guild.Id).ConfigureAwait(false);
+ return;
+ }
+
+ await TimedInvokeAsync(_roleUpdatedEvent, nameof(RoleUpdated), before, role).ConfigureAwait(false);
+ }
+ else
+ {
+ await UnknownRoleAsync(type, data.Role.Id, guild.Id).ConfigureAwait(false);
+ return;
+ }
+ }
+ else
{
- await UnsyncedGuildAsync(type, guild.Id).ConfigureAwait(false);
+ await UnknownGuildAsync(type, data.GuildId).ConfigureAwait(false);
return;
}
-
- SocketUser user = guild.GetUser(data.User.Id);
- if (user == null)
- user = SocketUnknownUser.Create(this, State, data.User);
- await TimedInvokeAsync(_userBannedEvent, nameof(UserBanned), user, guild).ConfigureAwait(false);
}
- else
+ break;
+ case "GUILD_ROLE_DELETE":
{
- await UnknownGuildAsync(type, data.GuildId).ConfigureAwait(false);
- return;
- }
- }
- break;
- case "GUILD_BAN_REMOVE":
- {
- await _gatewayLogger.DebugAsync("Received Dispatch (GUILD_BAN_REMOVE)").ConfigureAwait(false);
+ await _gatewayLogger.DebugAsync("Received Dispatch (GUILD_ROLE_DELETE)").ConfigureAwait(false);
- var data = (payload as JToken).ToObject(_serializer);
- var guild = State.GetGuild(data.GuildId);
- if (guild != null)
- {
- if (!guild.IsSynced)
+ var data = (payload as JToken).ToObject(_serializer);
+ var guild = State.GetGuild(data.GuildId);
+ if (guild != null)
{
- await UnsyncedGuildAsync(type, guild.Id).ConfigureAwait(false);
+ var role = guild.RemoveRole(data.RoleId);
+ if (role != null)
+ {
+ if (!guild.IsSynced)
+ {
+ await UnsyncedGuildAsync(type, guild.Id).ConfigureAwait(false);
+ return;
+ }
+
+ await TimedInvokeAsync(_roleDeletedEvent, nameof(RoleDeleted), role).ConfigureAwait(false);
+ }
+ else
+ {
+ await UnknownRoleAsync(type, data.RoleId, guild.Id).ConfigureAwait(false);
+ return;
+ }
+ }
+ else
+ {
+ await UnknownGuildAsync(type, data.GuildId).ConfigureAwait(false);
return;
}
-
- SocketUser user = State.GetUser(data.User.Id);
- if (user == null)
- user = SocketUnknownUser.Create(this, State, data.User);
- await TimedInvokeAsync(_userUnbannedEvent, nameof(UserUnbanned), user, guild).ConfigureAwait(false);
- }
- else
- {
- await UnknownGuildAsync(type, data.GuildId).ConfigureAwait(false);
- return;
}
- }
- break;
- #endregion
-
- #region Messages
- case "MESSAGE_CREATE":
- {
- await _gatewayLogger.DebugAsync("Received Dispatch (MESSAGE_CREATE)").ConfigureAwait(false);
-
- var data = (payload as JToken).ToObject(_serializer);
- var channel = GetChannel(data.ChannelId) as ISocketMessageChannel;
+ break;
+ #endregion
- var guild = (channel as SocketGuildChannel)?.Guild;
- if (guild != null && !guild.IsSynced)
+ #region Bans
+ case "GUILD_BAN_ADD":
{
- await UnsyncedGuildAsync(type, guild.Id).ConfigureAwait(false);
- return;
- }
+ await _gatewayLogger.DebugAsync("Received Dispatch (GUILD_BAN_ADD)").ConfigureAwait(false);
- if (channel == null)
- {
- if (!data.GuildId.IsSpecified) // assume it is a DM
+ var data = (payload as JToken).ToObject(_serializer);
+ var guild = State.GetGuild(data.GuildId);
+ if (guild != null)
{
- channel = CreateDMChannel(data.ChannelId, data.Author.Value, State);
+ if (!guild.IsSynced)
+ {
+ await UnsyncedGuildAsync(type, guild.Id).ConfigureAwait(false);
+ return;
+ }
+
+ SocketUser user = guild.GetUser(data.User.Id);
+ if (user == null)
+ user = SocketUnknownUser.Create(this, State, data.User);
+ await TimedInvokeAsync(_userBannedEvent, nameof(UserBanned), user, guild).ConfigureAwait(false);
}
else
{
- await UnknownChannelAsync(type, data.ChannelId).ConfigureAwait(false);
+ await UnknownGuildAsync(type, data.GuildId).ConfigureAwait(false);
return;
}
}
-
- SocketUser author;
- if (guild != null)
+ break;
+ case "GUILD_BAN_REMOVE":
{
- if (data.WebhookId.IsSpecified)
- author = SocketWebhookUser.Create(guild, State, data.Author.Value, data.WebhookId.Value);
- else
- author = guild.GetUser(data.Author.Value.Id);
- }
- else
- author = (channel as SocketChannel).GetUser(data.Author.Value.Id);
+ await _gatewayLogger.DebugAsync("Received Dispatch (GUILD_BAN_REMOVE)").ConfigureAwait(false);
- if (author == null)
- {
+ var data = (payload as JToken).ToObject(_serializer);
+ var guild = State.GetGuild(data.GuildId);
if (guild != null)
{
- if (data.Member.IsSpecified) // member isn't always included, but use it when we can
+ if (!guild.IsSynced)
{
- data.Member.Value.User = data.Author.Value;
- author = guild.AddOrUpdateUser(data.Member.Value);
+ await UnsyncedGuildAsync(type, guild.Id).ConfigureAwait(false);
+ return;
}
- else
- author = guild.AddOrUpdateUser(data.Author.Value); // user has no guild-specific data
+
+ SocketUser user = State.GetUser(data.User.Id);
+ if (user == null)
+ user = SocketUnknownUser.Create(this, State, data.User);
+ await TimedInvokeAsync(_userUnbannedEvent, nameof(UserUnbanned), user, guild).ConfigureAwait(false);
}
- else if (channel is SocketGroupChannel groupChannel)
- author = groupChannel.GetOrAddUser(data.Author.Value);
else
{
- await UnknownChannelUserAsync(type, data.Author.Value.Id, channel.Id).ConfigureAwait(false);
+ await UnknownGuildAsync(type, data.GuildId).ConfigureAwait(false);
return;
}
}
+ break;
+ #endregion
- var msg = SocketMessage.Create(this, State, author, channel, data);
- SocketChannelHelper.AddMessage(channel, this, msg);
- await TimedInvokeAsync(_messageReceivedEvent, nameof(MessageReceived), msg).ConfigureAwait(false);
- }
- break;
- case "MESSAGE_UPDATE":
- {
- await _gatewayLogger.DebugAsync("Received Dispatch (MESSAGE_UPDATE)").ConfigureAwait(false);
+ #region Messages
+ case "MESSAGE_CREATE":
+ {
+ await _gatewayLogger.DebugAsync("Received Dispatch (MESSAGE_CREATE)").ConfigureAwait(false);
- var data = (payload as JToken).ToObject(_serializer);
- var channel = GetChannel(data.ChannelId) as ISocketMessageChannel;
+ var data = (payload as JToken).ToObject(_serializer);
+ var channel = GetChannel(data.ChannelId) as ISocketMessageChannel;
- var guild = (channel as SocketGuildChannel)?.Guild;
- if (guild != null && !guild.IsSynced)
- {
- await UnsyncedGuildAsync(type, guild.Id).ConfigureAwait(false);
- return;
- }
+ var guild = (channel as SocketGuildChannel)?.Guild;
+ if (guild != null && !guild.IsSynced)
+ {
+ await UnsyncedGuildAsync(type, guild.Id).ConfigureAwait(false);
+ return;
+ }
- SocketMessage before = null, after = null;
- SocketMessage cachedMsg = channel?.GetCachedMessage(data.Id);
- bool isCached = cachedMsg != null;
- if (isCached)
- {
- before = cachedMsg.Clone();
- cachedMsg.Update(State, data);
- after = cachedMsg;
- }
- else
- {
- //Edited message isn't in cache, create a detached one
- SocketUser author;
- if (data.Author.IsSpecified)
+ if (channel == null)
{
- if (guild != null)
+ if (!data.GuildId.IsSpecified) // assume it is a DM
{
- if (data.WebhookId.IsSpecified)
- author = SocketWebhookUser.Create(guild, State, data.Author.Value, data.WebhookId.Value);
- else
- author = guild.GetUser(data.Author.Value.Id);
+ channel = CreateDMChannel(data.ChannelId, data.Author.Value, State);
}
else
- author = (channel as SocketChannel)?.GetUser(data.Author.Value.Id);
-
- if (author == null)
{
- if (guild != null)
- {
- if (data.Member.IsSpecified) // member isn't always included, but use it when we can
- {
- data.Member.Value.User = data.Author.Value;
- author = guild.AddOrUpdateUser(data.Member.Value);
- }
- else
- author = guild.AddOrUpdateUser(data.Author.Value); // user has no guild-specific data
- }
- else if (channel is SocketGroupChannel groupChannel)
- author = groupChannel.GetOrAddUser(data.Author.Value);
+ await UnknownChannelAsync(type, data.ChannelId).ConfigureAwait(false);
+ return;
}
}
+
+ SocketUser author;
+ if (guild != null)
+ {
+ if (data.WebhookId.IsSpecified)
+ author = SocketWebhookUser.Create(guild, State, data.Author.Value, data.WebhookId.Value);
+ else
+ author = guild.GetUser(data.Author.Value.Id);
+ }
else
- // Message author wasn't specified in the payload, so create a completely anonymous unknown user
- author = new SocketUnknownUser(this, id: 0);
+ author = (channel as SocketChannel).GetUser(data.Author.Value.Id);
- if (channel == null)
+ if (author == null)
{
- if (!data.GuildId.IsSpecified) // assume it is a DM
+ if (guild != null)
{
- if (data.Author.IsSpecified)
+ if (data.Member.IsSpecified) // member isn't always included, but use it when we can
{
- var dmChannel = CreateDMChannel(data.ChannelId, data.Author.Value, State);
- channel = dmChannel;
- author = dmChannel.Recipient;
+ data.Member.Value.User = data.Author.Value;
+ author = guild.AddOrUpdateUser(data.Member.Value);
}
else
- channel = CreateDMChannel(data.ChannelId, author, State);
+ author = guild.AddOrUpdateUser(data.Author.Value); // user has no guild-specific data
}
+ else if (channel is SocketGroupChannel groupChannel)
+ author = groupChannel.GetOrAddUser(data.Author.Value);
else
{
- await UnknownChannelAsync(type, data.ChannelId).ConfigureAwait(false);
+ await UnknownChannelUserAsync(type, data.Author.Value.Id, channel.Id).ConfigureAwait(false);
return;
}
}
- after = SocketMessage.Create(this, State, author, channel, data);
+ var msg = SocketMessage.Create(this, State, author, channel, data);
+ SocketChannelHelper.AddMessage(channel, this, msg);
+ await TimedInvokeAsync(_messageReceivedEvent, nameof(MessageReceived), msg).ConfigureAwait(false);
}
- var cacheableBefore = new Cacheable(before, data.Id, isCached, async () => await channel.GetMessageAsync(data.Id).ConfigureAwait(false));
-
- await TimedInvokeAsync(_messageUpdatedEvent, nameof(MessageUpdated), cacheableBefore, after, channel).ConfigureAwait(false);
- }
- break;
- case "MESSAGE_DELETE":
- {
- await _gatewayLogger.DebugAsync("Received Dispatch (MESSAGE_DELETE)").ConfigureAwait(false);
-
- var data = (payload as JToken).ToObject(_serializer);
- var channel = GetChannel(data.ChannelId) as ISocketMessageChannel;
-
- var guild = (channel as SocketGuildChannel)?.Guild;
- if (!(guild?.IsSynced ?? true))
+ break;
+ case "MESSAGE_UPDATE":
{
- await UnsyncedGuildAsync(type, guild.Id).ConfigureAwait(false);
- return;
- }
+ await _gatewayLogger.DebugAsync("Received Dispatch (MESSAGE_UPDATE)").ConfigureAwait(false);
- SocketMessage msg = null;
- if (channel != null)
- msg = SocketChannelHelper.RemoveMessage(channel, this, data.Id);
- var cacheableMsg = new Cacheable(msg, data.Id, msg != null, () => Task.FromResult((IMessage)null));
- var cacheableChannel = new Cacheable(channel, data.ChannelId, channel != null, async () => await GetChannelAsync(data.ChannelId).ConfigureAwait(false) as IMessageChannel);
+ var data = (payload as JToken).ToObject(_serializer);
+ var channel = GetChannel(data.ChannelId) as ISocketMessageChannel;
- await TimedInvokeAsync(_messageDeletedEvent, nameof(MessageDeleted), cacheableMsg, cacheableChannel).ConfigureAwait(false);
- }
- break;
- case "MESSAGE_REACTION_ADD":
- {
- await _gatewayLogger.DebugAsync("Received Dispatch (MESSAGE_REACTION_ADD)").ConfigureAwait(false);
-
- var data = (payload as JToken).ToObject(_serializer);
- var channel = GetChannel(data.ChannelId) as ISocketMessageChannel;
-
- var cachedMsg = channel?.GetCachedMessage(data.MessageId) as SocketUserMessage;
- bool isMsgCached = cachedMsg != null;
- IUser user = null;
- if (channel != null)
- user = await channel.GetUserAsync(data.UserId, CacheMode.CacheOnly).ConfigureAwait(false);
-
- var optionalMsg = !isMsgCached
- ? Optional.Create()
- : Optional.Create(cachedMsg);
-
- if (data.Member.IsSpecified)
- {
var guild = (channel as SocketGuildChannel)?.Guild;
+ if (guild != null && !guild.IsSynced)
+ {
+ await UnsyncedGuildAsync(type, guild.Id).ConfigureAwait(false);
+ return;
+ }
- if (guild != null)
- user = guild.AddOrUpdateUser(data.Member.Value);
- }
- else
- user = GetUser(data.UserId);
-
- var optionalUser = user is null
- ? Optional.Create()
- : Optional.Create(user);
-
- var cacheableChannel = new Cacheable(channel, data.ChannelId, channel != null, async () => await GetChannelAsync(data.ChannelId).ConfigureAwait(false) as IMessageChannel);
- var cacheableMsg = new Cacheable(cachedMsg, data.MessageId, isMsgCached, async () =>
- {
- var channelObj = await cacheableChannel.GetOrDownloadAsync().ConfigureAwait(false);
- return await channelObj.GetMessageAsync(data.MessageId).ConfigureAwait(false) as IUserMessage;
- });
- var reaction = SocketReaction.Create(data, channel, optionalMsg, optionalUser);
-
- cachedMsg?.AddReaction(reaction);
-
- await TimedInvokeAsync(_reactionAddedEvent, nameof(ReactionAdded), cacheableMsg, cacheableChannel, reaction).ConfigureAwait(false);
- }
- break;
- case "MESSAGE_REACTION_REMOVE":
- {
- await _gatewayLogger.DebugAsync("Received Dispatch (MESSAGE_REACTION_REMOVE)").ConfigureAwait(false);
-
- var data = (payload as JToken).ToObject(_serializer);
- var channel = GetChannel(data.ChannelId) as ISocketMessageChannel;
+ SocketMessage before = null, after = null;
+ SocketMessage cachedMsg = channel?.GetCachedMessage(data.Id);
+ bool isCached = cachedMsg != null;
+ if (isCached)
+ {
+ before = cachedMsg.Clone();
+ cachedMsg.Update(State, data);
+ after = cachedMsg;
+ }
+ else
+ {
+ //Edited message isn't in cache, create a detached one
+ SocketUser author;
+ if (data.Author.IsSpecified)
+ {
+ if (guild != null)
+ {
+ if (data.WebhookId.IsSpecified)
+ author = SocketWebhookUser.Create(guild, State, data.Author.Value, data.WebhookId.Value);
+ else
+ author = guild.GetUser(data.Author.Value.Id);
+ }
+ else
+ author = (channel as SocketChannel)?.GetUser(data.Author.Value.Id);
- var cachedMsg = channel?.GetCachedMessage(data.MessageId) as SocketUserMessage;
- bool isMsgCached = cachedMsg != null;
- IUser user = null;
- if (channel != null)
- user = await channel.GetUserAsync(data.UserId, CacheMode.CacheOnly).ConfigureAwait(false);
- else if (!data.GuildId.IsSpecified)
- user = GetUser(data.UserId);
+ if (author == null)
+ {
+ if (guild != null)
+ {
+ if (data.Member.IsSpecified) // member isn't always included, but use it when we can
+ {
+ data.Member.Value.User = data.Author.Value;
+ author = guild.AddOrUpdateUser(data.Member.Value);
+ }
+ else
+ author = guild.AddOrUpdateUser(data.Author.Value); // user has no guild-specific data
+ }
+ else if (channel is SocketGroupChannel groupChannel)
+ author = groupChannel.GetOrAddUser(data.Author.Value);
+ }
+ }
+ else
+ // Message author wasn't specified in the payload, so create a completely anonymous unknown user
+ author = new SocketUnknownUser(this, id: 0);
- var optionalMsg = !isMsgCached
- ? Optional.Create()
- : Optional.Create(cachedMsg);
+ if (channel == null)
+ {
+ if (!data.GuildId.IsSpecified) // assume it is a DM
+ {
+ if (data.Author.IsSpecified)
+ {
+ var dmChannel = CreateDMChannel(data.ChannelId, data.Author.Value, State);
+ channel = dmChannel;
+ author = dmChannel.Recipient;
+ }
+ else
+ channel = CreateDMChannel(data.ChannelId, author, State);
+ }
+ else
+ {
+ await UnknownChannelAsync(type, data.ChannelId).ConfigureAwait(false);
+ return;
+ }
+ }
- var optionalUser = user is null
- ? Optional.Create()
- : Optional.Create(user);
+ after = SocketMessage.Create(this, State, author, channel, data);
+ }
+ var cacheableBefore = new Cacheable(before, data.Id, isCached, async () => await channel.GetMessageAsync(data.Id).ConfigureAwait(false));
- var cacheableChannel = new Cacheable(channel, data.ChannelId, channel != null, async () => await GetChannelAsync(data.ChannelId).ConfigureAwait(false) as IMessageChannel);
- var cacheableMsg = new Cacheable(cachedMsg, data.MessageId, isMsgCached, async () =>
+ await TimedInvokeAsync(_messageUpdatedEvent, nameof(MessageUpdated), cacheableBefore, after, channel).ConfigureAwait(false);
+ }
+ break;
+ case "MESSAGE_DELETE":
{
- var channelObj = await cacheableChannel.GetOrDownloadAsync().ConfigureAwait(false);
- return await channelObj.GetMessageAsync(data.MessageId).ConfigureAwait(false) as IUserMessage;
- });
- var reaction = SocketReaction.Create(data, channel, optionalMsg, optionalUser);
+ await _gatewayLogger.DebugAsync("Received Dispatch (MESSAGE_DELETE)").ConfigureAwait(false);
- cachedMsg?.RemoveReaction(reaction);
+ var data = (payload as JToken).ToObject(_serializer);
+ var channel = GetChannel(data.ChannelId) as ISocketMessageChannel;
- await TimedInvokeAsync(_reactionRemovedEvent, nameof(ReactionRemoved), cacheableMsg, cacheableChannel, reaction).ConfigureAwait(false);
- }
- break;
- case "MESSAGE_REACTION_REMOVE_ALL":
- {
- await _gatewayLogger.DebugAsync("Received Dispatch (MESSAGE_REACTION_REMOVE_ALL)").ConfigureAwait(false);
+ var guild = (channel as SocketGuildChannel)?.Guild;
+ if (!(guild?.IsSynced ?? true))
+ {
+ await UnsyncedGuildAsync(type, guild.Id).ConfigureAwait(false);
+ return;
+ }
- var data = (payload as JToken).ToObject(_serializer);
- var channel = GetChannel(data.ChannelId) as ISocketMessageChannel;
+ SocketMessage msg = null;
+ if (channel != null)
+ msg = SocketChannelHelper.RemoveMessage(channel, this, data.Id);
+ var cacheableMsg = new Cacheable(msg, data.Id, msg != null, () => Task.FromResult((IMessage)null));
+ var cacheableChannel = new Cacheable(channel, data.ChannelId, channel != null, async () => await GetChannelAsync(data.ChannelId).ConfigureAwait(false) as IMessageChannel);
- var cacheableChannel = new Cacheable(channel, data.ChannelId, channel != null, async () => await GetChannelAsync(data.ChannelId).ConfigureAwait(false) as IMessageChannel);
- var cachedMsg = channel?.GetCachedMessage(data.MessageId) as SocketUserMessage;
- bool isMsgCached = cachedMsg != null;
- var cacheableMsg = new Cacheable(cachedMsg, data.MessageId, isMsgCached, async () =>
+ await TimedInvokeAsync(_messageDeletedEvent, nameof(MessageDeleted), cacheableMsg, cacheableChannel).ConfigureAwait(false);
+ }
+ break;
+ case "MESSAGE_REACTION_ADD":
{
- var channelObj = await cacheableChannel.GetOrDownloadAsync().ConfigureAwait(false);
- return await channelObj.GetMessageAsync(data.MessageId).ConfigureAwait(false) as IUserMessage;
- });
+ await _gatewayLogger.DebugAsync("Received Dispatch (MESSAGE_REACTION_ADD)").ConfigureAwait(false);
- cachedMsg?.ClearReactions();
+ var data = (payload as JToken).ToObject(_serializer);
+ var channel = GetChannel(data.ChannelId) as ISocketMessageChannel;
- await TimedInvokeAsync(_reactionsClearedEvent, nameof(ReactionsCleared), cacheableMsg, cacheableChannel).ConfigureAwait(false);
- }
- break;
- case "MESSAGE_REACTION_REMOVE_EMOJI":
- {
- await _gatewayLogger.DebugAsync("Received Dispatch (MESSAGE_REACTION_REMOVE_EMOJI)").ConfigureAwait(false);
-
- var data = (payload as JToken).ToObject(_serializer);
- var channel = GetChannel(data.ChannelId) as ISocketMessageChannel;
+ var cachedMsg = channel?.GetCachedMessage(data.MessageId) as SocketUserMessage;
+ bool isMsgCached = cachedMsg != null;
+ IUser user = null;
+ if (channel != null)
+ user = await channel.GetUserAsync(data.UserId, CacheMode.CacheOnly).ConfigureAwait(false);
- var cachedMsg = channel?.GetCachedMessage(data.MessageId) as SocketUserMessage;
- bool isMsgCached = cachedMsg != null;
+ var optionalMsg = !isMsgCached
+ ? Optional.Create()
+ : Optional.Create(cachedMsg);
- var optionalMsg = !isMsgCached
- ? Optional.Create()
- : Optional.Create(cachedMsg);
+ if (data.Member.IsSpecified)
+ {
+ var guild = (channel as SocketGuildChannel)?.Guild;
- var cacheableChannel = new Cacheable(channel, data.ChannelId, channel != null, async () => await GetChannelAsync(data.ChannelId).ConfigureAwait(false) as IMessageChannel);
- var cacheableMsg = new Cacheable(cachedMsg, data.MessageId, isMsgCached, async () =>
- {
- var channelObj = await cacheableChannel.GetOrDownloadAsync().ConfigureAwait(false);
- return await channelObj.GetMessageAsync(data.MessageId).ConfigureAwait(false) as IUserMessage;
- });
- var emote = data.Emoji.ToIEmote();
+ if (guild != null)
+ user = guild.AddOrUpdateUser(data.Member.Value);
+ }
+ else
+ user = GetUser(data.UserId);
- cachedMsg?.RemoveReactionsForEmote(emote);
+ var optionalUser = user is null
+ ? Optional.Create()
+ : Optional.Create(user);
- await TimedInvokeAsync(_reactionsRemovedForEmoteEvent, nameof(ReactionsRemovedForEmote), cacheableMsg, cacheableChannel, emote).ConfigureAwait(false);
- }
- break;
- case "MESSAGE_DELETE_BULK":
- {
- await _gatewayLogger.DebugAsync("Received Dispatch (MESSAGE_DELETE_BULK)").ConfigureAwait(false);
+ var cacheableChannel = new Cacheable(channel, data.ChannelId, channel != null, async () => await GetChannelAsync(data.ChannelId).ConfigureAwait(false) as IMessageChannel);
+ var cacheableMsg = new Cacheable(cachedMsg, data.MessageId, isMsgCached, async () =>
+ {
+ var channelObj = await cacheableChannel.GetOrDownloadAsync().ConfigureAwait(false);
+ return await channelObj.GetMessageAsync(data.MessageId).ConfigureAwait(false) as IUserMessage;
+ });
+ var reaction = SocketReaction.Create(data, channel, optionalMsg, optionalUser);
- var data = (payload as JToken).ToObject(_serializer);
- var channel = GetChannel(data.ChannelId) as ISocketMessageChannel;
+ cachedMsg?.AddReaction(reaction);
- var guild = (channel as SocketGuildChannel)?.Guild;
- if (!(guild?.IsSynced ?? true))
- {
- await UnsyncedGuildAsync(type, guild.Id).ConfigureAwait(false);
- return;
+ await TimedInvokeAsync(_reactionAddedEvent, nameof(ReactionAdded), cacheableMsg, cacheableChannel, reaction).ConfigureAwait(false);
}
-
- var cacheableChannel = new Cacheable(channel, data.ChannelId, channel != null, async () => await GetChannelAsync(data.ChannelId).ConfigureAwait(false) as IMessageChannel);
- var cacheableList = new List>(data.Ids.Length);
- foreach (ulong id in data.Ids)
+ break;
+ case "MESSAGE_REACTION_REMOVE":
{
- SocketMessage msg = null;
- if (channel != null)
- msg = SocketChannelHelper.RemoveMessage(channel, this, id);
- bool isMsgCached = msg != null;
- var cacheableMsg = new Cacheable(msg, id, isMsgCached, () => Task.FromResult((IMessage)null));
- cacheableList.Add(cacheableMsg);
- }
+ await _gatewayLogger.DebugAsync("Received Dispatch (MESSAGE_REACTION_REMOVE)").ConfigureAwait(false);
- await TimedInvokeAsync(_messagesBulkDeletedEvent, nameof(MessagesBulkDeleted), cacheableList, cacheableChannel).ConfigureAwait(false);
- }
- break;
- #endregion
+ var data = (payload as JToken).ToObject(_serializer);
+ var channel = GetChannel(data.ChannelId) as ISocketMessageChannel;
- #region Polls
+ var cachedMsg = channel?.GetCachedMessage(data.MessageId) as SocketUserMessage;
+ bool isMsgCached = cachedMsg != null;
+ IUser user = null;
+ if (channel != null)
+ user = await channel.GetUserAsync(data.UserId, CacheMode.CacheOnly).ConfigureAwait(false);
+ else if (!data.GuildId.IsSpecified)
+ user = GetUser(data.UserId);
- case "MESSAGE_POLL_VOTE_ADD":
- {
- await _gatewayLogger.DebugAsync("Received Dispatch (MESSAGE_POLL_VOTE_ADD)").ConfigureAwait(false);
+ var optionalMsg = !isMsgCached
+ ? Optional.Create()
+ : Optional.Create(cachedMsg);
- var data = (payload as JToken).ToObject(_serializer);
+ var optionalUser = user is null
+ ? Optional.Create()
+ : Optional.Create(user);
- Cacheable? guildCacheable = null;
+ var cacheableChannel = new Cacheable(channel, data.ChannelId, channel != null, async () => await GetChannelAsync(data.ChannelId).ConfigureAwait(false) as IMessageChannel);
+ var cacheableMsg = new Cacheable(cachedMsg, data.MessageId, isMsgCached, async () =>
+ {
+ var channelObj = await cacheableChannel.GetOrDownloadAsync().ConfigureAwait(false);
+ return await channelObj.GetMessageAsync(data.MessageId).ConfigureAwait(false) as IUserMessage;
+ });
+ var reaction = SocketReaction.Create(data, channel, optionalMsg, optionalUser);
- Cacheable userCacheable;
- Cacheable channelCacheable;
- Cacheable messageCacheable;
+ cachedMsg?.RemoveReaction(reaction);
- if (data.GuildId.IsSpecified)
+ await TimedInvokeAsync(_reactionRemovedEvent, nameof(ReactionRemoved), cacheableMsg, cacheableChannel, reaction).ConfigureAwait(false);
+ }
+ break;
+ case "MESSAGE_REACTION_REMOVE_ALL":
{
- var guild = State.GetGuild(data.GuildId.Value);
- guildCacheable = new(guild, data.GuildId.Value, guild is not null, () => Rest.GetGuildAsync(data.GuildId.Value));
-
- if (guild is not null)
- {
- var user = guild.GetUser(data.UserId);
- userCacheable = new(user, data.UserId, user is not null, async () => await Rest.GetGuildUserAsync(data.GuildId.Value, data.UserId));
+ await _gatewayLogger.DebugAsync("Received Dispatch (MESSAGE_REACTION_REMOVE_ALL)").ConfigureAwait(false);
- var channel = guild.GetTextChannel(data.ChannelId);
- channelCacheable = new(channel, data.ChannelId, channel is not null, async () => (RestTextChannel)await Rest.GetChannelAsync(data.ChannelId));
+ var data = (payload as JToken).ToObject(_serializer);
+ var channel = GetChannel(data.ChannelId) as ISocketMessageChannel;
- var message = channel?.GetCachedMessage(data.MessageId) as IUserMessage;
- messageCacheable = new(message, data.MessageId, message is not null,
- async () => (channel ?? (ITextChannel)await Rest.GetChannelAsync(data.ChannelId)).GetMessageAsync(data.MessageId) as IUserMessage);
- }
- else
+ var cacheableChannel = new Cacheable(channel, data.ChannelId, channel != null, async () => await GetChannelAsync(data.ChannelId).ConfigureAwait(false) as IMessageChannel);
+ var cachedMsg = channel?.GetCachedMessage(data.MessageId) as SocketUserMessage;
+ bool isMsgCached = cachedMsg != null;
+ var cacheableMsg = new Cacheable(cachedMsg, data.MessageId, isMsgCached, async () =>
{
- userCacheable = new(null, data.UserId, false, async () => await Rest.GetGuildUserAsync(data.GuildId.Value, data.UserId));
- channelCacheable = new(null, data.ChannelId, false, async () => (RestTextChannel)(await Rest.GetChannelAsync(data.ChannelId)));
- messageCacheable = new(null, data.MessageId, false,
- async () => await ((ITextChannel)await Rest.GetChannelAsync(data.ChannelId)).GetMessageAsync(data.MessageId) as IUserMessage);
- }
- }
- else
- {
- var user = State.GetUser(data.UserId);
- userCacheable = new(user, data.UserId, user is not null, async () => await GetUserAsync(data.UserId));
+ var channelObj = await cacheableChannel.GetOrDownloadAsync().ConfigureAwait(false);
+ return await channelObj.GetMessageAsync(data.MessageId).ConfigureAwait(false) as IUserMessage;
+ });
- var channel = State.GetChannel(data.ChannelId) as ISocketMessageChannel;
- channelCacheable = new(channel, data.ChannelId, channel is not null, async () => await Rest.GetDMChannelAsync(data.ChannelId) as IRestMessageChannel);
+ cachedMsg?.ClearReactions();
- var message = channel?.GetCachedMessage(data.MessageId) as IUserMessage;
- messageCacheable = new(message, data.MessageId, message is not null, async () => await (channel ?? (IMessageChannel)await Rest.GetDMChannelAsync(data.ChannelId)).GetMessageAsync(data.MessageId) as IUserMessage);
+ await TimedInvokeAsync(_reactionsClearedEvent, nameof(ReactionsCleared), cacheableMsg, cacheableChannel).ConfigureAwait(false);
}
+ break;
+ case "MESSAGE_REACTION_REMOVE_EMOJI":
+ {
+ await _gatewayLogger.DebugAsync("Received Dispatch (MESSAGE_REACTION_REMOVE_EMOJI)").ConfigureAwait(false);
- await TimedInvokeAsync(_pollVoteAdded, nameof(PollVoteAdded), userCacheable, channelCacheable, messageCacheable, guildCacheable, data.AnswerId);
- }
- break;
+ var data = (payload as JToken).ToObject(_serializer);
+ var channel = GetChannel(data.ChannelId) as ISocketMessageChannel;
- case "MESSAGE_POLL_VOTE_REMOVE":
- {
- await _gatewayLogger.DebugAsync("Received Dispatch (MESSAGE_POLL_VOTE_REMOVE)").ConfigureAwait(false);
+ var cachedMsg = channel?.GetCachedMessage(data.MessageId) as SocketUserMessage;
+ bool isMsgCached = cachedMsg != null;
- var data = (payload as JToken).ToObject(_serializer);
+ var optionalMsg = !isMsgCached
+ ? Optional.Create()
+ : Optional.Create(cachedMsg);
- Cacheable? guildCacheable = null;
+ var cacheableChannel = new Cacheable(channel, data.ChannelId, channel != null, async () => await GetChannelAsync(data.ChannelId).ConfigureAwait(false) as IMessageChannel);
+ var cacheableMsg = new Cacheable(cachedMsg, data.MessageId, isMsgCached, async () =>
+ {
+ var channelObj = await cacheableChannel.GetOrDownloadAsync().ConfigureAwait(false);
+ return await channelObj.GetMessageAsync(data.MessageId).ConfigureAwait(false) as IUserMessage;
+ });
+ var emote = data.Emoji.ToIEmote();
- Cacheable userCacheable;
- Cacheable channelCacheable;
- Cacheable messageCacheable;
+ cachedMsg?.RemoveReactionsForEmote(emote);
- if (data.GuildId.IsSpecified)
+ await TimedInvokeAsync(_reactionsRemovedForEmoteEvent, nameof(ReactionsRemovedForEmote), cacheableMsg, cacheableChannel, emote).ConfigureAwait(false);
+ }
+ break;
+ case "MESSAGE_DELETE_BULK":
{
- var guild = State.GetGuild(data.GuildId.Value);
- guildCacheable = new(guild, data.GuildId.Value, guild is not null, () => Rest.GetGuildAsync(data.GuildId.Value));
-
- if (guild is not null)
- {
- var user = guild.GetUser(data.UserId);
- userCacheable = new(user, data.UserId, user is not null, async () => await Rest.GetGuildUserAsync(data.GuildId.Value, data.UserId));
+ await _gatewayLogger.DebugAsync("Received Dispatch (MESSAGE_DELETE_BULK)").ConfigureAwait(false);
- var channel = guild.GetTextChannel(data.ChannelId);
- channelCacheable = new(channel, data.ChannelId, channel is not null, async () => (RestTextChannel)await Rest.GetChannelAsync(data.ChannelId));
+ var data = (payload as JToken).ToObject(_serializer);
+ var channel = GetChannel(data.ChannelId) as ISocketMessageChannel;
- var message = channel?.GetCachedMessage(data.MessageId) as IUserMessage;
- messageCacheable = new(message, data.MessageId, message is not null,
- async () => (channel ?? (ITextChannel)await Rest.GetChannelAsync(data.ChannelId)).GetMessageAsync(data.MessageId) as IUserMessage);
- }
- else
+ var guild = (channel as SocketGuildChannel)?.Guild;
+ if (!(guild?.IsSynced ?? true))
{
- userCacheable = new(null, data.UserId, false, async () => await Rest.GetGuildUserAsync(data.GuildId.Value, data.UserId));
- channelCacheable = new(null, data.ChannelId, false, async () => (RestTextChannel)(await Rest.GetChannelAsync(data.ChannelId)));
- messageCacheable = new(null, data.MessageId, false,
- async () => await ((ITextChannel)await Rest.GetChannelAsync(data.ChannelId)).GetMessageAsync(data.MessageId) as IUserMessage);
+ await UnsyncedGuildAsync(type, guild.Id).ConfigureAwait(false);
+ return;
}
- }
- else
- {
- var user = State.GetUser(data.UserId);
- userCacheable = new(user, data.UserId, user is not null, async () => await GetUserAsync(data.UserId));
- var channel = State.GetChannel(data.ChannelId) as ISocketMessageChannel;
- channelCacheable = new(channel, data.ChannelId, channel is not null, async () => await Rest.GetDMChannelAsync(data.ChannelId) as IRestMessageChannel);
+ var cacheableChannel = new Cacheable(channel, data.ChannelId, channel != null, async () => await GetChannelAsync(data.ChannelId).ConfigureAwait(false) as IMessageChannel);
+ var cacheableList = new List>(data.Ids.Length);
+ foreach (ulong id in data.Ids)
+ {
+ SocketMessage msg = null;
+ if (channel != null)
+ msg = SocketChannelHelper.RemoveMessage(channel, this, id);
+ bool isMsgCached = msg != null;
+ var cacheableMsg = new Cacheable(msg, id, isMsgCached, () => Task.FromResult((IMessage)null));
+ cacheableList.Add(cacheableMsg);
+ }
- var message = channel?.GetCachedMessage(data.MessageId) as IUserMessage;
- messageCacheable = new(message, data.MessageId, message is not null, async () => await (channel ?? (IMessageChannel)await Rest.GetDMChannelAsync(data.ChannelId)).GetMessageAsync(data.MessageId) as IUserMessage);
+ await TimedInvokeAsync(_messagesBulkDeletedEvent, nameof(MessagesBulkDeleted), cacheableList, cacheableChannel).ConfigureAwait(false);
}
+ break;
+ #endregion
- await TimedInvokeAsync(_pollVoteRemoved, nameof(PollVoteRemoved), userCacheable, channelCacheable, messageCacheable, guildCacheable, data.AnswerId);
- }
- break;
+ #region Polls
- #endregion
+ case "MESSAGE_POLL_VOTE_ADD":
+ {
+ await _gatewayLogger.DebugAsync("Received Dispatch (MESSAGE_POLL_VOTE_ADD)").ConfigureAwait(false);
- #region Statuses
- case "PRESENCE_UPDATE":
- {
- await _gatewayLogger.DebugAsync("Received Dispatch (PRESENCE_UPDATE)").ConfigureAwait(false);
+ var data = (payload as JToken).ToObject(_serializer);
- var data = (payload as JToken).ToObject(_serializer);
+ Cacheable? guildCacheable = null;
- SocketUser user = null;
+ Cacheable userCacheable;
+ Cacheable channelCacheable;
+ Cacheable messageCacheable;
- if (data.GuildId.IsSpecified)
- {
- var guild = State.GetGuild(data.GuildId.Value);
- if (guild == null)
+ if (data.GuildId.IsSpecified)
{
- await UnknownGuildAsync(type, data.GuildId.Value).ConfigureAwait(false);
- return;
- }
- if (!guild.IsSynced)
- {
- await UnsyncedGuildAsync(type, guild.Id).ConfigureAwait(false);
- return;
- }
+ var guild = State.GetGuild(data.GuildId.Value);
+ guildCacheable = new(guild, data.GuildId.Value, guild is not null, () => Rest.GetGuildAsync(data.GuildId.Value));
- user = guild.GetUser(data.User.Id);
- if (user == null)
- {
- if (data.Status == UserStatus.Offline)
+ if (guild is not null)
{
- return;
+ var user = guild.GetUser(data.UserId);
+ userCacheable = new(user, data.UserId, user is not null, async () => await Rest.GetGuildUserAsync(data.GuildId.Value, data.UserId));
+
+ var channel = guild.GetTextChannel(data.ChannelId);
+ channelCacheable = new(channel, data.ChannelId, channel is not null, async () => (RestTextChannel)await Rest.GetChannelAsync(data.ChannelId));
+
+ var message = channel?.GetCachedMessage(data.MessageId) as IUserMessage;
+ messageCacheable = new(message, data.MessageId, message is not null,
+ async () => (channel ?? (ITextChannel)await Rest.GetChannelAsync(data.ChannelId)).GetMessageAsync(data.MessageId) as IUserMessage);
}
- user = guild.AddOrUpdateUser(data);
- }
- else
- {
- var globalBefore = user.GlobalUser.Clone();
- if (user.GlobalUser.Update(State, data.User))
+ else
{
- //Global data was updated, trigger UserUpdated
- await TimedInvokeAsync(_userUpdatedEvent, nameof(UserUpdated), globalBefore, user).ConfigureAwait(false);
+ userCacheable = new(null, data.UserId, false, async () => await Rest.GetGuildUserAsync(data.GuildId.Value, data.UserId));
+ channelCacheable = new(null, data.ChannelId, false, async () => (RestTextChannel)(await Rest.GetChannelAsync(data.ChannelId)));
+ messageCacheable = new(null, data.MessageId, false,
+ async () => await ((ITextChannel)await Rest.GetChannelAsync(data.ChannelId)).GetMessageAsync(data.MessageId) as IUserMessage);
}
}
- }
- else
- {
- user = State.GetUser(data.User.Id);
- if (user == null)
+ else
{
- await UnknownGlobalUserAsync(type, data.User.Id).ConfigureAwait(false);
- return;
- }
- }
+ var user = State.GetUser(data.UserId);
+ userCacheable = new(user, data.UserId, user is not null, async () => await GetUserAsync(data.UserId));
- var before = user.Presence?.Clone();
- user.Update(State, data.User);
- user.Update(data);
- await TimedInvokeAsync(_presenceUpdated, nameof(PresenceUpdated), user, before, user.Presence).ConfigureAwait(false);
- }
- break;
- case "TYPING_START":
- {
- await _gatewayLogger.DebugAsync("Received Dispatch (TYPING_START)").ConfigureAwait(false);
+ var channel = State.GetChannel(data.ChannelId) as ISocketMessageChannel;
+ channelCacheable = new(channel, data.ChannelId, channel is not null, async () => await Rest.GetDMChannelAsync(data.ChannelId) as IRestMessageChannel);
- var data = (payload as JToken).ToObject(_serializer);
- var channel = GetChannel(data.ChannelId) as ISocketMessageChannel;
+ var message = channel?.GetCachedMessage(data.MessageId) as IUserMessage;
+ messageCacheable = new(message, data.MessageId, message is not null, async () => await (channel ?? (IMessageChannel)await Rest.GetDMChannelAsync(data.ChannelId)).GetMessageAsync(data.MessageId) as IUserMessage);
+ }
- var guild = (channel as SocketGuildChannel)?.Guild;
- if (!(guild?.IsSynced ?? true))
- {
- await UnsyncedGuildAsync(type, guild.Id).ConfigureAwait(false);
- return;
+ await TimedInvokeAsync(_pollVoteAdded, nameof(PollVoteAdded), userCacheable, channelCacheable, messageCacheable, guildCacheable, data.AnswerId);
}
+ break;
- var cacheableChannel = new Cacheable(channel, data.ChannelId, channel != null, async () => await GetChannelAsync(data.ChannelId).ConfigureAwait(false) as IMessageChannel);
-
- var user = (channel as SocketChannel)?.GetUser(data.UserId);
- if (user == null)
+ case "MESSAGE_POLL_VOTE_REMOVE":
{
- if (guild != null && data.Member.IsSpecified)
- user = guild.AddOrUpdateUser(data.Member.Value);
- }
- var cacheableUser = new Cacheable(user, data.UserId, user != null, async () => await GetUserAsync(data.UserId).ConfigureAwait(false));
+ await _gatewayLogger.DebugAsync("Received Dispatch (MESSAGE_POLL_VOTE_REMOVE)").ConfigureAwait(false);
- await TimedInvokeAsync(_userIsTypingEvent, nameof(UserIsTyping), cacheableUser, cacheableChannel).ConfigureAwait(false);
- }
- break;
- #endregion
+ var data = (payload as JToken).ToObject(_serializer);
- #region Integrations
- case "INTEGRATION_CREATE":
- {
- await _gatewayLogger.DebugAsync("Received Dispatch (INTEGRATION_CREATE)").ConfigureAwait(false);
+ Cacheable? guildCacheable = null;
- var data = (payload as JToken).ToObject(_serializer);
+ Cacheable userCacheable;
+ Cacheable channelCacheable;
+ Cacheable messageCacheable;
- // Integrations from Gateway should always have guild IDs specified.
- if (!data.GuildId.IsSpecified)
- return;
+ if (data.GuildId.IsSpecified)
+ {
+ var guild = State.GetGuild(data.GuildId.Value);
+ guildCacheable = new(guild, data.GuildId.Value, guild is not null, () => Rest.GetGuildAsync(data.GuildId.Value));
- var guild = State.GetGuild(data.GuildId.Value);
+ if (guild is not null)
+ {
+ var user = guild.GetUser(data.UserId);
+ userCacheable = new(user, data.UserId, user is not null, async () => await Rest.GetGuildUserAsync(data.GuildId.Value, data.UserId));
- if (guild != null)
- {
- if (!guild.IsSynced)
+ var channel = guild.GetTextChannel(data.ChannelId);
+ channelCacheable = new(channel, data.ChannelId, channel is not null, async () => (RestTextChannel)await Rest.GetChannelAsync(data.ChannelId));
+
+ var message = channel?.GetCachedMessage(data.MessageId) as IUserMessage;
+ messageCacheable = new(message, data.MessageId, message is not null,
+ async () => (channel ?? (ITextChannel)await Rest.GetChannelAsync(data.ChannelId)).GetMessageAsync(data.MessageId) as IUserMessage);
+ }
+ else
+ {
+ userCacheable = new(null, data.UserId, false, async () => await Rest.GetGuildUserAsync(data.GuildId.Value, data.UserId));
+ channelCacheable = new(null, data.ChannelId, false, async () => (RestTextChannel)(await Rest.GetChannelAsync(data.ChannelId)));
+ messageCacheable = new(null, data.MessageId, false,
+ async () => await ((ITextChannel)await Rest.GetChannelAsync(data.ChannelId)).GetMessageAsync(data.MessageId) as IUserMessage);
+ }
+ }
+ else
{
- await UnsyncedGuildAsync(type, guild.Id).ConfigureAwait(false);
- return;
+ var user = State.GetUser(data.UserId);
+ userCacheable = new(user, data.UserId, user is not null, async () => await GetUserAsync(data.UserId));
+
+ var channel = State.GetChannel(data.ChannelId) as ISocketMessageChannel;
+ channelCacheable = new(channel, data.ChannelId, channel is not null, async () => await Rest.GetDMChannelAsync(data.ChannelId) as IRestMessageChannel);
+
+ var message = channel?.GetCachedMessage(data.MessageId) as IUserMessage;
+ messageCacheable = new(message, data.MessageId, message is not null, async () => await (channel ?? (IMessageChannel)await Rest.GetDMChannelAsync(data.ChannelId)).GetMessageAsync(data.MessageId) as IUserMessage);
}
- await TimedInvokeAsync(_integrationCreated, nameof(IntegrationCreated), RestIntegration.Create(this, guild, data)).ConfigureAwait(false);
+ await TimedInvokeAsync(_pollVoteRemoved, nameof(PollVoteRemoved), userCacheable, channelCacheable, messageCacheable, guildCacheable, data.AnswerId);
}
- else
+ break;
+
+ #endregion
+
+ #region Statuses
+ case "PRESENCE_UPDATE":
{
- await UnknownGuildAsync(type, data.GuildId.Value).ConfigureAwait(false);
- return;
- }
- }
- break;
- case "INTEGRATION_UPDATE":
- {
- await _gatewayLogger.DebugAsync("Received Dispatch (INTEGRATION_UPDATE)").ConfigureAwait(false);
+ await _gatewayLogger.DebugAsync("Received Dispatch (PRESENCE_UPDATE)").ConfigureAwait(false);
- var data = (payload as JToken).ToObject(_serializer);
+ var data = (payload as JToken).ToObject(_serializer);
- // Integrations from Gateway should always have guild IDs specified.
- if (!data.GuildId.IsSpecified)
- return;
+ SocketUser user = null;
- var guild = State.GetGuild(data.GuildId.Value);
+ if (data.GuildId.IsSpecified)
+ {
+ var guild = State.GetGuild(data.GuildId.Value);
+ if (guild == null)
+ {
+ await UnknownGuildAsync(type, data.GuildId.Value).ConfigureAwait(false);
+ return;
+ }
+ if (!guild.IsSynced)
+ {
+ await UnsyncedGuildAsync(type, guild.Id).ConfigureAwait(false);
+ return;
+ }
- if (guild != null)
- {
- if (!guild.IsSynced)
+ user = guild.GetUser(data.User.Id);
+ if (user == null)
+ {
+ if (data.Status == UserStatus.Offline)
+ {
+ return;
+ }
+ user = guild.AddOrUpdateUser(data);
+ }
+ else
+ {
+ var globalBefore = user.GlobalUser.Clone();
+ if (user.GlobalUser.Update(State, data.User))
+ {
+ //Global data was updated, trigger UserUpdated
+ await TimedInvokeAsync(_userUpdatedEvent, nameof(UserUpdated), globalBefore, user).ConfigureAwait(false);
+ }
+ }
+ }
+ else
{
- await UnsyncedGuildAsync(type, guild.Id).ConfigureAwait(false);
- return;
+ user = State.GetUser(data.User.Id);
+ if (user == null)
+ {
+ await UnknownGlobalUserAsync(type, data.User.Id).ConfigureAwait(false);
+ return;
+ }
}
- await TimedInvokeAsync(_integrationUpdated, nameof(IntegrationUpdated), RestIntegration.Create(this, guild, data)).ConfigureAwait(false);
+ var before = user.Presence?.Clone();
+ user.Update(State, data.User);
+ user.Update(data);
+ await TimedInvokeAsync(_presenceUpdated, nameof(PresenceUpdated), user, before, user.Presence).ConfigureAwait(false);
}
- else
+ break;
+ case "TYPING_START":
{
- await UnknownGuildAsync(type, data.GuildId.Value).ConfigureAwait(false);
- return;
- }
- }
- break;
- case "INTEGRATION_DELETE":
- {
- await _gatewayLogger.DebugAsync("Received Dispatch (INTEGRATION_DELETE)").ConfigureAwait(false);
-
- var data = (payload as JToken).ToObject(_serializer);
+ await _gatewayLogger.DebugAsync("Received Dispatch (TYPING_START)").ConfigureAwait(false);
- var guild = State.GetGuild(data.GuildId);
+ var data = (payload as JToken).ToObject(_serializer);
+ var channel = GetChannel(data.ChannelId) as ISocketMessageChannel;
- if (guild != null)
- {
- if (!guild.IsSynced)
+ var guild = (channel as SocketGuildChannel)?.Guild;
+ if (!(guild?.IsSynced ?? true))
{
await UnsyncedGuildAsync(type, guild.Id).ConfigureAwait(false);
return;
}
- await TimedInvokeAsync(_integrationDeleted, nameof(IntegrationDeleted), guild, data.Id, data.ApplicationID).ConfigureAwait(false);
- }
- else
- {
- await UnknownGuildAsync(type, data.GuildId).ConfigureAwait(false);
- return;
- }
- }
- break;
- #endregion
+ var cacheableChannel = new Cacheable(channel, data.ChannelId, channel != null, async () => await GetChannelAsync(data.ChannelId).ConfigureAwait(false) as IMessageChannel);
- #region Users
- case "USER_UPDATE":
- {
- await _gatewayLogger.DebugAsync("Received Dispatch (USER_UPDATE)").ConfigureAwait(false);
+ var user = (channel as SocketChannel)?.GetUser(data.UserId);
+ if (user == null)
+ {
+ if (guild != null && data.Member.IsSpecified)
+ user = guild.AddOrUpdateUser(data.Member.Value);
+ }
+ var cacheableUser = new Cacheable(user, data.UserId, user != null, async () => await GetUserAsync(data.UserId).ConfigureAwait(false));
- var data = (payload as JToken).ToObject(_serializer);
- if (data.Id == CurrentUser.Id)
- {
- var before = CurrentUser.Clone();
- CurrentUser.Update(State, data);
- await TimedInvokeAsync(_selfUpdatedEvent, nameof(CurrentUserUpdated), before, CurrentUser).ConfigureAwait(false);
+ await TimedInvokeAsync(_userIsTypingEvent, nameof(UserIsTyping), cacheableUser, cacheableChannel).ConfigureAwait(false);
}
- else
+ break;
+ #endregion
+
+ #region Integrations
+ case "INTEGRATION_CREATE":
{
- await _gatewayLogger.WarningAsync("Received USER_UPDATE for wrong user.").ConfigureAwait(false);
- return;
- }
- }
- break;
- #endregion
+ await _gatewayLogger.DebugAsync("Received Dispatch (INTEGRATION_CREATE)").ConfigureAwait(false);
- #region Voice
- case "VOICE_STATE_UPDATE":
- {
- await _gatewayLogger.DebugAsync("Received Dispatch (VOICE_STATE_UPDATE)").ConfigureAwait(false);
+ var data = (payload as JToken).ToObject(_serializer);
+
+ // Integrations from Gateway should always have guild IDs specified.
+ if (!data.GuildId.IsSpecified)
+ return;
- var data = (payload as JToken).ToObject(_serializer);
- SocketUser user;
- SocketVoiceState before, after;
- if (data.GuildId != null)
- {
var guild = State.GetGuild(data.GuildId.Value);
- if (guild == null)
+
+ if (guild != null)
{
- await UnknownGuildAsync(type, data.GuildId.Value).ConfigureAwait(false);
- return;
+ if (!guild.IsSynced)
+ {
+ await UnsyncedGuildAsync(type, guild.Id).ConfigureAwait(false);
+ return;
+ }
+
+ await TimedInvokeAsync(_integrationCreated, nameof(IntegrationCreated), RestIntegration.Create(this, guild, data)).ConfigureAwait(false);
}
- else if (!guild.IsSynced)
+ else
{
- await UnsyncedGuildAsync(type, guild.Id).ConfigureAwait(false);
+ await UnknownGuildAsync(type, data.GuildId.Value).ConfigureAwait(false);
return;
}
+ }
+ break;
+ case "INTEGRATION_UPDATE":
+ {
+ await _gatewayLogger.DebugAsync("Received Dispatch (INTEGRATION_UPDATE)").ConfigureAwait(false);
- if (data.ChannelId != null)
+ var data = (payload as JToken).ToObject(_serializer);
+
+ // Integrations from Gateway should always have guild IDs specified.
+ if (!data.GuildId.IsSpecified)
+ return;
+
+ var guild = State.GetGuild(data.GuildId.Value);
+
+ if (guild != null)
{
- before = guild.GetVoiceState(data.UserId)?.Clone() ?? SocketVoiceState.Default;
- after = await guild.AddOrUpdateVoiceStateAsync(State, data).ConfigureAwait(false);
- /*if (data.UserId == CurrentUser.Id)
+ if (!guild.IsSynced)
{
- var _ = guild.FinishJoinAudioChannel().ConfigureAwait(false);
- }*/
+ await UnsyncedGuildAsync(type, guild.Id).ConfigureAwait(false);
+ return;
+ }
+
+ await TimedInvokeAsync(_integrationUpdated, nameof(IntegrationUpdated), RestIntegration.Create(this, guild, data)).ConfigureAwait(false);
}
else
{
- before = await guild.RemoveVoiceStateAsync(data.UserId).ConfigureAwait(false) ?? SocketVoiceState.Default;
- after = SocketVoiceState.Create(null, data);
- }
-
- //Per g250k, this should always be sent, but apparently not always
- user = guild.GetUser(data.UserId)
- ?? (data.Member.IsSpecified ? guild.AddOrUpdateUser(data.Member.Value) : null);
- if (user == null)
- {
- await UnknownGuildUserAsync(type, data.UserId, guild.Id).ConfigureAwait(false);
+ await UnknownGuildAsync(type, data.GuildId.Value).ConfigureAwait(false);
return;
}
}
- else
+ break;
+ case "INTEGRATION_DELETE":
{
- var groupChannel = GetChannel(data.ChannelId.Value) as SocketGroupChannel;
- if (groupChannel == null)
+ await _gatewayLogger.DebugAsync("Received Dispatch (INTEGRATION_DELETE)").ConfigureAwait(false);
+
+ var data = (payload as JToken).ToObject(_serializer);
+
+ var guild = State.GetGuild(data.GuildId);
+
+ if (guild != null)
{
- await UnknownChannelAsync(type, data.ChannelId.Value).ConfigureAwait(false);
- return;
+ if (!guild.IsSynced)
+ {
+ await UnsyncedGuildAsync(type, guild.Id).ConfigureAwait(false);
+ return;
+ }
+
+ await TimedInvokeAsync(_integrationDeleted, nameof(IntegrationDeleted), guild, data.Id, data.ApplicationID).ConfigureAwait(false);
}
- if (data.ChannelId != null)
+ else
{
- before = groupChannel.GetVoiceState(data.UserId)?.Clone() ?? SocketVoiceState.Default;
- after = groupChannel.AddOrUpdateVoiceState(State, data);
+ await UnknownGuildAsync(type, data.GuildId).ConfigureAwait(false);
+ return;
}
- else
+ }
+ break;
+ #endregion
+
+ #region Users
+ case "USER_UPDATE":
+ {
+ await _gatewayLogger.DebugAsync("Received Dispatch (USER_UPDATE)").ConfigureAwait(false);
+
+ var data = (payload as JToken).ToObject(_serializer);
+ if (data.Id == CurrentUser.Id)
{
- before = groupChannel.RemoveVoiceState(data.UserId) ?? SocketVoiceState.Default;
- after = SocketVoiceState.Create(null, data);
+ var before = CurrentUser.Clone();
+ CurrentUser.Update(State, data);
+ await TimedInvokeAsync(_selfUpdatedEvent, nameof(CurrentUserUpdated), before, CurrentUser).ConfigureAwait(false);
}
- user = groupChannel.GetUser(data.UserId);
- if (user == null)
+ else
{
- await UnknownChannelUserAsync(type, data.UserId, groupChannel.Id).ConfigureAwait(false);
+ await _gatewayLogger.WarningAsync("Received USER_UPDATE for wrong user.").ConfigureAwait(false);
return;
}
}
+ break;
+ #endregion
- if (user is SocketGuildUser guildUser && data.ChannelId.HasValue)
+ #region Voice
+ case "VOICE_STATE_UPDATE":
{
- SocketStageChannel stage = guildUser.Guild.GetStageChannel(data.ChannelId.Value);
+ await _gatewayLogger.DebugAsync("Received Dispatch (VOICE_STATE_UPDATE)").ConfigureAwait(false);
- if (stage != null && before.VoiceChannel != null && after.VoiceChannel != null)
+ var data = (payload as JToken).ToObject(_serializer);
+ SocketUser user;
+ SocketVoiceState before, after;
+ if (data.GuildId != null)
{
- if (!before.RequestToSpeakTimestamp.HasValue && after.RequestToSpeakTimestamp.HasValue)
+ var guild = State.GetGuild(data.GuildId.Value);
+ if (guild == null)
{
- await TimedInvokeAsync(_requestToSpeak, nameof(RequestToSpeak), stage, guildUser);
+ await UnknownGuildAsync(type, data.GuildId.Value).ConfigureAwait(false);
return;
}
- if (before.IsSuppressed && !after.IsSuppressed)
+ else if (!guild.IsSynced)
{
- await TimedInvokeAsync(_speakerAdded, nameof(SpeakerAdded), stage, guildUser);
+ await UnsyncedGuildAsync(type, guild.Id).ConfigureAwait(false);
return;
}
- if (!before.IsSuppressed && after.IsSuppressed)
+
+ if (data.ChannelId != null)
{
- await TimedInvokeAsync(_speakerRemoved, nameof(SpeakerRemoved), stage, guildUser);
+ before = guild.GetVoiceState(data.UserId)?.Clone() ?? SocketVoiceState.Default;
+ after = await guild.AddOrUpdateVoiceStateAsync(State, data).ConfigureAwait(false);
+ /*if (data.UserId == CurrentUser.Id)
+ {
+ var _ = guild.FinishJoinAudioChannel().ConfigureAwait(false);
+ }*/
+ }
+ else
+ {
+ before = await guild.RemoveVoiceStateAsync(data.UserId).ConfigureAwait(false) ?? SocketVoiceState.Default;
+ after = SocketVoiceState.Create(null, data);
}
- }
- }
- await TimedInvokeAsync(_userVoiceStateUpdatedEvent, nameof(UserVoiceStateUpdated), user, before, after).ConfigureAwait(false);
- }
- break;
- case "VOICE_SERVER_UPDATE":
- {
- await _gatewayLogger.DebugAsync("Received Dispatch (VOICE_SERVER_UPDATE)").ConfigureAwait(false);
+ //Per g250k, this should always be sent, but apparently not always
+ user = guild.GetUser(data.UserId)
+ ?? (data.Member.IsSpecified ? guild.AddOrUpdateUser(data.Member.Value) : null);
+ if (user == null)
+ {
+ await UnknownGuildUserAsync(type, data.UserId, guild.Id).ConfigureAwait(false);
+ return;
+ }
+ }
+ else
+ {
+ var groupChannel = GetChannel(data.ChannelId.Value) as SocketGroupChannel;
+ if (groupChannel == null)
+ {
+ await UnknownChannelAsync(type, data.ChannelId.Value).ConfigureAwait(false);
+ return;
+ }
+ if (data.ChannelId != null)
+ {
+ before = groupChannel.GetVoiceState(data.UserId)?.Clone() ?? SocketVoiceState.Default;
+ after = groupChannel.AddOrUpdateVoiceState(State, data);
+ }
+ else
+ {
+ before = groupChannel.RemoveVoiceState(data.UserId) ?? SocketVoiceState.Default;
+ after = SocketVoiceState.Create(null, data);
+ }
+ user = groupChannel.GetUser(data.UserId);
+ if (user == null)
+ {
+ await UnknownChannelUserAsync(type, data.UserId, groupChannel.Id).ConfigureAwait(false);
+ return;
+ }
+ }
- var data = (payload as JToken).ToObject(_serializer);
- var guild = State.GetGuild(data.GuildId);
- var isCached = guild != null;
- var cachedGuild = new Cacheable(guild, data.GuildId, isCached,
- () => Task.FromResult(State.GetGuild(data.GuildId) as IGuild));
+ if (user is SocketGuildUser guildUser && data.ChannelId.HasValue)
+ {
+ SocketStageChannel stage = guildUser.Guild.GetStageChannel(data.ChannelId.Value);
- var voiceServer = new SocketVoiceServer(cachedGuild, data.Endpoint, data.Token);
- await TimedInvokeAsync(_voiceServerUpdatedEvent, nameof(UserVoiceStateUpdated), voiceServer).ConfigureAwait(false);
+ if (stage != null && before.VoiceChannel != null && after.VoiceChannel != null)
+ {
+ if (!before.RequestToSpeakTimestamp.HasValue && after.RequestToSpeakTimestamp.HasValue)
+ {
+ await TimedInvokeAsync(_requestToSpeak, nameof(RequestToSpeak), stage, guildUser);
+ return;
+ }
+ if (before.IsSuppressed && !after.IsSuppressed)
+ {
+ await TimedInvokeAsync(_speakerAdded, nameof(SpeakerAdded), stage, guildUser);
+ return;
+ }
+ if (!before.IsSuppressed && after.IsSuppressed)
+ {
+ await TimedInvokeAsync(_speakerRemoved, nameof(SpeakerRemoved), stage, guildUser);
+ }
+ }
+ }
- if (isCached)
+ await TimedInvokeAsync(_userVoiceStateUpdatedEvent, nameof(UserVoiceStateUpdated), user, before, after).ConfigureAwait(false);
+ }
+ break;
+ case "VOICE_SERVER_UPDATE":
{
- var endpoint = data.Endpoint;
+ await _gatewayLogger.DebugAsync("Received Dispatch (VOICE_SERVER_UPDATE)").ConfigureAwait(false);
- //Only strip out the port if the endpoint contains it
- var portBegin = endpoint.LastIndexOf(':');
- if (portBegin > 0)
- endpoint = endpoint.Substring(0, portBegin);
+ var data = (payload as JToken).ToObject(_serializer);
+ var guild = State.GetGuild(data.GuildId);
+ var isCached = guild != null;
+ var cachedGuild = new Cacheable(guild, data.GuildId, isCached,
+ () => Task.FromResult(State.GetGuild(data.GuildId) as IGuild));
- var _ = guild.FinishConnectAudio(endpoint, data.Token).ConfigureAwait(false);
- }
- else
- {
- await UnknownGuildAsync(type, data.GuildId).ConfigureAwait(false);
- }
+ var voiceServer = new SocketVoiceServer(cachedGuild, data.Endpoint, data.Token);
+ await TimedInvokeAsync(_voiceServerUpdatedEvent, nameof(UserVoiceStateUpdated), voiceServer).ConfigureAwait(false);
- }
- break;
+ if (isCached)
+ {
+ var endpoint = data.Endpoint;
- case "VOICE_CHANNEL_STATUS_UPDATE":
- {
- await _gatewayLogger.DebugAsync("Received Dispatch (VOICE_CHANNEL_STATUS_UPDATE)").ConfigureAwait(false);
+ //Only strip out the port if the endpoint contains it
+ var portBegin = endpoint.LastIndexOf(':');
+ if (portBegin > 0)
+ endpoint = endpoint.Substring(0, portBegin);
+
+ var _ = guild.FinishConnectAudio(endpoint, data.Token).ConfigureAwait(false);
+ }
+ else
+ {
+ await UnknownGuildAsync(type, data.GuildId).ConfigureAwait(false);
+ }
+
+ }
+ break;
- var data = (payload as JToken).ToObject(_serializer);
- var guild = State.GetGuild(data.GuildId);
+ case "VOICE_CHANNEL_STATUS_UPDATE":
+ {
+ await _gatewayLogger.DebugAsync("Received Dispatch (VOICE_CHANNEL_STATUS_UPDATE)").ConfigureAwait(false);
- var channel = State.GetChannel(data.Id) as SocketVoiceChannel;
- var channelCacheable = new Cacheable(channel, data.Id, channel is not null, () => null);
+ var data = (payload as JToken).ToObject(_serializer);
+ var guild = State.GetGuild(data.GuildId);
- var before = (string)channel?.Status?.Clone();
- var after = data.Status;
- channel?.UpdateVoiceStatus(data.Status);
+ var channel = State.GetChannel(data.Id) as SocketVoiceChannel;
+ var channelCacheable = new Cacheable(channel, data.Id, channel is not null, () => null);
- await TimedInvokeAsync(_voiceChannelStatusUpdated, nameof(VoiceChannelStatusUpdated), channelCacheable, before, after);
- }
- break;
- #endregion
+ var before = (string)channel?.Status?.Clone();
+ var after = data.Status;
+ channel?.UpdateVoiceStatus(data.Status);
- #region Invites
- case "INVITE_CREATE":
- {
- await _gatewayLogger.DebugAsync("Received Dispatch (INVITE_CREATE)").ConfigureAwait(false);
+ await TimedInvokeAsync(_voiceChannelStatusUpdated, nameof(VoiceChannelStatusUpdated), channelCacheable, before, after);
+ }
+ break;
+ #endregion
- var data = (payload as JToken).ToObject(_serializer);
- if (State.GetChannel(data.ChannelId) is SocketGuildChannel channel)
+ #region Invites
+ case "INVITE_CREATE":
{
- var guild = channel.Guild;
- if (!guild.IsSynced)
+ await _gatewayLogger.DebugAsync("Received Dispatch (INVITE_CREATE)").ConfigureAwait(false);
+
+ var data = (payload as JToken).ToObject(_serializer);
+ if (State.GetChannel(data.ChannelId) is SocketGuildChannel channel)
{
- await UnsyncedGuildAsync(type, guild.Id).ConfigureAwait(false);
- return;
- }
+ var guild = channel.Guild;
+ if (!guild.IsSynced)
+ {
+ await UnsyncedGuildAsync(type, guild.Id).ConfigureAwait(false);
+ return;
+ }
- SocketGuildUser inviter = data.Inviter.IsSpecified
- ? (guild.GetUser(data.Inviter.Value.Id) ?? guild.AddOrUpdateUser(data.Inviter.Value))
- : null;
+ SocketGuildUser inviter = data.Inviter.IsSpecified
+ ? (guild.GetUser(data.Inviter.Value.Id) ?? guild.AddOrUpdateUser(data.Inviter.Value))
+ : null;
- SocketUser target = data.TargetUser.IsSpecified
- ? (guild.GetUser(data.TargetUser.Value.Id) ?? (SocketUser)SocketUnknownUser.Create(this, State, data.TargetUser.Value))
- : null;
+ SocketUser target = data.TargetUser.IsSpecified
+ ? (guild.GetUser(data.TargetUser.Value.Id) ?? (SocketUser)SocketUnknownUser.Create(this, State, data.TargetUser.Value))
+ : null;
- var invite = SocketInvite.Create(this, guild, channel, inviter, target, data);
+ var invite = SocketInvite.Create(this, guild, channel, inviter, target, data);
- await TimedInvokeAsync(_inviteCreatedEvent, nameof(InviteCreated), invite).ConfigureAwait(false);
+ await TimedInvokeAsync(_inviteCreatedEvent, nameof(InviteCreated), invite).ConfigureAwait(false);
+ }
+ else
+ {
+ await UnknownChannelAsync(type, data.ChannelId).ConfigureAwait(false);
+ return;
+ }
}
- else
+ break;
+ case "INVITE_DELETE":
{
- await UnknownChannelAsync(type, data.ChannelId).ConfigureAwait(false);
- return;
+ await _gatewayLogger.DebugAsync("Received Dispatch (INVITE_DELETE)").ConfigureAwait(false);
+
+ var data = (payload as JToken).ToObject(_serializer);
+ if (State.GetChannel(data.ChannelId) is SocketGuildChannel channel)
+ {
+ var guild = channel.Guild;
+ if (!guild.IsSynced)
+ {
+ await UnsyncedGuildAsync(type, guild.Id).ConfigureAwait(false);
+ return;
+ }
+
+ await TimedInvokeAsync(_inviteDeletedEvent, nameof(InviteDeleted), channel, data.Code).ConfigureAwait(false);
+ }
+ else
+ {
+ await UnknownChannelAsync(type, data.ChannelId).ConfigureAwait(false);
+ return;
+ }
}
- }
- break;
- case "INVITE_DELETE":
- {
- await _gatewayLogger.DebugAsync("Received Dispatch (INVITE_DELETE)").ConfigureAwait(false);
+ break;
+ #endregion
- var data = (payload as JToken).ToObject(_serializer);
- if (State.GetChannel(data.ChannelId) is SocketGuildChannel channel)
+ #region Interactions
+ case "INTERACTION_CREATE":
{
- var guild = channel.Guild;
- if (!guild.IsSynced)
+ await _gatewayLogger.DebugAsync("Received Dispatch (INTERACTION_CREATE)").ConfigureAwait(false);
+
+ var data = (payload as JToken).ToObject(_serializer);
+
+ var guild = data.GuildId.IsSpecified ? GetGuild(data.GuildId.Value) : null;
+
+ if (guild != null && !guild.IsSynced)
{
await UnsyncedGuildAsync(type, guild.Id).ConfigureAwait(false);
- return;
}
- await TimedInvokeAsync(_inviteDeletedEvent, nameof(InviteDeleted), channel, data.Code).ConfigureAwait(false);
- }
- else
- {
- await UnknownChannelAsync(type, data.ChannelId).ConfigureAwait(false);
- return;
- }
- }
- break;
- #endregion
+ SocketUser user = data.User.IsSpecified
+ ? State.GetOrAddUser(data.User.Value.Id, (_) => SocketGlobalUser.Create(this, State, data.User.Value))
+ : guild != null
+ ? guild.AddOrUpdateUser(data.Member.Value) // null if the bot scope isn't set, so the guild cannot be retrieved.
+ : State.GetOrAddUser(data.Member.Value.User.Id, (_) => SocketGlobalUser.Create(this, State, data.Member.Value.User));
- #region Interactions
- case "INTERACTION_CREATE":
- {
- await _gatewayLogger.DebugAsync("Received Dispatch (INTERACTION_CREATE)").ConfigureAwait(false);
+ SocketChannel channel = null;
+ if (data.ChannelId.IsSpecified)
+ {
+ channel = State.GetChannel(data.ChannelId.Value);
- var data = (payload as JToken).ToObject(_serializer);
+ if (channel == null)
+ {
+ if (!data.GuildId.IsSpecified) // assume it is a DM
+ {
+ channel = CreateDMChannel(data.ChannelId.Value, user, State);
+ }
- var guild = data.GuildId.IsSpecified ? GetGuild(data.GuildId.Value) : null;
+ // The channel isn't required when responding to an interaction, so we can leave the channel null.
+ }
+ }
+ else if (data.User.IsSpecified)
+ {
+ channel = State.GetDMChannel(data.User.Value.Id);
+ }
- if (guild != null && !guild.IsSynced)
- {
- await UnsyncedGuildAsync(type, guild.Id).ConfigureAwait(false);
- }
+ var interaction = SocketInteraction.Create(this, data, channel as ISocketMessageChannel, user);
- SocketUser user = data.User.IsSpecified
- ? State.GetOrAddUser(data.User.Value.Id, (_) => SocketGlobalUser.Create(this, State, data.User.Value))
- : guild != null
- ? guild.AddOrUpdateUser(data.Member.Value) // null if the bot scope isn't set, so the guild cannot be retrieved.
- : State.GetOrAddUser(data.Member.Value.User.Id, (_) => SocketGlobalUser.Create(this, State, data.Member.Value.User));
+ await TimedInvokeAsync(_interactionCreatedEvent, nameof(InteractionCreated), interaction).ConfigureAwait(false);
- SocketChannel channel = null;
- if (data.ChannelId.IsSpecified)
+ switch (interaction)
+ {
+ case SocketSlashCommand slashCommand:
+ await TimedInvokeAsync(_slashCommandExecuted, nameof(SlashCommandExecuted), slashCommand).ConfigureAwait(false);
+ break;
+ case SocketMessageComponent messageComponent:
+ if (messageComponent.Data.Type.IsSelectType())
+ await TimedInvokeAsync(_selectMenuExecuted, nameof(SelectMenuExecuted), messageComponent).ConfigureAwait(false);
+ if (messageComponent.Data.Type == ComponentType.Button)
+ await TimedInvokeAsync(_buttonExecuted, nameof(ButtonExecuted), messageComponent).ConfigureAwait(false);
+ break;
+ case SocketUserCommand userCommand:
+ await TimedInvokeAsync(_userCommandExecuted, nameof(UserCommandExecuted), userCommand).ConfigureAwait(false);
+ break;
+ case SocketMessageCommand messageCommand:
+ await TimedInvokeAsync(_messageCommandExecuted, nameof(MessageCommandExecuted), messageCommand).ConfigureAwait(false);
+ break;
+ case SocketAutocompleteInteraction autocomplete:
+ await TimedInvokeAsync(_autocompleteExecuted, nameof(AutocompleteExecuted), autocomplete).ConfigureAwait(false);
+ break;
+ case SocketModal modal:
+ await TimedInvokeAsync(_modalSubmitted, nameof(ModalSubmitted), modal).ConfigureAwait(false);
+ break;
+ }
+ }
+ break;
+ case "APPLICATION_COMMAND_CREATE":
{
- channel = State.GetChannel(data.ChannelId.Value);
+ await _gatewayLogger.DebugAsync("Received Dispatch (APPLICATION_COMMAND_CREATE)").ConfigureAwait(false);
- if (channel == null)
+ var data = (payload as JToken).ToObject(_serializer);
+
+ if (data.GuildId.IsSpecified)
{
- if (!data.GuildId.IsSpecified) // assume it is a DM
+ var guild = State.GetGuild(data.GuildId.Value);
+ if (guild == null)
{
- channel = CreateDMChannel(data.ChannelId.Value, user, State);
+ await UnknownGuildAsync(type, data.GuildId.Value).ConfigureAwait(false);
+ return;
}
-
- // The channel isn't required when responding to an interaction, so we can leave the channel null.
}
- }
- else if (data.User.IsSpecified)
- {
- channel = State.GetDMChannel(data.User.Value.Id);
- }
- var interaction = SocketInteraction.Create(this, data, channel as ISocketMessageChannel, user);
+ var applicationCommand = SocketApplicationCommand.Create(this, data);
- await TimedInvokeAsync(_interactionCreatedEvent, nameof(InteractionCreated), interaction).ConfigureAwait(false);
+ State.AddCommand(applicationCommand);
- switch (interaction)
- {
- case SocketSlashCommand slashCommand:
- await TimedInvokeAsync(_slashCommandExecuted, nameof(SlashCommandExecuted), slashCommand).ConfigureAwait(false);
- break;
- case SocketMessageComponent messageComponent:
- if (messageComponent.Data.Type.IsSelectType())
- await TimedInvokeAsync(_selectMenuExecuted, nameof(SelectMenuExecuted), messageComponent).ConfigureAwait(false);
- if (messageComponent.Data.Type == ComponentType.Button)
- await TimedInvokeAsync(_buttonExecuted, nameof(ButtonExecuted), messageComponent).ConfigureAwait(false);
- break;
- case SocketUserCommand userCommand:
- await TimedInvokeAsync(_userCommandExecuted, nameof(UserCommandExecuted), userCommand).ConfigureAwait(false);
- break;
- case SocketMessageCommand messageCommand:
- await TimedInvokeAsync(_messageCommandExecuted, nameof(MessageCommandExecuted), messageCommand).ConfigureAwait(false);
- break;
- case SocketAutocompleteInteraction autocomplete:
- await TimedInvokeAsync(_autocompleteExecuted, nameof(AutocompleteExecuted), autocomplete).ConfigureAwait(false);
- break;
- case SocketModal modal:
- await TimedInvokeAsync(_modalSubmitted, nameof(ModalSubmitted), modal).ConfigureAwait(false);
- break;
+ await TimedInvokeAsync(_applicationCommandCreated, nameof(ApplicationCommandCreated), applicationCommand).ConfigureAwait(false);
}
- }
- break;
- case "APPLICATION_COMMAND_CREATE":
- {
- await _gatewayLogger.DebugAsync("Received Dispatch (APPLICATION_COMMAND_CREATE)").ConfigureAwait(false);
+ break;
+ case "APPLICATION_COMMAND_UPDATE":
+ {
+ await _gatewayLogger.DebugAsync("Received Dispatch (APPLICATION_COMMAND_UPDATE)").ConfigureAwait(false);
- var data = (payload as JToken).ToObject(_serializer);
+ var data = (payload as JToken).ToObject(_serializer);
- if (data.GuildId.IsSpecified)
- {
- var guild = State.GetGuild(data.GuildId.Value);
- if (guild == null)
+ if (data.GuildId.IsSpecified)
{
- await UnknownGuildAsync(type, data.GuildId.Value).ConfigureAwait(false);
- return;
+ var guild = State.GetGuild(data.GuildId.Value);
+ if (guild == null)
+ {
+ await UnknownGuildAsync(type, data.GuildId.Value).ConfigureAwait(false);
+ return;
+ }
}
+
+ var applicationCommand = SocketApplicationCommand.Create(this, data);
+
+ State.AddCommand(applicationCommand);
+
+ await TimedInvokeAsync(_applicationCommandUpdated, nameof(ApplicationCommandUpdated), applicationCommand).ConfigureAwait(false);
}
+ break;
+ case "APPLICATION_COMMAND_DELETE":
+ {
+ await _gatewayLogger.DebugAsync("Received Dispatch (APPLICATION_COMMAND_DELETE)").ConfigureAwait(false);
- var applicationCommand = SocketApplicationCommand.Create(this, data);
+ var data = (payload as JToken).ToObject(_serializer);
- State.AddCommand(applicationCommand);
+ if (data.GuildId.IsSpecified)
+ {
+ var guild = State.GetGuild(data.GuildId.Value);
+ if (guild == null)
+ {
+ await UnknownGuildAsync(type, data.GuildId.Value).ConfigureAwait(false);
+ return;
+ }
+ }
- await TimedInvokeAsync(_applicationCommandCreated, nameof(ApplicationCommandCreated), applicationCommand).ConfigureAwait(false);
- }
- break;
- case "APPLICATION_COMMAND_UPDATE":
- {
- await _gatewayLogger.DebugAsync("Received Dispatch (APPLICATION_COMMAND_UPDATE)").ConfigureAwait(false);
+ var applicationCommand = SocketApplicationCommand.Create(this, data);
+
+ State.RemoveCommand(applicationCommand.Id);
- var data = (payload as JToken).ToObject(_serializer);
+ await TimedInvokeAsync(_applicationCommandDeleted, nameof(ApplicationCommandDeleted), applicationCommand).ConfigureAwait(false);
+ }
+ break;
+ #endregion
- if (data.GuildId.IsSpecified)
+ #region Threads
+ case "THREAD_CREATE":
{
+ await _gatewayLogger.DebugAsync("Received Dispatch (THREAD_CREATE)").ConfigureAwait(false);
+
+ var data = (payload as JToken).ToObject(_serializer);
+
var guild = State.GetGuild(data.GuildId.Value);
+
if (guild == null)
{
- await UnknownGuildAsync(type, data.GuildId.Value).ConfigureAwait(false);
+ await UnknownGuildAsync(type, data.GuildId.Value);
return;
}
- }
- var applicationCommand = SocketApplicationCommand.Create(this, data);
+ SocketThreadChannel threadChannel = null;
- State.AddCommand(applicationCommand);
+ if ((threadChannel = guild.ThreadChannels.FirstOrDefault(x => x.Id == data.Id)) != null)
+ {
+ threadChannel.Update(State, data);
- await TimedInvokeAsync(_applicationCommandUpdated, nameof(ApplicationCommandUpdated), applicationCommand).ConfigureAwait(false);
- }
- break;
- case "APPLICATION_COMMAND_DELETE":
- {
- await _gatewayLogger.DebugAsync("Received Dispatch (APPLICATION_COMMAND_DELETE)").ConfigureAwait(false);
+ if (data.ThreadMember.IsSpecified)
+ threadChannel.AddOrUpdateThreadMember(data.ThreadMember.Value, guild.CurrentUser);
+ }
+ else
+ {
+ threadChannel = (SocketThreadChannel)guild.AddChannel(State, data);
+ if (data.ThreadMember.IsSpecified)
+ threadChannel.AddOrUpdateThreadMember(data.ThreadMember.Value, guild.CurrentUser);
+ }
- var data = (payload as JToken).ToObject(_serializer);
+ await TimedInvokeAsync(_threadCreated, nameof(ThreadCreated), threadChannel).ConfigureAwait(false);
+ }
- if (data.GuildId.IsSpecified)
+ break;
+ case "THREAD_UPDATE":
{
+ await _gatewayLogger.DebugAsync("Received Dispatch (THREAD_UPDATE)").ConfigureAwait(false);
+
+ var data = (payload as JToken).ToObject(_serializer);
var guild = State.GetGuild(data.GuildId.Value);
if (guild == null)
{
- await UnknownGuildAsync(type, data.GuildId.Value).ConfigureAwait(false);
+ await UnknownGuildAsync(type, data.GuildId.Value);
return;
}
- }
-
- var applicationCommand = SocketApplicationCommand.Create(this, data);
- State.RemoveCommand(applicationCommand.Id);
+ var threadChannel = guild.ThreadChannels.FirstOrDefault(x => x.Id == data.Id);
+ var before = threadChannel != null
+ ? new Cacheable(threadChannel.Clone(), data.Id, true, () => Task.FromResult((SocketThreadChannel)null))
+ : new Cacheable(null, data.Id, false, () => Task.FromResult((SocketThreadChannel)null));
- await TimedInvokeAsync(_applicationCommandDeleted, nameof(ApplicationCommandDeleted), applicationCommand).ConfigureAwait(false);
- }
- break;
- #endregion
-
- #region Threads
- case "THREAD_CREATE":
- {
- await _gatewayLogger.DebugAsync("Received Dispatch (THREAD_CREATE)").ConfigureAwait(false);
-
- var data = (payload as JToken).ToObject(_serializer);
-
- var guild = State.GetGuild(data.GuildId.Value);
-
- if (guild == null)
- {
- await UnknownGuildAsync(type, data.GuildId.Value);
- return;
- }
+ if (threadChannel != null)
+ {
+ threadChannel.Update(State, data);
- SocketThreadChannel threadChannel = null;
+ if (data.ThreadMember.IsSpecified)
+ threadChannel.AddOrUpdateThreadMember(data.ThreadMember.Value, guild.CurrentUser);
+ }
+ else
+ {
+ //Thread is updated but was not cached, likely meaning the thread was unarchived.
+ threadChannel = (SocketThreadChannel)guild.AddChannel(State, data);
+ if (data.ThreadMember.IsSpecified)
+ threadChannel.AddOrUpdateThreadMember(data.ThreadMember.Value, guild.CurrentUser);
+ }
- if ((threadChannel = guild.ThreadChannels.FirstOrDefault(x => x.Id == data.Id)) != null)
- {
- threadChannel.Update(State, data);
+ if (!(guild?.IsSynced ?? true))
+ {
+ await UnsyncedGuildAsync(type, guild.Id).ConfigureAwait(false);
+ return;
+ }
- if (data.ThreadMember.IsSpecified)
- threadChannel.AddOrUpdateThreadMember(data.ThreadMember.Value, guild.CurrentUser);
+ await TimedInvokeAsync(_threadUpdated, nameof(ThreadUpdated), before, threadChannel).ConfigureAwait(false);
}
- else
+ break;
+ case "THREAD_DELETE":
{
- threadChannel = (SocketThreadChannel)guild.AddChannel(State, data);
- if (data.ThreadMember.IsSpecified)
- threadChannel.AddOrUpdateThreadMember(data.ThreadMember.Value, guild.CurrentUser);
- }
+ await _gatewayLogger.DebugAsync("Received Dispatch (THREAD_DELETE)").ConfigureAwait(false);
- await TimedInvokeAsync(_threadCreated, nameof(ThreadCreated), threadChannel).ConfigureAwait(false);
- }
+ var data = (payload as JToken).ToObject(_serializer);
- break;
- case "THREAD_UPDATE":
- {
- await _gatewayLogger.DebugAsync("Received Dispatch (THREAD_UPDATE)").ConfigureAwait(false);
+ var guild = State.GetGuild(data.GuildId.Value);
- var data = (payload as JToken).ToObject(_serializer);
- var guild = State.GetGuild(data.GuildId.Value);
- if (guild == null)
- {
- await UnknownGuildAsync(type, data.GuildId.Value);
- return;
- }
+ if (guild == null)
+ {
+ await UnknownGuildAsync(type, data.GuildId.Value).ConfigureAwait(false);
+ return;
+ }
- var threadChannel = guild.ThreadChannels.FirstOrDefault(x => x.Id == data.Id);
- var before = threadChannel != null
- ? new Cacheable(threadChannel.Clone(), data.Id, true, () => Task.FromResult((SocketThreadChannel)null))
- : new Cacheable(null, data.Id, false, () => Task.FromResult((SocketThreadChannel)null));
+ var thread = (SocketThreadChannel)guild.RemoveChannel(State, data.Id);
- if (threadChannel != null)
- {
- threadChannel.Update(State, data);
+ var cacheable = new Cacheable(thread, data.Id, thread != null, null);
- if (data.ThreadMember.IsSpecified)
- threadChannel.AddOrUpdateThreadMember(data.ThreadMember.Value, guild.CurrentUser);
- }
- else
- {
- //Thread is updated but was not cached, likely meaning the thread was unarchived.
- threadChannel = (SocketThreadChannel)guild.AddChannel(State, data);
- if (data.ThreadMember.IsSpecified)
- threadChannel.AddOrUpdateThreadMember(data.ThreadMember.Value, guild.CurrentUser);
+ await TimedInvokeAsync(_threadDeleted, nameof(ThreadDeleted), cacheable).ConfigureAwait(false);
}
-
- if (!(guild?.IsSynced ?? true))
+ break;
+ case "THREAD_LIST_SYNC":
{
- await UnsyncedGuildAsync(type, guild.Id).ConfigureAwait(false);
- return;
- }
-
- await TimedInvokeAsync(_threadUpdated, nameof(ThreadUpdated), before, threadChannel).ConfigureAwait(false);
- }
- break;
- case "THREAD_DELETE":
- {
- await _gatewayLogger.DebugAsync("Received Dispatch (THREAD_DELETE)").ConfigureAwait(false);
-
- var data = (payload as JToken).ToObject(_serializer);
+ await _gatewayLogger.DebugAsync("Received Dispatch (THREAD_LIST_SYNC)").ConfigureAwait(false);
- var guild = State.GetGuild(data.GuildId.Value);
+ var data = (payload as JToken).ToObject(_serializer);
- if (guild == null)
- {
- await UnknownGuildAsync(type, data.GuildId.Value).ConfigureAwait(false);
- return;
- }
+ var guild = State.GetGuild(data.GuildId);
- var thread = (SocketThreadChannel)guild.RemoveChannel(State, data.Id);
-
- var cacheable = new Cacheable(thread, data.Id, thread != null, null);
+ if (guild == null)
+ {
+ await UnknownGuildAsync(type, data.GuildId).ConfigureAwait(false);
+ return;
+ }
- await TimedInvokeAsync(_threadDeleted, nameof(ThreadDeleted), cacheable).ConfigureAwait(false);
- }
- break;
- case "THREAD_LIST_SYNC":
- {
- await _gatewayLogger.DebugAsync("Received Dispatch (THREAD_LIST_SYNC)").ConfigureAwait(false);
+ foreach (var thread in data.Threads)
+ {
+ var entity = guild.ThreadChannels.FirstOrDefault(x => x.Id == thread.Id);
- var data = (payload as JToken).ToObject(_serializer);
+ if (entity == null)
+ {
+ entity = (SocketThreadChannel)guild.AddChannel(State, thread);
+ }
+ else
+ {
+ entity.Update(State, thread);
+ }
- var guild = State.GetGuild(data.GuildId);
+ foreach (var member in data.Members.Where(x => x.Id.Value == entity.Id))
+ {
+ var guildMember = guild.GetUser(member.Id.Value);
- if (guild == null)
- {
- await UnknownGuildAsync(type, data.GuildId).ConfigureAwait(false);
- return;
+ entity.AddOrUpdateThreadMember(member, guildMember);
+ }
+ }
}
-
- foreach (var thread in data.Threads)
+ break;
+ case "THREAD_MEMBER_UPDATE":
{
- var entity = guild.ThreadChannels.FirstOrDefault(x => x.Id == thread.Id);
-
- if (entity == null)
- {
- entity = (SocketThreadChannel)guild.AddChannel(State, thread);
- }
- else
- {
- entity.Update(State, thread);
- }
+ await _gatewayLogger.DebugAsync("Received Dispatch (THREAD_MEMBER_UPDATE)").ConfigureAwait(false);
- foreach (var member in data.Members.Where(x => x.Id.Value == entity.Id))
- {
- var guildMember = guild.GetUser(member.Id.Value);
+ var data = (payload as JToken).ToObject(_serializer);
- entity.AddOrUpdateThreadMember(member, guildMember);
- }
- }
- }
- break;
- case "THREAD_MEMBER_UPDATE":
- {
- await _gatewayLogger.DebugAsync("Received Dispatch (THREAD_MEMBER_UPDATE)").ConfigureAwait(false);
+ var thread = (SocketThreadChannel)State.GetChannel(data.Id.Value);
- var data = (payload as JToken).ToObject(_serializer);
+ if (thread == null)
+ {
+ await UnknownChannelAsync(type, data.Id.Value);
+ return;
+ }
- var thread = (SocketThreadChannel)State.GetChannel(data.Id.Value);
+ thread.AddOrUpdateThreadMember(data, thread.Guild.CurrentUser);
+ }
- if (thread == null)
+ break;
+ case "THREAD_MEMBERS_UPDATE":
{
- await UnknownChannelAsync(type, data.Id.Value);
- return;
- }
+ await _gatewayLogger.DebugAsync("Received Dispatch (THREAD_MEMBERS_UPDATE)").ConfigureAwait(false);
- thread.AddOrUpdateThreadMember(data, thread.Guild.CurrentUser);
- }
+ var data = (payload as JToken).ToObject(_serializer);
- break;
- case "THREAD_MEMBERS_UPDATE":
- {
- await _gatewayLogger.DebugAsync("Received Dispatch (THREAD_MEMBERS_UPDATE)").ConfigureAwait(false);
+ var guild = State.GetGuild(data.GuildId);
- var data = (payload as JToken).ToObject(_serializer);
+ if (guild == null)
+ {
+ await UnknownGuildAsync(type, data.GuildId).ConfigureAwait(false);
+ return;
+ }
- var guild = State.GetGuild(data.GuildId);
+ var thread = (SocketThreadChannel)guild.GetChannel(data.Id);
- if (guild == null)
- {
- await UnknownGuildAsync(type, data.GuildId).ConfigureAwait(false);
- return;
- }
+ if (thread == null)
+ {
+ await UnknownChannelAsync(type, data.Id);
+ return;
+ }
- var thread = (SocketThreadChannel)guild.GetChannel(data.Id);
+ IReadOnlyCollection leftUsers = null;
+ IReadOnlyCollection joinUsers = null;
- if (thread == null)
- {
- await UnknownChannelAsync(type, data.Id);
- return;
- }
- IReadOnlyCollection leftUsers = null;
- IReadOnlyCollection joinUsers = null;
+ if (data.RemovedMemberIds.IsSpecified)
+ {
+ leftUsers = thread.RemoveUsers(data.RemovedMemberIds.Value);
+ }
+ if (data.AddedMembers.IsSpecified)
+ {
+ List newThreadMembers = new List();
+ foreach (var threadMember in data.AddedMembers.Value)
+ {
+ SocketGuildUser guildMember;
- if (data.RemovedMemberIds.IsSpecified)
- {
- leftUsers = thread.RemoveUsers(data.RemovedMemberIds.Value);
- }
+ guildMember = guild.GetUser(threadMember.UserId.Value);
- if (data.AddedMembers.IsSpecified)
- {
- List newThreadMembers = new List();
- foreach (var threadMember in data.AddedMembers.Value)
- {
- SocketGuildUser guildMember;
+ if (guildMember == null)
+ {
+ await UnknownGuildUserAsync("THREAD_MEMBERS_UPDATE", threadMember.UserId.Value, guild.Id);
+ }
+ else
+ newThreadMembers.Add(thread.AddOrUpdateThreadMember(threadMember, guildMember));
+ }
- guildMember = guild.GetUser(threadMember.UserId.Value);
+ if (newThreadMembers.Any())
+ joinUsers = newThreadMembers.ToImmutableArray();
+ }
- if (guildMember == null)
+ if (leftUsers != null)
+ {
+ foreach (var threadUser in leftUsers)
{
- await UnknownGuildUserAsync("THREAD_MEMBERS_UPDATE", threadMember.UserId.Value, guild.Id);
+ await TimedInvokeAsync(_threadMemberLeft, nameof(ThreadMemberLeft), threadUser).ConfigureAwait(false);
}
- else
- newThreadMembers.Add(thread.AddOrUpdateThreadMember(threadMember, guildMember));
}
- if (newThreadMembers.Any())
- joinUsers = newThreadMembers.ToImmutableArray();
- }
-
- if (leftUsers != null)
- {
- foreach (var threadUser in leftUsers)
+ if (joinUsers != null)
{
- await TimedInvokeAsync(_threadMemberLeft, nameof(ThreadMemberLeft), threadUser).ConfigureAwait(false);
+ foreach (var threadUser in joinUsers)
+ {
+ await TimedInvokeAsync(_threadMemberJoined, nameof(ThreadMemberJoined), threadUser).ConfigureAwait(false);
+ }
}
}
- if (joinUsers != null)
+ break;
+ #endregion
+
+ #region Stage Channels
+ case "STAGE_INSTANCE_CREATE" or "STAGE_INSTANCE_UPDATE" or "STAGE_INSTANCE_DELETE":
{
- foreach (var threadUser in joinUsers)
+ await _gatewayLogger.DebugAsync($"Received Dispatch ({type})").ConfigureAwait(false);
+
+ var data = (payload as JToken).ToObject(_serializer);
+
+ var guild = State.GetGuild(data.GuildId);
+
+ if (guild == null)
{
- await TimedInvokeAsync(_threadMemberJoined, nameof(ThreadMemberJoined), threadUser).ConfigureAwait(false);
+ await UnknownGuildAsync(type, data.GuildId).ConfigureAwait(false);
+ return;
}
- }
- }
- break;
- #endregion
+ var stageChannel = guild.GetStageChannel(data.ChannelId);
- #region Stage Channels
- case "STAGE_INSTANCE_CREATE" or "STAGE_INSTANCE_UPDATE" or "STAGE_INSTANCE_DELETE":
- {
- await _gatewayLogger.DebugAsync($"Received Dispatch ({type})").ConfigureAwait(false);
+ if (stageChannel == null)
+ {
+ await UnknownChannelAsync(type, data.ChannelId).ConfigureAwait(false);
+ return;
+ }
- var data = (payload as JToken).ToObject(_serializer);
+ SocketStageChannel before = type == "STAGE_INSTANCE_UPDATE" ? stageChannel.Clone() : null;
- var guild = State.GetGuild(data.GuildId);
+ stageChannel.Update(data, type == "STAGE_INSTANCE_CREATE");
- if (guild == null)
- {
- await UnknownGuildAsync(type, data.GuildId).ConfigureAwait(false);
- return;
+ switch (type)
+ {
+ case "STAGE_INSTANCE_CREATE":
+ await TimedInvokeAsync(_stageStarted, nameof(StageStarted), stageChannel).ConfigureAwait(false);
+ return;
+ case "STAGE_INSTANCE_DELETE":
+ await TimedInvokeAsync(_stageEnded, nameof(StageEnded), stageChannel).ConfigureAwait(false);
+ return;
+ case "STAGE_INSTANCE_UPDATE":
+ await TimedInvokeAsync(_stageUpdated, nameof(StageUpdated), before, stageChannel).ConfigureAwait(false);
+ return;
+ }
}
+ break;
+ #endregion
- var stageChannel = guild.GetStageChannel(data.ChannelId);
-
- if (stageChannel == null)
+ #region Guild Scheduled Events
+ case "GUILD_SCHEDULED_EVENT_CREATE":
{
- await UnknownChannelAsync(type, data.ChannelId).ConfigureAwait(false);
- return;
- }
+ await _gatewayLogger.DebugAsync($"Received Dispatch ({type})").ConfigureAwait(false);
- SocketStageChannel before = type == "STAGE_INSTANCE_UPDATE" ? stageChannel.Clone() : null;
+ var data = (payload as JToken).ToObject(_serializer);
- stageChannel.Update(data, type == "STAGE_INSTANCE_CREATE");
+ var guild = State.GetGuild(data.GuildId);
- switch (type)
- {
- case "STAGE_INSTANCE_CREATE":
- await TimedInvokeAsync(_stageStarted, nameof(StageStarted), stageChannel).ConfigureAwait(false);
- return;
- case "STAGE_INSTANCE_DELETE":
- await TimedInvokeAsync(_stageEnded, nameof(StageEnded), stageChannel).ConfigureAwait(false);
- return;
- case "STAGE_INSTANCE_UPDATE":
- await TimedInvokeAsync(_stageUpdated, nameof(StageUpdated), before, stageChannel).ConfigureAwait(false);
+ if (guild == null)
+ {
+ await UnknownGuildAsync(type, data.GuildId).ConfigureAwait(false);
return;
- }
- }
- break;
- #endregion
+ }
- #region Guild Scheduled Events
- case "GUILD_SCHEDULED_EVENT_CREATE":
- {
- await _gatewayLogger.DebugAsync($"Received Dispatch ({type})").ConfigureAwait(false);
+ var newEvent = guild.AddOrUpdateEvent(data);
- var data = (payload as JToken).ToObject(_serializer);
+ await TimedInvokeAsync(_guildScheduledEventCreated, nameof(GuildScheduledEventCreated), newEvent).ConfigureAwait(false);
+ }
+ break;
+ case "GUILD_SCHEDULED_EVENT_UPDATE":
+ {
+ await _gatewayLogger.DebugAsync($"Received Dispatch ({type})").ConfigureAwait(false);
- var guild = State.GetGuild(data.GuildId);
+ var data = (payload as JToken).ToObject(_serializer);
- if (guild == null)
- {
- await UnknownGuildAsync(type, data.GuildId).ConfigureAwait(false);
- return;
- }
+ var guild = State.GetGuild(data.GuildId);
- var newEvent = guild.AddOrUpdateEvent(data);
+ if (guild == null)
+ {
+ await UnknownGuildAsync(type, data.GuildId).ConfigureAwait(false);
+ return;
+ }
- await TimedInvokeAsync(_guildScheduledEventCreated, nameof(GuildScheduledEventCreated), newEvent).ConfigureAwait(false);
- }
- break;
- case "GUILD_SCHEDULED_EVENT_UPDATE":
- {
- await _gatewayLogger.DebugAsync($"Received Dispatch ({type})").ConfigureAwait(false);
+ var before = guild.GetEvent(data.Id)?.Clone();
- var data = (payload as JToken).ToObject(_serializer);
+ var beforeCacheable = new Cacheable(before, data.Id, before != null, () => Task.FromResult((SocketGuildEvent)null));
- var guild = State.GetGuild(data.GuildId);
+ var after = guild.AddOrUpdateEvent(data);
- if (guild == null)
- {
- await UnknownGuildAsync(type, data.GuildId).ConfigureAwait(false);
- return;
+ if ((before != null ? before.Status != GuildScheduledEventStatus.Completed : true) && data.Status == GuildScheduledEventStatus.Completed)
+ {
+ await TimedInvokeAsync(_guildScheduledEventCompleted, nameof(GuildScheduledEventCompleted), after).ConfigureAwait(false);
+ }
+ else if ((before != null ? before.Status != GuildScheduledEventStatus.Active : false) && data.Status == GuildScheduledEventStatus.Active)
+ {
+ await TimedInvokeAsync(_guildScheduledEventStarted, nameof(GuildScheduledEventStarted), after).ConfigureAwait(false);
+ }
+ else
+ await TimedInvokeAsync(_guildScheduledEventUpdated, nameof(GuildScheduledEventUpdated), beforeCacheable, after).ConfigureAwait(false);
}
+ break;
+ case "GUILD_SCHEDULED_EVENT_DELETE":
+ {
+ await _gatewayLogger.DebugAsync($"Received Dispatch ({type})").ConfigureAwait(false);
- var before = guild.GetEvent(data.Id)?.Clone();
+ var data = (payload as JToken).ToObject(_serializer);
- var beforeCacheable = new Cacheable(before, data.Id, before != null, () => Task.FromResult((SocketGuildEvent)null));
+ var guild = State.GetGuild(data.GuildId);
+
+ if (guild == null)
+ {
+ await UnknownGuildAsync(type, data.GuildId).ConfigureAwait(false);
+ return;
+ }
- var after = guild.AddOrUpdateEvent(data);
+ var guildEvent = guild.RemoveEvent(data.Id) ?? SocketGuildEvent.Create(this, guild, data);
- if ((before != null ? before.Status != GuildScheduledEventStatus.Completed : true) && data.Status == GuildScheduledEventStatus.Completed)
- {
- await TimedInvokeAsync(_guildScheduledEventCompleted, nameof(GuildScheduledEventCompleted), after).ConfigureAwait(false);
+ await TimedInvokeAsync(_guildScheduledEventCancelled, nameof(GuildScheduledEventCancelled), guildEvent).ConfigureAwait(false);
}
- else if ((before != null ? before.Status != GuildScheduledEventStatus.Active : false) && data.Status == GuildScheduledEventStatus.Active)
+ break;
+ case "GUILD_SCHEDULED_EVENT_USER_ADD" or "GUILD_SCHEDULED_EVENT_USER_REMOVE":
{
- await TimedInvokeAsync(_guildScheduledEventStarted, nameof(GuildScheduledEventStarted), after).ConfigureAwait(false);
- }
- else
- await TimedInvokeAsync(_guildScheduledEventUpdated, nameof(GuildScheduledEventUpdated), beforeCacheable, after).ConfigureAwait(false);
- }
- break;
- case "GUILD_SCHEDULED_EVENT_DELETE":
- {
- await _gatewayLogger.DebugAsync($"Received Dispatch ({type})").ConfigureAwait(false);
+ await _gatewayLogger.DebugAsync($"Received Dispatch ({type})").ConfigureAwait(false);
- var data = (payload as JToken).ToObject(_serializer);
+ var data = (payload as JToken).ToObject(_serializer);
- var guild = State.GetGuild(data.GuildId);
+ var guild = State.GetGuild(data.GuildId);
- if (guild == null)
- {
- await UnknownGuildAsync(type, data.GuildId).ConfigureAwait(false);
- return;
- }
+ if (guild == null)
+ {
+ await UnknownGuildAsync(type, data.GuildId).ConfigureAwait(false);
+ return;
+ }
- var guildEvent = guild.RemoveEvent(data.Id) ?? SocketGuildEvent.Create(this, guild, data);
+ var guildEvent = guild.GetEvent(data.EventId);
- await TimedInvokeAsync(_guildScheduledEventCancelled, nameof(GuildScheduledEventCancelled), guildEvent).ConfigureAwait(false);
- }
- break;
- case "GUILD_SCHEDULED_EVENT_USER_ADD" or "GUILD_SCHEDULED_EVENT_USER_REMOVE":
- {
- await _gatewayLogger.DebugAsync($"Received Dispatch ({type})").ConfigureAwait(false);
+ if (guildEvent == null)
+ {
+ await UnknownGuildEventAsync(type, data.EventId, data.GuildId).ConfigureAwait(false);
+ return;
+ }
- var data = (payload as JToken).ToObject(_serializer);
+ var user = (SocketUser)guild.GetUser(data.UserId) ?? State.GetUser(data.UserId);
- var guild = State.GetGuild(data.GuildId);
+ var cacheableUser = new Cacheable(user, data.UserId, user != null, () => Rest.GetUserAsync(data.UserId));
- if (guild == null)
- {
- await UnknownGuildAsync(type, data.GuildId).ConfigureAwait(false);
- return;
+ switch (type)
+ {
+ case "GUILD_SCHEDULED_EVENT_USER_ADD":
+ await TimedInvokeAsync(_guildScheduledEventUserAdd, nameof(GuildScheduledEventUserAdd), cacheableUser, guildEvent).ConfigureAwait(false);
+ break;
+ case "GUILD_SCHEDULED_EVENT_USER_REMOVE":
+ await TimedInvokeAsync(_guildScheduledEventUserRemove, nameof(GuildScheduledEventUserRemove), cacheableUser, guildEvent).ConfigureAwait(false);
+ break;
+ }
}
+ break;
- var guildEvent = guild.GetEvent(data.EventId);
+ #endregion
- if (guildEvent == null)
- {
- await UnknownGuildEventAsync(type, data.EventId, data.GuildId).ConfigureAwait(false);
- return;
- }
+ #region Webhooks
- var user = (SocketUser)guild.GetUser(data.UserId) ?? State.GetUser(data.UserId);
+ case "WEBHOOKS_UPDATE":
+ {
+ var data = (payload as JToken).ToObject(_serializer);
+ type = "WEBHOOKS_UPDATE";
+ await _gatewayLogger.DebugAsync("Received Dispatch (WEBHOOKS_UPDATE)").ConfigureAwait(false);
- var cacheableUser = new Cacheable(user, data.UserId, user != null, () => Rest.GetUserAsync(data.UserId));
+ var guild = State.GetGuild(data.GuildId);
+ var channel = State.GetChannel(data.ChannelId);
- switch (type)
- {
- case "GUILD_SCHEDULED_EVENT_USER_ADD":
- await TimedInvokeAsync(_guildScheduledEventUserAdd, nameof(GuildScheduledEventUserAdd), cacheableUser, guildEvent).ConfigureAwait(false);
- break;
- case "GUILD_SCHEDULED_EVENT_USER_REMOVE":
- await TimedInvokeAsync(_guildScheduledEventUserRemove, nameof(GuildScheduledEventUserRemove), cacheableUser, guildEvent).ConfigureAwait(false);
- break;
+ await TimedInvokeAsync(_webhooksUpdated, nameof(WebhooksUpdated), guild, channel);
}
- }
- break;
+ break;
- #endregion
+ #endregion
- #region Webhooks
+ #region Audit Logs
- case "WEBHOOKS_UPDATE":
- {
- var data = (payload as JToken).ToObject(_serializer);
- type = "WEBHOOKS_UPDATE";
- await _gatewayLogger.DebugAsync("Received Dispatch (WEBHOOKS_UPDATE)").ConfigureAwait(false);
+ case "GUILD_AUDIT_LOG_ENTRY_CREATE":
+ {
+ var data = (payload as JToken).ToObject(_serializer);
+ type = "GUILD_AUDIT_LOG_ENTRY_CREATE";
+ await _gatewayLogger.DebugAsync("Received Dispatch (GUILD_AUDIT_LOG_ENTRY_CREATE)").ConfigureAwait(false);
- var guild = State.GetGuild(data.GuildId);
- var channel = State.GetChannel(data.ChannelId);
+ var guild = State.GetGuild(data.GuildId);
+ var auditLog = SocketAuditLogEntry.Create(this, data);
+ guild.AddAuditLog(auditLog);
- await TimedInvokeAsync(_webhooksUpdated, nameof(WebhooksUpdated), guild, channel);
- }
- break;
+ await TimedInvokeAsync(_auditLogCreated, nameof(AuditLogCreated), auditLog, guild);
+ }
+ break;
+ #endregion
- #endregion
+ #region Auto Moderation
- #region Audit Logs
+ case "AUTO_MODERATION_RULE_CREATE":
+ {
+ var data = (payload as JToken).ToObject(_serializer);
- case "GUILD_AUDIT_LOG_ENTRY_CREATE":
- {
- var data = (payload as JToken).ToObject(_serializer);
- type = "GUILD_AUDIT_LOG_ENTRY_CREATE";
- await _gatewayLogger.DebugAsync("Received Dispatch (GUILD_AUDIT_LOG_ENTRY_CREATE)").ConfigureAwait(false);
+ var guild = State.GetGuild(data.GuildId);
- var guild = State.GetGuild(data.GuildId);
- var auditLog = SocketAuditLogEntry.Create(this, data);
- guild.AddAuditLog(auditLog);
+ var rule = guild.AddOrUpdateAutoModRule(data);
- await TimedInvokeAsync(_auditLogCreated, nameof(AuditLogCreated), auditLog, guild);
- }
- break;
- #endregion
+ await TimedInvokeAsync(_autoModRuleCreated, nameof(AutoModRuleCreated), rule);
+ }
+ break;
- #region Auto Moderation
+ case "AUTO_MODERATION_RULE_UPDATE":
+ {
+ var data = (payload as JToken).ToObject(_serializer);
- case "AUTO_MODERATION_RULE_CREATE":
- {
- var data = (payload as JToken).ToObject(_serializer);
+ var guild = State.GetGuild(data.GuildId);
- var guild = State.GetGuild(data.GuildId);
+ var cachedRule = guild.GetAutoModRule(data.Id);
+ var cacheableBefore = new Cacheable(cachedRule?.Clone(),
+ data.Id,
+ cachedRule is not null,
+ async () => await guild.GetAutoModRuleAsync(data.Id));
- var rule = guild.AddOrUpdateAutoModRule(data);
+ await TimedInvokeAsync(_autoModRuleUpdated, nameof(AutoModRuleUpdated), cacheableBefore, guild.AddOrUpdateAutoModRule(data));
+ }
+ break;
- await TimedInvokeAsync(_autoModRuleCreated, nameof(AutoModRuleCreated), rule);
- }
- break;
+ case "AUTO_MODERATION_RULE_DELETE":
+ {
+ var data = (payload as JToken).ToObject(_serializer);
- case "AUTO_MODERATION_RULE_UPDATE":
- {
- var data = (payload as JToken).ToObject(_serializer);
+ var guild = State.GetGuild(data.GuildId);
- var guild = State.GetGuild(data.GuildId);
+ var rule = guild.RemoveAutoModRule(data);
- var cachedRule = guild.GetAutoModRule(data.Id);
- var cacheableBefore = new Cacheable(cachedRule?.Clone(),
- data.Id,
- cachedRule is not null,
- async () => await guild.GetAutoModRuleAsync(data.Id));
+ await TimedInvokeAsync(_autoModRuleDeleted, nameof(AutoModRuleDeleted), rule);
+ }
+ break;
- await TimedInvokeAsync(_autoModRuleUpdated, nameof(AutoModRuleUpdated), cacheableBefore, guild.AddOrUpdateAutoModRule(data));
- }
- break;
+ case "AUTO_MODERATION_ACTION_EXECUTION":
+ {
+ var data = (payload as JToken).ToObject(_serializer);
+
+ var guild = State.GetGuild(data.GuildId);
+ var action = new AutoModRuleAction(data.Action.Type,
+ data.Action.Metadata.IsSpecified
+ ? data.Action.Metadata.Value.ChannelId.IsSpecified
+ ? data.Action.Metadata.Value.ChannelId.Value
+ : null
+ : null,
+ data.Action.Metadata.IsSpecified
+ ? data.Action.Metadata.Value.DurationSeconds.IsSpecified
+ ? data.Action.Metadata.Value.DurationSeconds.Value
+ : null
+ : null,
+ data.Action.Metadata.IsSpecified
+ ? data.Action.Metadata.Value.CustomMessage.IsSpecified
+ ? data.Action.Metadata.Value.CustomMessage.Value
+ : null
+ : null);
+
+
+ var member = guild.GetUser(data.UserId);
+
+ var cacheableUser = new Cacheable(member,
+ data.UserId,
+ member is not null,
+ async () =>
+ {
+ var model = await ApiClient.GetGuildMemberAsync(data.GuildId, data.UserId);
+ return guild.AddOrUpdateUser(model);
+ }
+ );
- case "AUTO_MODERATION_RULE_DELETE":
- {
- var data = (payload as JToken).ToObject(_serializer);
+ ISocketMessageChannel channel = null;
+ if (data.ChannelId.IsSpecified)
+ channel = GetChannel(data.ChannelId.Value) as ISocketMessageChannel;
- var guild = State.GetGuild(data.GuildId);
+ var cacheableChannel = new Cacheable(channel,
+ data.ChannelId.GetValueOrDefault(0),
+ channel != null,
+ async () =>
+ {
+ if (data.ChannelId.IsSpecified)
+ return await GetChannelAsync(data.ChannelId.Value).ConfigureAwait(false) as ISocketMessageChannel;
+ return null;
+ });
- var rule = guild.RemoveAutoModRule(data);
- await TimedInvokeAsync(_autoModRuleDeleted, nameof(AutoModRuleDeleted), rule);
- }
- break;
+ IUserMessage cachedMsg = null;
+ if (data.MessageId.IsSpecified)
+ cachedMsg = channel?.GetCachedMessage(data.MessageId.GetValueOrDefault(0)) as IUserMessage;
- case "AUTO_MODERATION_ACTION_EXECUTION":
- {
- var data = (payload as JToken).ToObject(_serializer);
-
- var guild = State.GetGuild(data.GuildId);
- var action = new AutoModRuleAction(data.Action.Type,
- data.Action.Metadata.IsSpecified
- ? data.Action.Metadata.Value.ChannelId.IsSpecified
- ? data.Action.Metadata.Value.ChannelId.Value
- : null
- : null,
- data.Action.Metadata.IsSpecified
- ? data.Action.Metadata.Value.DurationSeconds.IsSpecified
- ? data.Action.Metadata.Value.DurationSeconds.Value
- : null
- : null,
- data.Action.Metadata.IsSpecified
- ? data.Action.Metadata.Value.CustomMessage.IsSpecified
- ? data.Action.Metadata.Value.CustomMessage.Value
- : null
- : null);
-
-
- var member = guild.GetUser(data.UserId);
-
- var cacheableUser = new Cacheable(member,
- data.UserId,
- member is not null,
+ var cacheableMessage = new Cacheable(cachedMsg,
+ data.MessageId.GetValueOrDefault(0),
+ cachedMsg is not null,
async () =>
{
- var model = await ApiClient.GetGuildMemberAsync(data.GuildId, data.UserId);
- return guild.AddOrUpdateUser(model);
- }
- );
+ if (data.MessageId.IsSpecified)
+ return (await channel!.GetMessageAsync(data.MessageId.Value).ConfigureAwait(false)) as IUserMessage;
+ return null;
+ });
+
+ var cachedRule = guild.GetAutoModRule(data.RuleId);
+
+ var cacheableRule = new Cacheable(cachedRule,
+ data.RuleId,
+ cachedRule is not null,
+ async () => await guild.GetAutoModRuleAsync(data.RuleId));
+
+ var eventData = new AutoModActionExecutedData(
+ cacheableRule,
+ data.TriggerType,
+ cacheableUser,
+ cacheableChannel,
+ data.MessageId.IsSpecified ? cacheableMessage : null,
+ data.AlertSystemMessageId.GetValueOrDefault(0),
+ data.Content,
+ data.MatchedContent.IsSpecified
+ ? data.MatchedContent.Value
+ : null,
+ data.MatchedKeyword.IsSpecified
+ ? data.MatchedKeyword.Value
+ : null);
+
+ await TimedInvokeAsync(_autoModActionExecuted, nameof(AutoModActionExecuted), guild, action, eventData);
+ }
+ break;
- ISocketMessageChannel channel = null;
- if (data.ChannelId.IsSpecified)
- channel = GetChannel(data.ChannelId.Value) as ISocketMessageChannel;
+ #endregion
- var cacheableChannel = new Cacheable(channel,
- data.ChannelId.GetValueOrDefault(0),
- channel != null,
- async () =>
- {
- if (data.ChannelId.IsSpecified)
- return await GetChannelAsync(data.ChannelId.Value).ConfigureAwait(false) as ISocketMessageChannel;
- return null;
- });
+ #region App Subscriptions
+ case "ENTITLEMENT_CREATE":
+ {
+ await _gatewayLogger.DebugAsync("Received Dispatch (ENTITLEMENT_CREATE)").ConfigureAwait(false);
+ var data = (payload as JToken).ToObject(_serializer);
- IUserMessage cachedMsg = null;
- if (data.MessageId.IsSpecified)
- cachedMsg = channel?.GetCachedMessage(data.MessageId.GetValueOrDefault(0)) as IUserMessage;
+ var entitlement = SocketEntitlement.Create(this, data);
+ State.AddEntitlement(data.Id, entitlement);
- var cacheableMessage = new Cacheable(cachedMsg,
- data.MessageId.GetValueOrDefault(0),
- cachedMsg is not null,
- async () =>
- {
- if (data.MessageId.IsSpecified)
- return (await channel!.GetMessageAsync(data.MessageId.Value).ConfigureAwait(false)) as IUserMessage;
- return null;
- });
+ await TimedInvokeAsync(_entitlementCreated, nameof(EntitlementCreated), entitlement);
+ }
+ break;
- var cachedRule = guild.GetAutoModRule(data.RuleId);
-
- var cacheableRule = new Cacheable(cachedRule,
- data.RuleId,
- cachedRule is not null,
- async () => await guild.GetAutoModRuleAsync(data.RuleId));
-
- var eventData = new AutoModActionExecutedData(
- cacheableRule,
- data.TriggerType,
- cacheableUser,
- cacheableChannel,
- data.MessageId.IsSpecified ? cacheableMessage : null,
- data.AlertSystemMessageId.GetValueOrDefault(0),
- data.Content,
- data.MatchedContent.IsSpecified
- ? data.MatchedContent.Value
- : null,
- data.MatchedKeyword.IsSpecified
- ? data.MatchedKeyword.Value
- : null);
-
- await TimedInvokeAsync(_autoModActionExecuted, nameof(AutoModActionExecuted), guild, action, eventData);
- }
- break;
+ case "ENTITLEMENT_UPDATE":
+ {
+ await _gatewayLogger.DebugAsync("Received Dispatch (ENTITLEMENT_UPDATE)").ConfigureAwait(false);
+ var data = (payload as JToken).ToObject(_serializer);
- #endregion
+ var entitlement = State.GetEntitlement(data.Id);
- #region App Subscriptions
+ var cacheableBefore = new Cacheable(entitlement?.Clone(), data.Id,
+ entitlement is not null, () => null);
- case "ENTITLEMENT_CREATE":
- {
- await _gatewayLogger.DebugAsync("Received Dispatch (ENTITLEMENT_CREATE)").ConfigureAwait(false);
- var data = (payload as JToken).ToObject(_serializer);
+ if (entitlement is null)
+ {
+ entitlement = SocketEntitlement.Create(this, data);
+ State.AddEntitlement(data.Id, entitlement);
+ }
+ else
+ {
+ entitlement.Update(data);
+ }
- var entitlement = SocketEntitlement.Create(this, data);
- State.AddEntitlement(data.Id, entitlement);
+ await TimedInvokeAsync(_entitlementUpdated, nameof(EntitlementUpdated), cacheableBefore, entitlement);
+ }
+ break;
- await TimedInvokeAsync(_entitlementCreated, nameof(EntitlementCreated), entitlement);
- }
- break;
+ case "ENTITLEMENT_DELETE":
+ {
+ await _gatewayLogger.DebugAsync("Received Dispatch (ENTITLEMENT_DELETE)").ConfigureAwait(false);
+ var data = (payload as JToken).ToObject(_serializer);
- case "ENTITLEMENT_UPDATE":
- {
- await _gatewayLogger.DebugAsync("Received Dispatch (ENTITLEMENT_UPDATE)").ConfigureAwait(false);
- var data = (payload as JToken).ToObject(_serializer);
+ var entitlement = State.RemoveEntitlement(data.Id);
- var entitlement = State.GetEntitlement(data.Id);
+ if (entitlement is null)
+ entitlement = SocketEntitlement.Create(this, data);
+ else
+ entitlement.Update(data);
- var cacheableBefore = new Cacheable(entitlement?.Clone(), data.Id,
- entitlement is not null, () => null);
+ var cacheableEntitlement = new Cacheable(entitlement, data.Id,
+ entitlement is not null, () => null);
- if (entitlement is null)
- {
- entitlement = SocketEntitlement.Create(this, data);
- State.AddEntitlement(data.Id, entitlement);
- }
- else
- {
- entitlement.Update(data);
+ await TimedInvokeAsync(_entitlementDeleted, nameof(EntitlementDeleted), cacheableEntitlement);
}
+ break;
- await TimedInvokeAsync(_entitlementUpdated, nameof(EntitlementUpdated), cacheableBefore, entitlement);
- }
- break;
+ case "SUBSCRIPTION_CREATE":
+ {
+ await _gatewayLogger.DebugAsync("Received Dispatch (SUBSCRIPTION_CREATE)").ConfigureAwait(false);
+ var data = (payload as JToken).ToObject