mirror of
https://github.com/RPCS3/discord-bot.git
synced 2026-01-31 01:25:22 +01:00
bot update, part 3
This commit is contained in:
@@ -11,8 +11,6 @@ namespace CompatBot.Commands.Attributes
|
||||
public RequiresBotSudoerRole(): base(reactOnFailure: Config.Reactions.Denied) { }
|
||||
|
||||
protected override Task<bool> IsAllowed(CommandContext ctx, bool help)
|
||||
{
|
||||
return Task.FromResult(ctx.User.IsModerator(ctx.Client, ctx.Guild));
|
||||
}
|
||||
=> Task.FromResult(ctx.User.IsModerator(ctx.Client, ctx.Guild));
|
||||
}
|
||||
}
|
||||
@@ -43,8 +43,6 @@ namespace CompatBot.Commands
|
||||
[Command("help"), LimitedToSpamChannel, Cooldown(1, 5, CooldownBucketType.Channel)]
|
||||
[Description("General math expression help, or description of specific math word")]
|
||||
public Task Help(CommandContext ctx)
|
||||
{
|
||||
return ctx.RespondAsync("Help for all the features and built-in constants and functions could be found at <https://mathparser.org/mxparser-math-collection/>");
|
||||
}
|
||||
=> ctx.RespondAsync("Help for all the features and built-in constants and functions could be found at <https://mathparser.org/mxparser-math-collection/>");
|
||||
}
|
||||
}
|
||||
@@ -48,7 +48,7 @@ namespace CompatBot.Commands
|
||||
$"CPUs: {Environment.ProcessorCount}\n" +
|
||||
$"Time zones: {TimeParser.TimeZoneMap.Count} out of {TimeParser.TimeZoneAcronyms.Count} resolved, {TimeZoneInfo.GetSystemTimeZones().Count} total", true);
|
||||
AppendPiracyStats(embed);
|
||||
AppendCmdStats(ctx, embed);
|
||||
AppendCmdStats(embed);
|
||||
AppendExplainStats(embed);
|
||||
AppendGameLookupStats(embed);
|
||||
AppendSyscallsStats(embed);
|
||||
@@ -163,7 +163,7 @@ namespace CompatBot.Commands
|
||||
}
|
||||
}
|
||||
|
||||
private static void AppendCmdStats(CommandContext ctx, DiscordEmbedBuilder embed)
|
||||
private static void AppendCmdStats(DiscordEmbedBuilder embed)
|
||||
{
|
||||
var commandStats = StatsStorage.CmdStatCache.GetCacheKeys<string>();
|
||||
var sortedCommandStats = commandStats
|
||||
|
||||
@@ -34,6 +34,12 @@ namespace CompatBot.Commands
|
||||
try
|
||||
{
|
||||
var msg = await ctx.GetMessageAsync(messageLink).ConfigureAwait(false);
|
||||
if (msg is null)
|
||||
{
|
||||
await ctx.ReactWithAsync(Config.Reactions.Failure, "Can't find linked message").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
await ReportMessage(ctx, comment, msg);
|
||||
}
|
||||
catch (Exception)
|
||||
|
||||
@@ -100,9 +100,9 @@ namespace CompatBot.Commands
|
||||
return;
|
||||
}
|
||||
|
||||
var prState = prInfo.GetState();
|
||||
var (state, _) = prInfo.GetState();
|
||||
var embed = prInfo.AsEmbed();
|
||||
if (prState.state == "Open" || prState.state == "Closed")
|
||||
if (state == "Open" || state == "Closed")
|
||||
{
|
||||
var windowsDownloadHeader = "Windows PR Build";
|
||||
var linuxDownloadHeader = "Linux PR Build";
|
||||
@@ -119,7 +119,7 @@ namespace CompatBot.Commands
|
||||
var latestBuild = await azureClient.GetPrBuildInfoAsync(commit, prInfo.MergedAt, pr, Config.Cts.Token).ConfigureAwait(false);
|
||||
if (latestBuild == null)
|
||||
{
|
||||
if (prState.state == "Open")
|
||||
if (state == "Open")
|
||||
embed.WithFooter($"Opened on {prInfo.CreatedAt:u} ({(DateTime.UtcNow - prInfo.CreatedAt).AsTimeDeltaDescription()} ago)");
|
||||
windowsDownloadText = null;
|
||||
linuxDownloadText = null;
|
||||
@@ -186,7 +186,7 @@ namespace CompatBot.Commands
|
||||
if (!string.IsNullOrEmpty(buildTime))
|
||||
embed.WithFooter(buildTime);
|
||||
}
|
||||
else if (prState.state == "Merged")
|
||||
else if (state == "Merged")
|
||||
{
|
||||
var mergeTime = prInfo.MergedAt.GetValueOrDefault();
|
||||
var now = DateTime.UtcNow;
|
||||
|
||||
@@ -24,7 +24,7 @@ namespace CompatBot.Commands
|
||||
public async Task List(CommandContext ctx)
|
||||
{
|
||||
await using var db = new BotDb();
|
||||
var setVars = await db.BotState.AsNoTracking().Where(v => v.Key != null && v.Key.StartsWith(SqlConfiguration.ConfigVarPrefix)).ToListAsync().ConfigureAwait(false);
|
||||
var setVars = await db.BotState.AsNoTracking().Where(v => v.Key.StartsWith(SqlConfiguration.ConfigVarPrefix)).ToListAsync().ConfigureAwait(false);
|
||||
if (setVars.Any())
|
||||
{
|
||||
var result = new StringBuilder("Set variables:").AppendLine();
|
||||
|
||||
@@ -58,7 +58,8 @@ namespace CompatBot.Database
|
||||
internal class BotState
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public string? Key { get; set; }
|
||||
[Required]
|
||||
public string Key { get; set; } = null!;
|
||||
public string? Value { get; set; }
|
||||
}
|
||||
|
||||
|
||||
407
CompatBot/Database/Migrations/BotDb/20201113092108_MakeStateKeyRequired.Designer.cs
generated
Normal file
407
CompatBot/Database/Migrations/BotDb/20201113092108_MakeStateKeyRequired.Designer.cs
generated
Normal file
@@ -0,0 +1,407 @@
|
||||
// <auto-generated />
|
||||
using System;
|
||||
using CompatBot.Database;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
|
||||
namespace CompatBot.Database.Migrations
|
||||
{
|
||||
[DbContext(typeof(BotDb))]
|
||||
[Migration("20201113092108_MakeStateKeyRequired")]
|
||||
partial class MakeStateKeyRequired
|
||||
{
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder
|
||||
.HasAnnotation("ProductVersion", "5.0.0");
|
||||
|
||||
modelBuilder.Entity("CompatBot.Database.BotState", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnName("id");
|
||||
|
||||
b.Property<string>("Key")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("key");
|
||||
|
||||
b.Property<string>("Value")
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("value");
|
||||
|
||||
b.HasKey("Id")
|
||||
.HasName("id");
|
||||
|
||||
b.HasIndex("Key")
|
||||
.IsUnique()
|
||||
.HasDatabaseName("bot_state_key");
|
||||
|
||||
b.ToTable("bot_state");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CompatBot.Database.DisabledCommand", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnName("id");
|
||||
|
||||
b.Property<string>("Command")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("command");
|
||||
|
||||
b.HasKey("Id")
|
||||
.HasName("id");
|
||||
|
||||
b.HasIndex("Command")
|
||||
.IsUnique()
|
||||
.HasDatabaseName("disabled_command_command");
|
||||
|
||||
b.ToTable("disabled_commands");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CompatBot.Database.Doggo", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnName("id");
|
||||
|
||||
b.Property<ulong>("UserId")
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnName("user_id");
|
||||
|
||||
b.HasKey("Id")
|
||||
.HasName("id");
|
||||
|
||||
b.HasIndex("UserId")
|
||||
.IsUnique()
|
||||
.HasDatabaseName("doggo_user_id");
|
||||
|
||||
b.ToTable("doggo");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CompatBot.Database.EventSchedule", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnName("id");
|
||||
|
||||
b.Property<long>("End")
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnName("end");
|
||||
|
||||
b.Property<string>("EventName")
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("event_name");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("name");
|
||||
|
||||
b.Property<long>("Start")
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnName("start");
|
||||
|
||||
b.Property<int>("Year")
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnName("year");
|
||||
|
||||
b.HasKey("Id")
|
||||
.HasName("id");
|
||||
|
||||
b.HasIndex("Year", "EventName")
|
||||
.HasDatabaseName("event_schedule_year_event_name");
|
||||
|
||||
b.ToTable("event_schedule");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CompatBot.Database.Explanation", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnName("id");
|
||||
|
||||
b.Property<byte[]>("Attachment")
|
||||
.HasMaxLength(7340032)
|
||||
.HasColumnType("BLOB")
|
||||
.HasColumnName("attachment");
|
||||
|
||||
b.Property<string>("AttachmentFilename")
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("attachment_filename");
|
||||
|
||||
b.Property<string>("Keyword")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("keyword");
|
||||
|
||||
b.Property<string>("Text")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("text");
|
||||
|
||||
b.HasKey("Id")
|
||||
.HasName("id");
|
||||
|
||||
b.HasIndex("Keyword")
|
||||
.IsUnique()
|
||||
.HasDatabaseName("explanation_keyword");
|
||||
|
||||
b.ToTable("explanation");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CompatBot.Database.ForcedNickname", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnName("id");
|
||||
|
||||
b.Property<ulong>("GuildId")
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnName("guild_id");
|
||||
|
||||
b.Property<string>("Nickname")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("nickname");
|
||||
|
||||
b.Property<ulong>("UserId")
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnName("user_id");
|
||||
|
||||
b.HasKey("Id")
|
||||
.HasName("id");
|
||||
|
||||
b.HasIndex("GuildId", "UserId")
|
||||
.IsUnique()
|
||||
.HasDatabaseName("forced_nickname_guild_id_user_id");
|
||||
|
||||
b.ToTable("forced_nicknames");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CompatBot.Database.Kot", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnName("id");
|
||||
|
||||
b.Property<ulong>("UserId")
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnName("user_id");
|
||||
|
||||
b.HasKey("Id")
|
||||
.HasName("id");
|
||||
|
||||
b.HasIndex("UserId")
|
||||
.IsUnique()
|
||||
.HasDatabaseName("kot_user_id");
|
||||
|
||||
b.ToTable("kot");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CompatBot.Database.Moderator", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnName("id");
|
||||
|
||||
b.Property<ulong>("DiscordId")
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnName("discord_id");
|
||||
|
||||
b.Property<bool>("Sudoer")
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnName("sudoer");
|
||||
|
||||
b.HasKey("Id")
|
||||
.HasName("id");
|
||||
|
||||
b.HasIndex("DiscordId")
|
||||
.IsUnique()
|
||||
.HasDatabaseName("moderator_discord_id");
|
||||
|
||||
b.ToTable("moderator");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CompatBot.Database.Piracystring", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnName("id");
|
||||
|
||||
b.Property<int>("Actions")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER")
|
||||
.HasDefaultValue(11)
|
||||
.HasColumnName("actions");
|
||||
|
||||
b.Property<byte>("Context")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER")
|
||||
.HasDefaultValue((byte)3)
|
||||
.HasColumnName("context");
|
||||
|
||||
b.Property<string>("CustomMessage")
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("custom_message");
|
||||
|
||||
b.Property<bool>("Disabled")
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnName("disabled");
|
||||
|
||||
b.Property<string>("ExplainTerm")
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("explain_term");
|
||||
|
||||
b.Property<string>("String")
|
||||
.IsRequired()
|
||||
.HasColumnType("varchar(255)")
|
||||
.HasColumnName("string");
|
||||
|
||||
b.Property<string>("ValidatingRegex")
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("validating_regex");
|
||||
|
||||
b.HasKey("Id")
|
||||
.HasName("id");
|
||||
|
||||
b.HasIndex("String")
|
||||
.HasDatabaseName("piracystring_string");
|
||||
|
||||
b.ToTable("piracystring");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CompatBot.Database.Stats", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnName("id");
|
||||
|
||||
b.Property<string>("Category")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("category");
|
||||
|
||||
b.Property<long>("ExpirationTimestamp")
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnName("expiration_timestamp");
|
||||
|
||||
b.Property<string>("Key")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("key");
|
||||
|
||||
b.Property<int>("Value")
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnName("value");
|
||||
|
||||
b.HasKey("Id")
|
||||
.HasName("id");
|
||||
|
||||
b.HasIndex("Category", "Key")
|
||||
.IsUnique()
|
||||
.HasDatabaseName("stats_category_key");
|
||||
|
||||
b.ToTable("stats");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CompatBot.Database.Warning", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnName("id");
|
||||
|
||||
b.Property<ulong>("DiscordId")
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnName("discord_id");
|
||||
|
||||
b.Property<string>("FullReason")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("full_reason");
|
||||
|
||||
b.Property<ulong>("IssuerId")
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnName("issuer_id");
|
||||
|
||||
b.Property<string>("Reason")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("reason");
|
||||
|
||||
b.Property<bool>("Retracted")
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnName("retracted");
|
||||
|
||||
b.Property<ulong?>("RetractedBy")
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnName("retracted_by");
|
||||
|
||||
b.Property<string>("RetractionReason")
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("retraction_reason");
|
||||
|
||||
b.Property<long?>("RetractionTimestamp")
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnName("retraction_timestamp");
|
||||
|
||||
b.Property<long?>("Timestamp")
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnName("timestamp");
|
||||
|
||||
b.HasKey("Id")
|
||||
.HasName("id");
|
||||
|
||||
b.HasIndex("DiscordId")
|
||||
.HasDatabaseName("warning_discord_id");
|
||||
|
||||
b.ToTable("warning");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("CompatBot.Database.WhitelistedInvite", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnName("id");
|
||||
|
||||
b.Property<ulong>("GuildId")
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnName("guild_id");
|
||||
|
||||
b.Property<string>("InviteCode")
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("invite_code");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("name");
|
||||
|
||||
b.HasKey("Id")
|
||||
.HasName("id");
|
||||
|
||||
b.HasIndex("GuildId")
|
||||
.IsUnique()
|
||||
.HasDatabaseName("whitelisted_invite_guild_id");
|
||||
|
||||
b.ToTable("whitelisted_invites");
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
namespace CompatBot.Database.Migrations
|
||||
{
|
||||
public partial class MakeStateKeyRequired : Migration
|
||||
{
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AlterColumn<string>(
|
||||
name: "key",
|
||||
table: "bot_state",
|
||||
type: "TEXT",
|
||||
nullable: false,
|
||||
defaultValue: "",
|
||||
oldClrType: typeof(string),
|
||||
oldType: "TEXT",
|
||||
oldNullable: true);
|
||||
}
|
||||
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AlterColumn<string>(
|
||||
name: "key",
|
||||
table: "bot_state",
|
||||
type: "TEXT",
|
||||
nullable: true,
|
||||
oldClrType: typeof(string),
|
||||
oldType: "TEXT");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -14,29 +14,30 @@ namespace CompatBot.Database.Migrations
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder
|
||||
.HasAnnotation("ProductVersion", "3.0.0");
|
||||
.HasAnnotation("ProductVersion", "5.0.0");
|
||||
|
||||
modelBuilder.Entity("CompatBot.Database.BotState", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnName("id")
|
||||
.HasColumnType("INTEGER");
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnName("id");
|
||||
|
||||
b.Property<string>("Key")
|
||||
.HasColumnName("key")
|
||||
.HasColumnType("TEXT");
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("key");
|
||||
|
||||
b.Property<string>("Value")
|
||||
.HasColumnName("value")
|
||||
.HasColumnType("TEXT");
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("value");
|
||||
|
||||
b.HasKey("Id")
|
||||
.HasName("id");
|
||||
|
||||
b.HasIndex("Key")
|
||||
.IsUnique()
|
||||
.HasName("bot_state_key");
|
||||
.HasDatabaseName("bot_state_key");
|
||||
|
||||
b.ToTable("bot_state");
|
||||
});
|
||||
@@ -45,20 +46,20 @@ namespace CompatBot.Database.Migrations
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnName("id")
|
||||
.HasColumnType("INTEGER");
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnName("id");
|
||||
|
||||
b.Property<string>("Command")
|
||||
.IsRequired()
|
||||
.HasColumnName("command")
|
||||
.HasColumnType("TEXT");
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("command");
|
||||
|
||||
b.HasKey("Id")
|
||||
.HasName("id");
|
||||
|
||||
b.HasIndex("Command")
|
||||
.IsUnique()
|
||||
.HasName("disabled_command_command");
|
||||
.HasDatabaseName("disabled_command_command");
|
||||
|
||||
b.ToTable("disabled_commands");
|
||||
});
|
||||
@@ -67,19 +68,19 @@ namespace CompatBot.Database.Migrations
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnName("id")
|
||||
.HasColumnType("INTEGER");
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnName("id");
|
||||
|
||||
b.Property<ulong>("UserId")
|
||||
.HasColumnName("user_id")
|
||||
.HasColumnType("INTEGER");
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnName("user_id");
|
||||
|
||||
b.HasKey("Id")
|
||||
.HasName("id");
|
||||
|
||||
b.HasIndex("UserId")
|
||||
.IsUnique()
|
||||
.HasName("doggo_user_id");
|
||||
.HasDatabaseName("doggo_user_id");
|
||||
|
||||
b.ToTable("doggo");
|
||||
});
|
||||
@@ -88,34 +89,34 @@ namespace CompatBot.Database.Migrations
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnName("id")
|
||||
.HasColumnType("INTEGER");
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnName("id");
|
||||
|
||||
b.Property<long>("End")
|
||||
.HasColumnName("end")
|
||||
.HasColumnType("INTEGER");
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnName("end");
|
||||
|
||||
b.Property<string>("EventName")
|
||||
.HasColumnName("event_name")
|
||||
.HasColumnType("TEXT");
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("event_name");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.HasColumnName("name")
|
||||
.HasColumnType("TEXT");
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("name");
|
||||
|
||||
b.Property<long>("Start")
|
||||
.HasColumnName("start")
|
||||
.HasColumnType("INTEGER");
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnName("start");
|
||||
|
||||
b.Property<int>("Year")
|
||||
.HasColumnName("year")
|
||||
.HasColumnType("INTEGER");
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnName("year");
|
||||
|
||||
b.HasKey("Id")
|
||||
.HasName("id");
|
||||
|
||||
b.HasIndex("Year", "EventName")
|
||||
.HasName("event_schedule_year_event_name");
|
||||
.HasDatabaseName("event_schedule_year_event_name");
|
||||
|
||||
b.ToTable("event_schedule");
|
||||
});
|
||||
@@ -124,34 +125,34 @@ namespace CompatBot.Database.Migrations
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnName("id")
|
||||
.HasColumnType("INTEGER");
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnName("id");
|
||||
|
||||
b.Property<byte[]>("Attachment")
|
||||
.HasColumnName("attachment")
|
||||
.HasMaxLength(7340032)
|
||||
.HasColumnType("BLOB")
|
||||
.HasMaxLength(7340032);
|
||||
.HasColumnName("attachment");
|
||||
|
||||
b.Property<string>("AttachmentFilename")
|
||||
.HasColumnName("attachment_filename")
|
||||
.HasColumnType("TEXT");
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("attachment_filename");
|
||||
|
||||
b.Property<string>("Keyword")
|
||||
.IsRequired()
|
||||
.HasColumnName("keyword")
|
||||
.HasColumnType("TEXT");
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("keyword");
|
||||
|
||||
b.Property<string>("Text")
|
||||
.IsRequired()
|
||||
.HasColumnName("text")
|
||||
.HasColumnType("TEXT");
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("text");
|
||||
|
||||
b.HasKey("Id")
|
||||
.HasName("id");
|
||||
|
||||
b.HasIndex("Keyword")
|
||||
.IsUnique()
|
||||
.HasName("explanation_keyword");
|
||||
.HasDatabaseName("explanation_keyword");
|
||||
|
||||
b.ToTable("explanation");
|
||||
});
|
||||
@@ -160,28 +161,28 @@ namespace CompatBot.Database.Migrations
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnName("id")
|
||||
.HasColumnType("INTEGER");
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnName("id");
|
||||
|
||||
b.Property<ulong>("GuildId")
|
||||
.HasColumnName("guild_id")
|
||||
.HasColumnType("INTEGER");
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnName("guild_id");
|
||||
|
||||
b.Property<string>("Nickname")
|
||||
.IsRequired()
|
||||
.HasColumnName("nickname")
|
||||
.HasColumnType("TEXT");
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("nickname");
|
||||
|
||||
b.Property<ulong>("UserId")
|
||||
.HasColumnName("user_id")
|
||||
.HasColumnType("INTEGER");
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnName("user_id");
|
||||
|
||||
b.HasKey("Id")
|
||||
.HasName("id");
|
||||
|
||||
b.HasIndex("GuildId", "UserId")
|
||||
.IsUnique()
|
||||
.HasName("forced_nickname_guild_id_user_id");
|
||||
.HasDatabaseName("forced_nickname_guild_id_user_id");
|
||||
|
||||
b.ToTable("forced_nicknames");
|
||||
});
|
||||
@@ -190,19 +191,19 @@ namespace CompatBot.Database.Migrations
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnName("id")
|
||||
.HasColumnType("INTEGER");
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnName("id");
|
||||
|
||||
b.Property<ulong>("UserId")
|
||||
.HasColumnName("user_id")
|
||||
.HasColumnType("INTEGER");
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnName("user_id");
|
||||
|
||||
b.HasKey("Id")
|
||||
.HasName("id");
|
||||
|
||||
b.HasIndex("UserId")
|
||||
.IsUnique()
|
||||
.HasName("kot_user_id");
|
||||
.HasDatabaseName("kot_user_id");
|
||||
|
||||
b.ToTable("kot");
|
||||
});
|
||||
@@ -211,23 +212,23 @@ namespace CompatBot.Database.Migrations
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnName("id")
|
||||
.HasColumnType("INTEGER");
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnName("id");
|
||||
|
||||
b.Property<ulong>("DiscordId")
|
||||
.HasColumnName("discord_id")
|
||||
.HasColumnType("INTEGER");
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnName("discord_id");
|
||||
|
||||
b.Property<bool>("Sudoer")
|
||||
.HasColumnName("sudoer")
|
||||
.HasColumnType("INTEGER");
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnName("sudoer");
|
||||
|
||||
b.HasKey("Id")
|
||||
.HasName("id");
|
||||
|
||||
b.HasIndex("DiscordId")
|
||||
.IsUnique()
|
||||
.HasName("moderator_discord_id");
|
||||
.HasDatabaseName("moderator_discord_id");
|
||||
|
||||
b.ToTable("moderator");
|
||||
});
|
||||
@@ -236,47 +237,47 @@ namespace CompatBot.Database.Migrations
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnName("id")
|
||||
.HasColumnType("INTEGER");
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnName("id");
|
||||
|
||||
b.Property<int>("Actions")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnName("actions")
|
||||
.HasColumnType("INTEGER")
|
||||
.HasDefaultValue(11);
|
||||
.HasDefaultValue(11)
|
||||
.HasColumnName("actions");
|
||||
|
||||
b.Property<byte>("Context")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnName("context")
|
||||
.HasColumnType("INTEGER")
|
||||
.HasDefaultValue((byte)3);
|
||||
.HasDefaultValue((byte)3)
|
||||
.HasColumnName("context");
|
||||
|
||||
b.Property<string>("CustomMessage")
|
||||
.HasColumnName("custom_message")
|
||||
.HasColumnType("TEXT");
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("custom_message");
|
||||
|
||||
b.Property<bool>("Disabled")
|
||||
.HasColumnName("disabled")
|
||||
.HasColumnType("INTEGER");
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnName("disabled");
|
||||
|
||||
b.Property<string>("ExplainTerm")
|
||||
.HasColumnName("explain_term")
|
||||
.HasColumnType("TEXT");
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("explain_term");
|
||||
|
||||
b.Property<string>("String")
|
||||
.IsRequired()
|
||||
.HasColumnName("string")
|
||||
.HasColumnType("varchar(255)");
|
||||
.HasColumnType("varchar(255)")
|
||||
.HasColumnName("string");
|
||||
|
||||
b.Property<string>("ValidatingRegex")
|
||||
.HasColumnName("validating_regex")
|
||||
.HasColumnType("TEXT");
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("validating_regex");
|
||||
|
||||
b.HasKey("Id")
|
||||
.HasName("id");
|
||||
|
||||
b.HasIndex("String")
|
||||
.HasName("piracystring_string");
|
||||
.HasDatabaseName("piracystring_string");
|
||||
|
||||
b.ToTable("piracystring");
|
||||
});
|
||||
@@ -285,33 +286,33 @@ namespace CompatBot.Database.Migrations
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnName("id")
|
||||
.HasColumnType("INTEGER");
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnName("id");
|
||||
|
||||
b.Property<string>("Category")
|
||||
.IsRequired()
|
||||
.HasColumnName("category")
|
||||
.HasColumnType("TEXT");
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("category");
|
||||
|
||||
b.Property<long>("ExpirationTimestamp")
|
||||
.HasColumnName("expiration_timestamp")
|
||||
.HasColumnType("INTEGER");
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnName("expiration_timestamp");
|
||||
|
||||
b.Property<string>("Key")
|
||||
.IsRequired()
|
||||
.HasColumnName("key")
|
||||
.HasColumnType("TEXT");
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("key");
|
||||
|
||||
b.Property<int>("Value")
|
||||
.HasColumnName("value")
|
||||
.HasColumnType("INTEGER");
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnName("value");
|
||||
|
||||
b.HasKey("Id")
|
||||
.HasName("id");
|
||||
|
||||
b.HasIndex("Category", "Key")
|
||||
.IsUnique()
|
||||
.HasName("stats_category_key");
|
||||
.HasDatabaseName("stats_category_key");
|
||||
|
||||
b.ToTable("stats");
|
||||
});
|
||||
@@ -320,52 +321,52 @@ namespace CompatBot.Database.Migrations
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnName("id")
|
||||
.HasColumnType("INTEGER");
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnName("id");
|
||||
|
||||
b.Property<ulong>("DiscordId")
|
||||
.HasColumnName("discord_id")
|
||||
.HasColumnType("INTEGER");
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnName("discord_id");
|
||||
|
||||
b.Property<string>("FullReason")
|
||||
.IsRequired()
|
||||
.HasColumnName("full_reason")
|
||||
.HasColumnType("TEXT");
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("full_reason");
|
||||
|
||||
b.Property<ulong>("IssuerId")
|
||||
.HasColumnName("issuer_id")
|
||||
.HasColumnType("INTEGER");
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnName("issuer_id");
|
||||
|
||||
b.Property<string>("Reason")
|
||||
.IsRequired()
|
||||
.HasColumnName("reason")
|
||||
.HasColumnType("TEXT");
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("reason");
|
||||
|
||||
b.Property<bool>("Retracted")
|
||||
.HasColumnName("retracted")
|
||||
.HasColumnType("INTEGER");
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnName("retracted");
|
||||
|
||||
b.Property<ulong?>("RetractedBy")
|
||||
.HasColumnName("retracted_by")
|
||||
.HasColumnType("INTEGER");
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnName("retracted_by");
|
||||
|
||||
b.Property<string>("RetractionReason")
|
||||
.HasColumnName("retraction_reason")
|
||||
.HasColumnType("TEXT");
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("retraction_reason");
|
||||
|
||||
b.Property<long?>("RetractionTimestamp")
|
||||
.HasColumnName("retraction_timestamp")
|
||||
.HasColumnType("INTEGER");
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnName("retraction_timestamp");
|
||||
|
||||
b.Property<long?>("Timestamp")
|
||||
.HasColumnName("timestamp")
|
||||
.HasColumnType("INTEGER");
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnName("timestamp");
|
||||
|
||||
b.HasKey("Id")
|
||||
.HasName("id");
|
||||
|
||||
b.HasIndex("DiscordId")
|
||||
.HasName("warning_discord_id");
|
||||
.HasDatabaseName("warning_discord_id");
|
||||
|
||||
b.ToTable("warning");
|
||||
});
|
||||
@@ -374,27 +375,27 @@ namespace CompatBot.Database.Migrations
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnName("id")
|
||||
.HasColumnType("INTEGER");
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnName("id");
|
||||
|
||||
b.Property<ulong>("GuildId")
|
||||
.HasColumnName("guild_id")
|
||||
.HasColumnType("INTEGER");
|
||||
.HasColumnType("INTEGER")
|
||||
.HasColumnName("guild_id");
|
||||
|
||||
b.Property<string>("InviteCode")
|
||||
.HasColumnName("invite_code")
|
||||
.HasColumnType("TEXT");
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("invite_code");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.HasColumnName("name")
|
||||
.HasColumnType("TEXT");
|
||||
.HasColumnType("TEXT")
|
||||
.HasColumnName("name");
|
||||
|
||||
b.HasKey("Id")
|
||||
.HasName("id");
|
||||
|
||||
b.HasIndex("GuildId")
|
||||
.IsUnique()
|
||||
.HasName("whitelisted_invite_guild_id");
|
||||
.HasDatabaseName("whitelisted_invite_guild_id");
|
||||
|
||||
b.ToTable("whitelisted_invites");
|
||||
});
|
||||
|
||||
@@ -10,48 +10,40 @@ namespace CompatBot.Database.Providers
|
||||
private static readonly TimeSpan CheckInterval = TimeSpan.FromDays(365);
|
||||
|
||||
public static bool IsFresh(long timestamp)
|
||||
{
|
||||
return IsFresh(new DateTime(timestamp, DateTimeKind.Utc));
|
||||
}
|
||||
=> IsFresh(new DateTime(timestamp, DateTimeKind.Utc));
|
||||
|
||||
public static bool IsFresh(DateTime timestamp)
|
||||
{
|
||||
return timestamp.Add(CheckInterval) > DateTime.UtcNow;
|
||||
}
|
||||
=> timestamp.Add(CheckInterval) > DateTime.UtcNow;
|
||||
|
||||
public static bool IsFresh(string locale, string containerId = null)
|
||||
public static bool IsFresh(string locale, string? containerId = null)
|
||||
{
|
||||
var id = GetId(locale, containerId);
|
||||
using (var db = new ThumbnailDb())
|
||||
{
|
||||
var timestamp = string.IsNullOrEmpty(id) ? db.State.OrderBy(s => s.Timestamp).FirstOrDefault() : db.State.FirstOrDefault(s => s.Locale == id);
|
||||
if (timestamp?.Timestamp is long checkDate && checkDate > 0)
|
||||
return IsFresh(new DateTime(checkDate, DateTimeKind.Utc));
|
||||
}
|
||||
using var db = new ThumbnailDb();
|
||||
var timestamp = string.IsNullOrEmpty(id) ? db.State.OrderBy(s => s.Timestamp).FirstOrDefault() : db.State.FirstOrDefault(s => s.Locale == id);
|
||||
if (timestamp?.Timestamp is long checkDate && checkDate > 0)
|
||||
return IsFresh(new DateTime(checkDate, DateTimeKind.Utc));
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool IsFresh(string locale, DateTime dataTimestamp)
|
||||
{
|
||||
using (var db = new ThumbnailDb())
|
||||
{
|
||||
var timestamp = string.IsNullOrEmpty(locale) ? db.State.OrderBy(s => s.Timestamp).FirstOrDefault() : db.State.FirstOrDefault(s => s.Locale == locale);
|
||||
if (timestamp?.Timestamp is long checkDate && checkDate > 0)
|
||||
return new DateTime(checkDate, DateTimeKind.Utc) > dataTimestamp;
|
||||
}
|
||||
using var db = new ThumbnailDb();
|
||||
var timestamp = string.IsNullOrEmpty(locale) ? db.State.OrderBy(s => s.Timestamp).FirstOrDefault() : db.State.FirstOrDefault(s => s.Locale == locale);
|
||||
if (timestamp?.Timestamp is long checkDate && checkDate > 0)
|
||||
return new DateTime(checkDate, DateTimeKind.Utc) > dataTimestamp;
|
||||
return false;
|
||||
}
|
||||
|
||||
public static async Task SetLastRunTimestampAsync(string locale, string containerId = null)
|
||||
public static async Task SetLastRunTimestampAsync(string locale, string? containerId = null)
|
||||
{
|
||||
if (string.IsNullOrEmpty(locale))
|
||||
throw new ArgumentException(nameof(locale));
|
||||
throw new ArgumentException("Locale is mandatory", nameof(locale));
|
||||
|
||||
var id = GetId(locale, containerId);
|
||||
using var db = new ThumbnailDb();
|
||||
await using var db = new ThumbnailDb();
|
||||
var timestamp = db.State.FirstOrDefault(s => s.Locale == id);
|
||||
if (timestamp == null)
|
||||
db.State.Add(new State {Locale = id, Timestamp = DateTime.UtcNow.Ticks});
|
||||
await db.State.AddAsync(new State {Locale = id, Timestamp = DateTime.UtcNow.Ticks}).ConfigureAwait(false);
|
||||
else
|
||||
timestamp.Timestamp = DateTime.UtcNow.Ticks;
|
||||
await db.SaveChangesAsync().ConfigureAwait(false);
|
||||
@@ -59,7 +51,7 @@ namespace CompatBot.Database.Providers
|
||||
|
||||
public static async Task CleanAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
using var db = new ThumbnailDb();
|
||||
await using var db = new ThumbnailDb();
|
||||
var latestTimestamp = db.State.OrderByDescending(s => s.Timestamp).FirstOrDefault()?.Timestamp;
|
||||
if (!latestTimestamp.HasValue)
|
||||
return;
|
||||
@@ -70,11 +62,7 @@ namespace CompatBot.Database.Providers
|
||||
await db.SaveChangesAsync(cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private static string GetId(string locale, string containerId)
|
||||
{
|
||||
if (string.IsNullOrEmpty(locale) || string.IsNullOrEmpty(containerId))
|
||||
return locale;
|
||||
return $"{locale} - {containerId}";
|
||||
}
|
||||
private static string GetId(string locale, string? containerId)
|
||||
=> string.IsNullOrEmpty(containerId) ? locale : $"{locale} - {containerId}";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,12 +10,13 @@ namespace CompatBot.Database.Providers
|
||||
|
||||
public static async Task RestoreAsync()
|
||||
{
|
||||
using var db = new BotDb();
|
||||
await using var db = new BotDb();
|
||||
var setVars = await db.BotState.AsNoTracking().Where(v => v.Key.StartsWith(ConfigVarPrefix)).ToListAsync().ConfigureAwait(false);
|
||||
if (setVars.Any())
|
||||
{
|
||||
foreach (var v in setVars)
|
||||
Config.inMemorySettings[v.Key[ConfigVarPrefix.Length ..]] = v.Value;
|
||||
foreach (var stateVar in setVars)
|
||||
if (stateVar.Value is string value)
|
||||
Config.inMemorySettings[stateVar.Key[ConfigVarPrefix.Length ..]] = value;
|
||||
Config.RebuildConfiguration();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -227,7 +227,7 @@ namespace CompatBot.EventHandlers.LogParsing
|
||||
}
|
||||
};
|
||||
|
||||
public static readonly HashSet<string> MultiValueItems = new HashSet<string>
|
||||
private static readonly HashSet<string> MultiValueItems = new HashSet<string>
|
||||
{
|
||||
"pad_handler",
|
||||
"fatal_error_context",
|
||||
@@ -248,7 +248,7 @@ namespace CompatBot.EventHandlers.LogParsing
|
||||
"rsx_not_supported_feature",
|
||||
};
|
||||
|
||||
public static readonly string[] CountValueItems = {"enqueue_buffer_error"};
|
||||
private static readonly string[] CountValueItems = {"enqueue_buffer_error"};
|
||||
|
||||
private static async Task PiracyCheckAsync(string line, LogParseState state)
|
||||
{
|
||||
@@ -291,15 +291,6 @@ namespace CompatBot.EventHandlers.LogParsing
|
||||
}
|
||||
}
|
||||
|
||||
private static Task LimitedPiracyCheckAsync(string line, LogParseState state)
|
||||
{
|
||||
if (state.LinesAfterConfig > 10)
|
||||
return Task.CompletedTask;
|
||||
|
||||
state.LinesAfterConfig++;
|
||||
return PiracyCheckAsync(line, state);
|
||||
}
|
||||
|
||||
private static void ClearResults(LogParseState state)
|
||||
{
|
||||
void Copy(params string[] keys)
|
||||
|
||||
@@ -18,9 +18,10 @@ namespace CompatBot.EventHandlers.LogParsing
|
||||
|
||||
public static async Task<LogParseState> ReadPipeAsync(PipeReader reader, CancellationToken cancellationToken)
|
||||
{
|
||||
var currentSectionLines = new LinkedList<ReadOnlySequence<byte>>();
|
||||
#warning benchmark other collections
|
||||
var currentSectionLines = new LinkedList<ReadOnlySequence<byte>>();
|
||||
var state = new LogParseState();
|
||||
bool skippedBom = false;
|
||||
var skippedBom = false;
|
||||
long totalReadBytes = 0;
|
||||
ReadResult result;
|
||||
do
|
||||
@@ -47,20 +48,20 @@ namespace CompatBot.EventHandlers.LogParsing
|
||||
SequencePosition? lineEnd;
|
||||
do
|
||||
{
|
||||
if (currentSectionLines.Count > 0)
|
||||
buffer = buffer.Slice(buffer.GetPosition(1, currentSectionLines.Last.Value.End));
|
||||
if (currentSectionLines.Last is {} lastLine)
|
||||
buffer = buffer.Slice(buffer.GetPosition(1, lastLine.Value.End));
|
||||
lineEnd = buffer.PositionOf((byte)'\n');
|
||||
if (lineEnd != null)
|
||||
if (lineEnd is null)
|
||||
continue;
|
||||
|
||||
await OnNewLineAsync(buffer.Slice(0, lineEnd.Value), result.Buffer, currentSectionLines, state).ConfigureAwait(false);
|
||||
if (state.Error != LogParseState.ErrorCode.None)
|
||||
{
|
||||
await OnNewLineAsync(buffer.Slice(0, lineEnd.Value), result.Buffer, currentSectionLines, state).ConfigureAwait(false);
|
||||
if (state.Error != LogParseState.ErrorCode.None)
|
||||
{
|
||||
await reader.CompleteAsync();
|
||||
return state;
|
||||
}
|
||||
|
||||
buffer = buffer.Slice(buffer.GetPosition(1, lineEnd.Value));
|
||||
await reader.CompleteAsync();
|
||||
return state;
|
||||
}
|
||||
|
||||
buffer = buffer.Slice(buffer.GetPosition(1, lineEnd.Value));
|
||||
} while (lineEnd != null);
|
||||
|
||||
if (result.IsCanceled || cancellationToken.IsCancellationRequested)
|
||||
@@ -70,11 +71,11 @@ namespace CompatBot.EventHandlers.LogParsing
|
||||
}
|
||||
else if (result.IsCompleted)
|
||||
{
|
||||
if (!buffer.End.Equals(currentSectionLines.Last.Value.End))
|
||||
if (!buffer.End.Equals(currentSectionLines.Last?.Value.End))
|
||||
await OnNewLineAsync(buffer.Slice(0), result.Buffer, currentSectionLines, state).ConfigureAwait(false);
|
||||
await FlushAllLinesAsync(result.Buffer, currentSectionLines, state).ConfigureAwait(false);
|
||||
}
|
||||
var sectionStart = currentSectionLines.Count == 0 ? buffer : currentSectionLines.First.Value;
|
||||
var sectionStart = currentSectionLines.First is {} firstLine ? firstLine.Value : buffer;
|
||||
totalReadBytes += result.Buffer.Slice(0, sectionStart.Start).Length;
|
||||
reader.AdvanceTo(sectionStart.Start);
|
||||
}
|
||||
@@ -117,15 +118,16 @@ namespace CompatBot.EventHandlers.LogParsing
|
||||
private static async Task ProcessFirstLineInBufferAsync(ReadOnlySequence<byte> buffer, LinkedList<ReadOnlySequence<byte>> sectionLines, LogParseState state)
|
||||
{
|
||||
var currentProcessor = SectionParsers[state.Id];
|
||||
if (sectionLines.First is null)
|
||||
return;
|
||||
|
||||
var firstSectionLine = sectionLines.First.Value.AsString();
|
||||
await PiracyCheckAsync(firstSectionLine, state).ConfigureAwait(false);
|
||||
//await currentProcessor.OnLineCheckAsync(firstSectionLine, state).ConfigureAwait(false);
|
||||
if (state.Error != LogParseState.ErrorCode.None)
|
||||
return;
|
||||
|
||||
var section = buffer.Slice(sectionLines.First.Value.Start, sectionLines.Last.Value.End).AsString();
|
||||
if (currentProcessor.OnExtract != null)
|
||||
await TaskScheduler.AddAsync(state, Task.Run(() => currentProcessor.OnExtract(firstSectionLine, section, state)));
|
||||
var section = buffer.Slice(sectionLines.First.Value.Start, sectionLines.Last!.Value.End).AsString();
|
||||
await TaskScheduler.AddAsync(state, Task.Run(() => currentProcessor.OnExtract(firstSectionLine, section, state)));
|
||||
sectionLines.RemoveFirst();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
using CompatBot.EventHandlers.LogParsing.POCOs;
|
||||
using CompatBot.Utils;
|
||||
using NReco.Text;
|
||||
@@ -24,7 +22,6 @@ namespace CompatBot.EventHandlers.LogParsing
|
||||
{
|
||||
var parser = new LogSectionParser
|
||||
{
|
||||
//OnLineCheckAsync = sectionDescription.OnNewLineAsync ?? ((l, s) => Task.CompletedTask),
|
||||
OnSectionEnd = sectionDescription.OnSectionEnd,
|
||||
EndTrigger = sectionDescription.EndTrigger.Select(s => s.ToLatin8BitEncoding()).ToArray(),
|
||||
};
|
||||
@@ -37,7 +34,7 @@ namespace CompatBot.EventHandlers.LogParsing
|
||||
(buffer, state) =>
|
||||
{
|
||||
#if DEBUG
|
||||
var timer = Stopwatch.StartNew();
|
||||
var timer = System.Diagnostics.Stopwatch.StartNew();
|
||||
#endif
|
||||
OnExtractorHit(buffer, extractorPair.Key, extractorPair.Value, state);
|
||||
|
||||
@@ -60,19 +57,18 @@ namespace CompatBot.EventHandlers.LogParsing
|
||||
|
||||
private static void OnExtractorHit(string buffer, string trigger, Regex extractor, LogParseState state)
|
||||
{
|
||||
if (trigger == "⁂" || trigger == "{PPU[")
|
||||
if (trigger == "{PPU[" || trigger == "⁂")
|
||||
{
|
||||
if (state.WipCollection["serial"] is string serial)
|
||||
if (state.WipCollection["serial"] is string serial
|
||||
&& extractor.Match(buffer) is Match match
|
||||
&& match.Success
|
||||
&& match.Groups["syscall_name"].Value is string syscallName)
|
||||
{
|
||||
var match = extractor.Match(buffer);
|
||||
if (match.Success && match.Groups["syscall_name"]?.Value is string syscallName)
|
||||
lock (state)
|
||||
{
|
||||
lock (state)
|
||||
{
|
||||
if (!state.Syscalls.TryGetValue(serial, out var serialSyscallStats))
|
||||
state.Syscalls[serial] = serialSyscallStats = new HashSet<string>();
|
||||
serialSyscallStats.Add(syscallName);
|
||||
}
|
||||
if (!state.Syscalls.TryGetValue(serial, out var serialSyscallStats))
|
||||
state.Syscalls[serial] = serialSyscallStats = new HashSet<string>();
|
||||
serialSyscallStats.Add(syscallName);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -84,26 +80,27 @@ namespace CompatBot.EventHandlers.LogParsing
|
||||
|
||||
foreach (Match match in matches)
|
||||
foreach (Group group in match.Groups)
|
||||
if (!string.IsNullOrEmpty(group.Name) && group.Name != "0" && !string.IsNullOrWhiteSpace(group.Value))
|
||||
{
|
||||
if (string.IsNullOrEmpty(group.Value))
|
||||
continue;
|
||||
{
|
||||
if (string.IsNullOrEmpty(group.Name)
|
||||
|| group.Name == "0"
|
||||
|| string.IsNullOrWhiteSpace(group.Value))
|
||||
continue;
|
||||
|
||||
var strValue = group.Value.ToUtf8();
|
||||
//Config.Log.Trace($"regex {group.Name} = {group.Value}");
|
||||
lock (state)
|
||||
{
|
||||
if (MultiValueItems.Contains(group.Name))
|
||||
state.WipMultiValueCollection[group.Name].Add(strValue);
|
||||
else
|
||||
state.WipCollection[group.Name] = strValue;
|
||||
if (CountValueItems.Contains(group.Name))
|
||||
{
|
||||
state.ValueHitStats.TryGetValue(group.Name, out var hits);
|
||||
state.ValueHitStats[group.Name] = ++hits;
|
||||
}
|
||||
}
|
||||
var strValue = group.Value.ToUtf8();
|
||||
//Config.Log.Trace($"regex {group.Name} = {group.Value}");
|
||||
lock (state)
|
||||
{
|
||||
if (MultiValueItems.Contains(group.Name))
|
||||
state.WipMultiValueCollection[group.Name].Add(strValue);
|
||||
else
|
||||
state.WipCollection[group.Name] = strValue;
|
||||
if (!CountValueItems.Contains(group.Name))
|
||||
continue;
|
||||
|
||||
state.ValueHitStats.TryGetValue(group.Name, out var hits);
|
||||
state.ValueHitStats[group.Name] = ++hits;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -111,10 +108,9 @@ namespace CompatBot.EventHandlers.LogParsing
|
||||
|
||||
private class LogSectionParser
|
||||
{
|
||||
public OnNewLineDelegate OnExtract;
|
||||
//public Func<string, LogParseState, Task> OnLineCheckAsync;
|
||||
public Action<LogParseState> OnSectionEnd;
|
||||
public string[] EndTrigger;
|
||||
public OnNewLineDelegate OnExtract = null!;
|
||||
public Action<LogParseState>? OnSectionEnd;
|
||||
public string[] EndTrigger = null!;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -21,7 +21,6 @@ namespace CompatBot.EventHandlers.LogParsing.POCOs
|
||||
public string? SelectedFilterContext;
|
||||
public long ReadBytes;
|
||||
public long TotalBytes;
|
||||
public int LinesAfterConfig;
|
||||
public TimeSpan ParsingTime;
|
||||
#if DEBUG
|
||||
public readonly Dictionary<string, (int count, long regexTime)> ExtractorHitStats = new Dictionary<string, (int, long)>();
|
||||
|
||||
@@ -1,15 +1,13 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace CompatBot.EventHandlers.LogParsing.POCOs
|
||||
{
|
||||
internal class LogSection
|
||||
{
|
||||
public string[] EndTrigger;
|
||||
public Dictionary<string, Regex> Extractors;
|
||||
//public Func<string, LogParseState, Task> OnNewLineAsync;
|
||||
public Action<LogParseState> OnSectionEnd;
|
||||
public string[] EndTrigger = null!;
|
||||
public Dictionary<string, Regex> Extractors = null!;
|
||||
public Action<LogParseState>? OnSectionEnd;
|
||||
}
|
||||
}
|
||||
@@ -140,6 +140,16 @@ namespace CompatBot.EventHandlers
|
||||
{
|
||||
if (result.Error == LogParseState.ErrorCode.PiracyDetected)
|
||||
{
|
||||
if (result.SelectedFilter is null)
|
||||
{
|
||||
Config.Log.Error("Piracy was detectedin log, but no trigger provided");
|
||||
result.SelectedFilter = new Piracystring
|
||||
{
|
||||
String = "Unknown trigger, plz kick 13xforever",
|
||||
Actions = FilterAction.IssueWarning | FilterAction.RemoveContent,
|
||||
Context = FilterContext.Log,
|
||||
};
|
||||
}
|
||||
var yarr = client.GetEmoji(":piratethink:", "☠");
|
||||
result.ReadBytes = 0;
|
||||
if (message.Author.IsWhitelisted(client, channel.Guild))
|
||||
@@ -147,7 +157,7 @@ namespace CompatBot.EventHandlers
|
||||
var piracyWarning = await result.AsEmbedAsync(client, message, source).ConfigureAwait(false);
|
||||
piracyWarning = piracyWarning.WithDescription("Please remove the log and issue warning to the original author of the log");
|
||||
botMsg = await botMsg.UpdateOrCreateMessageAsync(channel, embed: piracyWarning).ConfigureAwait(false);
|
||||
await client.ReportAsync(yarr + " Pirated Release (whitelisted by role)", message, result.SelectedFilter?.String, result.SelectedFilterContext, ReportSeverity.Low).ConfigureAwait(false);
|
||||
await client.ReportAsync(yarr + " Pirated Release (whitelisted by role)", message, result.SelectedFilter.String, result.SelectedFilterContext, ReportSeverity.Low).ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -180,14 +190,14 @@ namespace CompatBot.EventHandlers
|
||||
}
|
||||
try
|
||||
{
|
||||
await client.ReportAsync(yarr + " Pirated Release", message, result.SelectedFilter?.String, result.SelectedFilterContext, severity).ConfigureAwait(false);
|
||||
await client.ReportAsync(yarr + " Pirated Release", message, result.SelectedFilter.String, result.SelectedFilterContext, severity).ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Config.Log.Error(e, "Failed to send piracy report");
|
||||
}
|
||||
if (!(message.Channel.IsPrivate || (message.Channel.Name?.Contains("spam") ?? true)))
|
||||
await Warnings.AddAsync(client, message, message.Author.Id, message.Author.Username, client.CurrentUser, "Pirated Release", $"{result.SelectedFilter?.String} - {result.SelectedFilterContext?.Sanitize()}");
|
||||
await Warnings.AddAsync(client, message, message.Author.Id, message.Author.Username, client.CurrentUser, "Pirated Release", $"{result.SelectedFilter.String} - {result.SelectedFilterContext?.Sanitize()}");
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
@@ -13,7 +13,7 @@ namespace CompatBot.Utils
|
||||
public const int MaxFieldTitleLength = 256;
|
||||
public const int MaxFields = 25;
|
||||
|
||||
public static IEnumerable<DiscordEmbed> BreakInEmbeds(this IEnumerable<string> lines, DiscordEmbedBuilder builder, int maxLinesPerField = 10, string titleBase = null)
|
||||
public static IEnumerable<DiscordEmbed> BreakInEmbeds(this IEnumerable<string> lines, DiscordEmbedBuilder builder, int maxLinesPerField = 10, string? titleBase = null)
|
||||
{
|
||||
string getTitle(string autoGeneratedTitle, int count)
|
||||
{
|
||||
@@ -38,17 +38,15 @@ namespace CompatBot.Utils
|
||||
yield return builder.Build();
|
||||
}
|
||||
|
||||
public static IEnumerable<(string title, string content)> BreakInFieldContent(this IEnumerable<string> lines, int maxLinesPerField = 10, Func<string, string, string> makeTitle = null)
|
||||
public static IEnumerable<(string title, string content)> BreakInFieldContent(this IEnumerable<string> lines, int maxLinesPerField = 10, Func<string?, string?, string>? makeTitle = null)
|
||||
{
|
||||
if (maxLinesPerField < 1)
|
||||
throw new ArgumentException("Expected a number greater than 0, but was " + maxLinesPerField, nameof(maxLinesPerField));
|
||||
|
||||
makeTitle ??= MakeTitle;
|
||||
|
||||
var buffer = new StringBuilder();
|
||||
var lineCount = 0;
|
||||
string firstLine = null;
|
||||
string lastLine = null;
|
||||
string? firstLine = null, lastLine = null;
|
||||
foreach (var line in lines)
|
||||
{
|
||||
if (string.IsNullOrEmpty(firstLine))
|
||||
@@ -96,7 +94,7 @@ namespace CompatBot.Utils
|
||||
yield return (makeTitle(firstLine, lastLine), buffer.ToString());
|
||||
}
|
||||
|
||||
private static string MakeTitle(string first, string last)
|
||||
private static string MakeTitle(string? first, string? last)
|
||||
{
|
||||
if (string.IsNullOrEmpty(first) || string.IsNullOrEmpty(last))
|
||||
return first + last;
|
||||
|
||||
@@ -12,40 +12,30 @@ namespace CompatBot.Utils
|
||||
{
|
||||
internal static readonly Regex MessageLinkRegex = new Regex(@"(?:https?://)?discord(app)?\.com/channels/(?<guild>\d+)/(?<channel>\d+)/(?<message>\d+)", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.Singleline);
|
||||
|
||||
public static async Task<DiscordMember> ResolveMemberAsync(this CommandContext ctx, string word)
|
||||
public static async Task<DiscordMember?> ResolveMemberAsync(this CommandContext ctx, string word)
|
||||
{
|
||||
try
|
||||
{
|
||||
var result = await ((IArgumentConverter<DiscordMember>)new DiscordMemberConverter()).ConvertAsync(word, ctx).ConfigureAwait(false);
|
||||
return result.HasValue ? result.Value : null;
|
||||
}
|
||||
#pragma warning disable CS0168 // Variable is declared but never used
|
||||
catch (Exception e)
|
||||
#pragma warning restore CS0168 // Variable is declared but never used
|
||||
{
|
||||
#if DEBUG
|
||||
Config.Log.Warn(e, $"Failed to resolve member {word}");
|
||||
#endif
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static async Task<DiscordChannel> CreateDmAsync(this CommandContext ctx)
|
||||
{
|
||||
return ctx.Channel.IsPrivate ? ctx.Channel : await ctx.Member.CreateDmChannelAsync().ConfigureAwait(false);
|
||||
}
|
||||
=> ctx.Channel.IsPrivate ? ctx.Channel : await ctx.Member.CreateDmChannelAsync().ConfigureAwait(false);
|
||||
|
||||
public static Task<DiscordChannel> GetChannelForSpamAsync(this CommandContext ctx)
|
||||
{
|
||||
return LimitedToSpamChannel.IsSpamChannel(ctx.Channel) ? Task.FromResult(ctx.Channel) : ctx.CreateDmAsync();
|
||||
}
|
||||
=> LimitedToSpamChannel.IsSpamChannel(ctx.Channel) ? Task.FromResult(ctx.Channel) : ctx.CreateDmAsync();
|
||||
|
||||
public static Task<string> GetUserNameAsync(this CommandContext ctx, ulong userId, bool? forDmPurposes = null, string defaultName = "Unknown user")
|
||||
{
|
||||
return ctx.Client.GetUserNameAsync(ctx.Channel, userId, forDmPurposes, defaultName);
|
||||
}
|
||||
=> ctx.Client.GetUserNameAsync(ctx.Channel, userId, forDmPurposes, defaultName);
|
||||
|
||||
public static Task<DiscordMessage> GetMessageAsync(this CommandContext ctx, string messageLink)
|
||||
public static Task<DiscordMessage?> GetMessageAsync(this CommandContext ctx, string messageLink)
|
||||
{
|
||||
if (MessageLinkRegex.Match(messageLink) is Match m
|
||||
&& ulong.TryParse(m.Groups["guild"].Value, out var guildId)
|
||||
@@ -54,7 +44,7 @@ namespace CompatBot.Utils
|
||||
&& ctx.Client.Guilds.TryGetValue(guildId, out var guild)
|
||||
&& guild.GetChannel(channelId) is DiscordChannel channel)
|
||||
return channel.GetMessageAsync(msgId);
|
||||
return Task.FromResult<DiscordMessage>(null);
|
||||
return Task.FromResult((DiscordMessage?)null);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11,7 +11,7 @@ namespace CompatBot.Utils.Extensions
|
||||
{
|
||||
try
|
||||
{
|
||||
return user?.IsBot ?? false;
|
||||
return user.IsBot;
|
||||
}
|
||||
catch (KeyNotFoundException)
|
||||
{
|
||||
@@ -24,13 +24,13 @@ namespace CompatBot.Utils.Extensions
|
||||
}
|
||||
}
|
||||
|
||||
public static string ToSaltedSha256(this DiscordUser user)
|
||||
public static string? ToSaltedSha256(this DiscordUser user)
|
||||
{
|
||||
var data = BitConverter.GetBytes(user.Id);
|
||||
using var sha256 = System.Security.Cryptography.SHA256.Create();
|
||||
sha256.TransformBlock(Config.CryptoSalt, 0, Config.CryptoSalt.Length, null, 0);
|
||||
sha256.TransformFinalBlock(data, 0, data.Length);
|
||||
return sha256.Hash.ToHexString();
|
||||
return sha256.Hash?.ToHexString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
|
||||
namespace CompatBot.Utils
|
||||
@@ -34,9 +35,9 @@ namespace CompatBot.Utils
|
||||
yield return item;
|
||||
}
|
||||
|
||||
public static T RandomElement<T>(this IList<T> collection, int? seed = null)
|
||||
public static T? RandomElement<T>(this IList<T> collection, int? seed = null)
|
||||
{
|
||||
if (collection?.Count > 0)
|
||||
if (collection.Count > 0)
|
||||
{
|
||||
var rng = seed.HasValue ? new Random(seed.Value) : new Random();
|
||||
return collection[rng.Next(collection.Count)];
|
||||
|
||||
@@ -8,22 +8,19 @@ namespace CompatBot.Utils
|
||||
{
|
||||
internal static class RolesExtensions
|
||||
{
|
||||
public static bool IsModerator(this DiscordUser user, DiscordClient client, DiscordGuild guild = null)
|
||||
public static bool IsModerator(this DiscordUser? user, DiscordClient client, DiscordGuild? guild = null)
|
||||
{
|
||||
if (user == null)
|
||||
return false;
|
||||
|
||||
|
||||
if (ModProvider.IsSudoer(user.Id))
|
||||
return true;
|
||||
|
||||
if (client == null)
|
||||
return false;
|
||||
|
||||
var member = guild == null ? client.GetMember(user) : client.GetMember(guild, user);
|
||||
return member?.Roles.IsModerator() ?? false;
|
||||
return member?.Roles.IsModerator() is true;
|
||||
}
|
||||
|
||||
public static bool IsWhitelisted(this DiscordUser user, DiscordClient client, DiscordGuild guild = null)
|
||||
public static bool IsWhitelisted(this DiscordUser? user, DiscordClient client, DiscordGuild? guild = null)
|
||||
{
|
||||
if (user == null)
|
||||
return false;
|
||||
@@ -31,14 +28,11 @@ namespace CompatBot.Utils
|
||||
if (ModProvider.IsMod(user.Id))
|
||||
return true;
|
||||
|
||||
if (client == null)
|
||||
return false;
|
||||
|
||||
var member = guild == null ? client.GetMember(user) : client.GetMember(guild, user);
|
||||
return member?.Roles.IsWhitelisted() ?? false;
|
||||
return member?.Roles.IsWhitelisted() is true;
|
||||
}
|
||||
|
||||
public static bool IsSmartlisted(this DiscordUser user, DiscordClient client, DiscordGuild guild = null)
|
||||
public static bool IsSmartlisted(this DiscordUser? user, DiscordClient client, DiscordGuild? guild = null)
|
||||
{
|
||||
if (user == null)
|
||||
return false;
|
||||
@@ -46,53 +40,35 @@ namespace CompatBot.Utils
|
||||
if (ModProvider.IsMod(user.Id))
|
||||
return true;
|
||||
|
||||
if (client == null)
|
||||
return false;
|
||||
|
||||
var member = guild == null ? client.GetMember(user) : client.GetMember(guild, user);
|
||||
return member?.Roles.IsSmartlisted() ?? false;
|
||||
return member?.Roles.IsSmartlisted() is true;
|
||||
}
|
||||
|
||||
public static bool IsSupporter(this DiscordUser user, DiscordClient client, DiscordGuild guild = null)
|
||||
public static bool IsSupporter(this DiscordUser? user, DiscordClient client, DiscordGuild? guild = null)
|
||||
{
|
||||
if (user == null)
|
||||
return false;
|
||||
|
||||
if (client == null)
|
||||
return false;
|
||||
|
||||
var member = guild == null ? client.GetMember(user) : client.GetMember(guild, user);
|
||||
return member?.Roles.IsSupporter() ?? false;
|
||||
return member?.Roles.IsSupporter() is true;
|
||||
}
|
||||
|
||||
public static bool IsWhitelisted(this DiscordMember member)
|
||||
{
|
||||
return ModProvider.IsMod(member.Id) || member.Roles.IsWhitelisted();
|
||||
}
|
||||
=> ModProvider.IsMod(member.Id) || member.Roles.IsWhitelisted();
|
||||
|
||||
public static bool IsSmartlisted(this DiscordMember member)
|
||||
{
|
||||
return ModProvider.IsMod(member.Id) || member.Roles.IsSmartlisted();
|
||||
}
|
||||
=> ModProvider.IsMod(member.Id) || member.Roles.IsSmartlisted();
|
||||
|
||||
public static bool IsModerator(this IEnumerable<DiscordRole> memberRoles)
|
||||
{
|
||||
return memberRoles?.Any(r => r.Name.Equals("Moderator")) ?? false;
|
||||
}
|
||||
=> memberRoles.Any(r => r.Name.Equals("Moderator"));
|
||||
|
||||
public static bool IsWhitelisted(this IEnumerable<DiscordRole> memberRoles)
|
||||
{
|
||||
return memberRoles?.Any(r => Config.Moderation.RoleWhiteList.Contains(r.Name)) ?? false;
|
||||
}
|
||||
=> memberRoles.Any(r => Config.Moderation.RoleWhiteList.Contains(r.Name));
|
||||
|
||||
public static bool IsSmartlisted(this IEnumerable<DiscordRole> memberRoles)
|
||||
{
|
||||
return memberRoles?.Any(r => Config.Moderation.RoleSmartList.Contains(r.Name)) ?? false;
|
||||
}
|
||||
=> memberRoles.Any(r => Config.Moderation.RoleSmartList.Contains(r.Name));
|
||||
|
||||
public static bool IsSupporter(this IEnumerable<DiscordRole> memberRoles)
|
||||
{
|
||||
return memberRoles?.Any(r => Config.Moderation.SupporterRoleList.Contains(r.Name)) ?? false;
|
||||
}
|
||||
=> memberRoles.Any(r => Config.Moderation.SupporterRoleList.Contains(r.Name));
|
||||
}
|
||||
}
|
||||
@@ -71,7 +71,7 @@ namespace CompatBot.Utils
|
||||
return GetOldItems(Count - MaxLength);
|
||||
}
|
||||
|
||||
public TValue Evict(TKey key)
|
||||
public TValue? Evict(TKey key)
|
||||
{
|
||||
if (!lookup.TryGetValue(key, out var result))
|
||||
return result;
|
||||
|
||||
@@ -7,9 +7,9 @@ namespace CompatBot.Utils
|
||||
public class NameUniqueObjectCollection<TValue>: IDictionary<string, UniqueList<TValue>>
|
||||
{
|
||||
private readonly Dictionary<string, UniqueList<TValue>> dict;
|
||||
private readonly IEqualityComparer<TValue> valueComparer;
|
||||
private readonly IEqualityComparer<TValue>? valueComparer;
|
||||
|
||||
public NameUniqueObjectCollection(IEqualityComparer<string> keyComparer = null, IEqualityComparer<TValue> valueComparer = null)
|
||||
public NameUniqueObjectCollection(IEqualityComparer<string>? keyComparer = null, IEqualityComparer<TValue>? valueComparer = null)
|
||||
{
|
||||
dict = new Dictionary<string, UniqueList<TValue>>(keyComparer);
|
||||
this.valueComparer = valueComparer;
|
||||
@@ -23,7 +23,6 @@ namespace CompatBot.Utils
|
||||
|
||||
public void Add(string key, UniqueList<TValue> value)
|
||||
{
|
||||
value ??= new UniqueList<TValue>(valueComparer);
|
||||
if (dict.TryGetValue(key, out var c))
|
||||
c.AddRange(value);
|
||||
else
|
||||
@@ -57,21 +56,22 @@ namespace CompatBot.Utils
|
||||
public bool Remove(string key) => dict.Remove(key);
|
||||
|
||||
public bool TryGetValue(string key, out UniqueList<TValue> value)
|
||||
{
|
||||
var result = dict.TryGetValue(key, out value);
|
||||
if (!result)
|
||||
dict[key] = value = new UniqueList<TValue>(valueComparer);
|
||||
return result;
|
||||
}
|
||||
{
|
||||
if (dict.TryGetValue(key, out value!))
|
||||
return true;
|
||||
|
||||
public UniqueList<TValue> this[string key]
|
||||
dict[key] = value = new UniqueList<TValue>(valueComparer);
|
||||
return false;
|
||||
}
|
||||
|
||||
public UniqueList<TValue> this[string key]
|
||||
{
|
||||
get
|
||||
{
|
||||
TryGetValue(key, out var value);
|
||||
return value;
|
||||
}
|
||||
set => dict[key] = (value ?? new UniqueList<TValue>(valueComparer));
|
||||
set => dict[key] = value;
|
||||
}
|
||||
|
||||
public ICollection<string> Keys => dict.Keys;
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace CompatBot.Utils
|
||||
{
|
||||
public static class PathUtils
|
||||
{
|
||||
public static string[] GetSegments(string path)
|
||||
public static string[] GetSegments(string? path)
|
||||
{
|
||||
if (string.IsNullOrEmpty(path))
|
||||
return new string[0];
|
||||
return Array.Empty<string>();
|
||||
|
||||
var result = new List<string>();
|
||||
string segment;
|
||||
|
||||
@@ -6,6 +6,7 @@ using System.Threading.Tasks;
|
||||
namespace CompatBot.Utils
|
||||
{
|
||||
internal class PoorMansTaskScheduler<T>
|
||||
where T: notnull
|
||||
{
|
||||
private readonly int queueLimit;
|
||||
private readonly ConcurrentDictionary<Task, T> taskQueue = new ConcurrentDictionary<Task, T>();
|
||||
@@ -14,16 +15,13 @@ namespace CompatBot.Utils
|
||||
public PoorMansTaskScheduler(int simultaneousTaskCountLimit)
|
||||
{
|
||||
if (simultaneousTaskCountLimit < 1)
|
||||
throw new ArgumentException();
|
||||
throw new ArgumentException("Task count can't be lower than 1", nameof(simultaneousTaskCountLimit));
|
||||
|
||||
queueLimit = simultaneousTaskCountLimit;
|
||||
}
|
||||
|
||||
public async Task AddAsync(T tag, Task task)
|
||||
{
|
||||
if (task == null)
|
||||
return;
|
||||
|
||||
if (taskQueue.Count < queueLimit)
|
||||
{
|
||||
taskQueue.TryAdd(task, tag);
|
||||
|
||||
@@ -21,8 +21,8 @@ namespace CompatBot.Utils.ResultFormatters
|
||||
|
||||
private static async Task BuildNotesSectionAsync(DiscordEmbedBuilder builder, LogParseState state, DiscordClient discordClient)
|
||||
{
|
||||
var items = state.CompletedCollection;
|
||||
var multiItems = state.CompleteMultiValueCollection;
|
||||
var items = state.CompletedCollection!;
|
||||
var multiItems = state.CompleteMultiValueCollection!;
|
||||
var notes = new List<string>();
|
||||
var (_, brokenDump, longestPath) = await HasBrokenFilesAsync(state).ConfigureAwait(false);
|
||||
brokenDump |= multiItems["edat_block_offset"].Any();
|
||||
@@ -608,8 +608,8 @@ namespace CompatBot.Utils.ResultFormatters
|
||||
|
||||
private static async Task<(bool irdChecked, bool broken, int longestPath)> HasBrokenFilesAsync(LogParseState state)
|
||||
{
|
||||
var items = state.CompletedCollection;
|
||||
var multiItems = state.CompleteMultiValueCollection;
|
||||
var items = state.CompletedCollection!;
|
||||
var multiItems = state.CompleteMultiValueCollection!;
|
||||
var defaultLongestPath = "/PS3_GAME/USRDIR/".Length + (1+8+3)*2; // usually there's at least one more level for data files
|
||||
if (items["serial"] is not string productCode)
|
||||
return (false, false, defaultLongestPath);
|
||||
|
||||
@@ -15,8 +15,8 @@ namespace CompatBot.Utils.ResultFormatters
|
||||
{
|
||||
private static void BuildWeirdSettingsSection(DiscordEmbedBuilder builder, LogParseState state, List<string> generalNotes)
|
||||
{
|
||||
var items = state.CompletedCollection;
|
||||
var multiItems = state.CompleteMultiValueCollection;
|
||||
var items = state.CompletedCollection!;
|
||||
var multiItems = state.CompleteMultiValueCollection!;
|
||||
var notes = new List<string>();
|
||||
var serial = items["serial"] ?? "";
|
||||
_ = int.TryParse(items["thread_count"], out var threadCount);
|
||||
@@ -579,7 +579,7 @@ namespace CompatBot.Utils.ResultFormatters
|
||||
|
||||
private static void CheckJojoSettings(string serial, LogParseState state, List<string> notes, Dictionary<string, int> ppuPatches, HashSet<string> ppuHashes, List<string> generalNotes)
|
||||
{
|
||||
var items = state.CompletedCollection;
|
||||
var items = state.CompletedCollection!;
|
||||
if (AllStarBattleIds.Contains(serial) || serial == "BLJS10318" || serial == "NPJB00753")
|
||||
{
|
||||
if (items["audio_buffering"] == EnabledMark && items["audio_buffer_duration"] != "20")
|
||||
@@ -615,7 +615,7 @@ namespace CompatBot.Utils.ResultFormatters
|
||||
if (serial == "BLUS31405"
|
||||
&& items["compat_database_path"] is string compatDbPath
|
||||
&& compatDbPath.Contains("JoJo ASB Emulator v.04")
|
||||
&& state.CompleteMultiValueCollection["rap_file"].Any())
|
||||
&& state.CompleteMultiValueCollection!["rap_file"].Any())
|
||||
generalNotes.Add("🤔 Very interesting version of the game you got there");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=ASMJIT/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=blit/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Confusables/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=EBOOT/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=edat/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=framerate/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Homoglyph/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=liblv/@EntryIndexedValue">True</s:Boolean>
|
||||
|
||||
Reference in New Issue
Block a user