-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #41 from bobbahbrown/1.3.10
Version 1.3.10 - Add Discord Bot
- Loading branch information
Showing
51 changed files
with
27,623 additions
and
25,306 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
<Project Sdk="Microsoft.NET.Sdk"> | ||
|
||
<PropertyGroup> | ||
<OutputType>Exe</OutputType> | ||
<Version>1.3.10</Version> | ||
<TargetFramework>net5.0</TargetFramework> | ||
<UserSecretsId>c8af1449-8cdf-4707-a66d-51e896551bfb</UserSecretsId> | ||
</PropertyGroup> | ||
|
||
<ItemGroup> | ||
<PackageReference Include="Microsoft.Extensions.Configuration" Version="5.0.0" /> | ||
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="5.0.0" /> | ||
<PackageReference Include="Microsoft.Extensions.Configuration.CommandLine" Version="5.0.0" /> | ||
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="5.0.0" /> | ||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="5.0.2" /> | ||
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="5.0.0" /> | ||
<PackageReference Include="Quartz" Version="3.3.3" /> | ||
<PackageReference Include="Quartz.Extensions.DependencyInjection" Version="3.3.3" /> | ||
<PackageReference Include="Quartz.Extensions.Hosting" Version="3.3.3" /> | ||
<PackageReference Include="Remora.Discord" Version="3.0.52" /> | ||
<PackageReference Include="Serilog" Version="2.10.0" /> | ||
<PackageReference Include="Serilog.Extensions.Hosting" Version="4.1.2" /> | ||
<PackageReference Include="Serilog.Extensions.Logging" Version="3.0.1" /> | ||
<PackageReference Include="Serilog.Filters.Expressions" Version="2.1.0" /> | ||
<PackageReference Include="Serilog.Sinks.Console" Version="4.0.0" /> | ||
<PackageReference Include="Serilog.Sinks.File" Version="5.0.0" /> | ||
</ItemGroup> | ||
|
||
<ItemGroup> | ||
<None Update="appsettings.json"> | ||
<CopyToOutputDirectory>Always</CopyToOutputDirectory> | ||
</None> | ||
</ItemGroup> | ||
|
||
<ItemGroup> | ||
<ProjectReference Include="..\CentCom.Common\CentCom.Common.csproj" /> | ||
</ItemGroup> | ||
|
||
<ItemGroup> | ||
<Reference Include="Microsoft.Extensions.Hosting, Version=5.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60"> | ||
<HintPath>..\..\..\..\..\Program Files\dotnet\shared\Microsoft.AspNetCore.App\5.0.7\Microsoft.Extensions.Hosting.dll</HintPath> | ||
</Reference> | ||
</ItemGroup> | ||
|
||
</Project> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
using Remora.Discord.Core; | ||
|
||
namespace CentCom.Bot.Configuration | ||
{ | ||
public class DiscordConfiguration | ||
{ | ||
public string Token { get; set; } | ||
|
||
public ulong? FailureChannel { get; set; } | ||
|
||
public ulong? FailureMention { get; set; } | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using System.Text; | ||
using System.Threading.Tasks; | ||
using CentCom.Bot.Configuration; | ||
using CentCom.Common.Data; | ||
using CentCom.Common.Models; | ||
using Microsoft.EntityFrameworkCore; | ||
using Microsoft.Extensions.Options; | ||
using Quartz; | ||
using Remora.Discord.API.Abstractions.Rest; | ||
using Remora.Discord.Core; | ||
|
||
namespace CentCom.Bot.Jobs | ||
{ | ||
[DisallowConcurrentExecution] | ||
public class FailedParseJob : IJob | ||
{ | ||
private readonly DatabaseContext _dbContext; | ||
private readonly IDiscordRestChannelAPI _channelAPI; | ||
private readonly IOptions<DiscordConfiguration> _config; | ||
|
||
public FailedParseJob(DatabaseContext dbContext, IOptions<DiscordConfiguration> config, | ||
IDiscordRestChannelAPI channelAPI) | ||
{ | ||
_dbContext = dbContext; | ||
_channelAPI = channelAPI; | ||
_config = config; | ||
} | ||
|
||
public async Task Execute(IJobExecutionContext context) | ||
{ | ||
var failures = await _dbContext.CheckHistory | ||
.Include(x => x.Notification) | ||
.Where(x => !x.Success && x.Notification == null) | ||
.ToListAsync(); | ||
if (failures.Count == 0) | ||
return; | ||
|
||
if (_config.Value == null) | ||
throw new Exception("Missing or invalid Discord configuration, cannot dispatch failure notifications"); | ||
|
||
// Don't bother if we haven't configured a channel to use | ||
if (_config.Value.FailureChannel == null) | ||
return; | ||
|
||
// Get channel, check it exists | ||
var channelRequest = await _channelAPI.GetChannelAsync(new Snowflake(_config.Value.FailureChannel.Value)); | ||
if (!channelRequest.IsSuccess || channelRequest.Entity == null) | ||
throw new Exception("Failed to get Discord channel to dispatch parse failure notifications into."); | ||
|
||
var notified = new List<NotifiedFailure>(); | ||
var channel = channelRequest.Entity; | ||
foreach (var failure in failures) | ||
{ | ||
var message = new StringBuilder(); | ||
if (_config.Value.FailureMention.HasValue) | ||
message.Append($"<@{_config.Value.FailureMention}> "); | ||
message.Append( | ||
$"Failed to parse bans for {failure.Parser} at <t:{failure.Failed.Value.ToUnixTimeSeconds()}>, exception is as follows... ```"); | ||
|
||
// Ensure that our length fits | ||
var currLength = message.Length + failure.Exception.Length + 3; | ||
message.Append(currLength > 2000 | ||
? $"{failure.Exception[0..^(currLength - 2000 + 4)]}...```" | ||
: $"{failure.Exception}```"); | ||
|
||
// Try to send, only mark completed if successful | ||
var result = await _channelAPI.CreateMessageAsync(channel.ID, message.ToString()); | ||
if (result.IsSuccess) | ||
notified.Add(new NotifiedFailure() | ||
{ | ||
CheckHistory = failure, | ||
Timestamp = DateTimeOffset.UtcNow | ||
}); | ||
} | ||
|
||
_dbContext.NotifiedFailures.AddRange(notified); | ||
await _dbContext.SaveChangesAsync(); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,116 @@ | ||
using System; | ||
using System.Threading.Tasks; | ||
using CentCom.Bot.Configuration; | ||
using CentCom.Bot.Jobs; | ||
using Microsoft.Extensions.Configuration; | ||
using Microsoft.Extensions.DependencyInjection; | ||
using Microsoft.Extensions.Hosting; | ||
using Remora.Discord.Commands.Extensions; | ||
using Remora.Discord.Hosting.Extensions; | ||
using CentCom.Common.Configuration; | ||
using CentCom.Common.Data; | ||
using Quartz; | ||
using Serilog; | ||
using Serilog.Filters; | ||
|
||
namespace CentCom.Bot | ||
{ | ||
public class Program | ||
{ | ||
public static Task Main(string[] args) | ||
{ | ||
// Setup Serilog | ||
Log.Logger = new LoggerConfiguration() | ||
.Enrich.FromLogContext() | ||
.WriteTo.Logger(lc => | ||
{ | ||
lc.Filter.ByExcluding( | ||
"Contains(SourceContext, 'Quartz') and (@Level = 'Information')"); | ||
lc.WriteTo.Console( | ||
outputTemplate: | ||
"[{Timestamp:HH:mm:ss} {Level:u3}] ({SourceContext}) {Message:lj}{NewLine}{Exception}"); | ||
}) | ||
.WriteTo.Logger(lc => | ||
{ | ||
lc.WriteTo.File(path: "centcom-discord-bot.txt", | ||
outputTemplate: | ||
"[{Timestamp:HH:mm:ss} {Level:u3}] ({SourceContext}) {Message:lj}{NewLine}{Exception}"); | ||
}) | ||
.CreateLogger(); | ||
|
||
return CreateHostBuilder(args).RunConsoleAsync(); | ||
} | ||
|
||
private static IHostBuilder CreateHostBuilder(string[] args) => Host.CreateDefaultBuilder(args) | ||
.AddDiscordService(services => | ||
{ | ||
var configuration = services.GetRequiredService<IConfiguration>(); | ||
return configuration.GetValue<string>("discord:token") ?? | ||
throw new InvalidOperationException | ||
( | ||
"Failed to read Discord configuration, bot token not found in appsettings.json." | ||
); | ||
}) | ||
.ConfigureServices((_, services) => | ||
{ | ||
// Add configuration | ||
var config = new ConfigurationBuilder() | ||
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: false) | ||
.AddCommandLine(args) | ||
.AddUserSecrets<Program>() | ||
.Build(); | ||
services.AddSingleton<IConfiguration>(config); | ||
|
||
// Add Discord config | ||
services.AddOptions<DiscordConfiguration>() | ||
.Bind(config.GetSection("discord")) | ||
.Validate(x => x.Token != null); | ||
|
||
// Get DB configuration | ||
var dbConfig = new DbConfig(); | ||
config.Bind("dbConfig", dbConfig); | ||
|
||
// Add appropriate DB context | ||
if (dbConfig == null) | ||
{ | ||
throw new Exception( | ||
"Failed to read DB configuration, please ensure you provide one in appsettings.json"); | ||
} | ||
|
||
switch (dbConfig.DbType) | ||
{ | ||
case DbType.Postgres: | ||
services.AddDbContext<DatabaseContext, NpgsqlDbContext>(); | ||
break; | ||
case DbType.MariaDB: | ||
services.AddDbContext<DatabaseContext, MariaDbContext>(); | ||
break; | ||
case DbType.MySql: | ||
services.AddDbContext<DatabaseContext, MySqlDbContext>(); | ||
break; | ||
default: | ||
throw new ArgumentOutOfRangeException(); | ||
} | ||
|
||
// Add Quartz | ||
services.AddQuartz(q => | ||
{ | ||
q.UseMicrosoftDependencyInjectionJobFactory(); | ||
|
||
q.ScheduleJob<FailedParseJob>(trigger => | ||
trigger | ||
.StartNow() | ||
.WithSimpleSchedule(x => x.WithIntervalInSeconds(10).RepeatForever()), | ||
job => job.WithIdentity("failed-parse")); | ||
}); | ||
services.AddQuartzHostedService(); | ||
|
||
// Add Quartz jobs | ||
services.AddTransient<FailedParseJob>(); | ||
|
||
// Add Discord commands | ||
services.AddDiscordCommands(); | ||
}) | ||
.UseSerilog(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
{ | ||
"Logging": { | ||
"LogLevel": { | ||
"Default": "Debug", | ||
"System": "Information", | ||
"Microsoft": "Information" | ||
} | ||
}, | ||
"dbConfig": { | ||
"connectionString": "connection_string_goes_here", | ||
"dbType": "db_type_goes_here" | ||
}, | ||
"discord": { | ||
"token": null, | ||
"failureChannel": 0, | ||
"failureMention": 0 | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.