refactor(bot): remove saving own user ID from ready event, rely on ID in config
This commit is contained in:
parent
aeb6411b6c
commit
9303dbb91e
@ -10,8 +10,6 @@ public static class DiscordCacheExtensions
|
|||||||
{
|
{
|
||||||
switch (evt)
|
switch (evt)
|
||||||
{
|
{
|
||||||
case ReadyEvent ready:
|
|
||||||
return cache.SaveOwnUser(ready.User.Id);
|
|
||||||
case GuildCreateEvent gc:
|
case GuildCreateEvent gc:
|
||||||
return cache.SaveGuildCreate(gc);
|
return cache.SaveGuildCreate(gc);
|
||||||
case GuildUpdateEvent gu:
|
case GuildUpdateEvent gu:
|
||||||
@ -108,7 +106,7 @@ public static class DiscordCacheExtensions
|
|||||||
|
|
||||||
if (channel.GuildId != null)
|
if (channel.GuildId != null)
|
||||||
{
|
{
|
||||||
var userId = await cache.GetOwnUser();
|
var userId = cache.GetOwnUser();
|
||||||
var member = await cache.TryGetSelfMember(channel.GuildId.Value);
|
var member = await cache.TryGetSelfMember(channel.GuildId.Value);
|
||||||
return await cache.PermissionsFor(channelId, userId, member);
|
return await cache.PermissionsFor(channelId, userId, member);
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,6 @@ namespace Myriad.Cache;
|
|||||||
|
|
||||||
public interface IDiscordCache
|
public interface IDiscordCache
|
||||||
{
|
{
|
||||||
public ValueTask SaveOwnUser(ulong userId);
|
|
||||||
public ValueTask SaveGuild(Guild guild);
|
public ValueTask SaveGuild(Guild guild);
|
||||||
public ValueTask SaveChannel(Channel channel);
|
public ValueTask SaveChannel(Channel channel);
|
||||||
public ValueTask SaveUser(User user);
|
public ValueTask SaveUser(User user);
|
||||||
@ -17,7 +16,7 @@ public interface IDiscordCache
|
|||||||
public ValueTask RemoveUser(ulong userId);
|
public ValueTask RemoveUser(ulong userId);
|
||||||
public ValueTask RemoveRole(ulong guildId, ulong roleId);
|
public ValueTask RemoveRole(ulong guildId, ulong roleId);
|
||||||
|
|
||||||
public Task<ulong> GetOwnUser();
|
internal ulong GetOwnUser();
|
||||||
public Task<Guild?> TryGetGuild(ulong guildId);
|
public Task<Guild?> TryGetGuild(ulong guildId);
|
||||||
public Task<Channel?> TryGetChannel(ulong channelId);
|
public Task<Channel?> TryGetChannel(ulong channelId);
|
||||||
public Task<User?> TryGetUser(ulong userId);
|
public Task<User?> TryGetUser(ulong userId);
|
||||||
|
@ -11,7 +11,12 @@ public class MemoryDiscordCache: IDiscordCache
|
|||||||
private readonly ConcurrentDictionary<ulong, CachedGuild> _guilds = new();
|
private readonly ConcurrentDictionary<ulong, CachedGuild> _guilds = new();
|
||||||
private readonly ConcurrentDictionary<ulong, Role> _roles = new();
|
private readonly ConcurrentDictionary<ulong, Role> _roles = new();
|
||||||
private readonly ConcurrentDictionary<ulong, User> _users = new();
|
private readonly ConcurrentDictionary<ulong, User> _users = new();
|
||||||
private ulong? _ownUserId { get; set; }
|
private readonly ulong _ownUserId;
|
||||||
|
|
||||||
|
public MemoryDiscordCache(ulong ownUserId)
|
||||||
|
{
|
||||||
|
_ownUserId = ownUserId;
|
||||||
|
}
|
||||||
|
|
||||||
public ValueTask SaveGuild(Guild guild)
|
public ValueTask SaveGuild(Guild guild)
|
||||||
{
|
{
|
||||||
@ -48,15 +53,6 @@ public class MemoryDiscordCache: IDiscordCache
|
|||||||
await SaveUser(recipient);
|
await SaveUser(recipient);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ValueTask SaveOwnUser(ulong userId)
|
|
||||||
{
|
|
||||||
// this (hopefully) never changes at runtime, so we skip out on re-assigning it
|
|
||||||
if (_ownUserId == null)
|
|
||||||
_ownUserId = userId;
|
|
||||||
|
|
||||||
return default;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ValueTask SaveUser(User user)
|
public ValueTask SaveUser(User user)
|
||||||
{
|
{
|
||||||
_users[user.Id] = user;
|
_users[user.Id] = user;
|
||||||
@ -127,7 +123,7 @@ public class MemoryDiscordCache: IDiscordCache
|
|||||||
return default;
|
return default;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task<ulong> GetOwnUser() => Task.FromResult(_ownUserId!.Value);
|
public ulong GetOwnUser() => _ownUserId;
|
||||||
|
|
||||||
public ValueTask RemoveRole(ulong guildId, ulong roleId)
|
public ValueTask RemoveRole(ulong guildId, ulong roleId)
|
||||||
{
|
{
|
||||||
|
@ -13,18 +13,18 @@ namespace Myriad.Cache;
|
|||||||
public class RedisDiscordCache: IDiscordCache
|
public class RedisDiscordCache: IDiscordCache
|
||||||
{
|
{
|
||||||
private readonly ILogger _logger;
|
private readonly ILogger _logger;
|
||||||
public RedisDiscordCache(ILogger logger)
|
private readonly ulong _ownUserId;
|
||||||
|
public RedisDiscordCache(ILogger logger, ulong ownUserId)
|
||||||
{
|
{
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
|
_ownUserId = ownUserId;
|
||||||
}
|
}
|
||||||
|
|
||||||
private ConnectionMultiplexer _redis { get; set; }
|
private ConnectionMultiplexer _redis { get; set; }
|
||||||
private ulong _ownUserId { get; set; }
|
|
||||||
|
|
||||||
public async Task InitAsync(string addr, ulong ownUserId)
|
public async Task InitAsync(string addr)
|
||||||
{
|
{
|
||||||
_redis = await ConnectionMultiplexer.ConnectAsync(addr);
|
_redis = await ConnectionMultiplexer.ConnectAsync(addr);
|
||||||
_ownUserId = ownUserId;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private IDatabase db => _redis.GetDatabase().WithKeyPrefix("discord:");
|
private IDatabase db => _redis.GetDatabase().WithKeyPrefix("discord:");
|
||||||
@ -78,12 +78,6 @@ public class RedisDiscordCache: IDiscordCache
|
|||||||
await SaveUser(recipient);
|
await SaveUser(recipient);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ValueTask SaveOwnUser(ulong userId)
|
|
||||||
{
|
|
||||||
// we get the own user ID in InitAsync, so no need to save it here
|
|
||||||
return default;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async ValueTask SaveUser(User user)
|
public async ValueTask SaveUser(User user)
|
||||||
{
|
{
|
||||||
_logger.Verbose("Saving user {UserId} to redis", user.Id);
|
_logger.Verbose("Saving user {UserId} to redis", user.Id);
|
||||||
@ -161,8 +155,7 @@ public class RedisDiscordCache: IDiscordCache
|
|||||||
public async ValueTask RemoveUser(ulong userId)
|
public async ValueTask RemoveUser(ulong userId)
|
||||||
=> await db.HashDeleteAsync("users", userId);
|
=> await db.HashDeleteAsync("users", userId);
|
||||||
|
|
||||||
// todo: try getting this from redis if we don't have it yet
|
public ulong GetOwnUser() => _ownUserId;
|
||||||
public Task<ulong> GetOwnUser() => Task.FromResult(_ownUserId);
|
|
||||||
|
|
||||||
public async ValueTask RemoveRole(ulong guildId, ulong roleId)
|
public async ValueTask RemoveRole(ulong guildId, ulong roleId)
|
||||||
{
|
{
|
||||||
|
@ -94,8 +94,7 @@ public class Bot
|
|||||||
// we HandleGatewayEvent **before** getting the own user, because the own user is set in HandleGatewayEvent for ReadyEvent
|
// we HandleGatewayEvent **before** getting the own user, because the own user is set in HandleGatewayEvent for ReadyEvent
|
||||||
await _cache.HandleGatewayEvent(evt);
|
await _cache.HandleGatewayEvent(evt);
|
||||||
|
|
||||||
var userId = await _cache.GetOwnUser();
|
await _cache.TryUpdateSelfMember(_config.ClientId, evt);
|
||||||
await _cache.TryUpdateSelfMember(userId, evt);
|
|
||||||
|
|
||||||
await OnEventReceivedInner(shardId, evt);
|
await OnEventReceivedInner(shardId, evt);
|
||||||
}
|
}
|
||||||
@ -200,13 +199,11 @@ public class Bot
|
|||||||
{
|
{
|
||||||
_metrics.Measure.Meter.Mark(BotMetrics.BotErrors, exc.GetType().FullName);
|
_metrics.Measure.Meter.Mark(BotMetrics.BotErrors, exc.GetType().FullName);
|
||||||
|
|
||||||
var ourUserId = await _cache.GetOwnUser();
|
|
||||||
|
|
||||||
// Make this beforehand so we can access the event ID for logging
|
// Make this beforehand so we can access the event ID for logging
|
||||||
var sentryEvent = new SentryEvent(exc);
|
var sentryEvent = new SentryEvent(exc);
|
||||||
|
|
||||||
// If the event is us responding to our own error messages, don't bother logging
|
// If the event is us responding to our own error messages, don't bother logging
|
||||||
if (evt is MessageCreateEvent mc && mc.Author.Id == ourUserId)
|
if (evt is MessageCreateEvent mc && mc.Author.Id == _config.ClientId)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var shouldReport = exc.IsOurProblem();
|
var shouldReport = exc.IsOurProblem();
|
||||||
@ -235,7 +232,7 @@ public class Bot
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
// Once we've sent it to Sentry, report it to the user (if we have permission to)
|
// Once we've sent it to Sentry, report it to the user (if we have permission to)
|
||||||
var reportChannel = handler.ErrorChannelFor(evt, ourUserId);
|
var reportChannel = handler.ErrorChannelFor(evt, _config.ClientId);
|
||||||
if (reportChannel == null)
|
if (reportChannel == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -5,7 +5,7 @@ public class BotConfig
|
|||||||
public static readonly string[] DefaultPrefixes = { "pk;", "pk!" };
|
public static readonly string[] DefaultPrefixes = { "pk;", "pk!" };
|
||||||
|
|
||||||
public string Token { get; set; }
|
public string Token { get; set; }
|
||||||
public ulong? ClientId { get; set; }
|
public ulong ClientId { get; set; }
|
||||||
|
|
||||||
// ASP.NET configuration merges arrays with defaults, so we leave this field nullable
|
// ASP.NET configuration merges arrays with defaults, so we leave this field nullable
|
||||||
// and fall back to the separate default array at the use site :)
|
// and fall back to the separate default array at the use site :)
|
||||||
|
@ -14,8 +14,6 @@ namespace PluralKit.Bot;
|
|||||||
public class Checks
|
public class Checks
|
||||||
{
|
{
|
||||||
private readonly BotConfig _botConfig;
|
private readonly BotConfig _botConfig;
|
||||||
// this must ONLY be used to get the bot's user ID
|
|
||||||
private readonly IDiscordCache _cache;
|
|
||||||
private readonly ProxyMatcher _matcher;
|
private readonly ProxyMatcher _matcher;
|
||||||
private readonly ProxyService _proxy;
|
private readonly ProxyService _proxy;
|
||||||
private readonly DiscordApiClient _rest;
|
private readonly DiscordApiClient _rest;
|
||||||
@ -28,10 +26,9 @@ public class Checks
|
|||||||
};
|
};
|
||||||
|
|
||||||
// todo: make sure everything uses the minimum amount of REST calls necessary
|
// todo: make sure everything uses the minimum amount of REST calls necessary
|
||||||
public Checks(DiscordApiClient rest, IDiscordCache cache, BotConfig botConfig, ProxyService proxy, ProxyMatcher matcher)
|
public Checks(DiscordApiClient rest, BotConfig botConfig, ProxyService proxy, ProxyMatcher matcher)
|
||||||
{
|
{
|
||||||
_rest = rest;
|
_rest = rest;
|
||||||
_cache = cache;
|
|
||||||
_botConfig = botConfig;
|
_botConfig = botConfig;
|
||||||
_proxy = proxy;
|
_proxy = proxy;
|
||||||
_matcher = matcher;
|
_matcher = matcher;
|
||||||
@ -69,14 +66,14 @@ public class Checks
|
|||||||
throw Errors.GuildNotFound(guildId);
|
throw Errors.GuildNotFound(guildId);
|
||||||
}
|
}
|
||||||
|
|
||||||
var guildMember = await _rest.GetGuildMember(guild.Id, await _cache.GetOwnUser());
|
var guildMember = await _rest.GetGuildMember(guild.Id, _botConfig.ClientId);
|
||||||
|
|
||||||
// Loop through every channel and group them by sets of permissions missing
|
// Loop through every channel and group them by sets of permissions missing
|
||||||
var permissionsMissing = new Dictionary<ulong, List<Channel>>();
|
var permissionsMissing = new Dictionary<ulong, List<Channel>>();
|
||||||
var hiddenChannels = false;
|
var hiddenChannels = false;
|
||||||
foreach (var channel in await _rest.GetGuildChannels(guild.Id))
|
foreach (var channel in await _rest.GetGuildChannels(guild.Id))
|
||||||
{
|
{
|
||||||
var botPermissions = PermissionExtensions.PermissionsFor(guild, channel, await _cache.GetOwnUser(), guildMember);
|
var botPermissions = PermissionExtensions.PermissionsFor(guild, channel, _botConfig.ClientId, guildMember);
|
||||||
var userPermissions = PermissionExtensions.PermissionsFor(guild, channel, ctx.Author.Id, senderGuildUser);
|
var userPermissions = PermissionExtensions.PermissionsFor(guild, channel, ctx.Author.Id, senderGuildUser);
|
||||||
|
|
||||||
if ((userPermissions & PermissionSet.ViewChannel) == 0)
|
if ((userPermissions & PermissionSet.ViewChannel) == 0)
|
||||||
@ -152,12 +149,12 @@ public class Checks
|
|||||||
if (guild == null)
|
if (guild == null)
|
||||||
throw new PKError(error);
|
throw new PKError(error);
|
||||||
|
|
||||||
var guildMember = await _rest.GetGuildMember(channel.GuildId.Value, await _cache.GetOwnUser());
|
var guildMember = await _rest.GetGuildMember(channel.GuildId.Value, _botConfig.ClientId);
|
||||||
|
|
||||||
if (!await ctx.CheckPermissionsInGuildChannel(channel, PermissionSet.ViewChannel))
|
if (!await ctx.CheckPermissionsInGuildChannel(channel, PermissionSet.ViewChannel))
|
||||||
throw new PKError(error);
|
throw new PKError(error);
|
||||||
|
|
||||||
var botPermissions = PermissionExtensions.PermissionsFor(guild, channel, await _cache.GetOwnUser(), guildMember);
|
var botPermissions = PermissionExtensions.PermissionsFor(guild, channel, _botConfig.ClientId, guildMember);
|
||||||
|
|
||||||
// We use a bitfield so we can set individual permission bits
|
// We use a bitfield so we can set individual permission bits
|
||||||
ulong missingPermissions = 0;
|
ulong missingPermissions = 0;
|
||||||
|
@ -18,26 +18,22 @@ namespace PluralKit.Bot;
|
|||||||
public class Misc
|
public class Misc
|
||||||
{
|
{
|
||||||
private readonly BotConfig _botConfig;
|
private readonly BotConfig _botConfig;
|
||||||
private readonly IDiscordCache _cache;
|
|
||||||
private readonly CpuStatService _cpu;
|
private readonly CpuStatService _cpu;
|
||||||
private readonly IMetrics _metrics;
|
private readonly IMetrics _metrics;
|
||||||
private readonly ShardInfoService _shards;
|
private readonly ShardInfoService _shards;
|
||||||
private readonly ModelRepository _repo;
|
private readonly ModelRepository _repo;
|
||||||
|
|
||||||
public Misc(BotConfig botConfig, IMetrics metrics, CpuStatService cpu, ModelRepository repo, ShardInfoService shards, IDiscordCache cache)
|
public Misc(BotConfig botConfig, IMetrics metrics, CpuStatService cpu, ModelRepository repo, ShardInfoService shards)
|
||||||
{
|
{
|
||||||
_botConfig = botConfig;
|
_botConfig = botConfig;
|
||||||
_metrics = metrics;
|
_metrics = metrics;
|
||||||
_cpu = cpu;
|
_cpu = cpu;
|
||||||
_repo = repo;
|
_repo = repo;
|
||||||
_shards = shards;
|
_shards = shards;
|
||||||
_cache = cache;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task Invite(Context ctx)
|
public async Task Invite(Context ctx)
|
||||||
{
|
{
|
||||||
var clientId = _botConfig.ClientId ?? await _cache.GetOwnUser();
|
|
||||||
|
|
||||||
var permissions =
|
var permissions =
|
||||||
PermissionSet.AddReactions |
|
PermissionSet.AddReactions |
|
||||||
PermissionSet.AttachFiles |
|
PermissionSet.AttachFiles |
|
||||||
@ -48,7 +44,7 @@ public class Misc
|
|||||||
PermissionSet.SendMessages;
|
PermissionSet.SendMessages;
|
||||||
|
|
||||||
var invite =
|
var invite =
|
||||||
$"https://discord.com/oauth2/authorize?client_id={clientId}&scope=bot%20applications.commands&permissions={(ulong)permissions}";
|
$"https://discord.com/oauth2/authorize?client_id={_botConfig.ClientId}&scope=bot%20applications.commands&permissions={(ulong)permissions}";
|
||||||
|
|
||||||
var botName = _botConfig.IsBetaBot ? "PluralKit Beta" : "PluralKit";
|
var botName = _botConfig.IsBetaBot ? "PluralKit Beta" : "PluralKit";
|
||||||
await ctx.Reply($"{Emojis.Success} Use this link to add {botName} to your server:\n<{invite}>");
|
await ctx.Reply($"{Emojis.Success} Use this link to add {botName} to your server:\n<{invite}>");
|
||||||
|
@ -59,7 +59,7 @@ public class MessageCreated: IEventHandler<MessageCreateEvent>
|
|||||||
|
|
||||||
public async Task Handle(int shardId, MessageCreateEvent evt)
|
public async Task Handle(int shardId, MessageCreateEvent evt)
|
||||||
{
|
{
|
||||||
if (evt.Author.Id == await _cache.GetOwnUser()) return;
|
if (evt.Author.Id == _config.ClientId) return;
|
||||||
if (evt.Type != Message.MessageType.Default && evt.Type != Message.MessageType.Reply) return;
|
if (evt.Type != Message.MessageType.Default && evt.Type != Message.MessageType.Reply) return;
|
||||||
if (IsDuplicateMessage(evt)) return;
|
if (IsDuplicateMessage(evt)) return;
|
||||||
|
|
||||||
@ -109,10 +109,8 @@ public class MessageCreated: IEventHandler<MessageCreateEvent>
|
|||||||
var content = evt.Content;
|
var content = evt.Content;
|
||||||
if (content == null) return false;
|
if (content == null) return false;
|
||||||
|
|
||||||
var ourUserId = await _cache.GetOwnUser();
|
|
||||||
|
|
||||||
// Check for command prefix
|
// Check for command prefix
|
||||||
if (!HasCommandPrefix(content, ourUserId, out var cmdStart) || cmdStart == content.Length)
|
if (!HasCommandPrefix(content, _config.ClientId, out var cmdStart) || cmdStart == content.Length)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Trim leading whitespace from command without actually modifying the string
|
// Trim leading whitespace from command without actually modifying the string
|
||||||
|
@ -15,6 +15,7 @@ namespace PluralKit.Bot;
|
|||||||
public class MessageEdited: IEventHandler<MessageUpdateEvent>
|
public class MessageEdited: IEventHandler<MessageUpdateEvent>
|
||||||
{
|
{
|
||||||
private readonly Bot _bot;
|
private readonly Bot _bot;
|
||||||
|
private readonly BotConfig _config;
|
||||||
private readonly IDiscordCache _cache;
|
private readonly IDiscordCache _cache;
|
||||||
private readonly Cluster _client;
|
private readonly Cluster _client;
|
||||||
private readonly IDatabase _db;
|
private readonly IDatabase _db;
|
||||||
@ -27,7 +28,7 @@ public class MessageEdited: IEventHandler<MessageUpdateEvent>
|
|||||||
|
|
||||||
public MessageEdited(LastMessageCacheService lastMessageCache, ProxyService proxy, IDatabase db,
|
public MessageEdited(LastMessageCacheService lastMessageCache, ProxyService proxy, IDatabase db,
|
||||||
IMetrics metrics, ModelRepository repo, Cluster client, IDiscordCache cache, Bot bot,
|
IMetrics metrics, ModelRepository repo, Cluster client, IDiscordCache cache, Bot bot,
|
||||||
DiscordApiClient rest, ILogger logger)
|
BotConfig config, DiscordApiClient rest, ILogger logger)
|
||||||
{
|
{
|
||||||
_lastMessageCache = lastMessageCache;
|
_lastMessageCache = lastMessageCache;
|
||||||
_proxy = proxy;
|
_proxy = proxy;
|
||||||
@ -37,13 +38,14 @@ public class MessageEdited: IEventHandler<MessageUpdateEvent>
|
|||||||
_client = client;
|
_client = client;
|
||||||
_cache = cache;
|
_cache = cache;
|
||||||
_bot = bot;
|
_bot = bot;
|
||||||
|
_config = config;
|
||||||
_rest = rest;
|
_rest = rest;
|
||||||
_logger = logger.ForContext<MessageEdited>();
|
_logger = logger.ForContext<MessageEdited>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task Handle(int shardId, MessageUpdateEvent evt)
|
public async Task Handle(int shardId, MessageUpdateEvent evt)
|
||||||
{
|
{
|
||||||
if (evt.Author.Value?.Id == await _cache.GetOwnUser()) return;
|
if (evt.Author.Value?.Id == _config.ClientId) return;
|
||||||
|
|
||||||
// Edit message events sometimes arrive with missing data; double-check it's all there
|
// Edit message events sometimes arrive with missing data; double-check it's all there
|
||||||
if (!evt.Content.HasValue || !evt.Author.HasValue || !evt.Member.HasValue)
|
if (!evt.Content.HasValue || !evt.Author.HasValue || !evt.Member.HasValue)
|
||||||
|
@ -18,6 +18,7 @@ namespace PluralKit.Bot;
|
|||||||
public class ReactionAdded: IEventHandler<MessageReactionAddEvent>
|
public class ReactionAdded: IEventHandler<MessageReactionAddEvent>
|
||||||
{
|
{
|
||||||
private readonly Bot _bot;
|
private readonly Bot _bot;
|
||||||
|
private readonly BotConfig _config;
|
||||||
private readonly IDiscordCache _cache;
|
private readonly IDiscordCache _cache;
|
||||||
private readonly Cluster _cluster;
|
private readonly Cluster _cluster;
|
||||||
private readonly CommandMessageService _commandMessageService;
|
private readonly CommandMessageService _commandMessageService;
|
||||||
@ -30,13 +31,14 @@ public class ReactionAdded: IEventHandler<MessageReactionAddEvent>
|
|||||||
|
|
||||||
public ReactionAdded(ILogger logger, IDatabase db, ModelRepository repo,
|
public ReactionAdded(ILogger logger, IDatabase db, ModelRepository repo,
|
||||||
CommandMessageService commandMessageService, IDiscordCache cache, Bot bot, Cluster cluster,
|
CommandMessageService commandMessageService, IDiscordCache cache, Bot bot, Cluster cluster,
|
||||||
DiscordApiClient rest, EmbedService embeds, PrivateChannelService dmCache)
|
BotConfig config, DiscordApiClient rest, EmbedService embeds, PrivateChannelService dmCache)
|
||||||
{
|
{
|
||||||
_db = db;
|
_db = db;
|
||||||
_repo = repo;
|
_repo = repo;
|
||||||
_commandMessageService = commandMessageService;
|
_commandMessageService = commandMessageService;
|
||||||
_cache = cache;
|
_cache = cache;
|
||||||
_bot = bot;
|
_bot = bot;
|
||||||
|
_config = config;
|
||||||
_cluster = cluster;
|
_cluster = cluster;
|
||||||
_rest = rest;
|
_rest = rest;
|
||||||
_embeds = embeds;
|
_embeds = embeds;
|
||||||
@ -52,7 +54,7 @@ public class ReactionAdded: IEventHandler<MessageReactionAddEvent>
|
|||||||
private async ValueTask TryHandleProxyMessageReactions(MessageReactionAddEvent evt)
|
private async ValueTask TryHandleProxyMessageReactions(MessageReactionAddEvent evt)
|
||||||
{
|
{
|
||||||
// ignore any reactions added by *us*
|
// ignore any reactions added by *us*
|
||||||
if (evt.UserId == await _cache.GetOwnUser())
|
if (evt.UserId == _config.ClientId)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Ignore reactions from bots (we can't DM them anyway)
|
// Ignore reactions from bots (we can't DM them anyway)
|
||||||
|
@ -58,7 +58,7 @@ public class Init
|
|||||||
|
|
||||||
var cache = services.Resolve<IDiscordCache>();
|
var cache = services.Resolve<IDiscordCache>();
|
||||||
if (cache is RedisDiscordCache)
|
if (cache is RedisDiscordCache)
|
||||||
await (cache as RedisDiscordCache).InitAsync(coreConfig.RedisAddr, config.ClientId!.Value);
|
await (cache as RedisDiscordCache).InitAsync(coreConfig.RedisAddr);
|
||||||
|
|
||||||
if (config.Cluster == null)
|
if (config.Cluster == null)
|
||||||
{
|
{
|
||||||
|
@ -49,8 +49,8 @@ public class BotModule: Module
|
|||||||
var botConfig = c.Resolve<BotConfig>();
|
var botConfig = c.Resolve<BotConfig>();
|
||||||
|
|
||||||
if (botConfig.UseRedisCache)
|
if (botConfig.UseRedisCache)
|
||||||
return new RedisDiscordCache(c.Resolve<ILogger>());
|
return new RedisDiscordCache(c.Resolve<ILogger>(), botConfig.ClientId);
|
||||||
return new MemoryDiscordCache();
|
return new MemoryDiscordCache(botConfig.ClientId);
|
||||||
}).AsSelf().SingleInstance();
|
}).AsSelf().SingleInstance();
|
||||||
builder.RegisterType<PrivateChannelService>().AsSelf().SingleInstance();
|
builder.RegisterType<PrivateChannelService>().AsSelf().SingleInstance();
|
||||||
|
|
||||||
|
@ -15,6 +15,7 @@ namespace PluralKit.Bot;
|
|||||||
public class LogChannelService
|
public class LogChannelService
|
||||||
{
|
{
|
||||||
private readonly Bot _bot;
|
private readonly Bot _bot;
|
||||||
|
private readonly BotConfig _config;
|
||||||
private readonly IDiscordCache _cache;
|
private readonly IDiscordCache _cache;
|
||||||
private readonly IDatabase _db;
|
private readonly IDatabase _db;
|
||||||
private readonly EmbedService _embed;
|
private readonly EmbedService _embed;
|
||||||
@ -23,7 +24,7 @@ public class LogChannelService
|
|||||||
private readonly DiscordApiClient _rest;
|
private readonly DiscordApiClient _rest;
|
||||||
|
|
||||||
public LogChannelService(EmbedService embed, ILogger logger, IDatabase db, ModelRepository repo,
|
public LogChannelService(EmbedService embed, ILogger logger, IDatabase db, ModelRepository repo,
|
||||||
IDiscordCache cache, DiscordApiClient rest, Bot bot)
|
IDiscordCache cache, DiscordApiClient rest, Bot bot, BotConfig config)
|
||||||
{
|
{
|
||||||
_embed = embed;
|
_embed = embed;
|
||||||
_db = db;
|
_db = db;
|
||||||
@ -31,6 +32,7 @@ public class LogChannelService
|
|||||||
_cache = cache;
|
_cache = cache;
|
||||||
_rest = rest;
|
_rest = rest;
|
||||||
_bot = bot;
|
_bot = bot;
|
||||||
|
_config = config;
|
||||||
_logger = logger.ForContext<LogChannelService>();
|
_logger = logger.ForContext<LogChannelService>();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -97,9 +99,9 @@ public class LogChannelService
|
|||||||
|
|
||||||
var guildMember = await _cache.TryGetSelfMember(channel.GuildId.Value);
|
var guildMember = await _cache.TryGetSelfMember(channel.GuildId.Value);
|
||||||
if (guildMember == null)
|
if (guildMember == null)
|
||||||
guildMember = await _rest.GetGuildMember(channel.GuildId.Value, await _cache.GetOwnUser());
|
guildMember = await _rest.GetGuildMember(channel.GuildId.Value, _config.ClientId);
|
||||||
|
|
||||||
var perms = PermissionExtensions.PermissionsFor(guild, channel, await _cache.GetOwnUser(), guildMember);
|
var perms = PermissionExtensions.PermissionsFor(guild, channel, _config.ClientId, guildMember);
|
||||||
return perms;
|
return perms;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,16 +17,18 @@ public class WebhookCacheService
|
|||||||
private readonly IDiscordCache _cache;
|
private readonly IDiscordCache _cache;
|
||||||
private readonly ILogger _logger;
|
private readonly ILogger _logger;
|
||||||
private readonly IMetrics _metrics;
|
private readonly IMetrics _metrics;
|
||||||
|
private readonly BotConfig _config;
|
||||||
|
|
||||||
|
|
||||||
private readonly DiscordApiClient _rest;
|
private readonly DiscordApiClient _rest;
|
||||||
private readonly ConcurrentDictionary<ulong, Lazy<Task<Webhook>>> _webhooks;
|
private readonly ConcurrentDictionary<ulong, Lazy<Task<Webhook>>> _webhooks;
|
||||||
|
|
||||||
public WebhookCacheService(ILogger logger, IMetrics metrics, DiscordApiClient rest, IDiscordCache cache)
|
public WebhookCacheService(ILogger logger, IMetrics metrics, DiscordApiClient rest, IDiscordCache cache, BotConfig config)
|
||||||
{
|
{
|
||||||
_metrics = metrics;
|
_metrics = metrics;
|
||||||
_rest = rest;
|
_rest = rest;
|
||||||
_cache = cache;
|
_cache = cache;
|
||||||
|
_config = config;
|
||||||
_logger = logger.ForContext<WebhookCacheService>();
|
_logger = logger.ForContext<WebhookCacheService>();
|
||||||
_webhooks = new ConcurrentDictionary<ulong, Lazy<Task<Webhook>>>();
|
_webhooks = new ConcurrentDictionary<ulong, Lazy<Task<Webhook>>>();
|
||||||
}
|
}
|
||||||
@ -86,8 +88,7 @@ public class WebhookCacheService
|
|||||||
var webhooks = await FetchChannelWebhooks(channelId);
|
var webhooks = await FetchChannelWebhooks(channelId);
|
||||||
|
|
||||||
// If the channel has a webhook created by PK, just return that one
|
// If the channel has a webhook created by PK, just return that one
|
||||||
var ourUserId = await _cache.GetOwnUser();
|
var ourWebhook = webhooks.FirstOrDefault(hook => IsWebhookMine(hook));
|
||||||
var ourWebhook = webhooks.FirstOrDefault(hook => IsWebhookMine(ourUserId, hook));
|
|
||||||
if (ourWebhook != null)
|
if (ourWebhook != null)
|
||||||
return ourWebhook;
|
return ourWebhook;
|
||||||
|
|
||||||
@ -122,5 +123,5 @@ public class WebhookCacheService
|
|||||||
return await _rest.CreateWebhook(channelId, new CreateWebhookRequest(WebhookName));
|
return await _rest.CreateWebhook(channelId, new CreateWebhookRequest(WebhookName));
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool IsWebhookMine(ulong userId, Webhook arg) => arg.User?.Id == userId && arg.Name == WebhookName;
|
private bool IsWebhookMine(Webhook arg) => arg.User?.Id == _config.ClientId && arg.Name == WebhookName;
|
||||||
}
|
}
|
@ -32,7 +32,7 @@ The bot can also take configuration from environment variables, which will overr
|
|||||||
The easiest way to get the bot running is with Docker. The repository contains a `docker-compose.yml` file ready to use.
|
The easiest way to get the bot running is with Docker. The repository contains a `docker-compose.yml` file ready to use.
|
||||||
|
|
||||||
* Clone this repository: `git clone https://github.com/PluralKit/PluralKit`
|
* Clone this repository: `git clone https://github.com/PluralKit/PluralKit`
|
||||||
* Create a `pluralkit.conf` file in the same directory as `docker-compose.yml` containing at least a `PluralKit.Bot.Token` field
|
* Create a `pluralkit.conf` file in the same directory as `docker-compose.yml` containing at least `PluralKit.Bot.Token` and `PluralKit.Bot.ClientId` fields
|
||||||
* (`PluralKit.Database` is overridden in `docker-compose.yml` to point to the Postgres container)
|
* (`PluralKit.Database` is overridden in `docker-compose.yml` to point to the Postgres container)
|
||||||
* Build the bot: `docker-compose build`
|
* Build the bot: `docker-compose build`
|
||||||
* Run the bot: `docker-compose up`
|
* Run the bot: `docker-compose up`
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
{
|
{
|
||||||
"PluralKit": {
|
"PluralKit": {
|
||||||
"Bot": {
|
"Bot": {
|
||||||
"Token": "BOT_TOKEN_GOES_HERE"
|
"Token": "BOT_TOKEN_GOES_HERE",
|
||||||
|
"ClientId": 466707357099884544,
|
||||||
},
|
},
|
||||||
"Database": "Host=localhost;Port=5432;Username=myusername;Password=mypassword;Database=mydatabasename"
|
"Database": "Host=localhost;Port=5432;Username=myusername;Password=mypassword;Database=mydatabasename"
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user