use managers rather than random lists
This commit is contained in:
parent
82a74a3e63
commit
ca02bba839
64
Maki/BaseManager.cs
Normal file
64
Maki/BaseManager.cs
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace Maki
|
||||||
|
{
|
||||||
|
internal abstract class BaseManager<T> : IDisposable
|
||||||
|
{
|
||||||
|
protected readonly HashSet<T> Collection = new HashSet<T>();
|
||||||
|
public IEnumerable<T> Items => Collection;
|
||||||
|
public int Count => Collection.Count;
|
||||||
|
|
||||||
|
public event Action<T> OnAdd;
|
||||||
|
public event Action<T> OnRemove;
|
||||||
|
|
||||||
|
protected virtual bool DisposeOnRemove => true;
|
||||||
|
|
||||||
|
protected bool IsDisposed = false;
|
||||||
|
|
||||||
|
~BaseManager()
|
||||||
|
=> Dispose(false);
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
Dispose(true);
|
||||||
|
GC.SuppressFinalize(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void Dispose(bool disposing)
|
||||||
|
{
|
||||||
|
if (IsDisposed)
|
||||||
|
return;
|
||||||
|
|
||||||
|
IsDisposed = true;
|
||||||
|
Collection.ToList().ForEach(x => Remove(x));
|
||||||
|
Collection.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual void Add(T item)
|
||||||
|
{
|
||||||
|
if (item == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
lock (Collection)
|
||||||
|
Collection.Add(item);
|
||||||
|
|
||||||
|
OnAdd?.Invoke(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual void Remove(T item)
|
||||||
|
{
|
||||||
|
if (item == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
lock (Collection)
|
||||||
|
Collection.Remove(item);
|
||||||
|
|
||||||
|
OnRemove?.Invoke(item);
|
||||||
|
|
||||||
|
if (DisposeOnRemove && item is IDisposable)
|
||||||
|
(item as IDisposable).Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
30
Maki/ChannelManager.cs
Normal file
30
Maki/ChannelManager.cs
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace Maki
|
||||||
|
{
|
||||||
|
internal sealed class ChannelManager : BaseManager<DiscordChannel>
|
||||||
|
{
|
||||||
|
internal ChannelManager()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public DiscordChannel Id(ulong id)
|
||||||
|
{
|
||||||
|
lock (Collection)
|
||||||
|
return Collection.Where(x => x.Id == id).FirstOrDefault();
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Exists(ulong id)
|
||||||
|
{
|
||||||
|
lock (Collection)
|
||||||
|
return Collection.Where(x => x.Id == id).Count() > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerable<DiscordChannel> Server(DiscordServer server)
|
||||||
|
{
|
||||||
|
lock (Collection)
|
||||||
|
return Collection.Where(x => x.Server == server).OrderBy(x => x.Position);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
361
Maki/Discord.cs
361
Maki/Discord.cs
|
@ -1,6 +1,5 @@
|
||||||
using Maki.Gateway;
|
using Maki.Gateway;
|
||||||
using Maki.Rest;
|
using Maki.Rest;
|
||||||
using Maki.Structures.Auth;
|
|
||||||
using Maki.Structures.Channels;
|
using Maki.Structures.Channels;
|
||||||
using Maki.Structures.Gateway;
|
using Maki.Structures.Gateway;
|
||||||
using Maki.Structures.Guilds;
|
using Maki.Structures.Guilds;
|
||||||
|
@ -10,6 +9,7 @@ using Maki.Structures.Roles;
|
||||||
using Maki.Structures.Users;
|
using Maki.Structures.Users;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
|
||||||
namespace Maki
|
namespace Maki
|
||||||
|
@ -64,35 +64,49 @@ namespace Maki
|
||||||
internal readonly GatewayShardClient ShardClient;
|
internal readonly GatewayShardClient ShardClient;
|
||||||
|
|
||||||
#region Containers
|
#region Containers
|
||||||
|
|
||||||
|
internal readonly ServerManager ServerManager;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Servers we're in
|
/// Servers we're in
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal readonly List<DiscordServer> servers = new List<DiscordServer>();
|
public IEnumerable<DiscordServer> Servers => ServerManager.Items;
|
||||||
|
|
||||||
|
internal readonly UserManager UserManager;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Users we are affiliated with
|
/// Users we are affiliated with
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal readonly List<DiscordUser> users = new List<DiscordUser>();
|
public IEnumerable<DiscordUser> Users => UserManager.Items;
|
||||||
|
|
||||||
|
internal readonly MemberManager MemberManager;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Members of servers, different from users!
|
/// Members of servers, different from users!
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal readonly List<DiscordMember> members = new List<DiscordMember>();
|
public IEnumerable<DiscordMember> Members => MemberManager.Items;
|
||||||
|
|
||||||
|
internal readonly RoleManager RoleManager;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Roles in servers
|
/// Roles in servers
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal readonly List<DiscordRole> roles = new List<DiscordRole>();
|
public IEnumerable<DiscordRole> Roles => RoleManager.Items;
|
||||||
|
|
||||||
|
internal readonly ChannelManager ChannelManager;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Channels
|
/// Channels
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal readonly List<DiscordChannel> channels = new List<DiscordChannel>();
|
public IEnumerable<DiscordChannel> Channels => ChannelManager.Items;
|
||||||
|
|
||||||
|
internal readonly MessageManager MessageManager;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Messages
|
/// Messages
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal readonly List<DiscordMessage> messages = new List<DiscordMessage>();
|
public IEnumerable<DiscordMessage> Messages => MessageManager.Items;
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Events
|
#region Events
|
||||||
|
@ -207,8 +221,7 @@ namespace Maki
|
||||||
public event Action<DiscordUser> OnUserUpdate;
|
public event Action<DiscordUser> OnUserUpdate;
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
public DiscordServer[] Servers => servers.ToArray();
|
public DiscordUser Me => UserManager.Items.FirstOrDefault();
|
||||||
public DiscordUser Me => users.FirstOrDefault();
|
|
||||||
|
|
||||||
private DiscordParams Params;
|
private DiscordParams Params;
|
||||||
|
|
||||||
|
@ -220,6 +233,13 @@ namespace Maki
|
||||||
Params = parameters ?? new DiscordParams();
|
Params = parameters ?? new DiscordParams();
|
||||||
ShardClient = new GatewayShardClient(this);
|
ShardClient = new GatewayShardClient(this);
|
||||||
|
|
||||||
|
UserManager = new UserManager();
|
||||||
|
RoleManager = new RoleManager();
|
||||||
|
MemberManager = new MemberManager();
|
||||||
|
ChannelManager = new ChannelManager();
|
||||||
|
MessageManager = new MessageManager();
|
||||||
|
ServerManager = new ServerManager();
|
||||||
|
|
||||||
#region Assigning event handlers
|
#region Assigning event handlers
|
||||||
ShardClient.OnChannelCreate += ShardManager_OnChannelCreate;
|
ShardClient.OnChannelCreate += ShardManager_OnChannelCreate;
|
||||||
ShardClient.OnChannelUpdate += ShardManager_OnChannelUpdate;
|
ShardClient.OnChannelUpdate += ShardManager_OnChannelUpdate;
|
||||||
|
@ -259,23 +279,11 @@ namespace Maki
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ClearContainers()
|
|
||||||
{
|
|
||||||
servers.Clear();
|
|
||||||
users.Clear();
|
|
||||||
roles.Clear();
|
|
||||||
channels.Clear();
|
|
||||||
messages.Clear();
|
|
||||||
members.Clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Connects to Discord using the token assigned to Token
|
/// Connects to Discord using the token assigned to Token
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void Connect()
|
public void Connect()
|
||||||
{
|
{
|
||||||
ClearContainers();
|
|
||||||
|
|
||||||
int shards = 1;
|
int shards = 1;
|
||||||
|
|
||||||
using (WebRequest wr = new WebRequest(HttpMethod.GET, IsBot ? RestEndpoints.GatewayBot : RestEndpoints.Gateway))
|
using (WebRequest wr = new WebRequest(HttpMethod.GET, IsBot ? RestEndpoints.GatewayBot : RestEndpoints.Gateway))
|
||||||
|
@ -303,76 +311,6 @@ namespace Maki
|
||||||
ShardClient.Create(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)
|
|
||||||
{
|
|
||||||
// TODO: not tested with new request backend yet
|
|
||||||
|
|
||||||
TokenType = DiscordTokenType.User;
|
|
||||||
LoginResponse login;
|
|
||||||
|
|
||||||
using (WebRequest wr = new WebRequest(HttpMethod.POST, RestEndpoints.AuthLogin))
|
|
||||||
{
|
|
||||||
wr.AddJson(new LoginRequest
|
|
||||||
{
|
|
||||||
Email = email,
|
|
||||||
Password = password,
|
|
||||||
});
|
|
||||||
wr.Perform();
|
|
||||||
|
|
||||||
if (wr.Response.Length < 1)
|
|
||||||
throw new DiscordException("Login failed");
|
|
||||||
|
|
||||||
login = wr.ResponseJson<LoginResponse>();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (login.UsernameError?.Length > 0)
|
|
||||||
throw new DiscordException(login.UsernameError.FirstOrDefault());
|
|
||||||
|
|
||||||
if (login.PasswordError?.Length > 0)
|
|
||||||
throw new DiscordException(login.PasswordError.FirstOrDefault());
|
|
||||||
|
|
||||||
Token = login.Token;
|
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(Token))
|
|
||||||
{
|
|
||||||
if (login.MFA == true && !string.IsNullOrEmpty(login.Ticket))
|
|
||||||
{
|
|
||||||
using (WebRequest wr = new WebRequest(HttpMethod.POST, RestEndpoints.AuthMfaTotp))
|
|
||||||
{
|
|
||||||
wr.AddJson(new LoginMultiFactorAuth
|
|
||||||
{
|
|
||||||
Code = code,
|
|
||||||
Ticket = login.Ticket,
|
|
||||||
});
|
|
||||||
wr.Perform();
|
|
||||||
|
|
||||||
if (wr.Response.Length < 1)
|
|
||||||
throw new DiscordException("Multi factor auth failed");
|
|
||||||
|
|
||||||
login = wr.ResponseJson<LoginResponse>();
|
|
||||||
}
|
|
||||||
|
|
||||||
//if (totp.ErrorCode != RestErrorCode.Ok)
|
|
||||||
// throw new DiscordException($"{totp.ErrorCode}: {totp.ErrorMessage}");
|
|
||||||
|
|
||||||
Token = login.Token;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
throw new DiscordException("Token was null but MFA is false and/or ticket is empty?");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(Token))
|
|
||||||
throw new DiscordException("Authentication failed");
|
|
||||||
|
|
||||||
Connect();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Connects to Discord using a provided token and token type
|
/// Connects to Discord using a provided token and token type
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -391,23 +329,27 @@ namespace Maki
|
||||||
public void Disconnect()
|
public void Disconnect()
|
||||||
{
|
{
|
||||||
ShardClient.Disconnect();
|
ShardClient.Disconnect();
|
||||||
ClearContainers();
|
|
||||||
Token = string.Empty;
|
Token = string.Empty;
|
||||||
Gateway = string.Empty;
|
Gateway = string.Empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
#region Event Handlers
|
#region Event Handlers
|
||||||
|
|
||||||
private void ShardManager_OnChannelCreate(GatewayShard shard, Channel channel)
|
private void ShardManager_OnChannelCreate(GatewayShard shard, Channel channel)
|
||||||
{
|
{
|
||||||
DiscordServer server = servers.Find(x => x.Id == channel.GuildId);
|
Debug.Assert(channel.GuildId.HasValue, "Guild ID does not have a value?");
|
||||||
|
DiscordServer server = ServerManager.Id(channel.GuildId ?? 0);
|
||||||
|
Debug.Assert(server != null, "Target guild/server was not present in ServerManager");
|
||||||
|
|
||||||
DiscordChannel chan = new DiscordChannel(this, channel, server);
|
DiscordChannel chan = new DiscordChannel(this, channel, server);
|
||||||
channels.Add(chan);
|
ChannelManager.Add(chan);
|
||||||
OnChannelCreate?.Invoke(chan);
|
OnChannelCreate?.Invoke(chan);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ShardManager_OnChannelUpdate(GatewayShard shard, Channel channel)
|
private void ShardManager_OnChannelUpdate(GatewayShard shard, Channel channel)
|
||||||
{
|
{
|
||||||
DiscordChannel chan = channels.Find(x => x.Id == channel.Id);
|
DiscordChannel chan = ChannelManager.Id(channel.Id);
|
||||||
|
Debug.Assert(chan != null, "channel is null");
|
||||||
|
|
||||||
chan.Name = channel.Name;
|
chan.Name = channel.Name;
|
||||||
|
|
||||||
|
@ -435,8 +377,10 @@ namespace Maki
|
||||||
|
|
||||||
private void ShardManager_OnChannelDelete(GatewayShard shard, Channel channel)
|
private void ShardManager_OnChannelDelete(GatewayShard shard, Channel channel)
|
||||||
{
|
{
|
||||||
DiscordChannel chan = channels.Find(x => x.Id == channel.Id);
|
DiscordChannel chan = ChannelManager.Id(channel.Id);
|
||||||
channels.Remove(chan);
|
Debug.Assert(chan != null, "channel is null");
|
||||||
|
|
||||||
|
ChannelManager.Remove(chan);
|
||||||
OnChannelDelete?.Invoke(chan);
|
OnChannelDelete?.Invoke(chan);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -452,9 +396,15 @@ namespace Maki
|
||||||
$"Is verified?: {user.IsVerified}",
|
$"Is verified?: {user.IsVerified}",
|
||||||
$"E-mail: {user.EMail}"*/
|
$"E-mail: {user.EMail}"*/
|
||||||
|
|
||||||
DiscordUser user = users.Find(x => x.Id == sUser.Id);
|
DiscordUser user = UserManager.Id(sUser.Id);
|
||||||
DiscordServer server = servers.Find(x => x.Id == sUser.GuildId);
|
Debug.Assert(user != null, "user is null");
|
||||||
|
|
||||||
|
Debug.Assert(sUser.GuildId.HasValue, "Guild ID does not have a value.");
|
||||||
|
DiscordServer server = ServerManager.Id(sUser.GuildId ?? 0);
|
||||||
|
|
||||||
|
Debug.Assert(user != null, "user is null");
|
||||||
|
Debug.Assert(server != null, "server is null");
|
||||||
|
|
||||||
OnBanAdd?.Invoke(user, server);
|
OnBanAdd?.Invoke(user, server);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -470,24 +420,28 @@ namespace Maki
|
||||||
$"Is verified?: {user.IsVerified}",
|
$"Is verified?: {user.IsVerified}",
|
||||||
$"E-mail: {user.EMail}"*/
|
$"E-mail: {user.EMail}"*/
|
||||||
|
|
||||||
DiscordUser user = users.Find(x => x.Id == sUser.Id);
|
DiscordUser user = UserManager.Id(sUser.Id);
|
||||||
DiscordServer server = servers.Find(x => x.Id == sUser.GuildId);
|
Debug.Assert(user != null, "user is null");
|
||||||
|
|
||||||
|
DiscordServer server = ServerManager.Id(sUser.GuildId ?? 0);
|
||||||
|
|
||||||
|
Debug.Assert(user != null, "user is null");
|
||||||
|
Debug.Assert(server != null, "server is null");
|
||||||
|
|
||||||
OnBanRemove?.Invoke(user, server);
|
OnBanRemove?.Invoke(user, server);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ShardManager_OnGuildCreate(GatewayShard shard, Guild guild)
|
private void ShardManager_OnGuildCreate(GatewayShard shard, Guild guild)
|
||||||
{
|
{
|
||||||
DiscordServer server = servers.Where(x => x.Id == guild.Id).FirstOrDefault();
|
DiscordServer server = ServerManager.Id(guild.Id);
|
||||||
|
|
||||||
if (server == default(DiscordServer))
|
if (server == null)
|
||||||
{
|
{
|
||||||
server = new DiscordServer(this, guild);
|
server = new DiscordServer(this, guild);
|
||||||
servers.Add(server);
|
ServerManager.Add(server);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
server = servers.Find(x => x.Id == guild.Id);
|
|
||||||
server.Name = guild.Name;
|
server.Name = guild.Name;
|
||||||
server.OwnerId = guild.OwnerId ?? 0;
|
server.OwnerId = guild.OwnerId ?? 0;
|
||||||
server.IconHash = guild.IconHash;
|
server.IconHash = guild.IconHash;
|
||||||
|
@ -500,7 +454,7 @@ namespace Maki
|
||||||
Channel channel = guild.Channels[i];
|
Channel channel = guild.Channels[i];
|
||||||
channel.GuildId = server.Id;
|
channel.GuildId = server.Id;
|
||||||
|
|
||||||
if (channels.Where(x => x.Id == channel.Id).Count() > 0)
|
if (ChannelManager.Exists(channel.Id))
|
||||||
ShardManager_OnChannelUpdate(shard, channel);
|
ShardManager_OnChannelUpdate(shard, channel);
|
||||||
else
|
else
|
||||||
ShardManager_OnChannelCreate(shard, channel);
|
ShardManager_OnChannelCreate(shard, channel);
|
||||||
|
@ -515,7 +469,7 @@ namespace Maki
|
||||||
RoleId = role.Id
|
RoleId = role.Id
|
||||||
};
|
};
|
||||||
|
|
||||||
if (roles.Where(x => x.Id == role.Id).Count() > 0)
|
if (RoleManager.Exists(role.Id))
|
||||||
ShardManager_OnGuildRoleUpdate(shard, gRole);
|
ShardManager_OnGuildRoleUpdate(shard, gRole);
|
||||||
else
|
else
|
||||||
ShardManager_OnGuildRoleCreate(shard, gRole);
|
ShardManager_OnGuildRoleCreate(shard, gRole);
|
||||||
|
@ -532,7 +486,8 @@ namespace Maki
|
||||||
|
|
||||||
private void ShardManager_OnGuildDelete(GatewayShard shard, Guild guild)
|
private void ShardManager_OnGuildDelete(GatewayShard shard, Guild guild)
|
||||||
{
|
{
|
||||||
DiscordServer server = servers.Find(x => x.Id == guild.Id);
|
DiscordServer server = ServerManager.Id(guild.Id);
|
||||||
|
Debug.Assert(server != null, "server is null");
|
||||||
|
|
||||||
server.Name = guild.Name;
|
server.Name = guild.Name;
|
||||||
server.OwnerId = guild.OwnerId ?? 0;
|
server.OwnerId = guild.OwnerId ?? 0;
|
||||||
|
@ -549,16 +504,20 @@ namespace Maki
|
||||||
server.MultiFactorAuthLevel = guild.MultiFactorAuthLevel;*/
|
server.MultiFactorAuthLevel = guild.MultiFactorAuthLevel;*/
|
||||||
|
|
||||||
OnServerDelete?.Invoke(server);
|
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));
|
// NOT THREAD SAFE AT ALL
|
||||||
members.Where(x => x.Server == server).ToList().ForEach(x => members.Remove(x));
|
MessageManager .Server(server).ToList().ForEach(x => MessageManager.Remove(x));
|
||||||
roles.Where(x => x.Server == server).ToList().ForEach(x => roles.Remove(x));
|
ChannelManager .Server(server).ToList().ForEach(x => ChannelManager.Remove(x));
|
||||||
servers.Remove(server);
|
MemberManager .Server(server).ToList().ForEach(x => MemberManager.Remove(x));
|
||||||
|
RoleManager .Server(server).ToList().ForEach(x => RoleManager.Remove(x));
|
||||||
|
|
||||||
|
ServerManager.Remove(server);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ShardManager_OnGuildUpdate(GatewayShard shard, Guild guild)
|
private void ShardManager_OnGuildUpdate(GatewayShard shard, Guild guild)
|
||||||
{
|
{
|
||||||
DiscordServer server = servers.Find(x => x.Id == guild.Id);
|
DiscordServer server = ServerManager.Id(guild.Id);
|
||||||
|
Debug.Assert(server != null, "server is null");
|
||||||
|
|
||||||
server.Name = guild.Name;
|
server.Name = guild.Name;
|
||||||
server.OwnerId = guild.OwnerId ?? 0;
|
server.OwnerId = guild.OwnerId ?? 0;
|
||||||
|
@ -580,31 +539,41 @@ namespace Maki
|
||||||
|
|
||||||
private void ShardManager_OnGuildEmojisUpdate(GatewayShard shard, Guild guild)
|
private void ShardManager_OnGuildEmojisUpdate(GatewayShard shard, Guild guild)
|
||||||
{
|
{
|
||||||
DiscordServer server = servers.Find(x => x.Id == guild.Id);
|
DiscordServer server = ServerManager.Id(guild.Id);
|
||||||
|
Debug.Assert(server != null, "server is null");
|
||||||
|
|
||||||
//servers.Emojis = guild.Emojis;
|
//servers.Emojis = guild.Emojis;
|
||||||
OnEmojisUpdate?.Invoke(server);
|
OnEmojisUpdate?.Invoke(server);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ShardManager_OnGuildMemberAdd(GatewayShard shard, GuildMember sMember)
|
private void ShardManager_OnGuildMemberAdd(GatewayShard shard, GuildMember sMember)
|
||||||
{
|
{
|
||||||
DiscordServer server = servers.Find(x => x.Id == sMember.GuildId);
|
Debug.Assert(sMember.GuildId.HasValue, "GuildId has no value");
|
||||||
DiscordUser user = users.Where(x => x.Id == sMember.User.Id).FirstOrDefault();
|
|
||||||
|
|
||||||
if (user == default(DiscordUser))
|
DiscordServer server = ServerManager.Id(sMember.GuildId ?? 0);
|
||||||
|
Debug.Assert(server != null, "server is null");
|
||||||
|
|
||||||
|
DiscordUser user = UserManager.Id(sMember.User.Id);
|
||||||
|
//Debug.Assert(user != null, "user is null");
|
||||||
|
|
||||||
|
if (user == null)
|
||||||
{
|
{
|
||||||
user = new DiscordUser(this, sMember.User);
|
user = new DiscordUser(this, sMember.User);
|
||||||
users.Add(user);
|
UserManager.Add(user);
|
||||||
}
|
}
|
||||||
|
|
||||||
DiscordMember member = new DiscordMember(this, sMember, user, server);
|
DiscordMember member = new DiscordMember(this, sMember, user, server);
|
||||||
members.Add(member);
|
MemberManager.Add(member);
|
||||||
OnMemberAdd?.Invoke(member);
|
OnMemberAdd?.Invoke(member);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ShardManager_OnGuildMemberUpdate(GatewayShard shard, GuildMember sMember)
|
private void ShardManager_OnGuildMemberUpdate(GatewayShard shard, GuildMember sMember)
|
||||||
{
|
{
|
||||||
DiscordMember member = members.Find(x => x.User.Id == sMember.User.Id && x.Server.Id == sMember.GuildId);
|
Debug.Assert(sMember.GuildId.HasValue, "GuildId has no value");
|
||||||
|
|
||||||
|
DiscordMember member = MemberManager.Id(sMember.GuildId ?? 0, sMember.User.Id);
|
||||||
|
Debug.Assert(member != null, "member is null");
|
||||||
|
|
||||||
member.Nickname = sMember.Nickname;
|
member.Nickname = sMember.Nickname;
|
||||||
member.IsDeaf = sMember.IsDeafened == true;
|
member.IsDeaf = sMember.IsDeafened == true;
|
||||||
member.IsMute = sMember.IsMuted == true;
|
member.IsMute = sMember.IsMuted == true;
|
||||||
|
@ -615,8 +584,12 @@ namespace Maki
|
||||||
|
|
||||||
private void ShardManager_OnGuildMemberRemove(GatewayShard shard, GuildMember sMember)
|
private void ShardManager_OnGuildMemberRemove(GatewayShard shard, GuildMember sMember)
|
||||||
{
|
{
|
||||||
DiscordMember member = members.Find(x => x.User.Id == sMember.User.Id && x.Server.Id == sMember.GuildId);
|
Debug.Assert(sMember.GuildId.HasValue, "GuildId has no value");
|
||||||
members.Remove(member);
|
|
||||||
|
DiscordMember member = MemberManager.Id(sMember.GuildId ?? 0, sMember.User.Id);
|
||||||
|
Debug.Assert(member != null, "member is null");
|
||||||
|
|
||||||
|
MemberManager.Remove(member);
|
||||||
OnMemberRemove?.Invoke(member);
|
OnMemberRemove?.Invoke(member);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -632,13 +605,20 @@ namespace Maki
|
||||||
$"Is Mentionable?: {role.Role.Value.IsMentionable}",
|
$"Is Mentionable?: {role.Role.Value.IsMentionable}",
|
||||||
$"Permissions: {role.Role.Value.Permissions}"*/
|
$"Permissions: {role.Role.Value.Permissions}"*/
|
||||||
|
|
||||||
DiscordServer server = servers.Find(x => x.Id == sRole.Guild);
|
DiscordServer server = ServerManager.Id(sRole.Guild);
|
||||||
DiscordRole role = roles.Where(x => x.Id == sRole.Role.Value.Id).FirstOrDefault();
|
Debug.Assert(server != null, "server is null");
|
||||||
|
|
||||||
if (role == default(DiscordRole))
|
DiscordRole role = RoleManager.Id(sRole.Role.Value.Id);
|
||||||
|
//Debug.Assert(role != null, "role is null");
|
||||||
|
|
||||||
|
// fixme
|
||||||
|
if (server == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (role == null)
|
||||||
{
|
{
|
||||||
role = new DiscordRole(this, sRole.Role.Value, server);
|
role = new DiscordRole(this, sRole.Role.Value, server);
|
||||||
roles.Add(role);
|
RoleManager.Add(role);
|
||||||
} else
|
} else
|
||||||
{
|
{
|
||||||
role.Colour.Raw = sRole.Role.Value.Colour.Value;
|
role.Colour.Raw = sRole.Role.Value.Colour.Value;
|
||||||
|
@ -649,17 +629,25 @@ namespace Maki
|
||||||
|
|
||||||
private void ShardManager_OnGuildRoleDelete(GatewayShard shard, GuildRole sRole)
|
private void ShardManager_OnGuildRoleDelete(GatewayShard shard, GuildRole sRole)
|
||||||
{
|
{
|
||||||
DiscordRole role = roles.Find(x => x.Id == sRole.RoleId && x.Server.Id == sRole.Guild);
|
Debug.Assert(sRole.RoleId.HasValue, "RoleId has no value");
|
||||||
members.Where(x => x.roles.Contains(role.Id)).ToList().ForEach(x => x.roles.RemoveAll(y => y == role.Id));
|
DiscordRole role = RoleManager.Id(sRole.RoleId ?? 0);
|
||||||
roles.Remove(role);
|
Debug.Assert(role != null, "role is null");
|
||||||
|
|
||||||
|
// NOT THREAD SAFE
|
||||||
|
MemberManager.Role(role).ToList().ForEach(x => x.roles.RemoveAll(y => y == role.Id));
|
||||||
|
RoleManager.Remove(role);
|
||||||
|
|
||||||
OnRoleDelete?.Invoke(role);
|
OnRoleDelete?.Invoke(role);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ShardManager_OnGuildRoleUpdate(GatewayShard shard, GuildRole sRole)
|
private void ShardManager_OnGuildRoleUpdate(GatewayShard shard, GuildRole sRole)
|
||||||
{
|
{
|
||||||
|
Debug.Assert(sRole.Role.HasValue, "Role has no value");
|
||||||
Role dRole = sRole.Role.Value;
|
Role dRole = sRole.Role.Value;
|
||||||
DiscordRole role = roles.Find(x => x.Id == dRole.Id && x.Server.Id == sRole.Guild);
|
|
||||||
|
|
||||||
|
DiscordRole role = RoleManager.Id(dRole.Id);
|
||||||
|
Debug.Assert(role != null, "role is null");
|
||||||
|
|
||||||
role.Name = dRole.Name;
|
role.Name = dRole.Name;
|
||||||
role.IsHoisted = dRole.IsHoisted == true;
|
role.IsHoisted = dRole.IsHoisted == true;
|
||||||
role.IsMentionable = dRole.IsMentionable == true;
|
role.IsMentionable = dRole.IsMentionable == true;
|
||||||
|
@ -697,24 +685,32 @@ namespace Maki
|
||||||
|
|
||||||
private void ShardManager_OnMessageCreate(GatewayShard shard, Message message)
|
private void ShardManager_OnMessageCreate(GatewayShard shard, Message message)
|
||||||
{
|
{
|
||||||
DiscordChannel channel = channels.Find(x => x.Id == message.ChannelId);
|
DiscordChannel channel = ChannelManager.Id(message.ChannelId);
|
||||||
DiscordMember member = members.Where(x => x.User.Id == message.User.Id && x.Server == channel.Server).FirstOrDefault();
|
Debug.Assert(channel != null, "channel is null");
|
||||||
|
|
||||||
|
DiscordMember member = MemberManager.Id(channel.Server, message.User.Id);
|
||||||
|
Debug.Assert(member != null, "member is null");
|
||||||
|
|
||||||
DiscordMessage msg = new DiscordMessage(this, message, channel, member);
|
DiscordMessage msg = new DiscordMessage(this, message, channel, member);
|
||||||
messages.Add(msg);
|
MessageManager.Add(msg);
|
||||||
OnMessageCreate?.Invoke(msg);
|
OnMessageCreate?.Invoke(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ShardManager_OnMessageDelete(GatewayShard shard, Message message)
|
private void ShardManager_OnMessageDelete(GatewayShard shard, Message message)
|
||||||
{
|
{
|
||||||
DiscordMessage msg = messages.Find(x => x.Id == message.Id);
|
DiscordMessage msg = MessageManager.Id(message.Id);
|
||||||
messages.Remove(msg);
|
Debug.Assert(msg != null, "message is null");
|
||||||
|
|
||||||
|
MessageManager.Remove(msg);
|
||||||
OnMessageDelete?.Invoke(msg);
|
OnMessageDelete?.Invoke(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ShardManager_OnMessageUpdate(GatewayShard shard, Message message)
|
private void ShardManager_OnMessageUpdate(GatewayShard shard, Message message)
|
||||||
{
|
{
|
||||||
DiscordMessage msg = messages.Where(x => x.Id == message.Id).FirstOrDefault();
|
DiscordMessage msg = MessageManager.Id(message.Id);
|
||||||
|
//Debug.Assert(msg != null, "message is null");
|
||||||
|
|
||||||
|
// basically what should happen
|
||||||
if (msg == null)
|
if (msg == null)
|
||||||
{
|
{
|
||||||
using (WebRequest wr = new WebRequest(HttpMethod.GET, RestEndpoints.ChannelMessage(message.ChannelId, message.Id)))
|
using (WebRequest wr = new WebRequest(HttpMethod.GET, RestEndpoints.ChannelMessage(message.ChannelId, message.Id)))
|
||||||
|
@ -727,10 +723,14 @@ namespace Maki
|
||||||
message = wr.ResponseJson<Message>();
|
message = wr.ResponseJson<Message>();
|
||||||
}
|
}
|
||||||
|
|
||||||
DiscordChannel channel = channels.Where(x => x.Id == message.ChannelId).FirstOrDefault();
|
DiscordChannel channel = ChannelManager.Id(message.ChannelId);
|
||||||
DiscordMember member = members.Where(x => x.User.Id == message.User.Id && (channel.Server == null || channel.Server == x.Server)).FirstOrDefault();
|
Debug.Assert(channel != null, "channel is null");
|
||||||
|
|
||||||
|
DiscordMember member = MemberManager.Id(channel.Server, message.User.Id) ?? MemberManager.Id(message.User.Id);
|
||||||
|
Debug.Assert(member != null, "member is null");
|
||||||
|
|
||||||
msg = new DiscordMessage(this, message, channel, member);
|
msg = new DiscordMessage(this, message, channel, member);
|
||||||
messages.Add(msg);
|
MessageManager.Add(msg);
|
||||||
} else
|
} else
|
||||||
{
|
{
|
||||||
if (!string.IsNullOrEmpty(message.Content))
|
if (!string.IsNullOrEmpty(message.Content))
|
||||||
|
@ -746,14 +746,19 @@ namespace Maki
|
||||||
|
|
||||||
private void ShardManager_OnTypingStart(GatewayShard shard, TypingStart typing)
|
private void ShardManager_OnTypingStart(GatewayShard shard, TypingStart typing)
|
||||||
{
|
{
|
||||||
DiscordChannel channel = channels.Find(x => x.Id == typing.Channel);
|
DiscordChannel channel = ChannelManager.Id(typing.Channel);
|
||||||
DiscordUser user = users.Find(x => x.Id == typing.User);
|
Debug.Assert(channel != null, "channel is null");
|
||||||
|
|
||||||
|
DiscordUser user = UserManager.Id(typing.User);
|
||||||
|
Debug.Assert(user != null, "user is null");
|
||||||
|
|
||||||
OnTypingStart?.Invoke(user, channel);
|
OnTypingStart?.Invoke(user, channel);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ShardManager_OnPresenceUpdate(GatewayShard shard, Presence presence)
|
private void ShardManager_OnPresenceUpdate(GatewayShard shard, Presence presence)
|
||||||
{
|
{
|
||||||
DiscordMember member = members.Find(x => x.User.Id == presence.User.Id && x.Server.Id == presence.Guild);
|
DiscordMember member = MemberManager.Id(presence.Guild, presence.User.Id);
|
||||||
|
Debug.Assert(member != null, "member is null");
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(presence.User.Username))
|
if (!string.IsNullOrEmpty(presence.User.Username))
|
||||||
member.User.Username = presence.User.Username;
|
member.User.Username = presence.User.Username;
|
||||||
|
@ -771,20 +776,20 @@ namespace Maki
|
||||||
|
|
||||||
switch (presence.Status.ToLower())
|
switch (presence.Status.ToLower())
|
||||||
{
|
{
|
||||||
case @"online":
|
case "online":
|
||||||
member.User.Status = DiscordUserStatus.Online;
|
member.User.Status = DiscordUserStatus.Online;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case @"away":
|
case "away":
|
||||||
case @"idle":
|
case "idle":
|
||||||
member.User.Status = DiscordUserStatus.Idle;
|
member.User.Status = DiscordUserStatus.Idle;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case @"dnd":
|
case "dnd":
|
||||||
member.User.Status = DiscordUserStatus.DoNotDisturb;
|
member.User.Status = DiscordUserStatus.DoNotDisturb;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case @"offline":
|
case "offline":
|
||||||
default:
|
default:
|
||||||
member.User.Status = DiscordUserStatus.Offline;
|
member.User.Status = DiscordUserStatus.Offline;
|
||||||
break;
|
break;
|
||||||
|
@ -800,24 +805,24 @@ namespace Maki
|
||||||
DiscordChannel channel = new DiscordChannel(this, chan);
|
DiscordChannel channel = new DiscordChannel(this, chan);
|
||||||
|
|
||||||
// this shouldn't ever happen but just in case
|
// this shouldn't ever happen but just in case
|
||||||
if (channels.Where(x => x.Id == channel.Id).Count() > 0)
|
if (ChannelManager.Exists(channel.Id))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
channels.Add(channel);
|
ChannelManager.Add(channel);
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (Guild guild in ready.UnavailableGuilds)
|
foreach (Guild guild in ready.UnavailableGuilds)
|
||||||
{
|
{
|
||||||
DiscordServer server = new DiscordServer(this, guild);
|
DiscordServer server = new DiscordServer(this, guild);
|
||||||
|
|
||||||
if (servers.Where(x => x.Id == server.Id).Count() > 0)
|
if (ServerManager.Exists(server.Id))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
servers.Add(server);
|
ServerManager.Add(server);
|
||||||
}
|
}
|
||||||
|
|
||||||
DiscordUser user = new DiscordUser(this, ready.User);
|
DiscordUser user = new DiscordUser(this, ready.User);
|
||||||
users.Add(user);
|
UserManager.Add(user);
|
||||||
OnReady?.Invoke(user);
|
OnReady?.Invoke(user);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -838,12 +843,13 @@ namespace Maki
|
||||||
$"Is verified?: {user.IsVerified}",
|
$"Is verified?: {user.IsVerified}",
|
||||||
$"E-mail: {user.EMail}"*/
|
$"E-mail: {user.EMail}"*/
|
||||||
|
|
||||||
DiscordUser user = users.Where(x => x.Id == sUser.Id).FirstOrDefault();
|
DiscordUser user = UserManager.Id(sUser.Id);
|
||||||
|
//Debug.Assert(user != null, "user is null");
|
||||||
|
|
||||||
if (user == default(DiscordUser))
|
if (user == null)
|
||||||
{
|
{
|
||||||
user = new DiscordUser(this, sUser);
|
user = new DiscordUser(this, sUser);
|
||||||
users.Add(user);
|
UserManager.Add(user);
|
||||||
}
|
}
|
||||||
|
|
||||||
OnUserUpdate?.Invoke(user);
|
OnUserUpdate?.Invoke(user);
|
||||||
|
@ -864,32 +870,41 @@ namespace Maki
|
||||||
private void ShardManager_OnSocketMessage(GatewayShard shard, string text)
|
private void ShardManager_OnSocketMessage(GatewayShard shard, string text)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region IDisposable
|
#region IDisposable
|
||||||
private bool isDisposed = false;
|
|
||||||
|
|
||||||
private void Dispose(bool disposing)
|
private bool IsDisposed = false;
|
||||||
{
|
|
||||||
if (!isDisposed) {
|
|
||||||
isDisposed = true;
|
|
||||||
Disconnect();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
~Discord()
|
|
||||||
{
|
|
||||||
Dispose(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Disconnects and releases all unmanaged objects
|
/// Disconnects and releases all unmanaged objects
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void Dispose()
|
private void Dispose(bool disposing)
|
||||||
{
|
{
|
||||||
Dispose(true);
|
if (IsDisposed)
|
||||||
GC.SuppressFinalize(true);
|
return;
|
||||||
|
|
||||||
|
IsDisposed = true;
|
||||||
|
Disconnect();
|
||||||
|
|
||||||
|
ServerManager.Dispose();
|
||||||
|
MessageManager.Dispose();
|
||||||
|
ChannelManager.Dispose();
|
||||||
|
MemberManager.Dispose();
|
||||||
|
RoleManager.Dispose();
|
||||||
|
UserManager.Dispose();
|
||||||
|
|
||||||
|
if (disposing)
|
||||||
|
GC.SuppressFinalize(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
~Discord()
|
||||||
|
=> Dispose(false);
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
=> Dispose(true);
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ using Maki.Structures.Channels;
|
||||||
using Maki.Structures.Messages;
|
using Maki.Structures.Messages;
|
||||||
using Maki.Structures.Rest;
|
using Maki.Structures.Rest;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
|
using System.Diagnostics;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
|
||||||
namespace Maki
|
namespace Maki
|
||||||
|
@ -59,7 +60,8 @@ namespace Maki
|
||||||
|
|
||||||
if (wr.Status != 200 || wr.Response.Length < 1)
|
if (wr.Status != 200 || wr.Response.Length < 1)
|
||||||
// TODO: elaborate
|
// TODO: elaborate
|
||||||
throw new DiscordException("Failed to send message");
|
//throw new DiscordException("Failed to send message");
|
||||||
|
return null;
|
||||||
|
|
||||||
msg = wr.ResponseJson<Message>();
|
msg = wr.ResponseJson<Message>();
|
||||||
}
|
}
|
||||||
|
@ -67,8 +69,11 @@ namespace Maki
|
||||||
if (!msg.HasValue)
|
if (!msg.HasValue)
|
||||||
throw new DiscordException("Empty response?");
|
throw new DiscordException("Empty response?");
|
||||||
|
|
||||||
DiscordMessage message = new DiscordMessage(client, msg.Value, this, client.members.Find(x => x.User.Id == msg.Value.User.Id));
|
DiscordMember member = client.MemberManager.Id(Server, msg.Value.User.Id);
|
||||||
client.messages.Add(message);
|
Debug.Assert(member != null, "member is null");
|
||||||
|
|
||||||
|
DiscordMessage message = new DiscordMessage(client, msg.Value, this, member);
|
||||||
|
client.MessageManager.Add(message);
|
||||||
return message;
|
return message;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,41 @@ namespace Maki
|
||||||
{
|
{
|
||||||
public class DiscordColour
|
public class DiscordColour
|
||||||
{
|
{
|
||||||
|
public int Raw = 0;
|
||||||
|
|
||||||
|
public byte Red
|
||||||
|
{
|
||||||
|
get => (byte)(Raw >> 16 & 0xFF);
|
||||||
|
set
|
||||||
|
{
|
||||||
|
Raw &= ~0xFF0000;
|
||||||
|
Raw |= value << 16;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte Green
|
||||||
|
{
|
||||||
|
get => (byte)(Raw >> 8 & 0xFF);
|
||||||
|
set
|
||||||
|
{
|
||||||
|
Raw &= ~0xFF00;
|
||||||
|
Raw |= value << 8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte Blue
|
||||||
|
{
|
||||||
|
get => (byte)(Raw & 0xFF);
|
||||||
|
set
|
||||||
|
{
|
||||||
|
Raw &= ~0xFF;
|
||||||
|
Raw |= value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Hex => $"{Red:X2}{Green:X2}{Blue:X2}";
|
||||||
|
public override string ToString() => $"#{Hex}";
|
||||||
|
|
||||||
public DiscordColour(int raw)
|
public DiscordColour(int raw)
|
||||||
{
|
{
|
||||||
Raw = raw;
|
Raw = raw;
|
||||||
|
@ -12,7 +47,9 @@ namespace Maki
|
||||||
|
|
||||||
public DiscordColour(byte red, byte green, byte blue)
|
public DiscordColour(byte red, byte green, byte blue)
|
||||||
{
|
{
|
||||||
Raw = (red << 16) + (green << 8) + blue;
|
Raw |= red << 16;
|
||||||
|
Raw |= green << 8;
|
||||||
|
Raw |= blue;
|
||||||
}
|
}
|
||||||
|
|
||||||
public DiscordColour(string hex)
|
public DiscordColour(string hex)
|
||||||
|
@ -24,32 +61,10 @@ namespace Maki
|
||||||
|
|
||||||
if (hex.Length != 6)
|
if (hex.Length != 6)
|
||||||
throw new FormatException("Invalid hex colour format!");
|
throw new FormatException("Invalid hex colour format!");
|
||||||
|
|
||||||
Red = byte.Parse(hex.Substring(0, 2), NumberStyles.HexNumber);
|
Red = byte.Parse(hex.Substring(0, 2), NumberStyles.HexNumber);
|
||||||
Green = byte.Parse(hex.Substring(2, 2), NumberStyles.HexNumber);
|
Green = byte.Parse(hex.Substring(2, 2), NumberStyles.HexNumber);
|
||||||
Blue = byte.Parse(hex.Substring(4, 2), NumberStyles.HexNumber);
|
Blue = byte.Parse(hex.Substring(4, 2), NumberStyles.HexNumber);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int Raw = int.MinValue;
|
|
||||||
|
|
||||||
public byte Red
|
|
||||||
{
|
|
||||||
get => (byte)(Raw >> 16 & 0xFF);
|
|
||||||
set => Raw = (value << 16) + (Green << 8) + Blue;
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte Green
|
|
||||||
{
|
|
||||||
get => (byte)(Raw >> 8 & 0xFF);
|
|
||||||
set => Raw = (Red << 16) + (value << 8) + Blue;
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte Blue
|
|
||||||
{
|
|
||||||
get => (byte)(Raw & 0xFF);
|
|
||||||
set => Raw = (Red << 16) + (Green << 8) + value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public string Hex => $"{Red:X2}{Green:X2}{Blue:X2}";
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,7 @@ namespace Maki
|
||||||
public readonly DiscordServer Server;
|
public readonly DiscordServer Server;
|
||||||
private readonly Discord client;
|
private readonly Discord client;
|
||||||
|
|
||||||
public DiscordRole[] Roles => client.roles.Where(x => HasRole(x.Id) || x.Id == Server.Id).OrderByDescending(x => x.Position).ToArray();
|
public IEnumerable<DiscordRole> Roles => client.RoleManager.Server(Server).Where(x => HasRole(x.Id));
|
||||||
|
|
||||||
public DateTime Joined { get; internal set; }
|
public DateTime Joined { get; internal set; }
|
||||||
public string Nickname { get; internal set; }
|
public string Nickname { get; internal set; }
|
||||||
|
|
|
@ -2,6 +2,8 @@
|
||||||
using Maki.Structures.Messages;
|
using Maki.Structures.Messages;
|
||||||
using Maki.Structures.Rest;
|
using Maki.Structures.Rest;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
|
||||||
namespace Maki
|
namespace Maki
|
||||||
|
@ -17,18 +19,20 @@ namespace Maki
|
||||||
|
|
||||||
public string Text { get; internal set; }
|
public string Text { get; internal set; }
|
||||||
public DateTime Edited { get; internal set; }
|
public DateTime Edited { get; internal set; }
|
||||||
public DiscordMember[] MentionsUsers { get; internal set; }
|
public IEnumerable<DiscordMember> MentionsUsers { get; internal set; }
|
||||||
public DiscordRole[] MentionsRoles { get; internal set; }
|
public IEnumerable<DiscordRole> MentionsRoles { get; internal set; }
|
||||||
public bool MentionsEveryone { get; internal set; }
|
public bool MentionsEveryone { get; internal set; }
|
||||||
public bool IsPinned { get; internal set; }
|
public bool IsPinned { get; internal set; }
|
||||||
|
|
||||||
public bool MentionsMe(bool everyone = false, bool roles = true) =>
|
public bool MentionsMe(bool everyone = false, bool roles = true) =>
|
||||||
(everyone && MentionsEveryone)
|
(everyone && MentionsEveryone)
|
||||||
|| (Channel.Type != DiscordChannelType.Private && roles && client.members.Where(x => x.User == client.Me && x.Server == Channel.Server).FirstOrDefault()?.Roles.Where(x => MentionsRoles.Contains(x)).Count() > 0)
|
|| (Channel.Type != DiscordChannelType.Private && roles && client.MemberManager.Id(Channel.Server, client.Me)?.Roles.Where(x => MentionsRoles.Contains(x)).Count() > 0)
|
||||||
|| MentionsUsers.Select(x => x.User).Contains(client.Me);
|
|| MentionsUsers.Select(x => x.User).Contains(client.Me);
|
||||||
|
|
||||||
public bool IsMe => client.Me == User;
|
public bool IsMe => client.Me == User;
|
||||||
|
|
||||||
|
public DiscordServer Server => Channel.Server;
|
||||||
|
|
||||||
internal DiscordMessage(Discord discord, Message msg, DiscordChannel channel, DiscordMember member = null)
|
internal DiscordMessage(Discord discord, Message msg, DiscordChannel channel, DiscordMember member = null)
|
||||||
{
|
{
|
||||||
client = discord;
|
client = discord;
|
||||||
|
@ -43,12 +47,13 @@ namespace Maki
|
||||||
} else
|
} else
|
||||||
{
|
{
|
||||||
member = null;
|
member = null;
|
||||||
User = client.users.Where(x => x.Id == msg.User.Id).FirstOrDefault();
|
User = client.UserManager.Id(msg.User.Id);
|
||||||
|
Debug.Assert(User != null, "user is null");
|
||||||
}
|
}
|
||||||
|
|
||||||
Channel = channel;
|
Channel = channel;
|
||||||
MentionsUsers = client.members.Where(x => x.Server == channel.Server && msg.Mentions.Select(y => y.Id).Contains(x.User.Id)).ToArray();
|
MentionsUsers = client.MemberManager.Server(channel.Server).Where(x => msg.Mentions.Select(y => y.Id).Contains(x.User.Id));
|
||||||
MentionsRoles = client.roles.Where(x => x.Server == channel.Server && msg.MentionsRoles.Contains(x.Id)).ToArray();
|
MentionsRoles = client.RoleManager .Server(channel.Server).Where(x => msg.MentionsRoles.Contains(x.Id));
|
||||||
MentionsEveryone = msg.MentioningEveryone;
|
MentionsEveryone = msg.MentioningEveryone;
|
||||||
IsPinned = msg.IsPinned == true;
|
IsPinned = msg.IsPinned == true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ using Maki.Structures.Guilds;
|
||||||
using Maki.Structures.Rest;
|
using Maki.Structures.Rest;
|
||||||
using Maki.Structures.Roles;
|
using Maki.Structures.Roles;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
|
||||||
namespace Maki
|
namespace Maki
|
||||||
|
@ -17,13 +18,17 @@ namespace Maki
|
||||||
public DateTime Created { get; internal set; }
|
public DateTime Created { get; internal set; }
|
||||||
internal string IconHash;
|
internal string IconHash;
|
||||||
|
|
||||||
public DiscordMember[] Members => client.members.Where(x => x.Server == this).ToArray();
|
public IEnumerable<DiscordMember> Members => client.MemberManager.Server(this);
|
||||||
public DiscordMember Owner => Members.Where(x => x.User.Id == OwnerId).FirstOrDefault();
|
public DiscordMember Owner => Members.Where(x => x.User.Id == OwnerId).FirstOrDefault();
|
||||||
public DiscordMember Me => Members.Where(x => x.User == client.Me).FirstOrDefault();
|
public DiscordMember Me => Members.Where(x => x.User == client.Me).FirstOrDefault();
|
||||||
public DiscordChannel[] TextChannels => client.channels.Where(x => x.Server == this && x.Type == DiscordChannelType.Text).OrderBy(x => x.Position).ToArray();
|
|
||||||
public DiscordChannel[] VoiceChannels => client.channels.Where(x => x.Server == this && x.Type == DiscordChannelType.Voice).OrderBy(x => x.Position).ToArray();
|
public IEnumerable<DiscordChannel> Channels => client.ChannelManager.Server(this);
|
||||||
public DiscordRole[] Roles => client.roles.Where(x => x.Server == this).OrderByDescending(x => x.Position).ToArray();
|
public IEnumerable<DiscordChannel> TextChannels => Channels.Where(x => x.Type == DiscordChannelType.Text);
|
||||||
public string Icon(string ext = @"png", int size = 128) => RestEndpoints.CDN_URL + $@"/icons/{Id}/{IconHash}.{ext}?size={size}";
|
public IEnumerable<DiscordChannel> VoiceChannels => Channels.Where(x => x.Type == DiscordChannelType.Voice);
|
||||||
|
|
||||||
|
public IEnumerable<DiscordRole> Roles => client.RoleManager.Server(this);
|
||||||
|
|
||||||
|
public string Icon(string ext = "png", int size = 128) => RestEndpoints.CDN_URL + $@"/icons/{Id}/{IconHash}.{ext}?size={size}";
|
||||||
|
|
||||||
internal DiscordServer(Discord discord, Guild guild)
|
internal DiscordServer(Discord discord, Guild guild)
|
||||||
{
|
{
|
||||||
|
@ -60,14 +65,15 @@ namespace Maki
|
||||||
if (!roleStruct.HasValue)
|
if (!roleStruct.HasValue)
|
||||||
throw new DiscordException("Empty response?");
|
throw new DiscordException("Empty response?");
|
||||||
|
|
||||||
DiscordRole role = client.roles.Where(x => x.Id == roleStruct.Value.Id).FirstOrDefault();
|
DiscordRole role = client.RoleManager.Id(roleStruct.Value.Id);
|
||||||
|
//Debug.Assert(role != null, "role is null");
|
||||||
|
|
||||||
if (role == default(DiscordRole))
|
if (role == null)
|
||||||
{
|
{
|
||||||
role = new DiscordRole(client, roleStruct.Value, this);
|
role = new DiscordRole(client, roleStruct.Value, this);
|
||||||
client.roles.Add(role);
|
client.RoleManager.Add(role);
|
||||||
}
|
}
|
||||||
|
|
||||||
return role;
|
return role;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,26 +18,27 @@ namespace Maki.Gateway
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Managed (active) shards
|
/// Managed (active) shards
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private readonly Dictionary<int, GatewayShard> shards = new Dictionary<int, GatewayShard>();
|
private readonly List<GatewayShard> Shards = new List<GatewayShard>();
|
||||||
|
|
||||||
|
private readonly object Lock = new object();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Parent DiscordClient instance
|
/// Parent DiscordClient instance
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private Discord client;
|
private Discord Client;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Number of active managed shards
|
/// Number of active managed shards
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int ShardCount => shards.Count;
|
public int ShardCount
|
||||||
|
=> Shards.Count;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Constructor
|
/// Constructor
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="c">Parent DiscordClient instance</param>
|
/// <param name="client">Parent DiscordClient instance</param>
|
||||||
public GatewayShardClient(Discord c)
|
public GatewayShardClient(Discord client)
|
||||||
{
|
=> Client = client;
|
||||||
client = c;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a new Gateway Shard
|
/// Creates a new Gateway Shard
|
||||||
|
@ -46,25 +47,23 @@ namespace Maki.Gateway
|
||||||
/// <returns>New Gateway Shard</returns>
|
/// <returns>New Gateway Shard</returns>
|
||||||
public GatewayShard Create(int id)
|
public GatewayShard Create(int id)
|
||||||
{
|
{
|
||||||
GatewayShard shard = new GatewayShard(id, client);
|
GatewayShard shard = new GatewayShard(id, Client);
|
||||||
ApplyEvents(shard);
|
ApplyEvents(shard);
|
||||||
shards.Add(id, shard);
|
|
||||||
|
lock (Lock)
|
||||||
|
Shards.Add(shard);
|
||||||
|
|
||||||
return shard;
|
return shard;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Destroys a Gateway Shard using its id
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="id">Id of the shard to destroy</param>
|
|
||||||
public void Destroy(int id) => Destroy(shards[id]);
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Destroys a Gateway Shard
|
/// Destroys a Gateway Shard
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="shard">Shard to destroy</param>
|
/// <param name="shard">Shard to destroy</param>
|
||||||
public void Destroy(GatewayShard shard)
|
public void Destroy(GatewayShard shard)
|
||||||
{
|
{
|
||||||
shards.Remove(shard.Id);
|
lock (Lock)
|
||||||
|
Shards.Remove(shard);
|
||||||
|
|
||||||
// Disconnect and Dispose are called separately so OnSocketClose is called properly
|
// Disconnect and Dispose are called separately so OnSocketClose is called properly
|
||||||
shard.Disconnect();
|
shard.Disconnect();
|
||||||
|
@ -75,7 +74,11 @@ namespace Maki.Gateway
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Destroys all shards
|
/// Destroys all shards
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void Disconnect() => shards.Keys.ToList().ForEach(x => Destroy(x));
|
public void Disconnect()
|
||||||
|
{
|
||||||
|
lock (Lock)
|
||||||
|
Shards.ToList().ForEach(x => Destroy(x));
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Links all gateway events handlers to the shard
|
/// Links all gateway events handlers to the shard
|
||||||
|
@ -271,29 +274,27 @@ namespace Maki.Gateway
|
||||||
|
|
||||||
private bool IsDisposed = false;
|
private bool IsDisposed = false;
|
||||||
|
|
||||||
private void Dispose(bool disposing)
|
|
||||||
{
|
|
||||||
if (!IsDisposed)
|
|
||||||
{
|
|
||||||
IsDisposed = true;
|
|
||||||
Disconnect();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
~GatewayShardClient()
|
|
||||||
{
|
|
||||||
Dispose(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Releases all unmanaged resources used by this object
|
/// Releases all unmanaged resources used by this object
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void Dispose()
|
private void Dispose(bool disposing)
|
||||||
{
|
{
|
||||||
Dispose(true);
|
if (IsDisposed)
|
||||||
GC.SuppressFinalize(true);
|
return;
|
||||||
|
|
||||||
|
IsDisposed = true;
|
||||||
|
Disconnect();
|
||||||
|
|
||||||
|
if (disposing)
|
||||||
|
GC.SuppressFinalize(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
~GatewayShardClient()
|
||||||
|
=> Dispose(false);
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
=> Dispose(true);
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,17 +39,13 @@
|
||||||
<HintPath>..\..\packages\Newtonsoft.Json.10.0.3\lib\net40\Newtonsoft.Json.dll</HintPath>
|
<HintPath>..\..\packages\Newtonsoft.Json.10.0.3\lib\net40\Newtonsoft.Json.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="System" />
|
<Reference Include="System" />
|
||||||
<Reference Include="System.Core" />
|
|
||||||
<Reference Include="System.Xml.Linq" />
|
|
||||||
<Reference Include="System.Data.DataSetExtensions" />
|
|
||||||
<Reference Include="Microsoft.CSharp" />
|
|
||||||
<Reference Include="System.Data" />
|
|
||||||
<Reference Include="System.Xml" />
|
|
||||||
<Reference Include="websocket-sharp, Version=1.0.2.59611, Culture=neutral, PublicKeyToken=5660b08a1845a91e, processorArchitecture=MSIL">
|
<Reference Include="websocket-sharp, Version=1.0.2.59611, Culture=neutral, PublicKeyToken=5660b08a1845a91e, processorArchitecture=MSIL">
|
||||||
<HintPath>..\..\packages\WebSocketSharp.1.0.3-rc11\lib\websocket-sharp.dll</HintPath>
|
<HintPath>..\..\packages\WebSocketSharp.1.0.3-rc11\lib\websocket-sharp.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<Compile Include="BaseManager.cs" />
|
||||||
|
<Compile Include="ChannelManager.cs" />
|
||||||
<Compile Include="DiscordChannel.cs" />
|
<Compile Include="DiscordChannel.cs" />
|
||||||
<Compile Include="Discord.cs" />
|
<Compile Include="Discord.cs" />
|
||||||
<Compile Include="DiscordChannelType.cs" />
|
<Compile Include="DiscordChannelType.cs" />
|
||||||
|
@ -69,6 +65,8 @@
|
||||||
<Compile Include="DiscordUserStatus.cs" />
|
<Compile Include="DiscordUserStatus.cs" />
|
||||||
<Compile Include="DiscordUser.cs" />
|
<Compile Include="DiscordUser.cs" />
|
||||||
<Compile Include="Gateway\GatewayEvent.cs" />
|
<Compile Include="Gateway\GatewayEvent.cs" />
|
||||||
|
<Compile Include="MemberManager.cs" />
|
||||||
|
<Compile Include="MessageManager.cs" />
|
||||||
<Compile Include="Rest\RestErrorCode.cs" />
|
<Compile Include="Rest\RestErrorCode.cs" />
|
||||||
<Compile Include="Rest\HttpMethod.cs" />
|
<Compile Include="Rest\HttpMethod.cs" />
|
||||||
<Compile Include="Rest\RestEndpoints.cs" />
|
<Compile Include="Rest\RestEndpoints.cs" />
|
||||||
|
@ -78,9 +76,8 @@
|
||||||
<Compile Include="DiscordTokenType.cs" />
|
<Compile Include="DiscordTokenType.cs" />
|
||||||
<Compile Include="Gateway\GatewayCloseCode.cs" />
|
<Compile Include="Gateway\GatewayCloseCode.cs" />
|
||||||
<Compile Include="Rest\WebRequest.cs" />
|
<Compile Include="Rest\WebRequest.cs" />
|
||||||
<Compile Include="Structures\Auth\LoginMultiFactorAuth.cs" />
|
<Compile Include="RoleManager.cs" />
|
||||||
<Compile Include="Structures\Auth\LoginRequest.cs" />
|
<Compile Include="ServerManager.cs" />
|
||||||
<Compile Include="Structures\Auth\LoginResponse.cs" />
|
|
||||||
<Compile Include="Structures\Channels\Channel.cs" />
|
<Compile Include="Structures\Channels\Channel.cs" />
|
||||||
<Compile Include="Structures\Channels\ChannelType.cs" />
|
<Compile Include="Structures\Channels\ChannelType.cs" />
|
||||||
<Compile Include="Structures\Embeds\Embed.cs" />
|
<Compile Include="Structures\Embeds\Embed.cs" />
|
||||||
|
@ -125,6 +122,7 @@
|
||||||
<Compile Include="Structures\Roles\Role.cs" />
|
<Compile Include="Structures\Roles\Role.cs" />
|
||||||
<Compile Include="Structures\Users\PermissionOverwrite.cs" />
|
<Compile Include="Structures\Users\PermissionOverwrite.cs" />
|
||||||
<Compile Include="Structures\Users\User.cs" />
|
<Compile Include="Structures\Users\User.cs" />
|
||||||
|
<Compile Include="UserManager.cs" />
|
||||||
<Compile Include="Utility.cs" />
|
<Compile Include="Utility.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|
48
Maki/MemberManager.cs
Normal file
48
Maki/MemberManager.cs
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace Maki
|
||||||
|
{
|
||||||
|
internal sealed class MemberManager : BaseManager<DiscordMember>
|
||||||
|
{
|
||||||
|
internal MemberManager()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public DiscordMember Id(ulong user)
|
||||||
|
{
|
||||||
|
lock (Collection)
|
||||||
|
return Collection.Where(x => x.Server == null && x.User.Id == user).FirstOrDefault();
|
||||||
|
}
|
||||||
|
|
||||||
|
public DiscordMember Id(ulong server, ulong user)
|
||||||
|
{
|
||||||
|
lock (Collection)
|
||||||
|
return Collection.Where(x => x.Server.Id == server && x.User.Id == user).FirstOrDefault();
|
||||||
|
}
|
||||||
|
|
||||||
|
public DiscordMember Id(DiscordServer server, ulong user)
|
||||||
|
{
|
||||||
|
lock (Collection)
|
||||||
|
return Collection.Where(x => x.Server == server && x.User.Id == user).FirstOrDefault();
|
||||||
|
}
|
||||||
|
|
||||||
|
public DiscordMember Id(DiscordServer server, DiscordUser user)
|
||||||
|
{
|
||||||
|
lock (Collection)
|
||||||
|
return Collection.Where(x => x.Server == server && x.User == user).FirstOrDefault();
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerable<DiscordMember> Server(DiscordServer server)
|
||||||
|
{
|
||||||
|
lock (Collection)
|
||||||
|
return Collection.Where(x => x.Server == server);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerable<DiscordMember> Role(DiscordRole role)
|
||||||
|
{
|
||||||
|
lock (Collection)
|
||||||
|
return Collection.Where(x => x.HasRole(role.Id));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
30
Maki/MessageManager.cs
Normal file
30
Maki/MessageManager.cs
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace Maki
|
||||||
|
{
|
||||||
|
internal sealed class MessageManager : BaseManager<DiscordMessage>
|
||||||
|
{
|
||||||
|
internal MessageManager()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public DiscordMessage Id(ulong id)
|
||||||
|
{
|
||||||
|
lock (Collection)
|
||||||
|
return Collection.Where(x => x.Id == id).FirstOrDefault();
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerable<DiscordMessage> Channel(DiscordChannel channel)
|
||||||
|
{
|
||||||
|
lock (Collection)
|
||||||
|
return Collection.Where(x => x.Channel == channel);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerable<DiscordMessage> Server(DiscordServer server)
|
||||||
|
{
|
||||||
|
lock (Collection)
|
||||||
|
return Collection.Where(x => x.Server == server);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,36 +1,10 @@
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
// General Information about an assembly is controlled through the following
|
|
||||||
// set of attributes. Change these attribute values to modify the information
|
|
||||||
// associated with an assembly.
|
|
||||||
[assembly: AssemblyTitle("Maki")]
|
[assembly: AssemblyTitle("Maki")]
|
||||||
[assembly: AssemblyDescription("Discord Client library")]
|
[assembly: AssemblyDescription("Discord Client library")]
|
||||||
[assembly: AssemblyConfiguration("")]
|
|
||||||
[assembly: AssemblyCompany("")]
|
|
||||||
[assembly: AssemblyProduct("Maki")]
|
[assembly: AssemblyProduct("Maki")]
|
||||||
[assembly: AssemblyCopyright("flash.moe 2017")]
|
[assembly: AssemblyCopyright("flash.moe 2017")]
|
||||||
[assembly: AssemblyTrademark("")]
|
|
||||||
[assembly: AssemblyCulture("")]
|
|
||||||
|
|
||||||
// Setting ComVisible to false makes the types in this assembly not visible
|
|
||||||
// to COM components. If you need to access a type in this assembly from
|
|
||||||
// COM, set the ComVisible attribute to true on that type.
|
|
||||||
[assembly: ComVisible(false)]
|
[assembly: ComVisible(false)]
|
||||||
|
|
||||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
|
||||||
[assembly: Guid("97523aed-b694-42c2-96ac-86a1d65109f7")]
|
[assembly: Guid("97523aed-b694-42c2-96ac-86a1d65109f7")]
|
||||||
|
[assembly: AssemblyVersion("1.0.*")]
|
||||||
// Version information for an assembly consists of the following four values:
|
|
||||||
//
|
|
||||||
// Major Version
|
|
||||||
// Minor Version
|
|
||||||
// Build Number
|
|
||||||
// Revision
|
|
||||||
//
|
|
||||||
// You can specify all the values or you can default the Build and Revision Numbers
|
|
||||||
// by using the '*' as shown below:
|
|
||||||
// [assembly: AssemblyVersion("1.0.*")]
|
|
||||||
[assembly: AssemblyVersion("1.0.0.0")]
|
|
||||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
|
||||||
|
|
|
@ -8,17 +8,17 @@
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Base URL of Discord
|
/// Base URL of Discord
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public const string BASE_URL = @"https://discordapp.com";
|
public const string BASE_URL = "https://discordapp.com";
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Path to the REST API
|
/// Path to the REST API
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static string BASE_PATH => @"/api/v" + Discord.GATEWAY_VERSION;
|
public static string BASE_PATH => "/api/v" + Discord.GATEWAY_VERSION;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Url of Discord's CDN
|
/// Url of Discord's CDN
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public const string CDN_URL = @"https://cdn.discordapp.com";
|
public const string CDN_URL = "https://cdn.discordapp.com";
|
||||||
|
|
||||||
#region Channels
|
#region Channels
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -349,18 +349,6 @@
|
||||||
public static string OAuth2Application(ulong appId) => $@"/oauth2/applications/{appId}";
|
public static string OAuth2Application(ulong appId) => $@"/oauth2/applications/{appId}";
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Auth
|
|
||||||
/// <summary>
|
|
||||||
/// Auth Login endpoint
|
|
||||||
/// </summary>
|
|
||||||
public static string AuthLogin => @"/auth/login";
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Auth MFA TOTP endpoint
|
|
||||||
/// </summary>
|
|
||||||
public static string AuthMfaTotp => @"/auth/mfa/totp";
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region User
|
#region User
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets a User endpoint
|
/// Gets a User endpoint
|
||||||
|
|
|
@ -16,7 +16,7 @@ namespace Maki.Rest
|
||||||
private const string JSON_CONTENT_TYPE = @"application/json";
|
private const string JSON_CONTENT_TYPE = @"application/json";
|
||||||
private const string FORM_CONTENT_TYPE = @"multipart/form-data";
|
private const string FORM_CONTENT_TYPE = @"multipart/form-data";
|
||||||
|
|
||||||
private const long BUFFER_SIZE = 5242880;
|
private const long BUFFER_SIZE = 8192000;
|
||||||
|
|
||||||
public readonly HttpMethod Method;
|
public readonly HttpMethod Method;
|
||||||
public readonly string Url;
|
public readonly string Url;
|
||||||
|
@ -24,16 +24,16 @@ namespace Maki.Rest
|
||||||
public string UserAgent { get; set; } = USER_AGENT;
|
public string UserAgent { get; set; } = USER_AGENT;
|
||||||
|
|
||||||
public string ContentType { get; set; } = GENERIC_CONTENT_TYPE;
|
public string ContentType { get; set; } = GENERIC_CONTENT_TYPE;
|
||||||
public long ContentLength => wResponse.ContentLength < 1 ? BUFFER_SIZE : wResponse.ContentLength;
|
public long ContentLength => HttpWebResponse.ContentLength < 1 ? BUFFER_SIZE : HttpWebResponse.ContentLength;
|
||||||
|
|
||||||
// TODO: make this not static
|
// TODO: make this not static
|
||||||
internal static string Authorisation { get; set; }
|
internal static string Authorisation { get; set; }
|
||||||
|
|
||||||
private readonly Dictionary<string, string> headers = new Dictionary<string, string>();
|
private readonly Dictionary<string, string> Headers = new Dictionary<string, string>();
|
||||||
private readonly Dictionary<string, string> parameters = new Dictionary<string, string>();
|
private readonly Dictionary<string, string> Parameters = new Dictionary<string, string>();
|
||||||
private readonly Dictionary<string, byte[]> files = new Dictionary<string, byte[]>();
|
private readonly Dictionary<string, byte[]> Files = new Dictionary<string, byte[]>();
|
||||||
|
|
||||||
private readonly Dictionary<string, string> mimeTypes = new Dictionary<string, string>()
|
private readonly Dictionary<string, string> MimeTypes = new Dictionary<string, string>()
|
||||||
{
|
{
|
||||||
{ "png", "image/png" },
|
{ "png", "image/png" },
|
||||||
{ "jpg", "image/jpeg" },
|
{ "jpg", "image/jpeg" },
|
||||||
|
@ -41,37 +41,47 @@ namespace Maki.Rest
|
||||||
{ "gif", "image/gif" },
|
{ "gif", "image/gif" },
|
||||||
};
|
};
|
||||||
|
|
||||||
private byte[] rawContent = new byte[0];
|
private byte[] RawRequestBody = new byte[0];
|
||||||
private HttpWebRequest wRequest;
|
private HttpWebRequest HttpWebRequest;
|
||||||
private Stream requestStream;
|
private Stream RequestStream;
|
||||||
private HttpWebResponse wResponse;
|
private HttpWebResponse HttpWebResponse;
|
||||||
private Stream responseStream;
|
private Stream ResponseStream;
|
||||||
|
|
||||||
private byte[] rawResponse;
|
private byte[] RawResponseValue;
|
||||||
public byte[] RawResponse
|
public byte[] RawResponse
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
if (rawResponse == null)
|
if (RawResponseValue == null)
|
||||||
{
|
{
|
||||||
rawResponse = new byte[BUFFER_SIZE];
|
using (MemoryStream ms = new MemoryStream())
|
||||||
responseStream.Read(rawResponse, 0, rawResponse.Length);
|
{
|
||||||
|
byte[] bytes = new byte[4096];
|
||||||
|
int read = 0;
|
||||||
|
|
||||||
|
while ((read = ResponseStream.Read(bytes, 0, bytes.Length)) > 0)
|
||||||
|
ms.Write(bytes, 0, read);
|
||||||
|
|
||||||
|
ms.Seek(0, SeekOrigin.Begin);
|
||||||
|
RawResponseValue = new byte[ms.Length];
|
||||||
|
ms.Read(RawResponseValue, 0, RawResponseValue.Length);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return rawResponse;
|
return RawResponseValue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private string responseString = string.Empty;
|
private string ResponseString = string.Empty;
|
||||||
|
|
||||||
public string Response
|
public string Response
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(responseString))
|
if (string.IsNullOrEmpty(ResponseString))
|
||||||
responseString = Encoding.UTF8.GetString(RawResponse).Trim('\0');
|
ResponseString = Encoding.UTF8.GetString(RawResponse);
|
||||||
|
|
||||||
return responseString;
|
return ResponseString;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -79,7 +89,7 @@ namespace Maki.Rest
|
||||||
JsonConvert.DeserializeObject<T>(Response);
|
JsonConvert.DeserializeObject<T>(Response);
|
||||||
|
|
||||||
public short Status =>
|
public short Status =>
|
||||||
(short)wResponse?.StatusCode;
|
(short)HttpWebResponse?.StatusCode;
|
||||||
|
|
||||||
static WebRequest()
|
static WebRequest()
|
||||||
{
|
{
|
||||||
|
@ -93,7 +103,7 @@ namespace Maki.Rest
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AddRaw(byte[] bytes) =>
|
public void AddRaw(byte[] bytes) =>
|
||||||
rawContent = bytes;
|
RawRequestBody = bytes;
|
||||||
|
|
||||||
public void AddRaw(string str) =>
|
public void AddRaw(string str) =>
|
||||||
AddRaw(Encoding.UTF8.GetBytes(str));
|
AddRaw(Encoding.UTF8.GetBytes(str));
|
||||||
|
@ -105,10 +115,10 @@ namespace Maki.Rest
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AddParam(string name, string contents) =>
|
public void AddParam(string name, string contents) =>
|
||||||
parameters.Add(name, contents);
|
Parameters.Add(name, contents);
|
||||||
|
|
||||||
public void AddFile(string name, byte[] bytes) =>
|
public void AddFile(string name, byte[] bytes) =>
|
||||||
files.Add(name, bytes);
|
Files.Add(name, bytes);
|
||||||
|
|
||||||
public void Perform()
|
public void Perform()
|
||||||
{
|
{
|
||||||
|
@ -124,50 +134,50 @@ namespace Maki.Rest
|
||||||
|
|
||||||
if (Method == HttpMethod.GET
|
if (Method == HttpMethod.GET
|
||||||
|| Method == HttpMethod.DELETE)
|
|| Method == HttpMethod.DELETE)
|
||||||
if (parameters.Count > 1)
|
if (Parameters.Count > 1)
|
||||||
{
|
{
|
||||||
if (!Url.Contains('?'))
|
if (!Url.Contains('?'))
|
||||||
urlBuilder.Append(@"?");
|
urlBuilder.Append(@"?");
|
||||||
|
|
||||||
foreach (KeyValuePair<string, string> param in parameters)
|
foreach (KeyValuePair<string, string> param in Parameters)
|
||||||
urlBuilder.Append($@"{param.Key}={param.Value}&");
|
urlBuilder.Append($@"{param.Key}={param.Value}&");
|
||||||
}
|
}
|
||||||
|
|
||||||
string url = urlBuilder.ToString().TrimEnd('&');
|
string url = urlBuilder.ToString().TrimEnd('&');
|
||||||
|
|
||||||
wRequest = System.Net.WebRequest.Create(url) as HttpWebRequest;
|
HttpWebRequest = System.Net.WebRequest.Create(url) as HttpWebRequest;
|
||||||
wRequest.Method = Method.ToString();
|
HttpWebRequest.Method = Method.ToString();
|
||||||
wRequest.UserAgent = UserAgent;
|
HttpWebRequest.UserAgent = UserAgent;
|
||||||
wRequest.KeepAlive = true;
|
HttpWebRequest.KeepAlive = true;
|
||||||
//wRequest.AutomaticDecompression = DecompressionMethods.Deflate | DecompressionMethods.GZip;
|
//wRequest.AutomaticDecompression = DecompressionMethods.Deflate | DecompressionMethods.GZip;
|
||||||
wRequest.ReadWriteTimeout = Timeout.Infinite;
|
HttpWebRequest.ReadWriteTimeout = Timeout.Infinite;
|
||||||
wRequest.Timeout = Timeout.Infinite;
|
HttpWebRequest.Timeout = Timeout.Infinite;
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(Authorisation) && url.StartsWith(RestEndpoints.BASE_URL + RestEndpoints.BASE_PATH))
|
if (!string.IsNullOrEmpty(Authorisation) && url.StartsWith(RestEndpoints.BASE_URL + RestEndpoints.BASE_PATH))
|
||||||
wRequest.Headers[HttpRequestHeader.Authorization] = Authorisation;
|
HttpWebRequest.Headers[HttpRequestHeader.Authorization] = Authorisation;
|
||||||
|
|
||||||
foreach (KeyValuePair<string, string> header in headers)
|
foreach (KeyValuePair<string, string> header in Headers)
|
||||||
wRequest.Headers[header.Key] = header.Value;
|
HttpWebRequest.Headers[header.Key] = header.Value;
|
||||||
|
|
||||||
if (Method == HttpMethod.POST
|
if (Method == HttpMethod.POST
|
||||||
|| Method == HttpMethod.PUT
|
|| Method == HttpMethod.PUT
|
||||||
|| Method == HttpMethod.PATCH)
|
|| Method == HttpMethod.PATCH)
|
||||||
{
|
{
|
||||||
requestStream = wRequest.GetRequestStream();
|
RequestStream = HttpWebRequest.GetRequestStream();
|
||||||
|
|
||||||
if (parameters.Count + files.Count < 1)
|
if (Parameters.Count + Files.Count < 1)
|
||||||
requestStream.Write(rawContent, 0, rawContent.Length);
|
RequestStream.Write(RawRequestBody, 0, RawRequestBody.Length);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
string boundary = $@"-----------------------------{DateTime.Now.Ticks}";
|
string boundary = $@"-----------------------------{DateTime.Now.Ticks}";
|
||||||
ContentType = $@"{FORM_CONTENT_TYPE}; boundary={boundary}";
|
ContentType = $@"{FORM_CONTENT_TYPE}; boundary={boundary}";
|
||||||
|
|
||||||
if (parameters.Count >= 1)
|
if (Parameters.Count >= 1)
|
||||||
{
|
{
|
||||||
StringBuilder postBodyBuilder = new StringBuilder();
|
StringBuilder postBodyBuilder = new StringBuilder();
|
||||||
byte[] postBody = new byte[0];
|
byte[] postBody = new byte[0];
|
||||||
|
|
||||||
foreach (KeyValuePair<string, string> param in parameters)
|
foreach (KeyValuePair<string, string> param in Parameters)
|
||||||
{
|
{
|
||||||
postBodyBuilder.AppendLine($@"--{boundary}");
|
postBodyBuilder.AppendLine($@"--{boundary}");
|
||||||
postBodyBuilder.AppendLine($@"Content-Disposition: form-data; name=""{param.Key}""");
|
postBodyBuilder.AppendLine($@"Content-Disposition: form-data; name=""{param.Key}""");
|
||||||
|
@ -176,90 +186,90 @@ namespace Maki.Rest
|
||||||
}
|
}
|
||||||
|
|
||||||
postBody = Encoding.UTF8.GetBytes(postBodyBuilder.ToString());
|
postBody = Encoding.UTF8.GetBytes(postBodyBuilder.ToString());
|
||||||
requestStream.Write(postBody, 0, postBody.Length);
|
RequestStream.Write(postBody, 0, postBody.Length);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (files.Count >= 1)
|
if (Files.Count >= 1)
|
||||||
{
|
{
|
||||||
byte[] boundaryBytes = Encoding.UTF8.GetBytes($@"--{boundary}");
|
byte[] boundaryBytes = Encoding.UTF8.GetBytes($@"--{boundary}");
|
||||||
byte[] newLineBytes = Encoding.UTF8.GetBytes("\r\n");
|
byte[] newLineBytes = Encoding.UTF8.GetBytes("\r\n");
|
||||||
|
|
||||||
foreach (KeyValuePair<string, byte[]> file in files)
|
foreach (KeyValuePair<string, byte[]> file in Files)
|
||||||
{
|
{
|
||||||
string cType = GENERIC_CONTENT_TYPE;
|
string cType = GENERIC_CONTENT_TYPE;
|
||||||
string fileExt = Path.GetExtension(file.Key).ToLower().TrimStart('.');
|
string fileExt = Path.GetExtension(file.Key).ToLower().TrimStart('.');
|
||||||
|
|
||||||
if (mimeTypes.ContainsKey(fileExt))
|
if (MimeTypes.ContainsKey(fileExt))
|
||||||
cType = mimeTypes[fileExt];
|
cType = MimeTypes[fileExt];
|
||||||
|
|
||||||
byte[] cDisposBytes = Encoding.UTF8.GetBytes($@"Content-Disposition: form-data; name=""{file.Key}""; filename=""{file.Key}""");
|
byte[] cDisposBytes = Encoding.UTF8.GetBytes($@"Content-Disposition: form-data; name=""{file.Key}""; filename=""{file.Key}""");
|
||||||
byte[] cTypeBytes = Encoding.UTF8.GetBytes($@"Content-Type: {cType}");
|
byte[] cTypeBytes = Encoding.UTF8.GetBytes($@"Content-Type: {cType}");
|
||||||
|
|
||||||
// Boundary + newline
|
// Boundary + newline
|
||||||
requestStream.Write(boundaryBytes, 0, boundaryBytes.Length);
|
RequestStream.Write(boundaryBytes, 0, boundaryBytes.Length);
|
||||||
requestStream.Write(newLineBytes, 0, newLineBytes.Length);
|
RequestStream.Write(newLineBytes, 0, newLineBytes.Length);
|
||||||
|
|
||||||
// Disposition header + newline
|
// Disposition header + newline
|
||||||
requestStream.Write(cDisposBytes, 0, cDisposBytes.Length);
|
RequestStream.Write(cDisposBytes, 0, cDisposBytes.Length);
|
||||||
requestStream.Write(newLineBytes, 0, newLineBytes.Length);
|
RequestStream.Write(newLineBytes, 0, newLineBytes.Length);
|
||||||
|
|
||||||
// Type header + newline
|
// Type header + newline
|
||||||
requestStream.Write(cTypeBytes, 0, cTypeBytes.Length);
|
RequestStream.Write(cTypeBytes, 0, cTypeBytes.Length);
|
||||||
requestStream.Write(newLineBytes, 0, newLineBytes.Length);
|
RequestStream.Write(newLineBytes, 0, newLineBytes.Length);
|
||||||
|
|
||||||
// newline + contents + newline
|
// newline + contents + newline
|
||||||
requestStream.Write(newLineBytes, 0, newLineBytes.Length);
|
RequestStream.Write(newLineBytes, 0, newLineBytes.Length);
|
||||||
requestStream.Write(file.Value, 0, file.Value.Length);
|
RequestStream.Write(file.Value, 0, file.Value.Length);
|
||||||
requestStream.Write(newLineBytes, 0, newLineBytes.Length);
|
RequestStream.Write(newLineBytes, 0, newLineBytes.Length);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
byte[] closingBound = Encoding.UTF8.GetBytes($@"--{boundary}--");
|
byte[] closingBound = Encoding.UTF8.GetBytes($@"--{boundary}--");
|
||||||
requestStream.Write(closingBound, 0, closingBound.Length);
|
RequestStream.Write(closingBound, 0, closingBound.Length);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
wRequest.ContentType = ContentType;
|
HttpWebRequest.ContentType = ContentType;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
wResponse = wRequest.GetResponse() as HttpWebResponse;
|
HttpWebResponse = HttpWebRequest.GetResponse() as HttpWebResponse;
|
||||||
} catch (WebException ex)
|
} catch (WebException ex)
|
||||||
{
|
{
|
||||||
wResponse = ex.Response as HttpWebResponse;
|
HttpWebResponse = ex.Response as HttpWebResponse;
|
||||||
}
|
}
|
||||||
|
|
||||||
responseStream = wResponse.GetResponseStream();
|
ResponseStream = HttpWebResponse.GetResponseStream();
|
||||||
}
|
}
|
||||||
|
|
||||||
#region IDisposable
|
#region IDisposable
|
||||||
private bool isDisposed = false;
|
|
||||||
|
|
||||||
private void Dispose(bool disposing)
|
private bool IsDisposed = false;
|
||||||
{
|
|
||||||
if (!isDisposed)
|
|
||||||
{
|
|
||||||
isDisposed = true;
|
|
||||||
requestStream?.Dispose();
|
|
||||||
wRequest?.Abort();
|
|
||||||
responseStream?.Dispose();
|
|
||||||
wResponse?.Close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
~WebRequest()
|
|
||||||
{
|
|
||||||
Dispose(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Disconnects and releases all unmanaged objects
|
/// Disconnects and releases all unmanaged objects
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void Dispose()
|
private void Dispose(bool disposing)
|
||||||
{
|
{
|
||||||
Dispose(true);
|
if (IsDisposed)
|
||||||
GC.SuppressFinalize(true);
|
return;
|
||||||
|
|
||||||
|
IsDisposed = true;
|
||||||
|
RequestStream?.Dispose();
|
||||||
|
HttpWebRequest?.Abort();
|
||||||
|
ResponseStream?.Dispose();
|
||||||
|
HttpWebResponse?.Close();
|
||||||
|
|
||||||
|
if (disposing)
|
||||||
|
GC.SuppressFinalize(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
~WebRequest()
|
||||||
|
=> Dispose(false);
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
=> Dispose(true);
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
30
Maki/RoleManager.cs
Normal file
30
Maki/RoleManager.cs
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace Maki
|
||||||
|
{
|
||||||
|
internal sealed class RoleManager : BaseManager<DiscordRole>
|
||||||
|
{
|
||||||
|
internal RoleManager()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public DiscordRole Id(ulong id)
|
||||||
|
{
|
||||||
|
lock (Collection)
|
||||||
|
return Collection.Where(x => x.Id == id).FirstOrDefault();
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Exists(ulong id)
|
||||||
|
{
|
||||||
|
lock (Collection)
|
||||||
|
return Collection.Where(x => x.Id == id).Count() > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerable<DiscordRole> Server(DiscordServer server)
|
||||||
|
{
|
||||||
|
lock (Collection)
|
||||||
|
return Collection.Where(x => x.Server == server).OrderByDescending(x => x.Position);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
23
Maki/ServerManager.cs
Normal file
23
Maki/ServerManager.cs
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace Maki
|
||||||
|
{
|
||||||
|
internal sealed class ServerManager : BaseManager<DiscordServer>
|
||||||
|
{
|
||||||
|
internal ServerManager()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public DiscordServer Id(ulong id)
|
||||||
|
{
|
||||||
|
lock (Collection)
|
||||||
|
return Collection.Where(x => x.Id == id).FirstOrDefault();
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Exists(ulong id)
|
||||||
|
{
|
||||||
|
lock (Collection)
|
||||||
|
return Collection.Where(x => x.Id == id).Count() > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,22 +0,0 @@
|
||||||
using Newtonsoft.Json;
|
|
||||||
|
|
||||||
namespace Maki.Structures.Auth
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Multi Factor Auth login request
|
|
||||||
/// </summary>
|
|
||||||
internal struct LoginMultiFactorAuth
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Multi factor auth code
|
|
||||||
/// </summary>
|
|
||||||
[JsonProperty("code")]
|
|
||||||
public string Code;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Multi factor auth ticket
|
|
||||||
/// </summary>
|
|
||||||
[JsonProperty("ticket")]
|
|
||||||
public string Ticket;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,22 +0,0 @@
|
||||||
using Newtonsoft.Json;
|
|
||||||
|
|
||||||
namespace Maki.Structures.Auth
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Login request
|
|
||||||
/// </summary>
|
|
||||||
internal struct LoginRequest
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// E-mail address
|
|
||||||
/// </summary>
|
|
||||||
[JsonProperty("email")]
|
|
||||||
public string Email;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Password
|
|
||||||
/// </summary>
|
|
||||||
[JsonProperty("password")]
|
|
||||||
public string Password;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,40 +0,0 @@
|
||||||
using Newtonsoft.Json;
|
|
||||||
|
|
||||||
namespace Maki.Structures.Auth
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Login response
|
|
||||||
/// </summary>
|
|
||||||
internal struct LoginResponse
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Indicates whether we require multi factor, is usually either null or true
|
|
||||||
/// </summary>
|
|
||||||
[JsonProperty("mfa")]
|
|
||||||
public bool? MFA;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Token
|
|
||||||
/// </summary>
|
|
||||||
[JsonProperty("token")]
|
|
||||||
public string Token;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// MFA Ticket, to be bundled with the mfa request
|
|
||||||
/// </summary>
|
|
||||||
[JsonProperty("ticket")]
|
|
||||||
public string Ticket;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Username errors
|
|
||||||
/// </summary>
|
|
||||||
[JsonProperty("username")]
|
|
||||||
public string[] UsernameError;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Password errors
|
|
||||||
/// </summary>
|
|
||||||
[JsonProperty("password")]
|
|
||||||
public string[] PasswordError;
|
|
||||||
}
|
|
||||||
}
|
|
17
Maki/UserManager.cs
Normal file
17
Maki/UserManager.cs
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace Maki
|
||||||
|
{
|
||||||
|
internal sealed class UserManager : BaseManager<DiscordUser>
|
||||||
|
{
|
||||||
|
internal UserManager()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public DiscordUser Id(ulong id)
|
||||||
|
{
|
||||||
|
lock (Collection)
|
||||||
|
return Collection.Where(x => x.Id == id).FirstOrDefault();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,11 +4,8 @@ namespace Maki
|
||||||
{
|
{
|
||||||
internal static class Utility
|
internal static class Utility
|
||||||
{
|
{
|
||||||
public static readonly DateTime UnixEpoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
|
|
||||||
public static readonly DateTime DiscordEpoch = new DateTime(2015, 1, 1, 0, 0, 0, DateTimeKind.Utc);
|
public static readonly DateTime DiscordEpoch = new DateTime(2015, 1, 1, 0, 0, 0, DateTimeKind.Utc);
|
||||||
|
|
||||||
public static DateTime FromUnixTimeMilliseconds(long ms) => UnixEpoch.AddMilliseconds(ms);
|
|
||||||
|
|
||||||
public static DateTime FromDiscordTimeMilliseconds(long ms) => DiscordEpoch.AddMilliseconds(ms);
|
public static DateTime FromDiscordTimeMilliseconds(long ms) => DiscordEpoch.AddMilliseconds(ms);
|
||||||
|
|
||||||
public static DateTime FromDiscordSnowflake(ulong snowflake) => FromDiscordTimeMilliseconds((long)snowflake >> 22);
|
public static DateTime FromDiscordSnowflake(ulong snowflake) => FromDiscordTimeMilliseconds((long)snowflake >> 22);
|
||||||
|
|
Reference in a new issue