public async Task CollectStats()
        {
            var stopwatch = new Stopwatch();

            stopwatch.Start();

            // Aggregate guild/channel stats
            var guildCount   = 0;
            var channelCount = 0;

            // No LINQ today, sorry
            await foreach (var guild in _cache.GetAllGuilds())
            {
                guildCount++;
                foreach (var channel in _cache.GetGuildChannels(guild.Id))
                {
                    if (DiscordUtils.IsValidGuildChannel(channel))
                    {
                        channelCount++;
                    }
                }
            }

            _metrics.Measure.Gauge.SetValue(BotMetrics.Guilds, guildCount);
            _metrics.Measure.Gauge.SetValue(BotMetrics.Channels, channelCount);

            // Aggregate DB stats
            var counts = await _db.Execute(c => c.QueryFirstAsync <Counts>("select (select count(*) from systems) as systems, (select count(*) from members) as members, (select count(*) from switches) as switches, (select count(*) from messages) as messages, (select count(*) from groups) as groups"));

            _metrics.Measure.Gauge.SetValue(CoreMetrics.SystemCount, counts.Systems);
            _metrics.Measure.Gauge.SetValue(CoreMetrics.MemberCount, counts.Members);
            _metrics.Measure.Gauge.SetValue(CoreMetrics.SwitchCount, counts.Switches);
            _metrics.Measure.Gauge.SetValue(CoreMetrics.MessageCount, counts.Messages);
            _metrics.Measure.Gauge.SetValue(CoreMetrics.GroupCount, counts.Groups);

            // Process info
            var process = Process.GetCurrentProcess();

            _metrics.Measure.Gauge.SetValue(CoreMetrics.ProcessPhysicalMemory, process.WorkingSet64);
            _metrics.Measure.Gauge.SetValue(CoreMetrics.ProcessVirtualMemory, process.VirtualMemorySize64);
            _metrics.Measure.Gauge.SetValue(CoreMetrics.ProcessPrivateMemory, process.PrivateMemorySize64);
            _metrics.Measure.Gauge.SetValue(CoreMetrics.ProcessThreads, process.Threads.Count);
            _metrics.Measure.Gauge.SetValue(CoreMetrics.ProcessHandles, process.HandleCount);
            _metrics.Measure.Gauge.SetValue(CoreMetrics.CpuUsage, await _cpu.EstimateCpuUsage());

            // Database info
            _metrics.Measure.Gauge.SetValue(CoreMetrics.DatabaseConnections, _countHolder.ConnectionCount);

            // Other shiz
            _metrics.Measure.Gauge.SetValue(BotMetrics.WebhookCacheSize, _webhookCache.CacheSize);

            stopwatch.Stop();
            _logger.Debug("Updated metrics in {Time}", stopwatch.ElapsedDuration());
        }
Пример #2
0
        public static Task <Channel> MatchChannel(this Context ctx)
        {
            if (!MentionUtils.TryParseChannel(ctx.PeekArgument(), out var id))
            {
                return(Task.FromResult <Channel>(null));
            }

            if (!ctx.Cache.TryGetChannel(id, out var channel))
            {
                return(Task.FromResult <Channel>(null));
            }

            if (!DiscordUtils.IsValidGuildChannel(channel))
            {
                return(Task.FromResult <Channel>(null));
            }

            ctx.PopArgument();
            return(Task.FromResult(channel));
        }
Пример #3
0
        private bool ShouldProxy(Channel channel, Message msg, MessageContext ctx)
        {
            // Make sure author has a system
            if (ctx.SystemId == null)
            {
                return(false);
            }

            // Make sure channel is a guild text channel and this is a normal message
            if (!DiscordUtils.IsValidGuildChannel(channel))
            {
                return(false);
            }
            if (msg.Type != Message.MessageType.Default && msg.Type != Message.MessageType.Reply)
            {
                return(false);
            }

            // Make sure author is a normal user
            if (msg.Author.System == true || msg.Author.Bot || msg.WebhookId != null)
            {
                return(false);
            }

            // Make sure proxying is enabled here
            if (!ctx.ProxyEnabled || ctx.InBlacklist)
            {
                return(false);
            }

            // Make sure we have either an attachment or message content
            var isMessageBlank = msg.Content == null || msg.Content.Trim().Length == 0;

            if (isMessageBlank && msg.Attachments.Length == 0)
            {
                return(false);
            }

            // All good!
            return(true);
        }
Пример #4
0
        public async Task Handle(Shard shard, MessageUpdateEvent evt)
        {
            if (evt.Author.Value?.Id == _client.User?.Id)
            {
                return;
            }

            // Edit message events sometimes arrive with missing data; double-check it's all there
            if (!evt.Content.HasValue || !evt.Author.HasValue || !evt.Member.HasValue)
            {
                return;
            }

            var channel = _cache.GetChannel(evt.ChannelId);

            if (!DiscordUtils.IsValidGuildChannel(channel))
            {
                return;
            }
            var guild       = _cache.GetGuild(channel.GuildId !.Value);
            var lastMessage = _lastMessageCache.GetLastMessage(evt.ChannelId);

            // Only react to the last message in the channel
            if (lastMessage?.Id != evt.Id)
            {
                return;
            }

            // Just run the normal message handling code, with a flag to disable autoproxying
            MessageContext ctx;

            await using (var conn = await _db.Obtain())
                using (_metrics.Measure.Timer.Time(BotMetrics.MessageContextQueryTime))
                    ctx = await _repo.GetMessageContext(conn, evt.Author.Value !.Id, channel.GuildId !.Value, evt.ChannelId);

            var equivalentEvt = await GetMessageCreateEvent(evt, lastMessage, channel);

            var botPermissions = _bot.PermissionsIn(channel.Id);
            await _proxy.HandleIncomingMessage(shard, equivalentEvt, ctx, allowAutoproxy : false, guild : guild, channel : channel, botPermissions : botPermissions);
        }
Пример #5
0
        private async ValueTask TryHandleProxyMessageReactions(MessageReactionAddEvent evt)
        {
            // Sometimes we get events from users that aren't in the user cache
            // We just ignore all of those for now, should be quite rare...
            if (!_cache.TryGetUser(evt.UserId, out var user))
            {
                return;
            }

            var channel = _cache.GetChannel(evt.ChannelId);

            // check if it's a command message first
            // since this can happen in DMs as well
            if (evt.Emoji.Name == "\u274c")
            {
                await using var conn = await _db.Obtain();

                var commandMsg = await _commandMessageService.GetCommandMessage(conn, evt.MessageId);

                if (commandMsg != null)
                {
                    await HandleCommandDeleteReaction(evt, commandMsg);

                    return;
                }
            }

            // Proxied messages only exist in guild text channels, so skip checking if we're elsewhere
            if (!DiscordUtils.IsValidGuildChannel(channel))
            {
                return;
            }

            // Ignore reactions from bots (we can't DM them anyway)
            if (user.Bot)
            {
                return;
            }

            switch (evt.Emoji.Name)
            {
            // Message deletion
            case "\u274C":     // Red X
            {
                await using var conn = await _db.Obtain();

                var msg = await _repo.GetMessage(conn, evt.MessageId);

                if (msg != null)
                {
                    await HandleProxyDeleteReaction(evt, msg);
                }

                break;
            }

            case "\u2753":     // Red question mark
            case "\u2754":     // White question mark
            {
                await using var conn = await _db.Obtain();

                var msg = await _repo.GetMessage(conn, evt.MessageId);

                if (msg != null)
                {
                    await HandleQueryReaction(evt, msg);
                }

                break;
            }

            case "\U0001F514": // Bell
            case "\U0001F6CE": // Bellhop bell
            case "\U0001F3D3": // Ping pong paddle (lol)
            case "\u23F0":     // Alarm clock
            case "\u2757":     // Exclamation mark
            {
                await using var conn = await _db.Obtain();

                var msg = await _repo.GetMessage(conn, evt.MessageId);

                if (msg != null)
                {
                    await HandlePingReaction(evt, msg);
                }
                break;
            }
            }
        }