Initial commit, basic proxying working
This commit is contained in:
50
Myriad/Cache/DiscordCacheExtensions.cs
Normal file
50
Myriad/Cache/DiscordCacheExtensions.cs
Normal file
@@ -0,0 +1,50 @@
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using Myriad.Gateway;
|
||||
|
||||
namespace Myriad.Cache
|
||||
{
|
||||
public static class DiscordCacheExtensions
|
||||
{
|
||||
public static ValueTask HandleGatewayEvent(this IDiscordCache cache, IGatewayEvent evt)
|
||||
{
|
||||
switch (evt)
|
||||
{
|
||||
case GuildCreateEvent gc:
|
||||
return cache.SaveGuildCreate(gc);
|
||||
case GuildUpdateEvent gu:
|
||||
return cache.SaveGuild(gu);
|
||||
case GuildDeleteEvent gd:
|
||||
return cache.RemoveGuild(gd.Id);
|
||||
case ChannelCreateEvent cc:
|
||||
return cache.SaveChannel(cc);
|
||||
case ChannelUpdateEvent cu:
|
||||
return cache.SaveChannel(cu);
|
||||
case ChannelDeleteEvent cd:
|
||||
return cache.RemoveChannel(cd.Id);
|
||||
case GuildRoleCreateEvent grc:
|
||||
return cache.SaveRole(grc.GuildId, grc.Role);
|
||||
case GuildRoleUpdateEvent gru:
|
||||
return cache.SaveRole(gru.GuildId, gru.Role);
|
||||
case GuildRoleDeleteEvent grd:
|
||||
return cache.RemoveRole(grd.GuildId, grd.RoleId);
|
||||
case MessageCreateEvent mc:
|
||||
return cache.SaveUser(mc.Author);
|
||||
}
|
||||
|
||||
return default;
|
||||
}
|
||||
|
||||
private static async ValueTask SaveGuildCreate(this IDiscordCache cache, GuildCreateEvent guildCreate)
|
||||
{
|
||||
await cache.SaveGuild(guildCreate);
|
||||
|
||||
foreach (var channel in guildCreate.Channels)
|
||||
// The channel object does not include GuildId for some reason...
|
||||
await cache.SaveChannel(channel with { GuildId = guildCreate.Id });
|
||||
|
||||
foreach (var member in guildCreate.Members)
|
||||
await cache.SaveUser(member.User);
|
||||
}
|
||||
}
|
||||
}
|
28
Myriad/Cache/IDiscordCache.cs
Normal file
28
Myriad/Cache/IDiscordCache.cs
Normal file
@@ -0,0 +1,28 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using Myriad.Types;
|
||||
|
||||
namespace Myriad.Cache
|
||||
{
|
||||
public interface IDiscordCache
|
||||
{
|
||||
public ValueTask SaveGuild(Guild guild);
|
||||
public ValueTask SaveChannel(Channel channel);
|
||||
public ValueTask SaveUser(User user);
|
||||
public ValueTask SaveRole(ulong guildId, Role role);
|
||||
|
||||
public ValueTask RemoveGuild(ulong guildId);
|
||||
public ValueTask RemoveChannel(ulong channelId);
|
||||
public ValueTask RemoveUser(ulong userId);
|
||||
public ValueTask RemoveRole(ulong guildId, ulong roleId);
|
||||
|
||||
public ValueTask<Guild?> GetGuild(ulong guildId);
|
||||
public ValueTask<Channel?> GetChannel(ulong channelId);
|
||||
public ValueTask<User?> GetUser(ulong userId);
|
||||
public ValueTask<Role?> GetRole(ulong roleId);
|
||||
|
||||
public IAsyncEnumerable<Guild> GetAllGuilds();
|
||||
public ValueTask<IEnumerable<Channel>> GetGuildChannels(ulong guildId);
|
||||
}
|
||||
}
|
143
Myriad/Cache/MemoryDiscordCache.cs
Normal file
143
Myriad/Cache/MemoryDiscordCache.cs
Normal file
@@ -0,0 +1,143 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using Myriad.Types;
|
||||
|
||||
namespace Myriad.Cache
|
||||
{
|
||||
public class MemoryDiscordCache: IDiscordCache
|
||||
{
|
||||
private readonly ConcurrentDictionary<ulong, Channel> _channels;
|
||||
private readonly ConcurrentDictionary<ulong, CachedGuild> _guilds;
|
||||
private readonly ConcurrentDictionary<ulong, Role> _roles;
|
||||
private readonly ConcurrentDictionary<ulong, User> _users;
|
||||
|
||||
public MemoryDiscordCache()
|
||||
{
|
||||
_guilds = new ConcurrentDictionary<ulong, CachedGuild>();
|
||||
_channels = new ConcurrentDictionary<ulong, Channel>();
|
||||
_users = new ConcurrentDictionary<ulong, User>();
|
||||
_roles = new ConcurrentDictionary<ulong, Role>();
|
||||
}
|
||||
|
||||
public ValueTask SaveGuild(Guild guild)
|
||||
{
|
||||
SaveGuildRaw(guild);
|
||||
|
||||
foreach (var role in guild.Roles)
|
||||
// Don't call SaveRole because that updates guild state
|
||||
// and we just got a brand new one :)
|
||||
_roles[role.Id] = role;
|
||||
|
||||
return default;
|
||||
}
|
||||
|
||||
public ValueTask SaveChannel(Channel channel)
|
||||
{
|
||||
_channels[channel.Id] = channel;
|
||||
|
||||
if (channel.GuildId != null && _guilds.TryGetValue(channel.GuildId.Value, out var guild))
|
||||
guild.Channels.TryAdd(channel.Id, true);
|
||||
|
||||
return default;
|
||||
}
|
||||
|
||||
public ValueTask SaveUser(User user)
|
||||
{
|
||||
_users[user.Id] = user;
|
||||
return default;
|
||||
}
|
||||
|
||||
public ValueTask SaveRole(ulong guildId, Role role)
|
||||
{
|
||||
_roles[role.Id] = role;
|
||||
|
||||
if (_guilds.TryGetValue(guildId, out var guild))
|
||||
{
|
||||
// TODO: this code is stinky
|
||||
var found = false;
|
||||
for (var i = 0; i < guild.Guild.Roles.Length; i++)
|
||||
{
|
||||
if (guild.Guild.Roles[i].Id != role.Id)
|
||||
continue;
|
||||
|
||||
guild.Guild.Roles[i] = role;
|
||||
found = true;
|
||||
}
|
||||
|
||||
if (!found)
|
||||
{
|
||||
_guilds[guildId] = guild with {
|
||||
Guild = guild.Guild with {
|
||||
Roles = guild.Guild.Roles.Concat(new[] { role}).ToArray()
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return default;
|
||||
}
|
||||
|
||||
public ValueTask RemoveGuild(ulong guildId)
|
||||
{
|
||||
_guilds.TryRemove(guildId, out _);
|
||||
return default;
|
||||
}
|
||||
|
||||
public ValueTask RemoveChannel(ulong channelId)
|
||||
{
|
||||
if (!_channels.TryRemove(channelId, out var channel))
|
||||
return default;
|
||||
|
||||
if (channel.GuildId != null && _guilds.TryGetValue(channel.GuildId.Value, out var guild))
|
||||
guild.Channels.TryRemove(channel.Id, out _);
|
||||
|
||||
return default;
|
||||
}
|
||||
|
||||
public ValueTask RemoveUser(ulong userId)
|
||||
{
|
||||
_users.TryRemove(userId, out _);
|
||||
return default;
|
||||
}
|
||||
|
||||
public ValueTask RemoveRole(ulong guildId, ulong roleId)
|
||||
{
|
||||
_roles.TryRemove(roleId, out _);
|
||||
return default;
|
||||
}
|
||||
|
||||
public ValueTask<Guild?> GetGuild(ulong guildId) => new(_guilds.GetValueOrDefault(guildId)?.Guild);
|
||||
|
||||
public ValueTask<Channel?> GetChannel(ulong channelId) => new(_channels.GetValueOrDefault(channelId));
|
||||
|
||||
public ValueTask<User?> GetUser(ulong userId) => new(_users.GetValueOrDefault(userId));
|
||||
|
||||
public ValueTask<Role?> GetRole(ulong roleId) => new(_roles.GetValueOrDefault(roleId));
|
||||
|
||||
public async IAsyncEnumerable<Guild> GetAllGuilds()
|
||||
{
|
||||
foreach (var guild in _guilds.Values)
|
||||
yield return guild.Guild;
|
||||
}
|
||||
|
||||
public ValueTask<IEnumerable<Channel>> GetGuildChannels(ulong guildId)
|
||||
{
|
||||
if (!_guilds.TryGetValue(guildId, out var guild))
|
||||
throw new ArgumentException("Guild not found", nameof(guildId));
|
||||
|
||||
return new ValueTask<IEnumerable<Channel>>(guild.Channels.Keys.Select(c => _channels[c]));
|
||||
}
|
||||
|
||||
private CachedGuild SaveGuildRaw(Guild guild) =>
|
||||
_guilds.GetOrAdd(guild.Id, (_, g) => new CachedGuild(g), guild);
|
||||
|
||||
private record CachedGuild(Guild Guild)
|
||||
{
|
||||
public readonly ConcurrentDictionary<ulong, bool> Channels = new();
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user