Diff
checker
Text
Text
Bilder
Dokumente
Excel
Ordner
Legal
Enterprise
Desktop-App
Preise
Einloggen
Diffchecker Desktop herunterladen
Texte vergleichen
Finde den Unterschied zwischen zwei Textdateien
Werkzeuge
Verlauf
Live-Editor
Leerzeichen ausblenden
Gleiches ausblenden
Zeilenumbruch aus
Ansicht
Zweispaltig
Einspaltig
Vergleichsgenauigkeit
Intelligent
Wort
Zeichen
Textstile
Darstellung ändern
Syntaxhervorhebung
Syntax auswählen
Ignorieren
Text umwandeln
Zur ersten Änderung
Eingabe bearbeiten
Diffchecker Desktop
Der sicherste Weg, Diffchecker zu nutzen. Hol dir die Desktop-App: Deine Diffs verlassen nie deinen Computer!
Desktop holen
Untitled Diff
Erstellt
vor 5 Jahren
Diff läuft nie ab
Löschen
Exportieren
Teilen
Erklären
3 Entfernungen
Zeilen
Gesamt
Entfernt
Zeichen
Gesamt
Entfernt
Um diese Funktion weiterhin zu nutzen, aktualisiere auf
Diff
checker
Pro
Preise anzeigen
201 Zeilen
Kopieren
22 Hinzufügungen
Zeilen
Gesamt
Hinzugefügt
Zeichen
Gesamt
Hinzugefügt
Um diese Funktion weiterhin zu nutzen, aktualisiere auf
Diff
checker
Pro
Preise anzeigen
208 Zeilen
Kopieren
/*
/*
Kopieren
Kopiert
Kopieren
Kopiert
* File: Discord
ClientWrapper.cs
* File: Discord
Sharded
ClientWrapper.cs
* Author: Angelo Breuer
* Author: Angelo Breuer
*
*
* The MIT License (MIT)
* The MIT License (MIT)
*
*
Kopieren
Kopiert
Kopieren
Kopiert
* Copyright (c) Angelo Breuer 202
0
* Copyright (c) Angelo Breuer 202
1
*
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
* furnished to do so, subject to the following conditions:
*
*
* The above copyright notice and this permission notice shall be included in
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
* all copies or substantial portions of the Software.
*
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
* THE SOFTWARE.
*/
*/
namespace Lavalink4NET.DSharpPlus
namespace Lavalink4NET.DSharpPlus
{
{
using System;
using System;
using System.Collections.Generic;
using System.Collections.Generic;
using System.Linq;
using System.Linq;
using System.Threading.Tasks;
using System.Threading.Tasks;
using global::DSharpPlus;
using global::DSharpPlus;
using global::DSharpPlus.EventArgs;
using global::DSharpPlus.EventArgs;
using Lavalink4NET.Events;
using Lavalink4NET.Events;
using Newtonsoft.Json;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Linq;
/// <summary>
/// <summary>
Kopieren
Kopiert
Kopieren
Kopiert
/// A wrapper for the discord
client from the "DSharpPlus" discord client library. (https://github.com/DSharpPlus/DSharpPlus)
/// A wrapper for the discord
sharded
client from the "DSharpPlus" discord client library. (https://github.com/DSharpPlus/DSharpPlus)
/// </summary>
/// </summary>
Kopieren
Kopiert
Kopieren
Kopiert
public sealed class Discord
ClientWrapper : IDiscordClientWrapper, IDisposable
public sealed class Discord
Sharded
ClientWrapper : IDiscordClientWrapper, IDisposable
{
{
Kopieren
Kopiert
Kopieren
Kopiert
private readonly Discord
Client _client;
private readonly Discord
Sharded
Client _client;
private bool _disposed;
private bool _disposed;
/// <summary>
/// <summary>
/// Initializes a new instance of the <see cref="DiscordClientWrapper"/> class.
/// Initializes a new instance of the <see cref="DiscordClientWrapper"/> class.
/// </summary>
/// </summary>
/// <param name="client">the sharded discord client</param>
/// <param name="client">the sharded discord client</param>
/// <exception cref="ArgumentNullException">
/// <exception cref="ArgumentNullException">
/// thrown if the specified <paramref name="client"/> is <see langword="null"/>.
/// thrown if the specified <paramref name="client"/> is <see langword="null"/>.
/// </exception>
/// </exception>
Kopieren
Kopiert
Kopieren
Kopiert
public Discord
ClientWrapper(Discord
Client client)
public Discord
Sharded
ClientWrapper(Discord
Sharded
Client client)
{
{
_client = client ?? throw new ArgumentNullException(nameof(client));
_client = client ?? throw new ArgumentNullException(nameof(client));
_client.VoiceStateUpdated += OnVoiceStateUpdated;
_client.VoiceStateUpdated += OnVoiceStateUpdated;
_client.VoiceServerUpdated += OnVoiceServerUpdated;
_client.VoiceServerUpdated += OnVoiceServerUpdated;
}
}
/// <inheritdoc/>
/// <inheritdoc/>
public event AsyncEventHandler<VoiceServer>? VoiceServerUpdated;
public event AsyncEventHandler<VoiceServer>? VoiceServerUpdated;
/// <inheritdoc/>
/// <inheritdoc/>
public event AsyncEventHandler<Events.VoiceStateUpdateEventArgs>? VoiceStateUpdated;
public event AsyncEventHandler<Events.VoiceStateUpdateEventArgs>? VoiceStateUpdated;
/// <inheritdoc/>
/// <inheritdoc/>
public ulong CurrentUserId
public ulong CurrentUserId
{
{
get
get
{
{
EnsureNotDisposed();
EnsureNotDisposed();
return _client.CurrentUser.Id;
return _client.CurrentUser.Id;
}
}
}
}
/// <inheritdoc/>
/// <inheritdoc/>
public int ShardCount
public int ShardCount
{
{
get
get
{
{
EnsureNotDisposed();
EnsureNotDisposed();
Kopieren
Kopiert
Kopieren
Kopiert
return _client.Shard
Count;
return _client.Shard
Clients.
Count;
}
}
}
}
/// <inheritdoc/>
/// <inheritdoc/>
public void Dispose()
public void Dispose()
{
{
if (_disposed)
if (_disposed)
{
{
return;
return;
}
}
_disposed = true;
_disposed = true;
_client.VoiceStateUpdated -= OnVoiceStateUpdated;
_client.VoiceStateUpdated -= OnVoiceStateUpdated;
_client.VoiceServerUpdated -= OnVoiceServerUpdated;
_client.VoiceServerUpdated -= OnVoiceServerUpdated;
}
}
/// <inheritdoc/>
/// <inheritdoc/>
/// <exception cref="ObjectDisposedException">thrown if the instance is disposed</exception>
/// <exception cref="ObjectDisposedException">thrown if the instance is disposed</exception>
public async Task<IEnumerable<ulong>> GetChannelUsersAsync(ulong guildId, ulong voiceChannelId)
public async Task<IEnumerable<ulong>> GetChannelUsersAsync(ulong guildId, ulong voiceChannelId)
{
{
EnsureNotDisposed();
EnsureNotDisposed();
Kopieren
Kopiert
Kopieren
Kopiert
var guild = await
_client
.GetGuildAsync(guildId)
var shard = _client.GetShard(guildId)
?? throw new InvalidOperationException("Shard is not served by this client.");
var guild = await
shard
.GetGuildAsync(guildId)
.ConfigureAwait(false)
?? throw new ArgumentException("Invalid or inaccessible guild: " + guildId, nameof(guildId));
?? throw new ArgumentException("Invalid or inaccessible guild: " + guildId, nameof(guildId));
var channel = guild.GetChannel(voiceChannelId)
var channel = guild.GetChannel(voiceChannelId)
?? throw new ArgumentException("Invalid or inaccessible voice channel: " + voiceChannelId, nameof(voiceChannelId));
?? throw new ArgumentException("Invalid or inaccessible voice channel: " + voiceChannelId, nameof(voiceChannelId));
return channel.Users.Select(s => s.Id);
return channel.Users.Select(s => s.Id);
}
}
/// <inheritdoc/>
/// <inheritdoc/>
/// <exception cref="ObjectDisposedException">thrown if the instance is disposed</exception>
/// <exception cref="ObjectDisposedException">thrown if the instance is disposed</exception>
public async Task InitializeAsync()
public async Task InitializeAsync()
{
{
EnsureNotDisposed();
EnsureNotDisposed();
var startTime = DateTimeOffset.UtcNow;
var startTime = DateTimeOffset.UtcNow;
// await until current user arrived
// await until current user arrived
while (_client.CurrentUser is null)
while (_client.CurrentUser is null)
{
{
Kopieren
Kopiert
Kopieren
Kopiert
await Task.Delay(10)
;
await Task.Delay(10)
.ConfigureAwait(false)
;
// timeout exceeded
// timeout exceeded
if (DateTimeOffset.UtcNow - startTime > TimeSpan.FromSeconds(10))
if (DateTimeOffset.UtcNow - startTime > TimeSpan.FromSeconds(10))
{
{
throw new TimeoutException("Waited 10 seconds for current user to arrive! Make sure you start " +
throw new TimeoutException("Waited 10 seconds for current user to arrive! Make sure you start " +
"the discord client, before initializing the discord wrapper!");
"the discord client, before initializing the discord wrapper!");
}
}
}
}
}
}
/// <inheritdoc/>
/// <inheritdoc/>
/// <exception cref="ObjectDisposedException">thrown if the instance is disposed</exception>
/// <exception cref="ObjectDisposedException">thrown if the instance is disposed</exception>
public async Task SendVoiceUpdateAsync(ulong guildId, ulong? voiceChannelId, bool selfDeaf = false, bool selfMute = false)
public async Task SendVoiceUpdateAsync(ulong guildId, ulong? voiceChannelId, bool selfDeaf = false, bool selfMute = false)
{
{
EnsureNotDisposed();
EnsureNotDisposed();
var payload = new JObject();
var payload = new JObject();
var data = new VoiceStateUpdatePayload(guildId, voiceChannelId, selfMute, selfDeaf);
var data = new VoiceStateUpdatePayload(guildId, voiceChannelId, selfMute, selfDeaf);
payload.Add("op", 4);
payload.Add("op", 4);
payload.Add("d", JObject.FromObject(data));
payload.Add("d", JObject.FromObject(data));
var message = JsonConvert.SerializeObject(payload, Formatting.None);
var message = JsonConvert.SerializeObject(payload, Formatting.None);
Kopieren
Kopiert
Kopieren
Kopiert
await
_client
.GetWebSocketClient().SendMessageAsync(message)
;
var shard = _client.GetShard(guildId)
?? throw new InvalidOperationException("Shard is not served by this client.");
await
shard
.GetWebSocketClient().SendMessageAsync(message)
.ConfigureAwait(false)
;
}
}
/// <summary>
/// <summary>
/// Throws an <see cref="ObjectDisposedException"/> if the <see
/// Throws an <see cref="ObjectDisposedException"/> if the <see
/// cref="DiscordClientWrapper"/> is disposed.
/// cref="DiscordClientWrapper"/> is disposed.
/// </summary>
/// </summary>
/// <exception cref="ObjectDisposedException">thrown if the instance is disposed</exception>
/// <exception cref="ObjectDisposedException">thrown if the instance is disposed</exception>
private void EnsureNotDisposed()
private void EnsureNotDisposed()
{
{
if (_disposed)
if (_disposed)
{
{
throw new ObjectDisposedException(nameof(DiscordClientWrapper));
throw new ObjectDisposedException(nameof(DiscordClientWrapper));
}
}
}
}
/// <inheritdoc/>
/// <inheritdoc/>
/// <exception cref="ObjectDisposedException">thrown if the instance is disposed</exception>
/// <exception cref="ObjectDisposedException">thrown if the instance is disposed</exception>
private Task OnVoiceServerUpdated(DiscordClient _, VoiceServerUpdateEventArgs voiceServer)
private Task OnVoiceServerUpdated(DiscordClient _, VoiceServerUpdateEventArgs voiceServer)
{
{
EnsureNotDisposed();
EnsureNotDisposed();
var args = new VoiceServer(voiceServer.Guild.Id, voiceServer.GetVoiceToken(), voiceServer.Endpoint);
var args = new VoiceServer(voiceServer.Guild.Id, voiceServer.GetVoiceToken(), voiceServer.Endpoint);
return VoiceServerUpdated.InvokeAsync(this, args);
return VoiceServerUpdated.InvokeAsync(this, args);
}
}
/// <inheritdoc/>
/// <inheritdoc/>
/// <exception cref="ObjectDisposedException">thrown if the instance is disposed</exception>
/// <exception cref="ObjectDisposedException">thrown if the instance is disposed</exception>
private Task OnVoiceStateUpdated(DiscordClient _, global::DSharpPlus.EventArgs.VoiceStateUpdateEventArgs eventArgs)
private Task OnVoiceStateUpdated(DiscordClient _, global::DSharpPlus.EventArgs.VoiceStateUpdateEventArgs eventArgs)
{
{
EnsureNotDisposed();
EnsureNotDisposed();
// session id is the same as the resume key so DSharpPlus should be able to give us the
// session id is the same as the resume key so DSharpPlus should be able to give us the
// session key in either before or after voice state
// session key in either before or after voice state
var sessionId = eventArgs.Before?.GetSessionId() ?? eventArgs.After.GetSessionId();
var sessionId = eventArgs.Before?.GetSessionId() ?? eventArgs.After.GetSessionId();
// create voice state
// create voice state
var voiceState = new VoiceState(
var voiceState = new VoiceState(
voiceChannelId: eventArgs.After?.Channel?.Id,
voiceChannelId: eventArgs.After?.Channel?.Id,
guildId: eventArgs.Guild.Id,
guildId: eventArgs.Guild.Id,
voiceSessionId: sessionId);
voiceSessionId: sessionId);
// invoke event
// invoke event
return VoiceStateUpdated.InvokeAsync(this,
return VoiceStateUpdated.InvokeAsync(this,
new Events.VoiceStateUpdateEventArgs(eventArgs.User.Id, voiceState));
new Events.VoiceStateUpdateEventArgs(eventArgs.User.Id, voiceState));
}
}
}
}
}
}
Gespeicherte Diffs
Originaltext
Datei öffnen
/* * File: DiscordClientWrapper.cs * Author: Angelo Breuer * * The MIT License (MIT) * * Copyright (c) Angelo Breuer 2020 * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ namespace Lavalink4NET.DSharpPlus { using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using global::DSharpPlus; using global::DSharpPlus.EventArgs; using Lavalink4NET.Events; using Newtonsoft.Json; using Newtonsoft.Json.Linq; /// <summary> /// A wrapper for the discord client from the "DSharpPlus" discord client library. (https://github.com/DSharpPlus/DSharpPlus) /// </summary> public sealed class DiscordClientWrapper : IDiscordClientWrapper, IDisposable { private readonly DiscordClient _client; private bool _disposed; /// <summary> /// Initializes a new instance of the <see cref="DiscordClientWrapper"/> class. /// </summary> /// <param name="client">the sharded discord client</param> /// <exception cref="ArgumentNullException"> /// thrown if the specified <paramref name="client"/> is <see langword="null"/>. /// </exception> public DiscordClientWrapper(DiscordClient client) { _client = client ?? throw new ArgumentNullException(nameof(client)); _client.VoiceStateUpdated += OnVoiceStateUpdated; _client.VoiceServerUpdated += OnVoiceServerUpdated; } /// <inheritdoc/> public event AsyncEventHandler<VoiceServer>? VoiceServerUpdated; /// <inheritdoc/> public event AsyncEventHandler<Events.VoiceStateUpdateEventArgs>? VoiceStateUpdated; /// <inheritdoc/> public ulong CurrentUserId { get { EnsureNotDisposed(); return _client.CurrentUser.Id; } } /// <inheritdoc/> public int ShardCount { get { EnsureNotDisposed(); return _client.ShardCount; } } /// <inheritdoc/> public void Dispose() { if (_disposed) { return; } _disposed = true; _client.VoiceStateUpdated -= OnVoiceStateUpdated; _client.VoiceServerUpdated -= OnVoiceServerUpdated; } /// <inheritdoc/> /// <exception cref="ObjectDisposedException">thrown if the instance is disposed</exception> public async Task<IEnumerable<ulong>> GetChannelUsersAsync(ulong guildId, ulong voiceChannelId) { EnsureNotDisposed(); var guild = await _client.GetGuildAsync(guildId) ?? throw new ArgumentException("Invalid or inaccessible guild: " + guildId, nameof(guildId)); var channel = guild.GetChannel(voiceChannelId) ?? throw new ArgumentException("Invalid or inaccessible voice channel: " + voiceChannelId, nameof(voiceChannelId)); return channel.Users.Select(s => s.Id); } /// <inheritdoc/> /// <exception cref="ObjectDisposedException">thrown if the instance is disposed</exception> public async Task InitializeAsync() { EnsureNotDisposed(); var startTime = DateTimeOffset.UtcNow; // await until current user arrived while (_client.CurrentUser is null) { await Task.Delay(10); // timeout exceeded if (DateTimeOffset.UtcNow - startTime > TimeSpan.FromSeconds(10)) { throw new TimeoutException("Waited 10 seconds for current user to arrive! Make sure you start " + "the discord client, before initializing the discord wrapper!"); } } } /// <inheritdoc/> /// <exception cref="ObjectDisposedException">thrown if the instance is disposed</exception> public async Task SendVoiceUpdateAsync(ulong guildId, ulong? voiceChannelId, bool selfDeaf = false, bool selfMute = false) { EnsureNotDisposed(); var payload = new JObject(); var data = new VoiceStateUpdatePayload(guildId, voiceChannelId, selfMute, selfDeaf); payload.Add("op", 4); payload.Add("d", JObject.FromObject(data)); var message = JsonConvert.SerializeObject(payload, Formatting.None); await _client.GetWebSocketClient().SendMessageAsync(message); } /// <summary> /// Throws an <see cref="ObjectDisposedException"/> if the <see /// cref="DiscordClientWrapper"/> is disposed. /// </summary> /// <exception cref="ObjectDisposedException">thrown if the instance is disposed</exception> private void EnsureNotDisposed() { if (_disposed) { throw new ObjectDisposedException(nameof(DiscordClientWrapper)); } } /// <inheritdoc/> /// <exception cref="ObjectDisposedException">thrown if the instance is disposed</exception> private Task OnVoiceServerUpdated(DiscordClient _, VoiceServerUpdateEventArgs voiceServer) { EnsureNotDisposed(); var args = new VoiceServer(voiceServer.Guild.Id, voiceServer.GetVoiceToken(), voiceServer.Endpoint); return VoiceServerUpdated.InvokeAsync(this, args); } /// <inheritdoc/> /// <exception cref="ObjectDisposedException">thrown if the instance is disposed</exception> private Task OnVoiceStateUpdated(DiscordClient _, global::DSharpPlus.EventArgs.VoiceStateUpdateEventArgs eventArgs) { EnsureNotDisposed(); // session id is the same as the resume key so DSharpPlus should be able to give us the // session key in either before or after voice state var sessionId = eventArgs.Before?.GetSessionId() ?? eventArgs.After.GetSessionId(); // create voice state var voiceState = new VoiceState( voiceChannelId: eventArgs.After?.Channel?.Id, guildId: eventArgs.Guild.Id, voiceSessionId: sessionId); // invoke event return VoiceStateUpdated.InvokeAsync(this, new Events.VoiceStateUpdateEventArgs(eventArgs.User.Id, voiceState)); } } }
Bearbeitung
Datei öffnen
/* * File: DiscordShardedClientWrapper.cs * Author: Angelo Breuer * * The MIT License (MIT) * * Copyright (c) Angelo Breuer 2021 * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ namespace Lavalink4NET.DSharpPlus { using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using global::DSharpPlus; using global::DSharpPlus.EventArgs; using Lavalink4NET.Events; using Newtonsoft.Json; using Newtonsoft.Json.Linq; /// <summary> /// A wrapper for the discord sharded client from the "DSharpPlus" discord client library. (https://github.com/DSharpPlus/DSharpPlus) /// </summary> public sealed class DiscordShardedClientWrapper : IDiscordClientWrapper, IDisposable { private readonly DiscordShardedClient _client; private bool _disposed; /// <summary> /// Initializes a new instance of the <see cref="DiscordClientWrapper"/> class. /// </summary> /// <param name="client">the sharded discord client</param> /// <exception cref="ArgumentNullException"> /// thrown if the specified <paramref name="client"/> is <see langword="null"/>. /// </exception> public DiscordShardedClientWrapper(DiscordShardedClient client) { _client = client ?? throw new ArgumentNullException(nameof(client)); _client.VoiceStateUpdated += OnVoiceStateUpdated; _client.VoiceServerUpdated += OnVoiceServerUpdated; } /// <inheritdoc/> public event AsyncEventHandler<VoiceServer>? VoiceServerUpdated; /// <inheritdoc/> public event AsyncEventHandler<Events.VoiceStateUpdateEventArgs>? VoiceStateUpdated; /// <inheritdoc/> public ulong CurrentUserId { get { EnsureNotDisposed(); return _client.CurrentUser.Id; } } /// <inheritdoc/> public int ShardCount { get { EnsureNotDisposed(); return _client.ShardClients.Count; } } /// <inheritdoc/> public void Dispose() { if (_disposed) { return; } _disposed = true; _client.VoiceStateUpdated -= OnVoiceStateUpdated; _client.VoiceServerUpdated -= OnVoiceServerUpdated; } /// <inheritdoc/> /// <exception cref="ObjectDisposedException">thrown if the instance is disposed</exception> public async Task<IEnumerable<ulong>> GetChannelUsersAsync(ulong guildId, ulong voiceChannelId) { EnsureNotDisposed(); var shard = _client.GetShard(guildId) ?? throw new InvalidOperationException("Shard is not served by this client."); var guild = await shard.GetGuildAsync(guildId).ConfigureAwait(false) ?? throw new ArgumentException("Invalid or inaccessible guild: " + guildId, nameof(guildId)); var channel = guild.GetChannel(voiceChannelId) ?? throw new ArgumentException("Invalid or inaccessible voice channel: " + voiceChannelId, nameof(voiceChannelId)); return channel.Users.Select(s => s.Id); } /// <inheritdoc/> /// <exception cref="ObjectDisposedException">thrown if the instance is disposed</exception> public async Task InitializeAsync() { EnsureNotDisposed(); var startTime = DateTimeOffset.UtcNow; // await until current user arrived while (_client.CurrentUser is null) { await Task.Delay(10).ConfigureAwait(false); // timeout exceeded if (DateTimeOffset.UtcNow - startTime > TimeSpan.FromSeconds(10)) { throw new TimeoutException("Waited 10 seconds for current user to arrive! Make sure you start " + "the discord client, before initializing the discord wrapper!"); } } } /// <inheritdoc/> /// <exception cref="ObjectDisposedException">thrown if the instance is disposed</exception> public async Task SendVoiceUpdateAsync(ulong guildId, ulong? voiceChannelId, bool selfDeaf = false, bool selfMute = false) { EnsureNotDisposed(); var payload = new JObject(); var data = new VoiceStateUpdatePayload(guildId, voiceChannelId, selfMute, selfDeaf); payload.Add("op", 4); payload.Add("d", JObject.FromObject(data)); var message = JsonConvert.SerializeObject(payload, Formatting.None); var shard = _client.GetShard(guildId) ?? throw new InvalidOperationException("Shard is not served by this client."); await shard.GetWebSocketClient().SendMessageAsync(message).ConfigureAwait(false); } /// <summary> /// Throws an <see cref="ObjectDisposedException"/> if the <see /// cref="DiscordClientWrapper"/> is disposed. /// </summary> /// <exception cref="ObjectDisposedException">thrown if the instance is disposed</exception> private void EnsureNotDisposed() { if (_disposed) { throw new ObjectDisposedException(nameof(DiscordClientWrapper)); } } /// <inheritdoc/> /// <exception cref="ObjectDisposedException">thrown if the instance is disposed</exception> private Task OnVoiceServerUpdated(DiscordClient _, VoiceServerUpdateEventArgs voiceServer) { EnsureNotDisposed(); var args = new VoiceServer(voiceServer.Guild.Id, voiceServer.GetVoiceToken(), voiceServer.Endpoint); return VoiceServerUpdated.InvokeAsync(this, args); } /// <inheritdoc/> /// <exception cref="ObjectDisposedException">thrown if the instance is disposed</exception> private Task OnVoiceStateUpdated(DiscordClient _, global::DSharpPlus.EventArgs.VoiceStateUpdateEventArgs eventArgs) { EnsureNotDisposed(); // session id is the same as the resume key so DSharpPlus should be able to give us the // session key in either before or after voice state var sessionId = eventArgs.Before?.GetSessionId() ?? eventArgs.After.GetSessionId(); // create voice state var voiceState = new VoiceState( voiceChannelId: eventArgs.After?.Channel?.Id, guildId: eventArgs.Guild.Id, voiceSessionId: sessionId); // invoke event return VoiceStateUpdated.InvokeAsync(this, new Events.VoiceStateUpdateEventArgs(eventArgs.User.Id, voiceState)); } } }
Unterschied finden