mirror of
				https://gitlab.com/Kwoth/nadekobot.git
				synced 2025-11-04 08:34:27 -05:00 
			
		
		
		
	- Using PeriodicTimer in a few places instead of Timer
- Some small refactorings - Fixed reference to non-existent command in bot.yml
This commit is contained in:
		@@ -77,7 +77,7 @@ note: This setting is primarily used if you're afraid of raids, or you're runnin
 | 
			
		||||
    public bool GroupGreets { get; set; }
 | 
			
		||||
 | 
			
		||||
    [Comment(@"Whether the bot will rotate through all specified statuses.
 | 
			
		||||
This setting can be changed via .rots command.
 | 
			
		||||
This setting can be changed via .ropl command.
 | 
			
		||||
See RotatingStatuses submodule in Administration.")]
 | 
			
		||||
    public bool RotateStatuses { get; set; }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -16,7 +16,7 @@ public class MuteService : INService
 | 
			
		||||
{
 | 
			
		||||
    public enum TimerType { Mute, Ban, AddRole }
 | 
			
		||||
 | 
			
		||||
    private static readonly OverwritePermissions denyOverwrite = new(addReactions: PermValue.Deny,
 | 
			
		||||
    private static readonly OverwritePermissions _denyOverwrite = new(addReactions: PermValue.Deny,
 | 
			
		||||
        sendMessages: PermValue.Deny,
 | 
			
		||||
        attachFiles: PermValue.Deny);
 | 
			
		||||
 | 
			
		||||
@@ -26,7 +26,7 @@ public class MuteService : INService
 | 
			
		||||
    public ConcurrentDictionary<ulong, string> GuildMuteRoles { get; }
 | 
			
		||||
    public ConcurrentDictionary<ulong, ConcurrentHashSet<ulong>> MutedUsers { get; }
 | 
			
		||||
 | 
			
		||||
    public ConcurrentDictionary<ulong, ConcurrentDictionary<(ulong, TimerType), Timer>> Un_Timers { get; } = new();
 | 
			
		||||
    public ConcurrentDictionary<ulong, ConcurrentDictionary<(ulong, TimerType), Timer>> UnTimers { get; } = new();
 | 
			
		||||
 | 
			
		||||
    private readonly DiscordSocketClient _client;
 | 
			
		||||
    private readonly DbService _db;
 | 
			
		||||
@@ -312,7 +312,7 @@ public class MuteService : INService
 | 
			
		||||
                if (!toOverwrite.PermissionOverwrites.Any(x => x.TargetId == muteRole.Id
 | 
			
		||||
                                                               && x.TargetType == PermissionTarget.Role))
 | 
			
		||||
                {
 | 
			
		||||
                    await toOverwrite.AddPermissionOverwriteAsync(muteRole, denyOverwrite);
 | 
			
		||||
                    await toOverwrite.AddPermissionOverwriteAsync(muteRole, _denyOverwrite);
 | 
			
		||||
 | 
			
		||||
                    await Task.Delay(200);
 | 
			
		||||
                }
 | 
			
		||||
@@ -394,12 +394,13 @@ public class MuteService : INService
 | 
			
		||||
        ulong? roleId = null)
 | 
			
		||||
    {
 | 
			
		||||
        //load the unmute timers for this guild
 | 
			
		||||
        var userUnTimers = Un_Timers.GetOrAdd(guildId, new ConcurrentDictionary<(ulong, TimerType), Timer>());
 | 
			
		||||
        var userUnTimers = UnTimers.GetOrAdd(guildId, new ConcurrentDictionary<(ulong, TimerType), Timer>());
 | 
			
		||||
 | 
			
		||||
        //unmute timer to be added
 | 
			
		||||
        var toAdd = new Timer(async _ =>
 | 
			
		||||
            {
 | 
			
		||||
                if (type == TimerType.Ban)
 | 
			
		||||
                {
 | 
			
		||||
                    try
 | 
			
		||||
                    {
 | 
			
		||||
                        RemoveTimerFromDb(guildId, userId, type);
 | 
			
		||||
@@ -409,24 +410,28 @@ public class MuteService : INService
 | 
			
		||||
                    }
 | 
			
		||||
                    catch (Exception ex)
 | 
			
		||||
                    {
 | 
			
		||||
                        Log.Warning(ex, "Couldn't unban user {0} in guild {1}", userId, guildId);
 | 
			
		||||
                        Log.Warning(ex, "Couldn't unban user {UserId} in guild {GuildId}", userId, guildId);
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                else if (type == TimerType.AddRole)
 | 
			
		||||
                {
 | 
			
		||||
                    try
 | 
			
		||||
                    {
 | 
			
		||||
                        RemoveTimerFromDb(guildId, userId, type);
 | 
			
		||||
                        StopTimer(guildId, userId, type);
 | 
			
		||||
                        var guild = _client.GetGuild(guildId);
 | 
			
		||||
                        var user = guild?.GetUser(userId);
 | 
			
		||||
                        var role = guild.GetRole(roleId.Value);
 | 
			
		||||
                        var role = guild?.GetRole(roleId.Value);
 | 
			
		||||
                        if (guild is not null && user is not null && user.Roles.Contains(role))
 | 
			
		||||
                            await user.RemoveRoleAsync(role);
 | 
			
		||||
                    }
 | 
			
		||||
                    catch (Exception ex)
 | 
			
		||||
                    {
 | 
			
		||||
                        Log.Warning(ex, "Couldn't remove role from user {0} in guild {1}", userId, guildId);
 | 
			
		||||
                        Log.Warning(ex, "Couldn't remove role from user {UserId} in guild {GuildId}", userId, guildId);
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                else
 | 
			
		||||
                {
 | 
			
		||||
                    try
 | 
			
		||||
                    {
 | 
			
		||||
                        // unmute the user, this will also remove the timer from the db
 | 
			
		||||
@@ -435,8 +440,9 @@ public class MuteService : INService
 | 
			
		||||
                    catch (Exception ex)
 | 
			
		||||
                    {
 | 
			
		||||
                        RemoveTimerFromDb(guildId, userId, type); // if unmute errored, just remove unmute from db
 | 
			
		||||
                        Log.Warning(ex, "Couldn't unmute user {0} in guild {1}", userId, guildId);
 | 
			
		||||
                        Log.Warning(ex, "Couldn't unmute user {UserId} in guild {GuildId}", userId, guildId);
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            },
 | 
			
		||||
            null,
 | 
			
		||||
            after,
 | 
			
		||||
@@ -454,7 +460,7 @@ public class MuteService : INService
 | 
			
		||||
 | 
			
		||||
    public void StopTimer(ulong guildId, ulong userId, TimerType type)
 | 
			
		||||
    {
 | 
			
		||||
        if (!Un_Timers.TryGetValue(guildId, out var userTimer))
 | 
			
		||||
        if (!UnTimers.TryGetValue(guildId, out var userTimer))
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        if (userTimer.TryRemove((userId, type), out var removed)) removed.Change(Timeout.Infinite, Timeout.Infinite);
 | 
			
		||||
 
 | 
			
		||||
@@ -37,7 +37,8 @@ public sealed class PlayingRotateService : INService, IReadyExecutor
 | 
			
		||||
        {
 | 
			
		||||
            try
 | 
			
		||||
            {
 | 
			
		||||
                if (!_bss.Data.RotateStatuses) return;
 | 
			
		||||
                if (!_bss.Data.RotateStatuses) 
 | 
			
		||||
                    continue;
 | 
			
		||||
 | 
			
		||||
                IReadOnlyList<RotatingPlayingStatus> rotatingStatuses;
 | 
			
		||||
                await using (var uow = _db.GetDbContext())
 | 
			
		||||
@@ -46,7 +47,7 @@ public sealed class PlayingRotateService : INService, IReadyExecutor
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                if (rotatingStatuses.Count == 0)
 | 
			
		||||
                    return;
 | 
			
		||||
                    continue;
 | 
			
		||||
 | 
			
		||||
                var playingStatus = index >= rotatingStatuses.Count
 | 
			
		||||
                    ? rotatingStatuses[index = 0]
 | 
			
		||||
 
 | 
			
		||||
@@ -243,8 +243,8 @@ public partial class Administration
 | 
			
		||||
 | 
			
		||||
            var allShardStrings = statuses.Select(st =>
 | 
			
		||||
                                          {
 | 
			
		||||
                                              var stateStr = ConnectionStateToEmoji(st);
 | 
			
		||||
                                              var timeDiff = DateTime.UtcNow - st.LastUpdate;
 | 
			
		||||
                                              var stateStr = ConnectionStateToEmoji(st);
 | 
			
		||||
                                              var maxGuildCountLength =
 | 
			
		||||
                                                  statuses.Max(x => x.GuildCount).ToString().Length;
 | 
			
		||||
                                              return $"`{stateStr} "
 | 
			
		||||
@@ -272,9 +272,9 @@ public partial class Administration
 | 
			
		||||
            var timeDiff = DateTime.UtcNow - status.LastUpdate;
 | 
			
		||||
            return status.ConnectionState switch
 | 
			
		||||
            {
 | 
			
		||||
                ConnectionState.Connected => "✅",
 | 
			
		||||
                ConnectionState.Disconnected => "🔻",
 | 
			
		||||
                _ when timeDiff > TimeSpan.FromSeconds(30) => " ❗ ",
 | 
			
		||||
                ConnectionState.Connected => "✅",
 | 
			
		||||
                _ => " ⏳"
 | 
			
		||||
            };
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
@@ -1,19 +1,19 @@
 | 
			
		||||
using Microsoft.EntityFrameworkCore;
 | 
			
		||||
using Microsoft.Extensions.Caching.Memory;
 | 
			
		||||
using NadekoBot.Common.ModuleBehaviors;
 | 
			
		||||
using NadekoBot.Db;
 | 
			
		||||
using NadekoBot.Modules.Administration.Services;
 | 
			
		||||
using NadekoBot.Services.Database.Models;
 | 
			
		||||
 | 
			
		||||
namespace NadekoBot.Modules.Administration;
 | 
			
		||||
 | 
			
		||||
public sealed class LogCommandService : ILogCommandService
 | 
			
		||||
public sealed class LogCommandService : ILogCommandService, IReadyExecutor
 | 
			
		||||
{
 | 
			
		||||
    public ConcurrentDictionary<ulong, LogSetting> GuildLogSettings { get; }
 | 
			
		||||
 | 
			
		||||
    private ConcurrentDictionary<ITextChannel, List<string>> PresenceUpdates { get; } = new();
 | 
			
		||||
    private readonly DiscordSocketClient _client;
 | 
			
		||||
 | 
			
		||||
    private readonly Timer _timerReference;
 | 
			
		||||
    private readonly IBotStrings _strings;
 | 
			
		||||
    private readonly DbService _db;
 | 
			
		||||
    private readonly MuteService _mute;
 | 
			
		||||
@@ -58,11 +58,6 @@ public sealed class LogCommandService : ILogCommandService
 | 
			
		||||
            GuildLogSettings = configs.ToDictionary(ls => ls.GuildId).ToConcurrent();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        _timerReference = new(Callback,
 | 
			
		||||
            null,
 | 
			
		||||
            TimeSpan.FromSeconds(15),
 | 
			
		||||
            TimeSpan.FromSeconds(15));
 | 
			
		||||
 | 
			
		||||
        //_client.MessageReceived += _client_MessageReceived;
 | 
			
		||||
        _client.MessageUpdated += _client_MessageUpdated;
 | 
			
		||||
        _client.MessageDeleted += _client_MessageDeleted;
 | 
			
		||||
@@ -96,28 +91,34 @@ public sealed class LogCommandService : ILogCommandService
 | 
			
		||||
#endif
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private async void Callback(object? state)
 | 
			
		||||
    public async Task OnReadyAsync()
 | 
			
		||||
    {
 | 
			
		||||
        try
 | 
			
		||||
#if GLOBAL_NADEKO
 | 
			
		||||
        var timer = new PeriodicTimer(TimeSpan.FromSeconds(15));
 | 
			
		||||
        while (await timer.WaitForNextTickAsync())
 | 
			
		||||
        {
 | 
			
		||||
            var keys = PresenceUpdates.Keys.ToList();
 | 
			
		||||
 | 
			
		||||
            await keys.Select(key =>
 | 
			
		||||
                      {
 | 
			
		||||
                          if (!((SocketGuild)key.Guild).CurrentUser.GetPermissions(key).SendMessages)
 | 
			
		||||
                              return Task.CompletedTask;
 | 
			
		||||
                          if (PresenceUpdates.TryRemove(key, out var msgs))
 | 
			
		||||
                          {
 | 
			
		||||
                              var title = GetText(key.Guild, strs.presence_updates);
 | 
			
		||||
                              var desc = string.Join(Environment.NewLine, msgs);
 | 
			
		||||
                              return key.SendConfirmAsync(_eb, title, desc.TrimTo(2048)!);
 | 
			
		||||
                          }
 | 
			
		||||
            try
 | 
			
		||||
            {
 | 
			
		||||
                var keys = PresenceUpdates.Keys.ToList();
 | 
			
		||||
 | 
			
		||||
                await keys.Select(key =>
 | 
			
		||||
                  {
 | 
			
		||||
                      if (!((SocketGuild)key.Guild).CurrentUser.GetPermissions(key).SendMessages)
 | 
			
		||||
                          return Task.CompletedTask;
 | 
			
		||||
                      })
 | 
			
		||||
                      .WhenAll();
 | 
			
		||||
                      if (PresenceUpdates.TryRemove(key, out var msgs))
 | 
			
		||||
                      {
 | 
			
		||||
                          var title = GetText(key.Guild, strs.presence_updates);
 | 
			
		||||
                          var desc = string.Join(Environment.NewLine, msgs);
 | 
			
		||||
                          return key.SendConfirmAsync(_eb, title, desc.TrimTo(2048)!);
 | 
			
		||||
                      }
 | 
			
		||||
 | 
			
		||||
                      return Task.CompletedTask;
 | 
			
		||||
                  })
 | 
			
		||||
                  .WhenAll();
 | 
			
		||||
            }
 | 
			
		||||
            catch { }
 | 
			
		||||
        }
 | 
			
		||||
        catch { }
 | 
			
		||||
#endif
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public LogSetting? GetGuildLogSettings(ulong guildId)
 | 
			
		||||
 
 | 
			
		||||
@@ -362,7 +362,7 @@ public partial class Help : NadekoModule<HelpService>
 | 
			
		||||
                    ContentType = "application/json",
 | 
			
		||||
                    ContentBody = uploadData,
 | 
			
		||||
                    // either use a path provided in the argument or the default one for public nadeko, other/cmds.json
 | 
			
		||||
                    Key = $"cmds/{StatsService.BotVersion}.json",
 | 
			
		||||
                    Key = $"cmds/{StatsService.BOT_VERSION}.json",
 | 
			
		||||
                    CannedACL = S3CannedACL.PublicRead
 | 
			
		||||
                });
 | 
			
		||||
            }
 | 
			
		||||
@@ -372,11 +372,11 @@ public partial class Help : NadekoModule<HelpService>
 | 
			
		||||
            var versionListString = Encoding.UTF8.GetString(ms.ToArray());
 | 
			
		||||
 | 
			
		||||
            var versionList = JsonSerializer.Deserialize<List<string>>(versionListString);
 | 
			
		||||
            if (versionList is not null && !versionList.Contains(StatsService.BotVersion))
 | 
			
		||||
            if (versionList is not null && !versionList.Contains(StatsService.BOT_VERSION))
 | 
			
		||||
            {
 | 
			
		||||
                // save the file with new version added
 | 
			
		||||
                // versionList.Add(StatsService.BotVersion);
 | 
			
		||||
                versionListString = JsonSerializer.Serialize(versionList.Prepend(StatsService.BotVersion),
 | 
			
		||||
                versionListString = JsonSerializer.Serialize(versionList.Prepend(StatsService.BOT_VERSION),
 | 
			
		||||
                    new JsonSerializerOptions { WriteIndented = true });
 | 
			
		||||
 | 
			
		||||
                // upload the updated version list
 | 
			
		||||
@@ -395,7 +395,7 @@ public partial class Help : NadekoModule<HelpService>
 | 
			
		||||
            {
 | 
			
		||||
                Log.Warning(
 | 
			
		||||
                    "Version {Version} already exists in the version file. " + "Did you forget to increment it?",
 | 
			
		||||
                    StatsService.BotVersion);
 | 
			
		||||
                    StatsService.BOT_VERSION);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -253,7 +253,7 @@ public partial class Utility : NadekoModule
 | 
			
		||||
 | 
			
		||||
        await ctx.Channel.EmbedAsync(_eb.Create()
 | 
			
		||||
                                        .WithOkColor()
 | 
			
		||||
                                        .WithAuthor($"NadekoBot v{StatsService.BotVersion}",
 | 
			
		||||
                                        .WithAuthor($"NadekoBot v{StatsService.BOT_VERSION}",
 | 
			
		||||
                                            "https://nadeko-pictures.nyc3.digitaloceanspaces.com/other/avatar.png",
 | 
			
		||||
                                            "https://nadekobot.readthedocs.io/en/latest/")
 | 
			
		||||
                                        .AddField(GetText(strs.author), _stats.Author, true)
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,5 @@
 | 
			
		||||
#nullable disable
 | 
			
		||||
using Humanizer.Localisation;
 | 
			
		||||
using NadekoBot.Common.ModuleBehaviors;
 | 
			
		||||
using System.Diagnostics;
 | 
			
		||||
 | 
			
		||||
@@ -6,7 +7,7 @@ namespace NadekoBot.Services;
 | 
			
		||||
 | 
			
		||||
public class StatsService : IStatsService, IReadyExecutor, INService, IDisposable
 | 
			
		||||
{
 | 
			
		||||
    public const string BotVersion = "4.0.0";
 | 
			
		||||
    public const string BOT_VERSION = "4.0.0";
 | 
			
		||||
 | 
			
		||||
    public string Author
 | 
			
		||||
        => "Kwoth#2452";
 | 
			
		||||
@@ -18,28 +19,27 @@ public class StatsService : IStatsService, IReadyExecutor, INService, IDisposabl
 | 
			
		||||
        => MessageCounter / GetUptime().TotalSeconds;
 | 
			
		||||
 | 
			
		||||
    public long TextChannels
 | 
			
		||||
        => Interlocked.Read(ref _textChannels);
 | 
			
		||||
        => Interlocked.Read(ref textChannels);
 | 
			
		||||
 | 
			
		||||
    public long VoiceChannels
 | 
			
		||||
        => Interlocked.Read(ref _voiceChannels);
 | 
			
		||||
        => Interlocked.Read(ref voiceChannels);
 | 
			
		||||
 | 
			
		||||
    public long MessageCounter
 | 
			
		||||
        => Interlocked.Read(ref _messageCounter);
 | 
			
		||||
        => Interlocked.Read(ref messageCounter);
 | 
			
		||||
 | 
			
		||||
    public long CommandsRan
 | 
			
		||||
        => Interlocked.Read(ref _commandsRan);
 | 
			
		||||
        => Interlocked.Read(ref commandsRan);
 | 
			
		||||
 | 
			
		||||
    private readonly Process _currentProcess = Process.GetCurrentProcess();
 | 
			
		||||
    private readonly DiscordSocketClient _client;
 | 
			
		||||
    private readonly IBotCredentials _creds;
 | 
			
		||||
    private readonly DateTime _started;
 | 
			
		||||
 | 
			
		||||
    private long _textChannels;
 | 
			
		||||
    private long _voiceChannels;
 | 
			
		||||
    private long _messageCounter;
 | 
			
		||||
    private long _commandsRan;
 | 
			
		||||
    private long textChannels;
 | 
			
		||||
    private long voiceChannels;
 | 
			
		||||
    private long messageCounter;
 | 
			
		||||
    private long commandsRan;
 | 
			
		||||
 | 
			
		||||
    private readonly Timer _botlistTimer;
 | 
			
		||||
    private readonly IHttpClientFactory _httpFactory;
 | 
			
		||||
 | 
			
		||||
    public StatsService(
 | 
			
		||||
@@ -53,17 +53,17 @@ public class StatsService : IStatsService, IReadyExecutor, INService, IDisposabl
 | 
			
		||||
        _httpFactory = factory;
 | 
			
		||||
 | 
			
		||||
        _started = DateTime.UtcNow;
 | 
			
		||||
        _client.MessageReceived += _ => Task.FromResult(Interlocked.Increment(ref _messageCounter));
 | 
			
		||||
        cmdHandler.CommandExecuted += (_, _) => Task.FromResult(Interlocked.Increment(ref _commandsRan));
 | 
			
		||||
        _client.MessageReceived += _ => Task.FromResult(Interlocked.Increment(ref messageCounter));
 | 
			
		||||
        cmdHandler.CommandExecuted += (_, _) => Task.FromResult(Interlocked.Increment(ref commandsRan));
 | 
			
		||||
 | 
			
		||||
        _client.ChannelCreated += c =>
 | 
			
		||||
        {
 | 
			
		||||
            var _ = Task.Run(() =>
 | 
			
		||||
            {
 | 
			
		||||
                if (c is ITextChannel)
 | 
			
		||||
                    Interlocked.Increment(ref _textChannels);
 | 
			
		||||
                    Interlocked.Increment(ref textChannels);
 | 
			
		||||
                else if (c is IVoiceChannel)
 | 
			
		||||
                    Interlocked.Increment(ref _voiceChannels);
 | 
			
		||||
                    Interlocked.Increment(ref voiceChannels);
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            return Task.CompletedTask;
 | 
			
		||||
@@ -74,9 +74,9 @@ public class StatsService : IStatsService, IReadyExecutor, INService, IDisposabl
 | 
			
		||||
            var _ = Task.Run(() =>
 | 
			
		||||
            {
 | 
			
		||||
                if (c is ITextChannel)
 | 
			
		||||
                    Interlocked.Decrement(ref _textChannels);
 | 
			
		||||
                    Interlocked.Decrement(ref textChannels);
 | 
			
		||||
                else if (c is IVoiceChannel)
 | 
			
		||||
                    Interlocked.Decrement(ref _voiceChannels);
 | 
			
		||||
                    Interlocked.Decrement(ref voiceChannels);
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            return Task.CompletedTask;
 | 
			
		||||
@@ -88,8 +88,8 @@ public class StatsService : IStatsService, IReadyExecutor, INService, IDisposabl
 | 
			
		||||
            {
 | 
			
		||||
                var tc = g.Channels.Count(cx => cx is ITextChannel);
 | 
			
		||||
                var vc = g.Channels.Count - tc;
 | 
			
		||||
                Interlocked.Add(ref _textChannels, tc);
 | 
			
		||||
                Interlocked.Add(ref _voiceChannels, vc);
 | 
			
		||||
                Interlocked.Add(ref textChannels, tc);
 | 
			
		||||
                Interlocked.Add(ref voiceChannels, vc);
 | 
			
		||||
            });
 | 
			
		||||
            return Task.CompletedTask;
 | 
			
		||||
        };
 | 
			
		||||
@@ -100,8 +100,8 @@ public class StatsService : IStatsService, IReadyExecutor, INService, IDisposabl
 | 
			
		||||
            {
 | 
			
		||||
                var tc = g.Channels.Count(cx => cx is ITextChannel);
 | 
			
		||||
                var vc = g.Channels.Count - tc;
 | 
			
		||||
                Interlocked.Add(ref _textChannels, tc);
 | 
			
		||||
                Interlocked.Add(ref _voiceChannels, vc);
 | 
			
		||||
                Interlocked.Add(ref textChannels, tc);
 | 
			
		||||
                Interlocked.Add(ref voiceChannels, vc);
 | 
			
		||||
            });
 | 
			
		||||
            return Task.CompletedTask;
 | 
			
		||||
        };
 | 
			
		||||
@@ -112,8 +112,8 @@ public class StatsService : IStatsService, IReadyExecutor, INService, IDisposabl
 | 
			
		||||
            {
 | 
			
		||||
                var tc = g.Channels.Count(cx => cx is ITextChannel);
 | 
			
		||||
                var vc = g.Channels.Count - tc;
 | 
			
		||||
                Interlocked.Add(ref _textChannels, -tc);
 | 
			
		||||
                Interlocked.Add(ref _voiceChannels, -vc);
 | 
			
		||||
                Interlocked.Add(ref textChannels, -tc);
 | 
			
		||||
                Interlocked.Add(ref voiceChannels, -vc);
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            return Task.CompletedTask;
 | 
			
		||||
@@ -125,60 +125,57 @@ public class StatsService : IStatsService, IReadyExecutor, INService, IDisposabl
 | 
			
		||||
            {
 | 
			
		||||
                var tc = g.Channels.Count(cx => cx is ITextChannel);
 | 
			
		||||
                var vc = g.Channels.Count - tc;
 | 
			
		||||
                Interlocked.Add(ref _textChannels, -tc);
 | 
			
		||||
                Interlocked.Add(ref _voiceChannels, -vc);
 | 
			
		||||
                Interlocked.Add(ref textChannels, -tc);
 | 
			
		||||
                Interlocked.Add(ref voiceChannels, -vc);
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            return Task.CompletedTask;
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        _botlistTimer = new(async _ =>
 | 
			
		||||
            {
 | 
			
		||||
                if (string.IsNullOrWhiteSpace(_creds.BotListToken))
 | 
			
		||||
                    return;
 | 
			
		||||
                try
 | 
			
		||||
                {
 | 
			
		||||
                    using var http = _httpFactory.CreateClient();
 | 
			
		||||
                    using var content = new FormUrlEncodedContent(new Dictionary<string, string>
 | 
			
		||||
                    {
 | 
			
		||||
                        { "shard_count", _creds.TotalShards.ToString() },
 | 
			
		||||
                        { "shard_id", client.ShardId.ToString() },
 | 
			
		||||
                        { "server_count", client.Guilds.Count().ToString() }
 | 
			
		||||
                    });
 | 
			
		||||
                    content.Headers.Clear();
 | 
			
		||||
                    content.Headers.Add("Content-Type", "application/x-www-form-urlencoded");
 | 
			
		||||
                    http.DefaultRequestHeaders.Add("Authorization", _creds.BotListToken);
 | 
			
		||||
 | 
			
		||||
                    using (await http.PostAsync(
 | 
			
		||||
                               new Uri($"https://discordbots.org/api/bots/{client.CurrentUser.Id}/stats"),
 | 
			
		||||
                               content)) { }
 | 
			
		||||
                }
 | 
			
		||||
                catch (Exception ex)
 | 
			
		||||
                {
 | 
			
		||||
                    Log.Error(ex, "Error ");
 | 
			
		||||
                    // ignored
 | 
			
		||||
                }
 | 
			
		||||
            },
 | 
			
		||||
            null,
 | 
			
		||||
            TimeSpan.FromMinutes(5),
 | 
			
		||||
            TimeSpan.FromHours(1));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public async Task OnReadyAsync()
 | 
			
		||||
    {
 | 
			
		||||
        var guilds = _client.Guilds;
 | 
			
		||||
        textChannels = guilds.Sum(g => g.Channels.Count(cx => cx is ITextChannel));
 | 
			
		||||
        voiceChannels = guilds.Sum(g => g.Channels.Count(cx => cx is IVoiceChannel));
 | 
			
		||||
        
 | 
			
		||||
        var timer = new PeriodicTimer(TimeSpan.FromHours(1));
 | 
			
		||||
        do
 | 
			
		||||
        {
 | 
			
		||||
            if (string.IsNullOrWhiteSpace(_creds.BotListToken))
 | 
			
		||||
                continue;
 | 
			
		||||
 | 
			
		||||
            try
 | 
			
		||||
            {
 | 
			
		||||
                using var http = _httpFactory.CreateClient();
 | 
			
		||||
                using var content = new FormUrlEncodedContent(new Dictionary<string, string>
 | 
			
		||||
                {
 | 
			
		||||
                    { "shard_count", _creds.TotalShards.ToString() },
 | 
			
		||||
                    { "shard_id", _client.ShardId.ToString() },
 | 
			
		||||
                    { "server_count", _client.Guilds.Count().ToString() }
 | 
			
		||||
                });
 | 
			
		||||
                content.Headers.Clear();
 | 
			
		||||
                content.Headers.Add("Content-Type", "application/x-www-form-urlencoded");
 | 
			
		||||
                http.DefaultRequestHeaders.Add("Authorization", _creds.BotListToken);
 | 
			
		||||
 | 
			
		||||
                using var res = await http.PostAsync(
 | 
			
		||||
                    new Uri($"https://discordbots.org/api/bots/{_client.CurrentUser.Id}/stats"),
 | 
			
		||||
                    content);
 | 
			
		||||
            }
 | 
			
		||||
            catch (Exception ex)
 | 
			
		||||
            {
 | 
			
		||||
                Log.Error(ex, "Error in botlist post");
 | 
			
		||||
            }
 | 
			
		||||
        } while (await timer.WaitForNextTickAsync());
 | 
			
		||||
    } 
 | 
			
		||||
 | 
			
		||||
    public TimeSpan GetUptime()
 | 
			
		||||
        => DateTime.UtcNow - _started;
 | 
			
		||||
 | 
			
		||||
    public string GetUptimeString(string separator = ", ")
 | 
			
		||||
    {
 | 
			
		||||
        var time = GetUptime();
 | 
			
		||||
        return $"{time.Days} days{separator}{time.Hours} hours{separator}{time.Minutes} minutes";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public Task OnReadyAsync()
 | 
			
		||||
    {
 | 
			
		||||
        var guilds = _client.Guilds;
 | 
			
		||||
        _textChannels = guilds.Sum(g => g.Channels.Count(cx => cx is ITextChannel));
 | 
			
		||||
        _voiceChannels = guilds.Sum(g => g.Channels.Count(cx => cx is IVoiceChannel));
 | 
			
		||||
        return Task.CompletedTask;
 | 
			
		||||
        return time.Humanize(3, maxUnit: TimeUnit.Day, minUnit: TimeUnit.Minute);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public double GetPrivateMemory()
 | 
			
		||||
 
 | 
			
		||||
@@ -81,6 +81,6 @@ prefix: .
 | 
			
		||||
#       and (slightly) reduce the greet spam in those servers.
 | 
			
		||||
groupGreets: false
 | 
			
		||||
# Whether the bot will rotate through all specified statuses.
 | 
			
		||||
# This setting can be changed via .rots command.
 | 
			
		||||
# This setting can be changed via .ropl command.
 | 
			
		||||
# See RotatingStatuses submodule in Administration.
 | 
			
		||||
rotateStatuses: false
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user