use managers rather than random lists
This commit is contained in:
parent
82a74a3e63
commit
ca02bba839
22 changed files with 640 additions and 468 deletions
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.Rest;
|
||||
using Maki.Structures.Auth;
|
||||
using Maki.Structures.Channels;
|
||||
using Maki.Structures.Gateway;
|
||||
using Maki.Structures.Guilds;
|
||||
|
@ -10,6 +9,7 @@ using Maki.Structures.Roles;
|
|||
using Maki.Structures.Users;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
|
||||
namespace Maki
|
||||
|
@ -64,35 +64,49 @@ namespace Maki
|
|||
internal readonly GatewayShardClient ShardClient;
|
||||
|
||||
#region Containers
|
||||
|
||||
internal readonly ServerManager ServerManager;
|
||||
|
||||
/// <summary>
|
||||
/// Servers we're in
|
||||
/// </summary>
|
||||
internal readonly List<DiscordServer> servers = new List<DiscordServer>();
|
||||
public IEnumerable<DiscordServer> Servers => ServerManager.Items;
|
||||
|
||||
internal readonly UserManager UserManager;
|
||||
|
||||
/// <summary>
|
||||
/// Users we are affiliated with
|
||||
/// </summary>
|
||||
internal readonly List<DiscordUser> users = new List<DiscordUser>();
|
||||
public IEnumerable<DiscordUser> Users => UserManager.Items;
|
||||
|
||||
internal readonly MemberManager MemberManager;
|
||||
|
||||
/// <summary>
|
||||
/// Members of servers, different from users!
|
||||
/// </summary>
|
||||
internal readonly List<DiscordMember> members = new List<DiscordMember>();
|
||||
public IEnumerable<DiscordMember> Members => MemberManager.Items;
|
||||
|
||||
internal readonly RoleManager RoleManager;
|
||||
|
||||
/// <summary>
|
||||
/// Roles in servers
|
||||
/// </summary>
|
||||
internal readonly List<DiscordRole> roles = new List<DiscordRole>();
|
||||
public IEnumerable<DiscordRole> Roles => RoleManager.Items;
|
||||
|
||||
internal readonly ChannelManager ChannelManager;
|
||||
|
||||
/// <summary>
|
||||
/// Channels
|
||||
/// </summary>
|
||||
internal readonly List<DiscordChannel> channels = new List<DiscordChannel>();
|
||||
public IEnumerable<DiscordChannel> Channels => ChannelManager.Items;
|
||||
|
||||
internal readonly MessageManager MessageManager;
|
||||
|
||||
/// <summary>
|
||||
/// Messages
|
||||
/// </summary>
|
||||
internal readonly List<DiscordMessage> messages = new List<DiscordMessage>();
|
||||
public IEnumerable<DiscordMessage> Messages => MessageManager.Items;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Events
|
||||
|
@ -207,8 +221,7 @@ namespace Maki
|
|||
public event Action<DiscordUser> OnUserUpdate;
|
||||
#endregion
|
||||
|
||||
public DiscordServer[] Servers => servers.ToArray();
|
||||
public DiscordUser Me => users.FirstOrDefault();
|
||||
public DiscordUser Me => UserManager.Items.FirstOrDefault();
|
||||
|
||||
private DiscordParams Params;
|
||||
|
||||
|
@ -220,6 +233,13 @@ namespace Maki
|
|||
Params = parameters ?? new DiscordParams();
|
||||
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
|
||||
ShardClient.OnChannelCreate += ShardManager_OnChannelCreate;
|
||||
ShardClient.OnChannelUpdate += ShardManager_OnChannelUpdate;
|
||||
|
@ -259,23 +279,11 @@ namespace Maki
|
|||
#endregion
|
||||
}
|
||||
|
||||
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();
|
||||
|
||||
int shards = 1;
|
||||
|
||||
using (WebRequest wr = new WebRequest(HttpMethod.GET, IsBot ? RestEndpoints.GatewayBot : RestEndpoints.Gateway))
|
||||
|
@ -303,76 +311,6 @@ namespace Maki
|
|||
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>
|
||||
/// Connects to Discord using a provided token and token type
|
||||
/// </summary>
|
||||
|
@ -391,23 +329,27 @@ namespace Maki
|
|||
public void Disconnect()
|
||||
{
|
||||
ShardClient.Disconnect();
|
||||
ClearContainers();
|
||||
Token = string.Empty;
|
||||
Gateway = string.Empty;
|
||||
}
|
||||
|
||||
#region Event Handlers
|
||||
|
||||
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);
|
||||
channels.Add(chan);
|
||||
ChannelManager.Add(chan);
|
||||
OnChannelCreate?.Invoke(chan);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
|
@ -435,8 +377,10 @@ namespace Maki
|
|||
|
||||
private void ShardManager_OnChannelDelete(GatewayShard shard, Channel channel)
|
||||
{
|
||||
DiscordChannel chan = channels.Find(x => x.Id == channel.Id);
|
||||
channels.Remove(chan);
|
||||
DiscordChannel chan = ChannelManager.Id(channel.Id);
|
||||
Debug.Assert(chan != null, "channel is null");
|
||||
|
||||
ChannelManager.Remove(chan);
|
||||
OnChannelDelete?.Invoke(chan);
|
||||
}
|
||||
|
||||
|
@ -452,9 +396,15 @@ namespace Maki
|
|||
$"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);
|
||||
DiscordUser user = UserManager.Id(sUser.Id);
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -470,24 +420,28 @@ namespace Maki
|
|||
$"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);
|
||||
DiscordUser user = UserManager.Id(sUser.Id);
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
servers.Add(server);
|
||||
ServerManager.Add(server);
|
||||
}
|
||||
else
|
||||
{
|
||||
server = servers.Find(x => x.Id == guild.Id);
|
||||
server.Name = guild.Name;
|
||||
server.OwnerId = guild.OwnerId ?? 0;
|
||||
server.IconHash = guild.IconHash;
|
||||
|
@ -500,7 +454,7 @@ namespace Maki
|
|||
Channel channel = guild.Channels[i];
|
||||
channel.GuildId = server.Id;
|
||||
|
||||
if (channels.Where(x => x.Id == channel.Id).Count() > 0)
|
||||
if (ChannelManager.Exists(channel.Id))
|
||||
ShardManager_OnChannelUpdate(shard, channel);
|
||||
else
|
||||
ShardManager_OnChannelCreate(shard, channel);
|
||||
|
@ -515,7 +469,7 @@ namespace Maki
|
|||
RoleId = role.Id
|
||||
};
|
||||
|
||||
if (roles.Where(x => x.Id == role.Id).Count() > 0)
|
||||
if (RoleManager.Exists(role.Id))
|
||||
ShardManager_OnGuildRoleUpdate(shard, gRole);
|
||||
else
|
||||
ShardManager_OnGuildRoleCreate(shard, gRole);
|
||||
|
@ -532,7 +486,8 @@ namespace Maki
|
|||
|
||||
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.OwnerId = guild.OwnerId ?? 0;
|
||||
|
@ -549,16 +504,20 @@ namespace Maki
|
|||
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);
|
||||
|
||||
// NOT THREAD SAFE AT ALL
|
||||
MessageManager .Server(server).ToList().ForEach(x => MessageManager.Remove(x));
|
||||
ChannelManager .Server(server).ToList().ForEach(x => ChannelManager.Remove(x));
|
||||
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)
|
||||
{
|
||||
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.OwnerId = guild.OwnerId ?? 0;
|
||||
|
@ -580,31 +539,41 @@ namespace Maki
|
|||
|
||||
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;
|
||||
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();
|
||||
Debug.Assert(sMember.GuildId.HasValue, "GuildId has no value");
|
||||
|
||||
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);
|
||||
users.Add(user);
|
||||
UserManager.Add(user);
|
||||
}
|
||||
|
||||
DiscordMember member = new DiscordMember(this, sMember, user, server);
|
||||
members.Add(member);
|
||||
MemberManager.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);
|
||||
|
||||
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.IsDeaf = sMember.IsDeafened == true;
|
||||
member.IsMute = sMember.IsMuted == true;
|
||||
|
@ -615,8 +584,12 @@ namespace Maki
|
|||
|
||||
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);
|
||||
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");
|
||||
|
||||
MemberManager.Remove(member);
|
||||
OnMemberRemove?.Invoke(member);
|
||||
}
|
||||
|
||||
|
@ -632,13 +605,20 @@ namespace Maki
|
|||
$"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();
|
||||
DiscordServer server = ServerManager.Id(sRole.Guild);
|
||||
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);
|
||||
roles.Add(role);
|
||||
RoleManager.Add(role);
|
||||
} else
|
||||
{
|
||||
role.Colour.Raw = sRole.Role.Value.Colour.Value;
|
||||
|
@ -649,17 +629,25 @@ namespace Maki
|
|||
|
||||
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);
|
||||
Debug.Assert(sRole.RoleId.HasValue, "RoleId has no value");
|
||||
DiscordRole role = RoleManager.Id(sRole.RoleId ?? 0);
|
||||
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);
|
||||
}
|
||||
|
||||
private void ShardManager_OnGuildRoleUpdate(GatewayShard shard, GuildRole sRole)
|
||||
{
|
||||
Debug.Assert(sRole.Role.HasValue, "Role has no 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.IsHoisted = dRole.IsHoisted == true;
|
||||
role.IsMentionable = dRole.IsMentionable == true;
|
||||
|
@ -697,24 +685,32 @@ namespace Maki
|
|||
|
||||
private void ShardManager_OnMessageCreate(GatewayShard shard, Message message)
|
||||
{
|
||||
DiscordChannel channel = channels.Find(x => x.Id == message.ChannelId);
|
||||
DiscordMember member = members.Where(x => x.User.Id == message.User.Id && x.Server == channel.Server).FirstOrDefault();
|
||||
DiscordChannel channel = ChannelManager.Id(message.ChannelId);
|
||||
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);
|
||||
messages.Add(msg);
|
||||
MessageManager.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);
|
||||
DiscordMessage msg = MessageManager.Id(message.Id);
|
||||
Debug.Assert(msg != null, "message is null");
|
||||
|
||||
MessageManager.Remove(msg);
|
||||
OnMessageDelete?.Invoke(msg);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
using (WebRequest wr = new WebRequest(HttpMethod.GET, RestEndpoints.ChannelMessage(message.ChannelId, message.Id)))
|
||||
|
@ -727,10 +723,14 @@ namespace Maki
|
|||
message = wr.ResponseJson<Message>();
|
||||
}
|
||||
|
||||
DiscordChannel channel = channels.Where(x => x.Id == message.ChannelId).FirstOrDefault();
|
||||
DiscordMember member = members.Where(x => x.User.Id == message.User.Id && (channel.Server == null || channel.Server == x.Server)).FirstOrDefault();
|
||||
DiscordChannel channel = ChannelManager.Id(message.ChannelId);
|
||||
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);
|
||||
messages.Add(msg);
|
||||
MessageManager.Add(msg);
|
||||
} else
|
||||
{
|
||||
if (!string.IsNullOrEmpty(message.Content))
|
||||
|
@ -746,14 +746,19 @@ namespace Maki
|
|||
|
||||
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);
|
||||
DiscordChannel channel = ChannelManager.Id(typing.Channel);
|
||||
Debug.Assert(channel != null, "channel is null");
|
||||
|
||||
DiscordUser user = UserManager.Id(typing.User);
|
||||
Debug.Assert(user != null, "user is null");
|
||||
|
||||
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);
|
||||
DiscordMember member = MemberManager.Id(presence.Guild, presence.User.Id);
|
||||
Debug.Assert(member != null, "member is null");
|
||||
|
||||
if (!string.IsNullOrEmpty(presence.User.Username))
|
||||
member.User.Username = presence.User.Username;
|
||||
|
@ -771,20 +776,20 @@ namespace Maki
|
|||
|
||||
switch (presence.Status.ToLower())
|
||||
{
|
||||
case @"online":
|
||||
case "online":
|
||||
member.User.Status = DiscordUserStatus.Online;
|
||||
break;
|
||||
|
||||
case @"away":
|
||||
case @"idle":
|
||||
case "away":
|
||||
case "idle":
|
||||
member.User.Status = DiscordUserStatus.Idle;
|
||||
break;
|
||||
|
||||
case @"dnd":
|
||||
case "dnd":
|
||||
member.User.Status = DiscordUserStatus.DoNotDisturb;
|
||||
break;
|
||||
|
||||
case @"offline":
|
||||
case "offline":
|
||||
default:
|
||||
member.User.Status = DiscordUserStatus.Offline;
|
||||
break;
|
||||
|
@ -800,24 +805,24 @@ namespace Maki
|
|||
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)
|
||||
if (ChannelManager.Exists(channel.Id))
|
||||
continue;
|
||||
|
||||
channels.Add(channel);
|
||||
ChannelManager.Add(channel);
|
||||
}
|
||||
|
||||
foreach (Guild guild in ready.UnavailableGuilds)
|
||||
{
|
||||
DiscordServer server = new DiscordServer(this, guild);
|
||||
|
||||
if (servers.Where(x => x.Id == server.Id).Count() > 0)
|
||||
if (ServerManager.Exists(server.Id))
|
||||
continue;
|
||||
|
||||
servers.Add(server);
|
||||
ServerManager.Add(server);
|
||||
}
|
||||
|
||||
DiscordUser user = new DiscordUser(this, ready.User);
|
||||
users.Add(user);
|
||||
UserManager.Add(user);
|
||||
OnReady?.Invoke(user);
|
||||
}
|
||||
|
||||
|
@ -838,12 +843,13 @@ namespace Maki
|
|||
$"Is verified?: {user.IsVerified}",
|
||||
$"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);
|
||||
users.Add(user);
|
||||
UserManager.Add(user);
|
||||
}
|
||||
|
||||
OnUserUpdate?.Invoke(user);
|
||||
|
@ -864,32 +870,41 @@ namespace Maki
|
|||
private void ShardManager_OnSocketMessage(GatewayShard shard, string text)
|
||||
{
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IDisposable
|
||||
private bool isDisposed = false;
|
||||
|
||||
private void Dispose(bool disposing)
|
||||
{
|
||||
if (!isDisposed) {
|
||||
isDisposed = true;
|
||||
Disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
~Discord()
|
||||
{
|
||||
Dispose(false);
|
||||
}
|
||||
private bool IsDisposed = false;
|
||||
|
||||
/// <summary>
|
||||
/// Disconnects and releases all unmanaged objects
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
private void Dispose(bool disposing)
|
||||
{
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(true);
|
||||
if (IsDisposed)
|
||||
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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ using Maki.Structures.Channels;
|
|||
using Maki.Structures.Messages;
|
||||
using Maki.Structures.Rest;
|
||||
using Newtonsoft.Json;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
|
||||
namespace Maki
|
||||
|
@ -59,7 +60,8 @@ namespace Maki
|
|||
|
||||
if (wr.Status != 200 || wr.Response.Length < 1)
|
||||
// TODO: elaborate
|
||||
throw new DiscordException("Failed to send message");
|
||||
//throw new DiscordException("Failed to send message");
|
||||
return null;
|
||||
|
||||
msg = wr.ResponseJson<Message>();
|
||||
}
|
||||
|
@ -67,8 +69,11 @@ namespace Maki
|
|||
if (!msg.HasValue)
|
||||
throw new DiscordException("Empty response?");
|
||||
|
||||
DiscordMessage message = new DiscordMessage(client, msg.Value, this, client.members.Find(x => x.User.Id == msg.Value.User.Id));
|
||||
client.messages.Add(message);
|
||||
DiscordMember member = client.MemberManager.Id(Server, msg.Value.User.Id);
|
||||
Debug.Assert(member != null, "member is null");
|
||||
|
||||
DiscordMessage message = new DiscordMessage(client, msg.Value, this, member);
|
||||
client.MessageManager.Add(message);
|
||||
return message;
|
||||
}
|
||||
|
||||
|
|
|
@ -5,6 +5,41 @@ namespace Maki
|
|||
{
|
||||
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)
|
||||
{
|
||||
Raw = raw;
|
||||
|
@ -12,7 +47,9 @@ namespace Maki
|
|||
|
||||
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)
|
||||
|
@ -24,32 +61,10 @@ namespace Maki
|
|||
|
||||
if (hex.Length != 6)
|
||||
throw new FormatException("Invalid hex colour format!");
|
||||
|
||||
|
||||
Red = byte.Parse(hex.Substring(0, 2), NumberStyles.HexNumber);
|
||||
Green = byte.Parse(hex.Substring(2, 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;
|
||||
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 string Nickname { get; internal set; }
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
using Maki.Structures.Messages;
|
||||
using Maki.Structures.Rest;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
|
||||
namespace Maki
|
||||
|
@ -17,18 +19,20 @@ namespace Maki
|
|||
|
||||
public string Text { get; internal set; }
|
||||
public DateTime Edited { get; internal set; }
|
||||
public DiscordMember[] MentionsUsers { get; internal set; }
|
||||
public DiscordRole[] MentionsRoles { get; internal set; }
|
||||
public IEnumerable<DiscordMember> MentionsUsers { get; internal set; }
|
||||
public IEnumerable<DiscordRole> MentionsRoles { get; internal set; }
|
||||
public bool MentionsEveryone { get; internal set; }
|
||||
public bool IsPinned { get; internal set; }
|
||||
|
||||
public bool MentionsMe(bool everyone = false, bool roles = true) =>
|
||||
(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);
|
||||
|
||||
public bool IsMe => client.Me == User;
|
||||
|
||||
public DiscordServer Server => Channel.Server;
|
||||
|
||||
internal DiscordMessage(Discord discord, Message msg, DiscordChannel channel, DiscordMember member = null)
|
||||
{
|
||||
client = discord;
|
||||
|
@ -43,12 +47,13 @@ namespace Maki
|
|||
} else
|
||||
{
|
||||
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;
|
||||
MentionsUsers = client.members.Where(x => x.Server == channel.Server && msg.Mentions.Select(y => y.Id).Contains(x.User.Id)).ToArray();
|
||||
MentionsRoles = client.roles.Where(x => x.Server == channel.Server && msg.MentionsRoles.Contains(x.Id)).ToArray();
|
||||
MentionsUsers = client.MemberManager.Server(channel.Server).Where(x => msg.Mentions.Select(y => y.Id).Contains(x.User.Id));
|
||||
MentionsRoles = client.RoleManager .Server(channel.Server).Where(x => msg.MentionsRoles.Contains(x.Id));
|
||||
MentionsEveryone = msg.MentioningEveryone;
|
||||
IsPinned = msg.IsPinned == true;
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ using Maki.Structures.Guilds;
|
|||
using Maki.Structures.Rest;
|
||||
using Maki.Structures.Roles;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Maki
|
||||
|
@ -17,13 +18,17 @@ namespace Maki
|
|||
public DateTime Created { get; internal set; }
|
||||
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 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 DiscordRole[] Roles => client.roles.Where(x => x.Server == this).OrderByDescending(x => x.Position).ToArray();
|
||||
public string Icon(string ext = @"png", int size = 128) => RestEndpoints.CDN_URL + $@"/icons/{Id}/{IconHash}.{ext}?size={size}";
|
||||
|
||||
public IEnumerable<DiscordChannel> Channels => client.ChannelManager.Server(this);
|
||||
public IEnumerable<DiscordChannel> TextChannels => Channels.Where(x => x.Type == DiscordChannelType.Text);
|
||||
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)
|
||||
{
|
||||
|
@ -60,14 +65,15 @@ namespace Maki
|
|||
if (!roleStruct.HasValue)
|
||||
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);
|
||||
client.roles.Add(role);
|
||||
client.RoleManager.Add(role);
|
||||
}
|
||||
|
||||
|
||||
return role;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,26 +18,27 @@ namespace Maki.Gateway
|
|||
/// <summary>
|
||||
/// Managed (active) shards
|
||||
/// </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>
|
||||
/// Parent DiscordClient instance
|
||||
/// </summary>
|
||||
private Discord client;
|
||||
private Discord Client;
|
||||
|
||||
/// <summary>
|
||||
/// Number of active managed shards
|
||||
/// </summary>
|
||||
public int ShardCount => shards.Count;
|
||||
public int ShardCount
|
||||
=> Shards.Count;
|
||||
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
/// <param name="c">Parent DiscordClient instance</param>
|
||||
public GatewayShardClient(Discord c)
|
||||
{
|
||||
client = c;
|
||||
}
|
||||
/// <param name="client">Parent DiscordClient instance</param>
|
||||
public GatewayShardClient(Discord client)
|
||||
=> Client = client;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new Gateway Shard
|
||||
|
@ -46,25 +47,23 @@ namespace Maki.Gateway
|
|||
/// <returns>New Gateway Shard</returns>
|
||||
public GatewayShard Create(int id)
|
||||
{
|
||||
GatewayShard shard = new GatewayShard(id, client);
|
||||
GatewayShard shard = new GatewayShard(id, Client);
|
||||
ApplyEvents(shard);
|
||||
shards.Add(id, shard);
|
||||
|
||||
lock (Lock)
|
||||
Shards.Add(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>
|
||||
/// Destroys a Gateway Shard
|
||||
/// </summary>
|
||||
/// <param name="shard">Shard to destroy</param>
|
||||
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
|
||||
shard.Disconnect();
|
||||
|
@ -75,7 +74,11 @@ namespace Maki.Gateway
|
|||
/// <summary>
|
||||
/// Destroys all shards
|
||||
/// </summary>
|
||||
public void Disconnect() => shards.Keys.ToList().ForEach(x => Destroy(x));
|
||||
public void Disconnect()
|
||||
{
|
||||
lock (Lock)
|
||||
Shards.ToList().ForEach(x => Destroy(x));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Links all gateway events handlers to the shard
|
||||
|
@ -271,29 +274,27 @@ namespace Maki.Gateway
|
|||
|
||||
private bool IsDisposed = false;
|
||||
|
||||
private void Dispose(bool disposing)
|
||||
{
|
||||
if (!IsDisposed)
|
||||
{
|
||||
IsDisposed = true;
|
||||
Disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
~GatewayShardClient()
|
||||
{
|
||||
Dispose(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Releases all unmanaged resources used by this object
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
private void Dispose(bool disposing)
|
||||
{
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(true);
|
||||
if (IsDisposed)
|
||||
return;
|
||||
|
||||
IsDisposed = true;
|
||||
Disconnect();
|
||||
|
||||
if (disposing)
|
||||
GC.SuppressFinalize(true);
|
||||
}
|
||||
|
||||
~GatewayShardClient()
|
||||
=> Dispose(false);
|
||||
|
||||
public void Dispose()
|
||||
=> Dispose(true);
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
|
|
@ -39,17 +39,13 @@
|
|||
<HintPath>..\..\packages\Newtonsoft.Json.10.0.3\lib\net40\Newtonsoft.Json.dll</HintPath>
|
||||
</Reference>
|
||||
<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">
|
||||
<HintPath>..\..\packages\WebSocketSharp.1.0.3-rc11\lib\websocket-sharp.dll</HintPath>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="BaseManager.cs" />
|
||||
<Compile Include="ChannelManager.cs" />
|
||||
<Compile Include="DiscordChannel.cs" />
|
||||
<Compile Include="Discord.cs" />
|
||||
<Compile Include="DiscordChannelType.cs" />
|
||||
|
@ -69,6 +65,8 @@
|
|||
<Compile Include="DiscordUserStatus.cs" />
|
||||
<Compile Include="DiscordUser.cs" />
|
||||
<Compile Include="Gateway\GatewayEvent.cs" />
|
||||
<Compile Include="MemberManager.cs" />
|
||||
<Compile Include="MessageManager.cs" />
|
||||
<Compile Include="Rest\RestErrorCode.cs" />
|
||||
<Compile Include="Rest\HttpMethod.cs" />
|
||||
<Compile Include="Rest\RestEndpoints.cs" />
|
||||
|
@ -78,9 +76,8 @@
|
|||
<Compile Include="DiscordTokenType.cs" />
|
||||
<Compile Include="Gateway\GatewayCloseCode.cs" />
|
||||
<Compile Include="Rest\WebRequest.cs" />
|
||||
<Compile Include="Structures\Auth\LoginMultiFactorAuth.cs" />
|
||||
<Compile Include="Structures\Auth\LoginRequest.cs" />
|
||||
<Compile Include="Structures\Auth\LoginResponse.cs" />
|
||||
<Compile Include="RoleManager.cs" />
|
||||
<Compile Include="ServerManager.cs" />
|
||||
<Compile Include="Structures\Channels\Channel.cs" />
|
||||
<Compile Include="Structures\Channels\ChannelType.cs" />
|
||||
<Compile Include="Structures\Embeds\Embed.cs" />
|
||||
|
@ -125,6 +122,7 @@
|
|||
<Compile Include="Structures\Roles\Role.cs" />
|
||||
<Compile Include="Structures\Users\PermissionOverwrite.cs" />
|
||||
<Compile Include="Structures\Users\User.cs" />
|
||||
<Compile Include="UserManager.cs" />
|
||||
<Compile Include="Utility.cs" />
|
||||
</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.Runtime.CompilerServices;
|
||||
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: AssemblyDescription("Discord Client library")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("Maki")]
|
||||
[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)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("97523aed-b694-42c2-96ac-86a1d65109f7")]
|
||||
|
||||
// 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")]
|
||||
[assembly: AssemblyVersion("1.0.*")]
|
||||
|
|
|
@ -8,17 +8,17 @@
|
|||
/// <summary>
|
||||
/// Base URL of Discord
|
||||
/// </summary>
|
||||
public const string BASE_URL = @"https://discordapp.com";
|
||||
public const string BASE_URL = "https://discordapp.com";
|
||||
|
||||
/// <summary>
|
||||
/// Path to the REST API
|
||||
/// </summary>
|
||||
public static string BASE_PATH => @"/api/v" + Discord.GATEWAY_VERSION;
|
||||
public static string BASE_PATH => "/api/v" + Discord.GATEWAY_VERSION;
|
||||
|
||||
/// <summary>
|
||||
/// Url of Discord's CDN
|
||||
/// </summary>
|
||||
public const string CDN_URL = @"https://cdn.discordapp.com";
|
||||
public const string CDN_URL = "https://cdn.discordapp.com";
|
||||
|
||||
#region Channels
|
||||
/// <summary>
|
||||
|
@ -349,18 +349,6 @@
|
|||
public static string OAuth2Application(ulong appId) => $@"/oauth2/applications/{appId}";
|
||||
#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
|
||||
/// <summary>
|
||||
/// Gets a User endpoint
|
||||
|
|
|
@ -16,7 +16,7 @@ namespace Maki.Rest
|
|||
private const string JSON_CONTENT_TYPE = @"application/json";
|
||||
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 string Url;
|
||||
|
@ -24,16 +24,16 @@ namespace Maki.Rest
|
|||
public string UserAgent { get; set; } = USER_AGENT;
|
||||
|
||||
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
|
||||
internal static string Authorisation { get; set; }
|
||||
|
||||
private readonly Dictionary<string, string> headers = 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, string> Headers = 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, string> mimeTypes = new Dictionary<string, string>()
|
||||
private readonly Dictionary<string, string> MimeTypes = new Dictionary<string, string>()
|
||||
{
|
||||
{ "png", "image/png" },
|
||||
{ "jpg", "image/jpeg" },
|
||||
|
@ -41,37 +41,47 @@ namespace Maki.Rest
|
|||
{ "gif", "image/gif" },
|
||||
};
|
||||
|
||||
private byte[] rawContent = new byte[0];
|
||||
private HttpWebRequest wRequest;
|
||||
private Stream requestStream;
|
||||
private HttpWebResponse wResponse;
|
||||
private Stream responseStream;
|
||||
private byte[] RawRequestBody = new byte[0];
|
||||
private HttpWebRequest HttpWebRequest;
|
||||
private Stream RequestStream;
|
||||
private HttpWebResponse HttpWebResponse;
|
||||
private Stream ResponseStream;
|
||||
|
||||
private byte[] rawResponse;
|
||||
private byte[] RawResponseValue;
|
||||
public byte[] RawResponse
|
||||
{
|
||||
get
|
||||
{
|
||||
if (rawResponse == null)
|
||||
if (RawResponseValue == null)
|
||||
{
|
||||
rawResponse = new byte[BUFFER_SIZE];
|
||||
responseStream.Read(rawResponse, 0, rawResponse.Length);
|
||||
using (MemoryStream ms = new MemoryStream())
|
||||
{
|
||||
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
|
||||
{
|
||||
get
|
||||
{
|
||||
if (string.IsNullOrEmpty(responseString))
|
||||
responseString = Encoding.UTF8.GetString(RawResponse).Trim('\0');
|
||||
if (string.IsNullOrEmpty(ResponseString))
|
||||
ResponseString = Encoding.UTF8.GetString(RawResponse);
|
||||
|
||||
return responseString;
|
||||
return ResponseString;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -79,7 +89,7 @@ namespace Maki.Rest
|
|||
JsonConvert.DeserializeObject<T>(Response);
|
||||
|
||||
public short Status =>
|
||||
(short)wResponse?.StatusCode;
|
||||
(short)HttpWebResponse?.StatusCode;
|
||||
|
||||
static WebRequest()
|
||||
{
|
||||
|
@ -93,7 +103,7 @@ namespace Maki.Rest
|
|||
}
|
||||
|
||||
public void AddRaw(byte[] bytes) =>
|
||||
rawContent = bytes;
|
||||
RawRequestBody = bytes;
|
||||
|
||||
public void AddRaw(string str) =>
|
||||
AddRaw(Encoding.UTF8.GetBytes(str));
|
||||
|
@ -105,10 +115,10 @@ namespace Maki.Rest
|
|||
}
|
||||
|
||||
public void AddParam(string name, string contents) =>
|
||||
parameters.Add(name, contents);
|
||||
Parameters.Add(name, contents);
|
||||
|
||||
public void AddFile(string name, byte[] bytes) =>
|
||||
files.Add(name, bytes);
|
||||
Files.Add(name, bytes);
|
||||
|
||||
public void Perform()
|
||||
{
|
||||
|
@ -124,50 +134,50 @@ namespace Maki.Rest
|
|||
|
||||
if (Method == HttpMethod.GET
|
||||
|| Method == HttpMethod.DELETE)
|
||||
if (parameters.Count > 1)
|
||||
if (Parameters.Count > 1)
|
||||
{
|
||||
if (!Url.Contains('?'))
|
||||
urlBuilder.Append(@"?");
|
||||
|
||||
foreach (KeyValuePair<string, string> param in parameters)
|
||||
foreach (KeyValuePair<string, string> param in Parameters)
|
||||
urlBuilder.Append($@"{param.Key}={param.Value}&");
|
||||
}
|
||||
|
||||
string url = urlBuilder.ToString().TrimEnd('&');
|
||||
|
||||
wRequest = System.Net.WebRequest.Create(url) as HttpWebRequest;
|
||||
wRequest.Method = Method.ToString();
|
||||
wRequest.UserAgent = UserAgent;
|
||||
wRequest.KeepAlive = true;
|
||||
HttpWebRequest = System.Net.WebRequest.Create(url) as HttpWebRequest;
|
||||
HttpWebRequest.Method = Method.ToString();
|
||||
HttpWebRequest.UserAgent = UserAgent;
|
||||
HttpWebRequest.KeepAlive = true;
|
||||
//wRequest.AutomaticDecompression = DecompressionMethods.Deflate | DecompressionMethods.GZip;
|
||||
wRequest.ReadWriteTimeout = Timeout.Infinite;
|
||||
wRequest.Timeout = Timeout.Infinite;
|
||||
HttpWebRequest.ReadWriteTimeout = Timeout.Infinite;
|
||||
HttpWebRequest.Timeout = Timeout.Infinite;
|
||||
|
||||
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)
|
||||
wRequest.Headers[header.Key] = header.Value;
|
||||
foreach (KeyValuePair<string, string> header in Headers)
|
||||
HttpWebRequest.Headers[header.Key] = header.Value;
|
||||
|
||||
if (Method == HttpMethod.POST
|
||||
|| Method == HttpMethod.PUT
|
||||
|| Method == HttpMethod.PATCH)
|
||||
{
|
||||
requestStream = wRequest.GetRequestStream();
|
||||
RequestStream = HttpWebRequest.GetRequestStream();
|
||||
|
||||
if (parameters.Count + files.Count < 1)
|
||||
requestStream.Write(rawContent, 0, rawContent.Length);
|
||||
if (Parameters.Count + Files.Count < 1)
|
||||
RequestStream.Write(RawRequestBody, 0, RawRequestBody.Length);
|
||||
else
|
||||
{
|
||||
string boundary = $@"-----------------------------{DateTime.Now.Ticks}";
|
||||
ContentType = $@"{FORM_CONTENT_TYPE}; boundary={boundary}";
|
||||
|
||||
if (parameters.Count >= 1)
|
||||
if (Parameters.Count >= 1)
|
||||
{
|
||||
StringBuilder postBodyBuilder = new StringBuilder();
|
||||
byte[] postBody = new byte[0];
|
||||
|
||||
foreach (KeyValuePair<string, string> param in parameters)
|
||||
foreach (KeyValuePair<string, string> param in Parameters)
|
||||
{
|
||||
postBodyBuilder.AppendLine($@"--{boundary}");
|
||||
postBodyBuilder.AppendLine($@"Content-Disposition: form-data; name=""{param.Key}""");
|
||||
|
@ -176,90 +186,90 @@ namespace Maki.Rest
|
|||
}
|
||||
|
||||
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[] 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 fileExt = Path.GetExtension(file.Key).ToLower().TrimStart('.');
|
||||
|
||||
if (mimeTypes.ContainsKey(fileExt))
|
||||
cType = mimeTypes[fileExt];
|
||||
if (MimeTypes.ContainsKey(fileExt))
|
||||
cType = MimeTypes[fileExt];
|
||||
|
||||
byte[] cDisposBytes = Encoding.UTF8.GetBytes($@"Content-Disposition: form-data; name=""{file.Key}""; filename=""{file.Key}""");
|
||||
byte[] cTypeBytes = Encoding.UTF8.GetBytes($@"Content-Type: {cType}");
|
||||
|
||||
// Boundary + newline
|
||||
requestStream.Write(boundaryBytes, 0, boundaryBytes.Length);
|
||||
requestStream.Write(newLineBytes, 0, newLineBytes.Length);
|
||||
RequestStream.Write(boundaryBytes, 0, boundaryBytes.Length);
|
||||
RequestStream.Write(newLineBytes, 0, newLineBytes.Length);
|
||||
|
||||
// Disposition header + newline
|
||||
requestStream.Write(cDisposBytes, 0, cDisposBytes.Length);
|
||||
requestStream.Write(newLineBytes, 0, newLineBytes.Length);
|
||||
RequestStream.Write(cDisposBytes, 0, cDisposBytes.Length);
|
||||
RequestStream.Write(newLineBytes, 0, newLineBytes.Length);
|
||||
|
||||
// Type header + newline
|
||||
requestStream.Write(cTypeBytes, 0, cTypeBytes.Length);
|
||||
requestStream.Write(newLineBytes, 0, newLineBytes.Length);
|
||||
RequestStream.Write(cTypeBytes, 0, cTypeBytes.Length);
|
||||
RequestStream.Write(newLineBytes, 0, newLineBytes.Length);
|
||||
|
||||
// newline + contents + newline
|
||||
requestStream.Write(newLineBytes, 0, newLineBytes.Length);
|
||||
requestStream.Write(file.Value, 0, file.Value.Length);
|
||||
requestStream.Write(newLineBytes, 0, newLineBytes.Length);
|
||||
RequestStream.Write(newLineBytes, 0, newLineBytes.Length);
|
||||
RequestStream.Write(file.Value, 0, file.Value.Length);
|
||||
RequestStream.Write(newLineBytes, 0, newLineBytes.Length);
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
wResponse = wRequest.GetResponse() as HttpWebResponse;
|
||||
HttpWebResponse = HttpWebRequest.GetResponse() as HttpWebResponse;
|
||||
} catch (WebException ex)
|
||||
{
|
||||
wResponse = ex.Response as HttpWebResponse;
|
||||
HttpWebResponse = ex.Response as HttpWebResponse;
|
||||
}
|
||||
|
||||
responseStream = wResponse.GetResponseStream();
|
||||
ResponseStream = HttpWebResponse.GetResponseStream();
|
||||
}
|
||||
|
||||
#region IDisposable
|
||||
private bool isDisposed = false;
|
||||
|
||||
private void Dispose(bool disposing)
|
||||
{
|
||||
if (!isDisposed)
|
||||
{
|
||||
isDisposed = true;
|
||||
requestStream?.Dispose();
|
||||
wRequest?.Abort();
|
||||
responseStream?.Dispose();
|
||||
wResponse?.Close();
|
||||
}
|
||||
}
|
||||
|
||||
~WebRequest()
|
||||
{
|
||||
Dispose(false);
|
||||
}
|
||||
private bool IsDisposed = false;
|
||||
|
||||
/// <summary>
|
||||
/// Disconnects and releases all unmanaged objects
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
private void Dispose(bool disposing)
|
||||
{
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(true);
|
||||
if (IsDisposed)
|
||||
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
|
||||
}
|
||||
}
|
||||
|
|
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
|
||||
{
|
||||
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 DateTime FromUnixTimeMilliseconds(long ms) => UnixEpoch.AddMilliseconds(ms);
|
||||
|
||||
public static DateTime FromDiscordTimeMilliseconds(long ms) => DiscordEpoch.AddMilliseconds(ms);
|
||||
|
||||
public static DateTime FromDiscordSnowflake(ulong snowflake) => FromDiscordTimeMilliseconds((long)snowflake >> 22);
|
||||
|
|
Reference in a new issue