Merge pull request #1008 from 13xforever/vnext

Maintenance & the new default warning message
This commit is contained in:
Ilya
2025-10-24 20:44:13 +05:00
committed by GitHub
19 changed files with 94 additions and 81 deletions

View File

@@ -9,9 +9,9 @@
<ProjectReference Include="..\CompatApiClient\CompatApiClient.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="9.0.9" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="9.0.9" />
<PackageReference Include="Microsoft.Extensions.Http" Version="9.0.9" />
<PackageReference Include="StrawberryShake.Server" Version="15.1.10" />
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="9.0.10" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="9.0.10" />
<PackageReference Include="Microsoft.Extensions.Http" Version="9.0.10" />
<PackageReference Include="StrawberryShake.Server" Version="15.1.11" />
</ItemGroup>
</Project>

View File

@@ -8,9 +8,9 @@
<ItemGroup>
<PackageReference Include="Microsoft.AspNet.WebApi.Client" Version="6.0.0" />
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="9.0.9" />
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="9.0.10" />
<PackageReference Include="Microsoft.IO.RecyclableMemoryStream" Version="3.0.1" />
<PackageReference Include="NLog" Version="6.0.4" />
<PackageReference Include="NLog" Version="6.0.5" />
</ItemGroup>
</Project>

View File

@@ -5,9 +5,9 @@
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="9.0.9" />
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="9.0.10" />
<PackageReference Include="Octokit" Version="14.0.0" />
<PackageReference Include="SharpCompress" Version="0.40.0" />
<PackageReference Include="SharpCompress" Version="0.41.0" />
<PackageReference Include="System.Linq.Async" Version="6.0.3" />
</ItemGroup>
<ItemGroup>

View File

@@ -5,9 +5,9 @@
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="LTRData.DiscUtils.OpticalDisk" Version="1.0.65" />
<PackageReference Include="LTRData.DiscUtils.OpticalDisk" Version="1.0.66" />
<PackageReference Include="Microsoft.IO.RecyclableMemoryStream" Version="3.0.1" />
<PackageReference Include="System.IO.Hashing" Version="9.0.9" />
<PackageReference Include="System.IO.Hashing" Version="9.0.10" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\CompatApiClient\CompatApiClient.csproj" />

View File

@@ -12,7 +12,7 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNet.WebApi.Client" Version="6.0.0" />
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="9.0.9" />
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="9.0.10" />
<PackageReference Include="Microsoft.IO.RecyclableMemoryStream" Version="3.0.1" />
</ItemGroup>
<ItemGroup>

View File

@@ -37,8 +37,8 @@ internal static class Fortune
return;
}
using var timeouCts = new CancellationTokenSource(TimeSpan.FromSeconds(15*60-5));
using var cts = CancellationTokenSource.CreateLinkedTokenSource(timeouCts.Token, Config.Cts.Token);
using var timeoutCts = new CancellationTokenSource(TimeSpan.FromSeconds(15*60-5));
using var cts = CancellationTokenSource.CreateLinkedTokenSource(timeoutCts.Token, Config.Cts.Token);
try
{
url ??= attachment?.Url;

View File

@@ -69,10 +69,7 @@ internal static class WarningsContextMenus
if (!suppress)
{
var userMsgContent = $"""
User warning saved, {user.Mention} has {recent} recent warning{StringUtils.GetSuffix(recent)} ({total} total)
Warned for: {reason} by {ctx.User.Mention}
""";
var userMsgContent = await Warnings.GetDefaultWarningMessageAsync(ctx.Client, user, reason, recent, total, ctx.User).ConfigureAwait(false);
var userMsg = new DiscordMessageBuilder()
.WithContent(userMsgContent)
.AddMention(new UserMention(user.Id));

View File

@@ -29,10 +29,7 @@ internal static partial class Warnings
if (!suppress)
{
var userMsgContent = $"""
User warning saved, {user.Mention} has {recent} recent warning{StringUtils.GetSuffix(recent)} ({total} total)
Warned for: {reason} by {ctx.User.Mention}
""";
var userMsgContent = await GetDefaultWarningMessageAsync(ctx.Client, user, reason, recent, total, ctx.User).ConfigureAwait(false);
var userMsg = new DiscordMessageBuilder()
.WithContent(userMsgContent)
.AddMention(new UserMention(user));
@@ -175,6 +172,27 @@ internal static partial class Warnings
await ctx.RespondAsync($"{Config.Reactions.Failure} Warning is not retracted", ephemeral: true).ConfigureAwait(false);
}
internal static async ValueTask<string> GetDefaultWarningMessageAsync(
DiscordClient client,
DiscordUser userToWarn,
string reason,
int recentWarnCount,
int totalWarnCount,
DiscordUser moderator)
{
var rulesCh = await client.GetChannelAsync(Config.BotRulesChannelId).ConfigureAwait(false);
return $"""
## ⚠️ {userToWarn.Mention} you have been warned ⚠️
**Reason:** {reason}
**Read the {rulesCh.Mention} before continuing to chat**
Refusing to read/follow the server rules *will* result in a server ban
You have {recentWarnCount} recent warning{StringUtils.GetSuffix(recentWarnCount)} ({totalWarnCount} total)
-# Warning added by {moderator.Mention}
""";
}
internal static async ValueTask<(bool saved, bool suppress, int recentCount, int totalCount)>
AddAsync(ulong userId, DiscordUser issuer, string reason, string? fullReason = null)
{

View File

@@ -44,35 +44,35 @@
<ItemGroup>
<PackageReference Include="Blurhash.ImageSharp" Version="4.0.0" />
<PackageReference Include="CommunityToolkit.HighPerformance" Version="8.4.0" />
<PackageReference Include="DSharpPlus" Version="5.0.0-nightly-02551" />
<PackageReference Include="DSharpPlus.Commands" Version="5.0.0-nightly-02551" />
<PackageReference Include="DSharpPlus.Interactivity" Version="5.0.0-nightly-02551" />
<PackageReference Include="DSharpPlus" Version="5.0.0-nightly-02554" />
<PackageReference Include="DSharpPlus.Commands" Version="5.0.0-nightly-02554" />
<PackageReference Include="DSharpPlus.Interactivity" Version="5.0.0-nightly-02554" />
<PackageReference Include="DSharpPlus.Natives.Zstd" Version="1.5.7.21" />
<PackageReference Include="Florence2" Version="25.7.59767" />
<PackageReference Include="Google.Apis.Drive.v3" Version="1.71.0.3905" />
<PackageReference Include="Google.Apis.Drive.v3" Version="1.72.0.3938" />
<PackageReference Include="MathParser.org-mXparser" Version="6.1.0" />
<PackageReference Include="MegaApiClient" Version="1.10.5" />
<PackageReference Include="Microsoft.ApplicationInsights.DependencyCollector" Version="2.23.0" />
<PackageReference Include="Microsoft.ApplicationInsights.PerfCounterCollector" Version="2.23.0" />
<PackageReference Include="Microsoft.Azure.CognitiveServices.Vision.ComputerVision" Version="7.0.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="9.0.9" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="9.0.9">
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="9.0.10" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="9.0.10">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="9.0.9" />
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="9.0.9" />
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="9.0.9" />
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="9.0.9" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="9.0.10" />
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="9.0.10" />
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="9.0.10" />
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="9.0.10" />
<PackageReference Include="Microsoft.IO.RecyclableMemoryStream" Version="3.0.1" />
<PackageReference Include="Microsoft.TeamFoundationServer.Client" Version="19.225.1" />
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.22.1" />
<PackageReference Include="Nerdbank.Streams" Version="2.13.16" />
<PackageReference Include="Nito.AsyncEx" Version="5.1.2" />
<PackageReference Include="NLog" Version="6.0.4" />
<PackageReference Include="NLog.Extensions.Logging" Version="6.0.4" />
<PackageReference Include="NLog" Version="6.0.5" />
<PackageReference Include="NLog.Extensions.Logging" Version="6.0.5" />
<PackageReference Include="NReco.Text.AhoCorasickDoubleArrayTrie" Version="1.1.1" />
<PackageReference Include="SharpCompress" Version="0.40.0" />
<PackageReference Include="SharpCompress" Version="0.41.0" />
<PackageReference Include="SixLabors.ImageSharp.Drawing" Version="2.1.7" />
<PackageReference Include="System.Linq.Async" Version="6.0.3" />
<PackageReference Include="TesseractCSharp" Version="1.0.5" />

View File

@@ -233,20 +233,17 @@ internal static class ContentFilter
).ConfigureAwait(false);
if (saved && !suppress && message.Channel is not null)
{
var msgContent = await Warnings.GetDefaultWarningMessageAsync(client, message.Author, warningReason, recent, total, client.CurrentUser).ConfigureAwait(false);
var msg = new DiscordMessageBuilder()
.WithContent(
$"""
User warning saved, {message.Author.Mention} has {recent} recent warning{StringUtils.GetSuffix(recent)} ({total} total)
Warned for: {warningReason} by {client.CurrentUser.Mention}
"""
).AddMention(new UserMention(message.Author));
.WithContent(msgContent)
.AddMention(new UserMention(message.Author));
await message.Channel.SendMessageAsync(msg).ConfigureAwait(false);
}
completedActions.Add(FilterAction.IssueWarning);
}
catch (Exception e)
{
Config.Log.Warn(e, $"Couldn't issue warning in #{message.Channel.Name}");
Config.Log.Warn(e, $"Couldn't issue warning in #{message.Channel?.Name}");
}
}

View File

@@ -4,6 +4,7 @@ using System.Net.Http.Headers;
using System.Text.RegularExpressions;
using CompatApiClient.Compression;
using CompatBot.Commands;
using CompatBot.Database;
using CompatBot.Database.Providers;
using CompatBot.Utils.Extensions;
using Microsoft.Extensions.Caching.Memory;
@@ -130,13 +131,10 @@ internal static partial class DiscordInviteFilter
).ConfigureAwait(false);
if (saved && !suppress)
{
var content = await Warnings.GetDefaultWarningMessageAsync(client, message.Author, reason, recent, total, client.CurrentUser).ConfigureAwait(false);
var msg = new DiscordMessageBuilder()
.WithContent(
$"""
User warning saved, {message.Author.Mention} has {recent} recent warning{StringUtils.GetSuffix(recent)} ({total} total)
Warned for: {reason} by {client.CurrentUser.Mention}
"""
).AddMention(new UserMention(message.Author));
.WithContent(content)
.AddMention(new UserMention(message.Author));
await message.Channel.SendMessageAsync(msg).ConfigureAwait(false);
}
}

View File

@@ -21,7 +21,6 @@ internal sealed class GzipHandler: IArchiveHandler
else if (fileName.EndsWith(".log.gz", StringComparison.InvariantCultureIgnoreCase)
&& !fileName.Contains("tty.log", StringComparison.InvariantCultureIgnoreCase))
return (true, null);
return (false, null);
}
@@ -37,7 +36,8 @@ internal sealed class GzipHandler: IArchiveHandler
{
var memory = writer.GetMemory(Config.MinimumBufferSize);
read = await gzipStream.ReadAsync(memory, cancellationToken);
writer.Advance(read);
if (read > 0)
writer.Advance(read);
SourcePosition = statsStream.Position;
flushed = await writer.FlushAsync(cancellationToken).ConfigureAwait(false);
} while (read > 0 && !(flushed.IsCompleted || flushed.IsCanceled || cancellationToken.IsCancellationRequested));

View File

@@ -30,7 +30,8 @@ internal sealed class PlainTextHandler: IArchiveHandler
{
var memory = writer.GetMemory(Config.MinimumBufferSize);
read = await sourceStream.ReadAsync(memory, cancellationToken);
writer.Advance(read);
if (read > 0)
writer.Advance(read);
flushed = await writer.FlushAsync(cancellationToken).ConfigureAwait(false);
} while (read > 0 && !(flushed.IsCompleted || flushed.IsCanceled || cancellationToken.IsCancellationRequested));
}

View File

@@ -19,10 +19,8 @@ internal sealed class RarHandler: IArchiveHandler
var firstEntry = Encoding.ASCII.GetString(header);
if (!firstEntry.Contains(".log", StringComparison.InvariantCultureIgnoreCase))
return (false, "Archive doesn't contain any logs.");
return (true, null);
}
return (false, null);
}
@@ -46,7 +44,8 @@ internal sealed class RarHandler: IArchiveHandler
{
var memory = writer.GetMemory(Config.MinimumBufferSize);
read = await rarStream.ReadAsync(memory, cancellationToken);
writer.Advance(read);
if (read > 0)
writer.Advance(read);
SourcePosition = statsStream.Position;
flushed = await writer.FlushAsync(cancellationToken).ConfigureAwait(false);
SourcePosition = statsStream.Position;

View File

@@ -19,10 +19,8 @@ internal sealed class SevenZipHandler: IArchiveHandler
{
if (fileSize > Config.AttachmentSizeLimit)
return (false, $"Log size is too large for 7z format: {fileSize.AsStorageUnit()} (max allowed is {Config.AttachmentSizeLimit.AsStorageUnit()})");
return (true, null);
}
return (false, null);
}
@@ -48,7 +46,8 @@ internal sealed class SevenZipHandler: IArchiveHandler
{
var memory = writer.GetMemory(Config.MinimumBufferSize);
read = await entryStream.ReadAsync(memory, cancellationToken);
writer.Advance(read);
if (read > 0)
writer.Advance(read);
flushed = await writer.FlushAsync(cancellationToken).ConfigureAwait(false);
} while (read > 0 && !(flushed.IsCompleted || flushed.IsCanceled || cancellationToken.IsCancellationRequested));
await writer.CompleteAsync();

View File

@@ -40,19 +40,25 @@ internal sealed class ZipHandler: IArchiveHandler
&& !zipReader.Entry.Key.Contains("tty.log", StringComparison.InvariantCultureIgnoreCase))
{
LogSize = zipReader.Entry.Size;
await using var rarStream = zipReader.OpenEntryStream();
int read;
await using var zipStream = zipReader.OpenEntryStream();
int read, totalRead = 0;
FlushResult flushed;
do
{
var memory = writer.GetMemory(Config.MinimumBufferSize);
read = await rarStream.ReadAsync(memory, cancellationToken);
writer.Advance(read);
read = await zipStream.ReadAsync(memory, cancellationToken).ConfigureAwait(false);
Config.Log.Debug($"{nameof(ZipHandler)}: read {read} bytes from source stream");
if (read > 0)
writer.Advance(read);
totalRead += read;
Config.Log.Debug($"{nameof(ZipHandler)}: advanced the writer by {read} (total read {totalRead})");
SourcePosition = statsStream.Position;
Config.Log.Debug($"{nameof(ZipHandler)}: current source position is {SourcePosition}");
flushed = await writer.FlushAsync(cancellationToken).ConfigureAwait(false);
SourcePosition = statsStream.Position;
Config.Log.Debug($"{nameof(ZipHandler)}: flushed the writer");
} while (read > 0 && !(flushed.IsCompleted || flushed.IsCanceled || cancellationToken.IsCancellationRequested));
await writer.CompleteAsync();
await writer.CompleteAsync().ConfigureAwait(false);
Config.Log.Debug($"{nameof(ZipHandler)}: writer completed");
return;
}
SourcePosition = statsStream.Position;

View File

@@ -22,6 +22,7 @@ internal static partial class LogParser
{
result = await reader.ReadAsync(cancellationToken).ConfigureAwait(false);
var buffer = result.Buffer;
Config.Log.Debug($"{nameof(LogParser)}: Read {buffer.Length} bytes from reader");
if (!skippedBom)
{
if (buffer.Length < 3)
@@ -31,6 +32,7 @@ internal static partial class LogParser
if (potentialBom.ToArray().SequenceEqual(Bom))
{
reader.AdvanceTo(potentialBom.End);
Config.Log.Debug($"{nameof(LogParser)}: Reader advanced to {potentialBom.End} to skip BOM");
totalReadBytes += potentialBom.Length;
skippedBom = true;
continue;
@@ -50,6 +52,7 @@ internal static partial class LogParser
if (state.Error != LogParseState.ErrorCode.None)
{
await reader.CompleteAsync();
Config.Log.Debug($"{nameof(LogParser)}: Reader completed (error: {state.Error})");
return state;
}
@@ -70,6 +73,7 @@ internal static partial class LogParser
var sectionStart = currentSectionLines.First is {} firstLine ? firstLine.Value : buffer;
totalReadBytes += result.Buffer.Slice(0, sectionStart.Start).Length;
reader.AdvanceTo(sectionStart.Start);
Config.Log.Debug($"{nameof(LogParser)}: Reader advanced to {sectionStart.Start} (section start)");
}
catch (Exception e)
{
@@ -82,6 +86,7 @@ internal static partial class LogParser
await TaskScheduler.WaitForClearTagAsync(state).ConfigureAwait(false);
state.ReadBytes = totalReadBytes;
await reader.CompleteAsync();
Config.Log.Debug($"{nameof(LogParser)}: Reader completed");
return state;
}

View File

@@ -108,8 +108,7 @@ public static class LogParsingHandler
try
{
Config.Log.Debug(
$">>>>>>> {message.Id % 100} Parsing log '{source.FileName}' from {message.Author.Username}#{message.Author.Discriminator} ({message.Author.Id}) using {source.GetType().Name} ({source.SourceFileSize} bytes)…");
Config.Log.Debug($">>>>>>> {message.Id % 100} Parsing log '{source.FileName}' from {message.Author.Username}#{message.Author.Discriminator} ({message.Author.Id}) using {source.GetType().Name} ({source.SourceFileSize} bytes)…");
var analyzingProgressEmbed = GetAnalyzingMsgEmbed(client);
var msgBuilder = new DiscordMessageBuilder()
.AddEmbed(await analyzingProgressEmbed.AddAuthorAsync(client, message, source).ConfigureAwait(false))
@@ -120,8 +119,7 @@ public static class LogParsingHandler
LogParseState? result = null, tmpResult;
using (var timeout = new CancellationTokenSource(Config.LogParsingTimeoutInSec))
{
using var combinedTokenSource =
CancellationTokenSource.CreateLinkedTokenSource(timeout.Token, Config.Cts.Token);
using var combinedTokenSource = CancellationTokenSource.CreateLinkedTokenSource(timeout.Token, Config.Cts.Token);
var tries = 0;
do
{
@@ -147,9 +145,8 @@ public static class LogParsingHandler
Please run the game again and re-upload a new copy.
""",
Color = Config.Colors.LogResultFailed,
}
.AddAuthorAsync(client, message, source).ConfigureAwait(false))
.Build()
}.AddAuthorAsync(client, message, source).ConfigureAwait(false))
.Build()
).ConfigureAwait(false);
Config.TelemetryClient?.TrackRequest(nameof(LogParsingHandler), start,
DateTimeOffset.UtcNow - start, HttpStatusCode.InternalServerError.ToString(), false);
@@ -235,13 +232,10 @@ public static class LogParsingHandler
);
if (saved && !suppress)
{
var content = await Warnings.GetDefaultWarningMessageAsync(client, message.Author, reason, recent, total, client.CurrentUser).ConfigureAwait(false);
var msg = new DiscordMessageBuilder()
.WithContent(
$"""
User warning saved, {message.Author.Mention} has {recent} recent warning{StringUtils.GetSuffix(recent)} ({total} total)
Warned for: {reason} by {client.CurrentUser.Mention}
"""
).AddMention(new UserMention(message.Author));
.WithContent(content)
.AddMention(new UserMention(message.Author));
await message.Channel!.SendMessageAsync(msg).ConfigureAwait(false);
}
}
@@ -251,8 +245,7 @@ public static class LogParsingHandler
{
if (result.SelectedFilter != null)
{
var ignoreFlags = FilterAction.IssueWarning | FilterAction.SendMessage |
FilterAction.ShowExplain;
var ignoreFlags = FilterAction.IssueWarning | FilterAction.SendMessage | FilterAction.ShowExplain;
await ContentFilter.PerformFilterActions(client, message, result.SelectedFilter,
ignoreFlags, result.SelectedFilterContext!).ConfigureAwait(false);
}
@@ -385,9 +378,9 @@ public static class LogParsingHandler
}
catch (Exception pre)
{
if (!(pre is OperationCanceledException))
if (pre is not OperationCanceledException)
Config.Log.Error(pre);
if (result == null)
if (result is null)
throw;
}

View File

@@ -7,10 +7,10 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="DuoVia.FuzzyStrings" Version="2.1.0" />
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="9.0.9" />
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="9.0.10" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.0.0" />
<PackageReference Include="NUnit" Version="4.4.0" />
<PackageReference Include="NUnit3TestAdapter" Version="5.1.0">
<PackageReference Include="NUnit3TestAdapter" Version="5.2.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>