1
0
Fork 1
mirror of https://github.com/TeamOctolings/Octobot.git synced 2025-04-19 16:33:36 +03:00

Merge branch 'master' into wipeout-exclamation-mark

Signed-off-by: Macintxsh <95250141+mctaylors@users.noreply.github.com>
This commit is contained in:
Macintxsh 2023-12-28 10:01:00 +03:00 committed by GitHub
commit 1bcc62ee42
Signed by: GitHub
GPG key ID: 4AEE18F83AFDEB23
26 changed files with 276 additions and 137 deletions

View file

@ -18,3 +18,5 @@ P:System.DateTime.Now;Use System.DateTime.UtcNow instead.
P:System.DateTimeOffset.Now;Use System.DateTimeOffset.UtcNow instead.
P:System.DateTimeOffset.DateTime;Use System.DateTimeOffset.UtcDateTime instead.
M:System.IO.File.OpenWrite(System.String);File.OpenWrite(string) does not clear the file before writing to it. Use File.Create(string) instead.
M:System.Threading.Thread.Sleep(System.Int32);Use Task.Delay(int, CancellationToken) instead.
M:System.Threading.Thread.Sleep(System.TimeSpan);Use Task.Delay(TimeSpan, CancellationToken) instead.

View file

@ -20,7 +20,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="DiffPlex" Version="1.7.1" />
<PackageReference Include="DiffPlex" Version="1.7.2" />
<PackageReference Include="Humanizer.Core.ru" Version="2.14.1" />
<PackageReference Include="JetBrains.Annotations" Version="2023.3.0" />
<PackageReference Include="Microsoft.CodeAnalysis.BannedApiAnalyzers" Version="3.3.4" />

View file

@ -400,7 +400,7 @@
<value>Octobot's source code</value>
</data>
<data name="AboutBot" xml:space="preserve">
<value>About Octobot</value>
<value>About {0}</value>
</data>
<data name="AboutDeveloper@mctaylors" xml:space="preserve">
<value>developer &amp; designer, Octobot's Wiki creator</value>
@ -588,4 +588,7 @@
<data name="InvalidTimeSpan" xml:space="preserve">
<value>Incorrect time specified.</value>
</data>
<data name="UserInfoKicked" xml:space="preserve">
<value>Kicked</value>
</data>
</root>

View file

@ -400,7 +400,7 @@
<value>Исходный код Octobot</value>
</data>
<data name="AboutBot" xml:space="preserve">
<value>Об Octobot</value>
<value>О боте {0}</value>
</data>
<data name="AboutDeveloper@neroduckale" xml:space="preserve">
<value>разработчик</value>
@ -588,4 +588,7 @@
<data name="InvalidTimeSpan" xml:space="preserve">
<value>Указано некорректное время.</value>
</data>
<data name="UserInfoKicked" xml:space="preserve">
<value>Выгнан</value>
</data>
</root>

View file

@ -400,7 +400,7 @@
<value>репа Octobot (тык)</value>
</data>
<data name="AboutBot" xml:space="preserve">
<value>немного об Octobot</value>
<value>немного об {0}</value>
</data>
<data name="AboutDeveloper@mctaylors" xml:space="preserve">
<value>скучный девелопер + дизайнер создавший Octobot's Wiki</value>
@ -502,7 +502,7 @@
<value>приколы полученные по заслугам</value>
</data>
<data name="UserInfoBannedPermanently" xml:space="preserve">
<value>забанен</value>
<value>пермабан</value>
</data>
<data name="UserInfoNotOnGuild" xml:space="preserve">
<value>вышел из сервера</value>
@ -588,4 +588,7 @@
<data name="InvalidTimeSpan" xml:space="preserve">
<value>ты там правильно напиши таймспан</value>
</data>
<data name="UserInfoKicked" xml:space="preserve">
<value>кикнут</value>
</data>
</root>

View file

@ -15,6 +15,7 @@ using Remora.Discord.Commands.Contexts;
using Remora.Discord.Commands.Feedback.Messages;
using Remora.Discord.Commands.Feedback.Services;
using Remora.Discord.Extensions.Embeds;
using Remora.Discord.Extensions.Formatting;
using Remora.Rest.Core;
using Remora.Results;
@ -27,11 +28,11 @@ namespace Octobot.Commands;
public class AboutCommandGroup : CommandGroup
{
private static readonly (string Username, Snowflake Id)[] Developers =
{
[
("Octol1ttle", new Snowflake(504343489664909322)),
("mctaylors", new Snowflake(326642240229474304)),
("neroduckale", new Snowflake(474943797063843851))
};
];
private readonly ICommandContext _context;
private readonly IFeedbackService _feedback;
@ -88,12 +89,15 @@ public class AboutCommandGroup : CommandGroup
{
var guildMemberResult = await _guildApi.GetGuildMemberAsync(
guildId, dev.Id, ct);
var tag = guildMemberResult.IsSuccess ? $"<@{dev.Id}>" : $"@{dev.Username}";
var tag = guildMemberResult.IsSuccess
? $"<@{dev.Id}>"
: Markdown.Hyperlink($"@{dev.Username}", $"https://github.com/{dev.Username}");
builder.AppendBulletPointLine($"{tag} — {$"AboutDeveloper@{dev.Username}".Localized()}");
}
var embed = new EmbedBuilder().WithSmallTitle(Messages.AboutBot, bot)
var embed = new EmbedBuilder()
.WithSmallTitle(string.Format(Messages.AboutBot, bot.Username), bot)
.WithDescription(builder.ToString())
.WithColour(ColorsList.Cyan)
.WithImageUrl("https://cdn.mctaylors.ru/octobot-banner.png")

View file

@ -33,12 +33,12 @@ public class BanCommandGroup : CommandGroup
private readonly IDiscordRestGuildAPI _guildApi;
private readonly GuildDataService _guildData;
private readonly IDiscordRestUserAPI _userApi;
private readonly UtilityService _utility;
private readonly Utility _utility;
public BanCommandGroup(
ICommandContext context, IDiscordRestChannelAPI channelApi, GuildDataService guildData,
IFeedbackService feedback, IDiscordRestGuildAPI guildApi, IDiscordRestUserAPI userApi,
UtilityService utility)
Utility utility)
{
_context = context;
_channelApi = channelApi;

View file

@ -30,11 +30,11 @@ public class ClearCommandGroup : CommandGroup
private readonly IFeedbackService _feedback;
private readonly GuildDataService _guildData;
private readonly IDiscordRestUserAPI _userApi;
private readonly UtilityService _utility;
private readonly Utility _utility;
public ClearCommandGroup(
IDiscordRestChannelAPI channelApi, ICommandContext context, GuildDataService guildData,
IFeedbackService feedback, IDiscordRestUserAPI userApi, UtilityService utility)
IFeedbackService feedback, IDiscordRestUserAPI userApi, Utility utility)
{
_channelApi = channelApi;
_context = context;

View file

@ -30,12 +30,12 @@ public class KickCommandGroup : CommandGroup
private readonly IDiscordRestGuildAPI _guildApi;
private readonly GuildDataService _guildData;
private readonly IDiscordRestUserAPI _userApi;
private readonly UtilityService _utility;
private readonly Utility _utility;
public KickCommandGroup(
ICommandContext context, IDiscordRestChannelAPI channelApi, GuildDataService guildData,
IFeedbackService feedback, IDiscordRestGuildAPI guildApi, IDiscordRestUserAPI userApi,
UtilityService utility)
Utility utility)
{
_context = context;
_channelApi = channelApi;
@ -151,7 +151,9 @@ public class KickCommandGroup : CommandGroup
return Result.FromError(kickResult.Error);
}
data.GetOrCreateMemberData(target.ID).Roles.Clear();
var memberData = data.GetOrCreateMemberData(target.ID);
memberData.Roles.Clear();
memberData.Kicked = true;
var title = string.Format(Messages.UserKicked, target.GetTag());
var description = MarkdownExtensions.BulletPoint(string.Format(Messages.DescriptionActionReason, reason));

View file

@ -32,11 +32,11 @@ public class MuteCommandGroup : CommandGroup
private readonly IDiscordRestGuildAPI _guildApi;
private readonly GuildDataService _guildData;
private readonly IDiscordRestUserAPI _userApi;
private readonly UtilityService _utility;
private readonly Utility _utility;
public MuteCommandGroup(
ICommandContext context, GuildDataService guildData, IFeedbackService feedback,
IDiscordRestGuildAPI guildApi, IDiscordRestUserAPI userApi, UtilityService utility)
IDiscordRestGuildAPI guildApi, IDiscordRestUserAPI userApi, Utility utility)
{
_context = context;
_guildData = guildData;
@ -300,9 +300,9 @@ public class MuteCommandGroup : CommandGroup
}
var memberData = data.GetOrCreateMemberData(target.ID);
var isMuted = memberData.MutedUntil is not null || communicationDisabledUntil is not null;
var wasMuted = memberData.MutedUntil is not null || communicationDisabledUntil is not null;
if (!isMuted)
if (!wasMuted)
{
var failedEmbed = new EmbedBuilder().WithSmallTitle(Messages.UserNotMuted, bot)
.WithColour(ColorsList.Red).Build();

View file

@ -36,7 +36,7 @@ public class SettingsCommandGroup : CommandGroup
/// that the orders match.
/// </remarks>
private static readonly IOption[] AllOptions =
{
[
GuildSettings.Language,
GuildSettings.WelcomeMessage,
GuildSettings.ReceiveStartupMessages,
@ -51,17 +51,17 @@ public class SettingsCommandGroup : CommandGroup
GuildSettings.MuteRole,
GuildSettings.EventNotificationRole,
GuildSettings.EventEarlyNotificationOffset
};
];
private readonly ICommandContext _context;
private readonly IFeedbackService _feedback;
private readonly GuildDataService _guildData;
private readonly IDiscordRestUserAPI _userApi;
private readonly UtilityService _utility;
private readonly Utility _utility;
public SettingsCommandGroup(
ICommandContext context, GuildDataService guildData,
IFeedbackService feedback, IDiscordRestUserAPI userApi, UtilityService utility)
IFeedbackService feedback, IDiscordRestUserAPI userApi, Utility utility)
{
_context = context;
_guildData = guildData;

View file

@ -122,32 +122,21 @@ public class ToolsCommandGroup : CommandGroup
embedColor = AppendGuildInformation(embedColor, guildMember, builder);
}
var isMuted = (memberData.MutedUntil is not null && DateTimeOffset.UtcNow <= memberData.MutedUntil) ||
var wasMuted = (memberData.MutedUntil is not null && DateTimeOffset.UtcNow <= memberData.MutedUntil) ||
communicationDisabledUntil is not null;
var wasBanned = memberData.BannedUntil is not null;
var wasKicked = memberData.Kicked;
var existingBanResult = await _guildApi.GetGuildBanAsync(guildId, target.ID, ct);
if (isMuted || existingBanResult.IsDefined())
if (wasMuted || wasBanned || wasKicked)
{
builder.Append("### ")
.AppendLine(Markdown.Bold(Messages.UserInfoPunishments));
embedColor = AppendPunishmentsInformation(wasMuted, wasKicked, wasBanned, memberData,
builder, embedColor, communicationDisabledUntil);
}
if (isMuted)
{
AppendMuteInformation(memberData, communicationDisabledUntil, builder);
embedColor = ColorsList.Red;
}
if (existingBanResult.IsDefined())
{
AppendBanInformation(memberData, builder);
embedColor = ColorsList.Black;
}
if (!guildMemberResult.IsSuccess && !existingBanResult.IsDefined())
if (!guildMemberResult.IsSuccess && !wasBanned)
{
builder.Append("### ")
.AppendLine(Markdown.Bold(Messages.UserInfoNotOnGuild));
@ -166,6 +155,29 @@ public class ToolsCommandGroup : CommandGroup
return await _feedback.SendContextualEmbedResultAsync(embed, ct: ct);
}
private static Color AppendPunishmentsInformation(bool wasMuted, bool wasKicked, bool wasBanned,
MemberData memberData, StringBuilder builder, Color embedColor, DateTimeOffset? communicationDisabledUntil)
{
if (wasMuted)
{
AppendMuteInformation(memberData, communicationDisabledUntil, builder);
embedColor = ColorsList.Red;
}
if (wasKicked)
{
builder.AppendBulletPointLine(Messages.UserInfoKicked);
}
if (wasBanned)
{
AppendBanInformation(memberData, builder);
embedColor = ColorsList.Black;
}
return embedColor;
}
private static Color AppendGuildInformation(Color color, IGuildMember guildMember, StringBuilder builder)
{
if (guildMember.Nickname.IsDefined(out var nickname))
@ -393,7 +405,7 @@ public class ToolsCommandGroup : CommandGroup
}
private static readonly TimestampStyle[] AllStyles =
{
[
TimestampStyle.ShortDate,
TimestampStyle.LongDate,
TimestampStyle.ShortTime,
@ -401,7 +413,7 @@ public class ToolsCommandGroup : CommandGroup
TimestampStyle.ShortDateTime,
TimestampStyle.LongDateTime,
TimestampStyle.RelativeTime
};
];
/// <summary>
/// A slash command that shows the current timestamp with an optional offset in all styles supported by Discord.

View file

@ -18,6 +18,7 @@ public sealed class MemberData
public ulong Id { get; }
public DateTimeOffset? BannedUntil { get; set; }
public DateTimeOffset? MutedUntil { get; set; }
public bool Kicked { get; set; }
public List<ulong> Roles { get; set; } = [];
public List<Reminder> Reminders { get; } = [];
}

View file

@ -1044,5 +1044,13 @@ namespace Octobot {
return ResourceManager.GetString("InvalidTimeSpan", resourceCulture);
}
}
internal static string UserInfoKicked
{
get
{
return ResourceManager.GetString("UserInfoKicked", resourceCulture);
}
}
}
}

View file

@ -2,11 +2,10 @@ using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Octobot.Commands;
using Octobot.Commands.Events;
using Octobot.Services;
using Octobot.Services.Profiler;
using Octobot.Services.Update;
using Remora.Commands.Extensions;
using Remora.Discord.API.Abstractions.Gateway.Commands;
using Remora.Discord.API.Abstractions.Objects;
using Remora.Discord.API.Objects;
@ -14,8 +13,8 @@ using Remora.Discord.Caching.Extensions;
using Remora.Discord.Caching.Services;
using Remora.Discord.Commands.Extensions;
using Remora.Discord.Commands.Services;
using Remora.Discord.Extensions.Extensions;
using Remora.Discord.Gateway;
using Remora.Discord.Gateway.Extensions;
using Remora.Discord.Hosting.Extensions;
using Remora.Rest.Core;
using Serilog.Extensions.Logging;
@ -24,12 +23,12 @@ namespace Octobot;
public sealed class Octobot
{
public static readonly AllowedMentions NoMentions = new(
Array.Empty<MentionType>(), Array.Empty<Snowflake>(), Array.Empty<Snowflake>());
public const string RepositoryUrl = "https://github.com/LabsDevelopment/Octobot";
public const string IssuesUrl = $"{RepositoryUrl}/issues";
public static readonly AllowedMentions NoMentions = new(
Array.Empty<MentionType>(), Array.Empty<Snowflake>(), Array.Empty<Snowflake>());
public static async Task Main(string[] args)
{
var host = CreateHostBuilder(args).UseConsoleLifetime().Build();
@ -82,34 +81,20 @@ public sealed class Octobot
// Init
.AddDiscordCaching()
.AddDiscordCommands(true, false)
.AddRespondersFromAssembly(typeof(Octobot).Assembly)
.AddCommandGroupsFromAssembly(typeof(Octobot).Assembly)
// Slash command event handlers
.AddPreparationErrorEvent<LoggingPreparationErrorEvent>()
.AddPostExecutionEvent<ErrorLoggingPostExecutionEvent>()
// Services
.AddTransient<Profiler>()
.AddSingleton<ProfilerFactory>()
.AddSingleton<Utility>()
.AddSingleton<GuildDataService>()
.AddSingleton<UtilityService>()
.AddHostedService<GuildDataService>(provider => provider.GetRequiredService<GuildDataService>())
.AddHostedService<MemberUpdateService>()
.AddHostedService<ScheduledEventUpdateService>()
.AddHostedService<SongUpdateService>()
.AddHostedService<BackgroundGuildDataSaverService>()
// Slash commands
.AddCommandTree()
.WithCommandGroup<AboutCommandGroup>()
.WithCommandGroup<BanCommandGroup>()
.WithCommandGroup<ClearCommandGroup>()
.WithCommandGroup<KickCommandGroup>()
.WithCommandGroup<MuteCommandGroup>()
.WithCommandGroup<PingCommandGroup>()
.WithCommandGroup<RemindCommandGroup>()
.WithCommandGroup<SettingsCommandGroup>()
.WithCommandGroup<ToolsCommandGroup>();
var responderTypes = typeof(Octobot).Assembly
.GetExportedTypes()
.Where(t => t.IsResponder());
foreach (var responderType in responderTypes)
{
services.AddResponder(responderType);
}
.AddHostedService<SongUpdateService>();
}
).ConfigureLogging(
c => c.AddConsole()

View file

@ -25,11 +25,11 @@ public class GuildLoadedResponder : IResponder<IGuildCreate>
private readonly GuildDataService _guildData;
private readonly ILogger<GuildLoadedResponder> _logger;
private readonly IDiscordRestUserAPI _userApi;
private readonly UtilityService _utility;
private readonly Utility _utility;
public GuildLoadedResponder(
IDiscordRestChannelAPI channelApi, GuildDataService guildData, ILogger<GuildLoadedResponder> logger,
IDiscordRestUserAPI userApi, UtilityService utility)
IDiscordRestUserAPI userApi, Utility utility)
{
_channelApi = channelApi;
_guildData = guildData;

View file

@ -43,6 +43,8 @@ public class GuildMemberJoinedResponder : IResponder<IGuildMemberAdd>
var cfg = data.Settings;
var memberData = data.GetOrCreateMemberData(user.ID);
memberData.Kicked = false;
var returnRolesResult = await TryReturnRolesAsync(cfg, memberData, gatewayEvent.GuildID, user.ID, ct);
if (!returnRolesResult.IsSuccess)
{

View file

@ -1,23 +0,0 @@
using Microsoft.Extensions.Hosting;
namespace Octobot.Services;
public sealed class BackgroundGuildDataSaverService : BackgroundService
{
private readonly GuildDataService _guildData;
public BackgroundGuildDataSaverService(GuildDataService guildData)
{
_guildData = guildData;
}
protected override async Task ExecuteAsync(CancellationToken ct)
{
using var timer = new PeriodicTimer(TimeSpan.FromMinutes(5));
while (await timer.WaitForNextTickAsync(ct))
{
await _guildData.SaveAsync(ct);
}
}
}

View file

@ -11,35 +11,23 @@ namespace Octobot.Services;
/// <summary>
/// Handles saving, loading, initializing and providing <see cref="GuildData" />.
/// </summary>
public sealed class GuildDataService : IHostedService
public sealed class GuildDataService : BackgroundService
{
private readonly ConcurrentDictionary<Snowflake, GuildData> _datas = new();
private readonly ILogger<GuildDataService> _logger;
// https://github.com/dotnet/aspnetcore/issues/39139
public GuildDataService(
IHostApplicationLifetime lifetime, ILogger<GuildDataService> logger)
public GuildDataService(ILogger<GuildDataService> logger)
{
_logger = logger;
lifetime.ApplicationStopping.Register(ApplicationStopping);
}
public Task StartAsync(CancellationToken ct)
public override Task StopAsync(CancellationToken ct)
{
return Task.CompletedTask;
base.StopAsync(ct);
return SaveAsync(ct);
}
public Task StopAsync(CancellationToken ct)
{
return Task.CompletedTask;
}
private void ApplicationStopping()
{
SaveAsync(CancellationToken.None).GetAwaiter().GetResult();
}
public Task SaveAsync(CancellationToken ct)
private Task SaveAsync(CancellationToken ct)
{
var tasks = new List<Task>();
var datas = _datas.Values.ToArray();
@ -68,6 +56,16 @@ public sealed class GuildDataService : IHostedService
File.Delete(tempFilePath);
}
protected override async Task ExecuteAsync(CancellationToken ct)
{
using var timer = new PeriodicTimer(TimeSpan.FromMinutes(5));
while (await timer.WaitForNextTickAsync(ct))
{
await SaveAsync(ct);
}
}
public async Task<GuildData> GetData(Snowflake guildId, CancellationToken ct = default)
{
return _datas.TryGetValue(guildId, out var data) ? data : await InitializeData(guildId, ct);

View file

@ -0,0 +1,114 @@
using System.Diagnostics;
using System.Text;
using Microsoft.Extensions.Logging;
using Remora.Results;
// TODO: remove in future profiler PRs
// ReSharper disable All
namespace Octobot.Services.Profiler;
/// <summary>
/// Provides the ability to profile how long certain parts of code take to complete using <see cref="Stopwatch"/>es.
/// </summary>
/// <remarks>Resolve <see cref="ProfilerFactory"/> instead in singletons.</remarks>
public sealed class Profiler
{
private const int MaxProfilerTime = 1000; // milliseconds
private readonly List<ProfilerEvent> _events = [];
private readonly ILogger<Profiler> _logger;
public Profiler(ILogger<Profiler> logger)
{
_logger = logger;
}
/// <summary>
/// Pushes an event to the profiler.
/// </summary>
/// <param name="id">The ID of the event.</param>
public void Push(string id)
{
_events.Add(new ProfilerEvent
{
Id = id,
Stopwatch = Stopwatch.StartNew()
});
}
/// <summary>
/// Pops the last pushed event from the profiler.
/// </summary>
/// <exception cref="InvalidOperationException">Thrown if the profiler contains no events.</exception>
public void Pop()
{
if (_events.Count is 0)
{
throw new InvalidOperationException("Nothing to pop");
}
_events.Last().Stopwatch.Stop();
}
/// <summary>
/// If the profiler took too long to execute, this will log a warning with per-event time usage
/// </summary>
/// <exception cref="InvalidOperationException"></exception>
private void Report()
{
var main = _events[0];
if (main.Stopwatch.ElapsedMilliseconds < MaxProfilerTime)
{
return;
}
var unprofiled = main.Stopwatch.ElapsedMilliseconds;
var builder = new StringBuilder().AppendLine();
for (var i = 1; i < _events.Count; i++)
{
var profilerEvent = _events[i];
if (profilerEvent.Stopwatch.IsRunning)
{
throw new InvalidOperationException(
$"Tried to report on a profiler with running stopwatches: {profilerEvent.Id}");
}
builder.AppendLine($"{profilerEvent.Id}: {profilerEvent.Stopwatch.ElapsedMilliseconds}ms");
unprofiled -= profilerEvent.Stopwatch.ElapsedMilliseconds;
}
builder.AppendLine($"<unprofiled>: {unprofiled}ms");
_logger.LogWarning("Profiler {ID} took {Elapsed} milliseconds to execute (max: {Max}ms):{Events}", main.Id,
main.Stopwatch.ElapsedMilliseconds, MaxProfilerTime, builder.ToString());
}
/// <summary>
/// <see cref="Pop"/> the profiler and <see cref="Report"/> on it afterwards.
/// </summary>
public void PopAndReport()
{
Pop();
Report();
}
/// <summary>
/// <see cref="PopAndReport"/> on the profiler and return a <see cref="Result{TEntity}"/>.
/// </summary>
/// <param name="result"></param>
/// <returns></returns>
public Result ReportWithResult(Result result)
{
PopAndReport();
return result;
}
/// <summary>
/// Calls <see cref="ReportWithResult"/> with <see cref="Result.FromSuccess"/>
/// </summary>
/// <returns>A successful result.</returns>
public Result ReportWithSuccess()
{
return ReportWithResult(Result.FromSuccess());
}
}

View file

@ -0,0 +1,9 @@
using System.Diagnostics;
namespace Octobot.Services.Profiler;
public struct ProfilerEvent
{
public string Id { get; init; }
public Stopwatch Stopwatch { get; init; }
}

View file

@ -0,0 +1,27 @@
using Microsoft.Extensions.DependencyInjection;
namespace Octobot.Services.Profiler;
/// <summary>
/// Provides a method to create a <see cref="Profiler"/>. Useful in singletons.
/// </summary>
public sealed class ProfilerFactory
{
private readonly IServiceScopeFactory _scopeFactory;
public ProfilerFactory(IServiceScopeFactory scopeFactory)
{
_scopeFactory = scopeFactory;
}
/// <summary>
/// Creates a new <see cref="Profiler"/>.
/// </summary>
/// <returns>A new <see cref="Profiler"/>.</returns>
// TODO: remove in future profiler PRs
// ReSharper disable once UnusedMember.Global
public Profiler Create()
{
return _scopeFactory.CreateScope().ServiceProvider.GetRequiredService<Profiler>();
}
}

View file

@ -16,7 +16,7 @@ namespace Octobot.Services.Update;
public sealed partial class MemberUpdateService : BackgroundService
{
private static readonly string[] GenericNicknames =
{
[
"Albatross", "Alpha", "Anchor", "Banjo", "Bell", "Beta", "Blackbird", "Bulldog", "Canary",
"Cat", "Calf", "Cyclone", "Daisy", "Dalmatian", "Dart", "Delta", "Diamond", "Donkey", "Duck",
"Emu", "Eclipse", "Flamingo", "Flute", "Frog", "Goose", "Hatchet", "Heron", "Husky", "Hurricane",
@ -24,16 +24,16 @@ public sealed partial class MemberUpdateService : BackgroundService
"Nautilus", "Ostrich", "Octopus", "Pelican", "Puffin", "Pyramid", "Rattle", "Robin", "Rose",
"Salmon", "Seal", "Shark", "Sheep", "Snake", "Sonar", "Stump", "Sparrow", "Toaster", "Toucan",
"Torus", "Violet", "Vortex", "Vulture", "Wagon", "Whale", "Woodpecker", "Zebra", "Zigzag"
};
];
private readonly IDiscordRestChannelAPI _channelApi;
private readonly IDiscordRestGuildAPI _guildApi;
private readonly GuildDataService _guildData;
private readonly ILogger<MemberUpdateService> _logger;
private readonly UtilityService _utility;
private readonly Utility _utility;
public MemberUpdateService(IDiscordRestChannelAPI channelApi, IDiscordRestGuildAPI guildApi,
GuildDataService guildData, ILogger<MemberUpdateService> logger, UtilityService utility)
GuildDataService guildData, ILogger<MemberUpdateService> logger, Utility utility)
{
_channelApi = channelApi;
_guildApi = guildApi;

View file

@ -19,10 +19,10 @@ public sealed class ScheduledEventUpdateService : BackgroundService
private readonly IDiscordRestGuildScheduledEventAPI _eventApi;
private readonly GuildDataService _guildData;
private readonly ILogger<ScheduledEventUpdateService> _logger;
private readonly UtilityService _utility;
private readonly Utility _utility;
public ScheduledEventUpdateService(IDiscordRestChannelAPI channelApi, IDiscordRestGuildScheduledEventAPI eventApi,
GuildDataService guildData, ILogger<ScheduledEventUpdateService> logger, UtilityService utility)
GuildDataService guildData, ILogger<ScheduledEventUpdateService> logger, Utility utility)
{
_channelApi = channelApi;
_eventApi = eventApi;

View file

@ -9,7 +9,7 @@ namespace Octobot.Services.Update;
public sealed class SongUpdateService : BackgroundService
{
private static readonly (string Author, string Name, TimeSpan Duration)[] SongList =
{
[
("Yoko & the Gold Bazookas", "Rockagilly Blues", new TimeSpan(0, 2, 52)),
("Deep Cut", "Big Betrayal", new TimeSpan(0, 5, 55)),
("Squid Sisters", "Tomorrow's Nostalgia Today", new TimeSpan(0, 3, 7)),
@ -30,7 +30,7 @@ public sealed class SongUpdateService : BackgroundService
("Turquoise October", "Octoling Rendezvous", new TimeSpan(0, 1, 57)),
("Damp Socks feat. Off the Hook", "Tentacle to the Metal", new TimeSpan(0, 2, 51)),
("Off the Hook", "Fly Octo Fly ~ Ebb & Flow (Octo)", new TimeSpan(0, 3, 5))
};
];
private readonly List<Activity> _activityList = [new Activity("with Remora.Discord", ActivityType.Game)];

View file

@ -1,7 +1,6 @@
using System.Drawing;
using System.Text;
using System.Text.Json.Nodes;
using Microsoft.Extensions.Hosting;
using Octobot.Data;
using Octobot.Extensions;
using Remora.Discord.API.Abstractions.Objects;
@ -17,14 +16,14 @@ namespace Octobot.Services;
/// Provides utility methods that cannot be transformed to extension methods because they require usage
/// of some Discord APIs.
/// </summary>
public sealed class UtilityService : IHostedService
public sealed class Utility
{
private readonly IDiscordRestChannelAPI _channelApi;
private readonly IDiscordRestGuildScheduledEventAPI _eventApi;
private readonly IDiscordRestGuildAPI _guildApi;
private readonly IDiscordRestUserAPI _userApi;
public UtilityService(
public Utility(
IDiscordRestChannelAPI channelApi, IDiscordRestGuildScheduledEventAPI eventApi, IDiscordRestGuildAPI guildApi,
IDiscordRestUserAPI userApi)
{
@ -34,16 +33,6 @@ public sealed class UtilityService : IHostedService
_userApi = userApi;
}
public Task StartAsync(CancellationToken ct)
{
return Task.CompletedTask;
}
public Task StopAsync(CancellationToken ct)
{
return Task.CompletedTask;
}
/// <summary>
/// Checks whether or not a member can interact with another member
/// </summary>