Archived
1
0
Fork 0
This repository has been archived on 2024-05-21. You can view files and clone it, but cannot push or open issues or pull requests.
maki/Maki/Discord.cs
2017-05-18 00:33:09 +02:00

853 lines
30 KiB
C#

using Maki.Gateway;
using Maki.Rest;
using Maki.Structures.Auth;
using Maki.Structures.Channels;
using Maki.Structures.Gateway;
using Maki.Structures.Guilds;
using Maki.Structures.Messages;
using Maki.Structures.Presences;
using Maki.Structures.Roles;
using Maki.Structures.Users;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
namespace Maki
{
/// <summary>
/// Discord Client
/// </summary>
public class Discord : IDisposable
{
/// <summary>
/// Discord Gateway/API version we're targeting
/// </summary>
internal const int GATEWAY_VERSION = 6;
/// <summary>
/// Whether this client is a bot
/// </summary>
public bool IsBot => TokenType == DiscordTokenType.Bot;
/// <summary>
/// Token type, bot and user connections are handled differently
/// </summary>
public DiscordTokenType TokenType = DiscordTokenType.Bot;
/// <summary>
/// Discord token
/// </summary>
public string Token = string.Empty;
/// <summary>
/// Gateway Url
/// </summary>
internal string Gateway { get; private set; }
/// <summary>
/// Rest API request client
/// </summary>
internal readonly RestClient RestClient;
/// <summary>
/// Gateway shard client
/// </summary>
internal readonly GatewayShardClient ShardClient;
#region Containers
/// <summary>
/// Servers we're in
/// </summary>
internal readonly List<DiscordServer> servers = new List<DiscordServer>();
/// <summary>
/// Users we are affiliated with
/// </summary>
internal readonly List<DiscordUser> users = new List<DiscordUser>();
/// <summary>
/// Members of servers, different from users!
/// </summary>
internal readonly List<DiscordMember> members = new List<DiscordMember>();
/// <summary>
/// Roles in servers
/// </summary>
internal readonly List<DiscordRole> roles = new List<DiscordRole>();
/// <summary>
/// Channels
/// </summary>
internal readonly List<DiscordChannel> channels = new List<DiscordChannel>();
/// <summary>
/// Messages
/// </summary>
internal readonly List<DiscordMessage> messages = new List<DiscordMessage>();
#endregion
#region Events
/// <summary>
/// A channel has been created
/// </summary>
public event Action<DiscordChannel> OnChannelCreate;
/// <summary>
/// A channel has been updated
/// </summary>
public event Action<DiscordChannel> OnChannelUpdate;
/// <summary>
/// A channel has been deleted
/// </summary>
public event Action<DiscordChannel> OnChannelDelete;
/// <summary>
/// Someone has been banned from a server
/// </summary>
public event Action<DiscordUser, DiscordServer> OnBanAdd;
/// <summary>
/// Someone's ban has been lifted from a server
/// </summary>
public event Action<DiscordUser, DiscordServer> OnBanRemove;
/// <summary>
/// A server has been created
/// </summary>
public event Action<DiscordServer> OnServerCreate;
/// <summary>
/// A server has been updated
/// </summary>
public event Action<DiscordServer> OnServerUpdate;
/// <summary>
/// A server has been deleted
/// </summary>
public event Action<DiscordServer> OnServerDelete;
/// <summary>
/// A server's emoji set has been updated
/// </summary>
public event Action<DiscordServer> OnEmojisUpdate;
/// <summary>
/// Someone joined a server
/// </summary>
public event Action<DiscordMember> OnMemberAdd;
/// <summary>
/// A server member has been updated
/// </summary>
public event Action<DiscordMember> OnMemberUpdate;
/// <summary>
/// Someone left a server
/// </summary>
public event Action<DiscordMember> OnMemberRemove;
/// <summary>
/// A user role has been created in a server
/// </summary>
public event Action<DiscordRole> OnRoleCreate;
/// <summary>
/// A user role has been updated in a server
/// </summary>
public event Action<DiscordRole> OnRoleUpdate;
/// <summary>
/// A user role has been deleted in a server
/// </summary>
public event Action<DiscordRole> OnRoleDelete;
/// <summary>
/// A message has been received
/// </summary>
public event Action<DiscordMessage> OnMessageCreate;
/// <summary>
/// A message has been edited
/// </summary>
public event Action<DiscordMessage> OnMessageUpdate;
/// <summary>
/// A message has been deleted
/// </summary>
public event Action<DiscordMessage> OnMessageDelete;
/// <summary>
/// Someone started typing, fired again after 8 seconds
/// </summary>
public event Action<DiscordUser, DiscordChannel> OnTypingStart;
/// <summary>
/// Someone's status and/or game updated
/// </summary>
public event Action<DiscordMember> OnPresenceUpdate;
/// <summary>
/// Fired when the connection was successful and we're currently logged into Discord
/// </summary>
public event Action<DiscordUser> OnReady;
/// <summary>
/// Someone updated their account
/// </summary>
public event Action<DiscordUser> OnUserUpdate;
#endregion
public DiscordServer[] Servers => servers.ToArray();
public DiscordUser Me => users.FirstOrDefault();
/// <summary>
/// Constructor
/// </summary>
public Discord()
{
RestClient = new RestClient(this);
ShardClient = new GatewayShardClient(this);
ShardClient.OnChannelCreate += ShardManager_OnChannelCreate;
ShardClient.OnChannelUpdate += ShardManager_OnChannelUpdate;
ShardClient.OnChannelDelete += ShardManager_OnChannelDelete;
ShardClient.OnGuildBanAdd += ShardManager_OnGuildBanAdd;
ShardClient.OnGuildBanRemove += ShardManager_OnGuildBanRemove;
ShardClient.OnGuildCreate += ShardManager_OnGuildCreate;
ShardClient.OnGuildDelete += ShardManager_OnGuildDelete;
ShardClient.OnGuildUpdate += ShardManager_OnGuildUpdate;
ShardClient.OnGuildEmojisUpdate += ShardManager_OnGuildEmojisUpdate;
ShardClient.OnGuildMemberAdd += ShardManager_OnGuildMemberAdd;
ShardClient.OnGuildMemberUpdate += ShardManager_OnGuildMemberUpdate;
ShardClient.OnGuildMemberRemove += ShardManager_OnGuildMemberRemove;
ShardClient.OnGuildRoleCreate += ShardManager_OnGuildRoleCreate;
ShardClient.OnGuildRoleDelete += ShardManager_OnGuildRoleDelete;
ShardClient.OnGuildRoleUpdate += ShardManager_OnGuildRoleUpdate;
ShardClient.OnGuildIntegrationsUpdate += ShardManager_OnGuildIntegrationsUpdate;
ShardClient.OnGuildMembersChunk += ShardManager_OnGuildMembersChunk;
ShardClient.OnMessageCreate += ShardManager_OnMessageCreate;
ShardClient.OnMessageDelete += ShardManager_OnMessageDelete;
ShardClient.OnMessageUpdate += ShardManager_OnMessageUpdate;
ShardClient.OnTypingStart += ShardManager_OnTypingStart;
ShardClient.OnPresenceUpdate += ShardManager_OnPresenceUpdate;
ShardClient.OnReady += ShardManager_OnReady;
ShardClient.OnResumed += ShardManager_OnResumed;
ShardClient.OnUserUpdate += ShardManager_OnUserUpdate;
ShardClient.OnSocketOpen += ShardManager_OnSocketOpen;
ShardClient.OnSocketClose += ShardManager_OnSocketClose;
ShardClient.OnSocketError += ShardManager_OnSocketError;
ShardClient.OnSocketMessage += ShardManager_OnSocketMessage;
}
private void ClearContainers()
{
servers.Clear();
users.Clear();
roles.Clear();
channels.Clear();
messages.Clear();
members.Clear();
}
/// <summary>
/// Connects to Discord using the token assigned to Token
/// </summary>
public void Connect()
{
ClearContainers();
RestResponse<GatewayInfo> gateway = RestClient.Request<GatewayInfo>(
RestRequestMethod.GET,
IsBot ? RestEndpoints.GatewayBot : RestEndpoints.Gateway
);
if (gateway.ErrorCode != RestErrorCode.Ok)
throw new Exception($"{gateway.ErrorCode}: {gateway.ErrorMessage}");
Gateway = gateway.Response.Url;
if (Gateway.Contains("?"))
Gateway = Gateway.Substring(0, Gateway.IndexOf('?'));
if (!Gateway.EndsWith("/"))
Gateway += "/";
int shards = gateway.Response.Shards ?? 1;
for (int i = 0; i < shards; i++)
ShardClient.Create(i);
}
/// <summary>
/// Connects to Discord with the provided email, password and, optionally, mfa token
/// </summary>
/// <param name="email">Discord account email</param>
/// <param name="password">Discord account password</param>
/// <param name="code">Multi factor authentication token</param>
public void Connect(string email, string password, string code = null)
{
TokenType = DiscordTokenType.User;
RestResponse<LoginResponse> login = RestClient.Request<LoginResponse>(
RestRequestMethod.POST,
RestEndpoints.AuthLogin,
new LoginRequest
{
Email = email,
Password = password,
}
);
if (login.ErrorCode != RestErrorCode.Ok)
throw new Exception($"{login.ErrorCode}: {login.ErrorMessage}");
if (login.Response.UsernameError?.Length > 0)
throw new Exception(login.Response.UsernameError.FirstOrDefault());
if (login.Response.PasswordError?.Length > 0)
throw new Exception(login.Response.PasswordError.FirstOrDefault());
Token = login.Response.Token;
if (string.IsNullOrEmpty(Token))
{
if (login.Response.MFA == true && !string.IsNullOrEmpty(login.Response.Ticket))
{
RestResponse<LoginResponse> totp = RestClient.Request<LoginResponse>(
RestRequestMethod.POST,
RestEndpoints.AuthMfaTotp,
new LoginMultiFactorAuth
{
Code = code,
Ticket = login.Response.Ticket,
}
);
if (totp.ErrorCode != RestErrorCode.Ok)
throw new Exception($"{totp.ErrorCode}: {totp.ErrorMessage}");
Token = totp.Response.Token;
}
else
throw new Exception("Token was null but MFA is false and/or ticket is empty?");
}
if (string.IsNullOrEmpty(Token))
throw new Exception("Authentication failed!");
Connect();
}
/// <summary>
/// Connects to Discord using a provided token and token type
/// </summary>
/// <param name="token"></param>
/// <param name="type"></param>
public void Connect(string token, DiscordTokenType type = DiscordTokenType.Bot)
{
TokenType = type;
Token = token;
Connect();
}
/// <summary>
/// Disconnects from Discord, use Dispose instead if you're not restarting the connection
/// </summary>
public void Disconnect()
{
ShardClient.Disconnect();
ClearContainers();
Token = string.Empty;
Gateway = string.Empty;
}
private void ShardManager_OnChannelCreate(GatewayShard shard, Channel channel)
{
DiscordServer server = servers.Find(x => x.Id == channel.GuildId);
DiscordChannel chan = new DiscordChannel(this, channel, server);
channels.Add(chan);
OnChannelCreate?.Invoke(chan);
}
private void ShardManager_OnChannelUpdate(GatewayShard shard, Channel channel)
{
DiscordChannel chan = channels.Find(x => x.Id == channel.Id);
chan.Name = channel.Name;
if (chan.Type == DiscordChannelType.Private)
{
// update recipients
} else
{
// update permissions too
chan.Position = channel.Position ?? 0;
}
if (chan.Type == DiscordChannelType.Voice)
{
chan.Bitrate = channel.Bitrate ?? 0;
chan.UserLimit = channel.UserLimit ?? 0;
} else
{
chan.Topic = channel.Topic;
chan.LastMessageId = channel.LastMessageId ?? 0;
}
OnChannelUpdate?.Invoke(chan);
}
private void ShardManager_OnChannelDelete(GatewayShard shard, Channel channel)
{
DiscordChannel chan = channels.Find(x => x.Id == channel.Id);
channels.Remove(chan);
OnChannelDelete?.Invoke(chan);
}
private void ShardManager_OnGuildBanAdd(GatewayShard shard, User sUser)
{
/*$"Id: {user.Id}",
$"Guild Id: {user.GuildId}",
$"Username: {user.Username}",
$"Tag: {user.Tag:0000}",
$"Avatar Hash: {user.AvatarHash}",
$"Is bot?: {user.IsBot}",
$"Has MFA?: {user.HasMFA}",
$"Is verified?: {user.IsVerified}",
$"E-mail: {user.EMail}"*/
DiscordUser user = users.Find(x => x.Id == sUser.Id);
DiscordServer server = servers.Find(x => x.Id == sUser.GuildId);
OnBanAdd?.Invoke(user, server);
}
private void ShardManager_OnGuildBanRemove(GatewayShard shard, User sUser)
{
/*$"Id: {user.Id}",
$"Guild Id: {user.GuildId}",
$"Username: {user.Username}",
$"Tag: {user.Tag:0000}",
$"Avatar Hash: {user.AvatarHash}",
$"Is bot?: {user.IsBot}",
$"Has MFA?: {user.HasMFA}",
$"Is verified?: {user.IsVerified}",
$"E-mail: {user.EMail}"*/
DiscordUser user = users.Find(x => x.Id == sUser.Id);
DiscordServer server = servers.Find(x => x.Id == sUser.GuildId);
OnBanRemove?.Invoke(user, server);
}
private void ShardManager_OnGuildCreate(GatewayShard shard, Guild guild)
{
DiscordServer server = servers.Where(x => x.Id == guild.Id).FirstOrDefault();
if (server == default(DiscordServer))
{
server = new DiscordServer(this, guild);
servers.Add(server);
}
else
{
server = servers.Find(x => x.Id == guild.Id);
server.Name = guild.Name;
}
if (guild.Channels != null)
for (int i = 0; i < guild.Channels.Length; i++)
{
Channel channel = guild.Channels[i];
channel.GuildId = server.Id;
if (channels.Where(x => x.Id == channel.Id).Count() > 0)
ShardManager_OnChannelUpdate(shard, channel);
else
ShardManager_OnChannelCreate(shard, channel);
}
if (guild.Roles != null)
foreach (Role role in guild.Roles) {
GuildRole gRole = new GuildRole
{
Guild = server.Id,
Role = role,
RoleId = role.Id
};
if (roles.Where(x => x.Id == role.Id).Count() > 0)
ShardManager_OnGuildRoleUpdate(shard, gRole);
else
ShardManager_OnGuildRoleCreate(shard, gRole);
}
shard.Send(GatewayOPCode.RequestGuildMembers, new GatewayRequestGuildMembers {
Guild = server.Id,
Query = string.Empty,
Limit = 0,
});
OnServerCreate?.Invoke(server);
}
private void ShardManager_OnGuildDelete(GatewayShard shard, Guild guild)
{
DiscordServer server = servers.Find(x => x.Id == guild.Id);
server.Name = guild.Name;
/*server.OwnerId = guild.OwnerId;
server.VoiceRegionId = guild.VoiceRegionId;
server.AfkChannelId = guild.AfkChannelId;
server.AfkTimeout = guild.AfkTimeout;
server.EmbedEnabled = guild.EmbedEnabled;
server.EmbedChannelId = guild.EmbedChannelId;
server.VerificationLevel = guild.VerificationLevel;
server.MessageNotificationLevel = guild.MessageNotificationLevel;
server.Roles = guild.Roles;
server.Emojis = guild.Emojis;
server.Features = guild.Features;
server.MultiFactorAuthLevel = guild.MultiFactorAuthLevel;*/
OnServerDelete?.Invoke(server);
messages.Where(x => x.Channel.Server == server).ToList().ForEach(x => messages.Remove(x));
channels.Where(x => x.Server == server).ToList().ForEach(x => channels.Remove(x));
members.Where(x => x.Server == server).ToList().ForEach(x => members.Remove(x));
roles.Where(x => x.Server == server).ToList().ForEach(x => roles.Remove(x));
servers.Remove(server);
}
private void ShardManager_OnGuildUpdate(GatewayShard shard, Guild guild)
{
DiscordServer server = servers.Find(x => x.Id == guild.Id);
server.Name = guild.Name;
/*server.OwnerId = guild.OwnerId;
server.VoiceRegionId = guild.VoiceRegionId;
server.AfkChannelId = guild.AfkChannelId;
server.AfkTimeout = guild.AfkTimeout;
server.EmbedEnabled = guild.EmbedEnabled;
server.EmbedChannelId = guild.EmbedChannelId;
server.VerificationLevel = guild.VerificationLevel;
server.MessageNotificationLevel = guild.MessageNotificationLevel;
server.Roles = guild.Roles;
server.Emojis = guild.Emojis;
server.Features = guild.Features;
server.MultiFactorAuthLevel = guild.MultiFactorAuthLevel;*/
OnServerUpdate?.Invoke(server);
}
private void ShardManager_OnGuildEmojisUpdate(GatewayShard shard, Guild guild)
{
DiscordServer server = servers.Find(x => x.Id == guild.Id);
//servers.Emojis = guild.Emojis;
OnEmojisUpdate?.Invoke(server);
}
private void ShardManager_OnGuildMemberAdd(GatewayShard shard, GuildMember sMember)
{
DiscordServer server = servers.Find(x => x.Id == sMember.GuildId);
DiscordUser user = users.Where(x => x.Id == sMember.User.Id).FirstOrDefault();
if (user == default(DiscordUser))
{
user = new DiscordUser(this, sMember.User);
users.Add(user);
}
DiscordMember member = new DiscordMember(this, sMember, user, server);
members.Add(member);
OnMemberAdd?.Invoke(member);
}
private void ShardManager_OnGuildMemberUpdate(GatewayShard shard, GuildMember sMember)
{
DiscordMember member = members.Find(x => x.User.Id == sMember.User.Id && x.Server.Id == sMember.GuildId);
member.Nickname = sMember.Nickname;
member.IsDeaf = sMember.IsDeafened == true;
member.IsMute = sMember.IsMuted == true;
member.roles = new List<ulong>(sMember.Roles);
OnMemberUpdate?.Invoke(member);
}
private void ShardManager_OnGuildMemberRemove(GatewayShard shard, GuildMember sMember)
{
DiscordMember member = members.Find(x => x.User.Id == sMember.User.Id && x.Server.Id == sMember.GuildId);
members.Remove(member);
OnMemberRemove?.Invoke(member);
}
private void ShardManager_OnGuildRoleCreate(GatewayShard shard, GuildRole sRole)
{
/*$"Guild Id: {role.Guild}",
$"Id: {role.Role.Value.Id}",
$"Name: {role.Role.Value.Name}",
$"Colour: {role.Role.Value.Colour}",
$"Is Hoisted?: {role.Role.Value.IsHoisted}",
$"Position: {role.Role.Value.Position}",
$"Is Managed?: {role.Role.Value.IsManaged}",
$"Is Mentionable?: {role.Role.Value.IsMentionable}",
$"Permissions: {role.Role.Value.Permissions}"*/
DiscordServer server = servers.Find(x => x.Id == sRole.Guild);
DiscordRole role = roles.Where(x => x.Id == sRole.Role.Value.Id).FirstOrDefault();
if (role == default(DiscordRole))
{
role = new DiscordRole(this, sRole.Role.Value, server);
roles.Add(role);
} else
{
role.Colour.Raw = sRole.Role.Value.Colour.Value;
}
OnRoleCreate?.Invoke(role);
}
private void ShardManager_OnGuildRoleDelete(GatewayShard shard, GuildRole sRole)
{
DiscordRole role = roles.Find(x => x.Id == sRole.RoleId && x.Server.Id == sRole.Guild);
members.Where(x => x.roles.Contains(role.Id)).ToList().ForEach(x => x.roles.RemoveAll(y => y == role.Id));
roles.Remove(role);
OnRoleDelete?.Invoke(role);
}
private void ShardManager_OnGuildRoleUpdate(GatewayShard shard, GuildRole sRole)
{
Role dRole = sRole.Role.Value;
DiscordRole role = roles.Find(x => x.Id == dRole.Id && x.Server.Id == sRole.Guild);
role.Name = dRole.Name;
OnRoleUpdate?.Invoke(role);
}
private void ShardManager_OnGuildIntegrationsUpdate(GatewayShard shard, GuildIntegration integration)
{
/*$"Id: {integration.Id}",
$"Name: {integration.Name}",
$"Type: {integration.Type}",
$"Is Enabled?: {integration.IsEnabled}",
$"Is Syncing?: {integration.IsSyncing}",
$"Role Id: {integration.RoleId}",
$"Expire Behaviour: {integration.ExpireBehaviour}",
$"Expire Grace Period: {integration.ExpireGracePeriod}",
$"User: {integration.User.Id}",
$"Account: {integration.Account.Id}, {integration.Account.Name}",
$"Last Sync: {integration.LastSync}"*/
}
private void ShardManager_OnGuildMembersChunk(GatewayShard shard, GuildMembersChunk membersChunk)
{
for (int i = 0; i < membersChunk.Members.Length; i++)
{
GuildMember member = membersChunk.Members[i];
member.GuildId = membersChunk.Guild;
ShardManager_OnGuildMemberAdd(shard, member);
}
}
private void ShardManager_OnMessageCreate(GatewayShard shard, Message message)
{
DiscordChannel channel = channels.Find(x => x.Id == message.ChannelId);
DiscordMember member = members.Find(x => x.User.Id == message.User.Id);
DiscordMessage msg = new DiscordMessage(this, message, member, channel);
messages.Add(msg);
OnMessageCreate?.Invoke(msg);
}
private void ShardManager_OnMessageDelete(GatewayShard shard, Message message)
{
DiscordMessage msg = messages.Find(x => x.Id == message.Id);
messages.Remove(msg);
OnMessageDelete?.Invoke(msg);
}
private void ShardManager_OnMessageUpdate(GatewayShard shard, Message message)
{
DiscordMessage msg = messages.Where(x => x.Id == message.Id).FirstOrDefault();
if (msg == null)
{
RestResponse<Message> getMsg = RestClient.Request<Message>(RestRequestMethod.GET, RestEndpoints.ChannelMessage(message.ChannelId, message.Id));
DiscordChannel channel = channels.Where(x => x.Id == getMsg.Response.ChannelId).FirstOrDefault();
DiscordMember member = members.Where(x => x.User.Id == getMsg.Response.User.Id && (channel.Server == null || channel.Server == x.Server)).FirstOrDefault();
msg = new DiscordMessage(this, getMsg.Response, member, channel);
messages.Add(msg);
}
msg.Edited = DateTime.Now;
if (!string.IsNullOrEmpty(message.Content))
msg.Text = message.Content;
msg.IsPinned = message.IsPinned == true;
OnMessageUpdate?.Invoke(msg);
}
private void ShardManager_OnTypingStart(GatewayShard shard, TypingStart typing)
{
DiscordChannel channel = channels.Find(x => x.Id == typing.Channel);
DiscordUser user = users.Find(x => x.Id == typing.User);
OnTypingStart?.Invoke(user, channel);
}
private void ShardManager_OnPresenceUpdate(GatewayShard shard, Presence presence)
{
DiscordMember member = members.Find(x => x.User.Id == presence.User.Id && x.Server.Id == presence.Guild);
member.User.Game = presence.Game.HasValue ? new DiscordGame(presence.Game.Value) : null;
if (presence.Roles != null)
member.roles = new List<ulong>(presence.Roles);
switch (presence.Status.ToLower())
{
case @"online":
member.User.Status = DiscordUserStatus.Online;
break;
case @"away":
member.User.Status = DiscordUserStatus.Away;
break;
case @"dnd":
member.User.Status = DiscordUserStatus.DoNotDisturb;
break;
case @"offline":
default:
member.User.Status = DiscordUserStatus.Offline;
break;
}
OnPresenceUpdate?.Invoke(member);
}
private void ShardManager_OnReady(GatewayShard shard, GatewayReady ready)
{
foreach (Channel chan in ready.PrivateChannels)
{
DiscordChannel channel = new DiscordChannel(this, chan);
// this shouldn't ever happen but just in case
if (channels.Where(x => x.Id == channel.Id).Count() > 0)
continue;
channels.Add(channel);
}
foreach (Guild guild in ready.UnavailableGuilds)
{
DiscordServer server = new DiscordServer(this, guild);
if (servers.Where(x => x.Id == server.Id).Count() > 0)
continue;
servers.Add(server);
}
DiscordUser user = new DiscordUser(this, ready.User);
users.Add(user);
OnReady?.Invoke(user);
}
private void ShardManager_OnResumed(GatewayShard shard)
{
OnReady?.Invoke(Me);
}
private void ShardManager_OnUserUpdate(GatewayShard shard, User sUser)
{
/*$"Id: {user.Id}",
$"Guild Id: {user.GuildId}",
$"Username: {user.Username}",
$"Tag: {user.Tag:0000}",
$"Avatar Hash: {user.AvatarHash}",
$"Is bot?: {user.IsBot}",
$"Has MFA?: {user.HasMFA}",
$"Is verified?: {user.IsVerified}",
$"E-mail: {user.EMail}"*/
DiscordUser user = users.Where(x => x.Id == sUser.Id).FirstOrDefault();
if (user == default(DiscordUser))
{
user = new DiscordUser(this, sUser);
users.Add(user);
}
OnUserUpdate?.Invoke(user);
}
private void ShardManager_OnSocketOpen(GatewayShard shard)
{
//MultiLineWrite($"Connection opened on shard {shard.Id}");
}
private void ShardManager_OnSocketClose(GatewayShard shard, bool wasClean, ushort code, string reason)
{
//MultiLineWrite($"Connection closed on shard {shard.Id} ({wasClean}/{code}/{reason})");
}
private void ShardManager_OnSocketError(GatewayShard shard, Exception ex)
{
//MultiLineWrite($"Socket error on shard {shard.Id}", ex.Message);
}
private void ShardManager_OnSocketMessage(GatewayShard shard, string text)
{
if (!Directory.Exists("Json"))
Directory.CreateDirectory("Json");
File.WriteAllText(
$"Json/{DateTime.Now:yyyy-MM-dd HH-mm-ss.fffffff}.json",
JsonConvert.SerializeObject(
JsonConvert.DeserializeObject(text),
Formatting.Indented
)
);
}
#region IDisposable
private bool isDisposed = false;
private void Dispose(bool disposing)
{
if (!isDisposed) {
isDisposed = true;
Disconnect();
}
}
~Discord()
{
Dispose(false);
}
/// <summary>
/// Disconnects and releases all unmanaged objects
/// </summary>
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(true);
}
#endregion
}
}