-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
use hosted services over whatever was before
- Loading branch information
Showing
18 changed files
with
532 additions
and
391 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 was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
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 |
---|---|---|
@@ -1,64 +1,80 @@ | ||
using Microsoft.Extensions.DependencyInjection; | ||
using Microsoft.Extensions.Logging; | ||
using TrickFireDiscordBot.Discord; | ||
using DSharpPlus; | ||
using Microsoft.Extensions.Configuration; | ||
using Microsoft.Extensions.DependencyInjection; | ||
using Microsoft.Extensions.Hosting; | ||
using System.Reflection; | ||
using TrickFireDiscordBot.Services; | ||
|
||
namespace TrickFireDiscordBot | ||
{ | ||
internal class Program | ||
{ | ||
static async Task Main(string[] args) | ||
private static async Task Main(string[] args) | ||
{ | ||
string[] lines; | ||
if (args.Length == 1) | ||
string baseDir = args.Length > 0 ? args[0] : ""; | ||
string[] secrets = File.ReadAllLines(Path.Join(baseDir, "secrets.txt")); | ||
|
||
IHost host; | ||
try | ||
{ | ||
lines = File.ReadAllLines(args[0]); | ||
host = CreateHost(baseDir, secrets); | ||
} | ||
else | ||
catch (Exception e) | ||
{ | ||
lines = File.ReadAllLines("secrets.txt"); | ||
Console.WriteLine("Startup error. The bot is likely not in a working state: " + e.ToString()); | ||
await Task.Delay(-1); | ||
return; | ||
} | ||
|
||
|
||
try | ||
{ | ||
ServiceCollection services = new(); | ||
|
||
services | ||
// Add notion client | ||
.AddNotionClient(options => | ||
{ | ||
options.AuthToken = lines[1]; | ||
}) | ||
await host.StartAsync(); | ||
|
||
// Add webhook listener | ||
.AddSingleton(container => | ||
{ | ||
// This is not good security practice, but fly.io requires us to | ||
// expose 0.0.0.0:8080, which this is equivalent to | ||
WebhookListener webhookListener = new(container.GetRequiredService<ILogger<WebhookListener>>(), "http://*:8080/"); | ||
webhookListener.Start(); | ||
return webhookListener; | ||
}) | ||
|
||
// Add role syncer | ||
.AddSingleton<RoleSyncer>() | ||
// Hang the process forever so it doesn't quit after the bot | ||
// connects | ||
await host.WaitForShutdownAsync(); | ||
} | ||
finally | ||
{ | ||
// Dispose of discord client before host, since it needs the | ||
// service provider | ||
try | ||
{ | ||
host.Services.GetService<DiscordClient>()?.Dispose(); | ||
} | ||
finally | ||
{ | ||
host.Dispose(); | ||
} | ||
} | ||
} | ||
|
||
.AddSingleton<BotState>(); | ||
private static IHost CreateHost(string baseDir, string[] secrets) | ||
{ | ||
HostApplicationBuilder builder = Host.CreateApplicationBuilder(); | ||
|
||
// Start the bot | ||
DiscordBot bot = new(lines[0], services); | ||
await bot.Start(); | ||
// Add config.json | ||
builder.Configuration.AddJsonFile(Path.Join(baseDir, "config.json")); | ||
builder.Configuration["BOT_TOKEN"] = secrets[0]; | ||
builder.Configuration["NOTION_SECRET"] = secrets[1]; | ||
|
||
// Start the role syncer | ||
await bot.Client.ServiceProvider.GetRequiredService<RoleSyncer>().Start(); | ||
} | ||
catch (Exception e) | ||
// Get all types | ||
Assembly asm = Assembly.GetExecutingAssembly(); | ||
foreach (Type type in asm.GetTypes()) | ||
{ | ||
Console.WriteLine("Startup error. The bot is likely not in a working state: " + e.ToString()); | ||
// Filter to those that implement auto registered service | ||
if (!typeof(IAutoRegisteredService).IsAssignableFrom(type) || type == typeof(IAutoRegisteredService)) | ||
{ | ||
continue; | ||
} | ||
|
||
// Register type | ||
MethodInfo registerMethod = type.GetMethod(nameof(IAutoRegisteredService.Register), [typeof(IHostApplicationBuilder)])!; | ||
registerMethod.Invoke(null, [builder]); | ||
} | ||
|
||
// Hang the process forever so it doesn't quit after the bot | ||
// connects | ||
await Task.Delay(-1); | ||
return builder.Build(); | ||
} | ||
} | ||
} |
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,15 @@ | ||
using Microsoft.Extensions.Configuration; | ||
using Microsoft.Extensions.DependencyInjection; | ||
using Microsoft.Extensions.Hosting; | ||
|
||
namespace TrickFireDiscordBot | ||
{ | ||
public static class ServiceCollectionExtensions | ||
{ | ||
public static IServiceCollection AddInjectableHostedService<T>(this IServiceCollection services) where T : class, IHostedService | ||
=> services.AddSingleton<T>().AddHostedService(provider => provider.GetRequiredService<T>()); | ||
|
||
public static IServiceCollection ConfigureTypeSection<T>(this IServiceCollection services, IConfiguration config) where T : class | ||
=> services.Configure<T>(config.GetSection(typeof(T).Name)); | ||
} | ||
} |
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,38 @@ | ||
using Notion.Client; | ||
using System.Collections.Specialized; | ||
|
||
namespace TrickFireDiscordBot.Services | ||
{ | ||
public class AttendanceTracker | ||
{ | ||
public NotionClient NotionClient { get; } | ||
public BotState BotState { get; } | ||
|
||
public AttendanceTracker(NotionClient notionClient, BotState botState) | ||
{ | ||
NotionClient = notionClient; | ||
BotState = botState; | ||
|
||
BotState.Members.CollectionChanged += OnMembersChange; | ||
} | ||
|
||
private void OnMembersChange(object? _, NotifyCollectionChangedEventArgs ev) | ||
{ | ||
OnMembersChangeAsync(ev).GetAwaiter().GetResult(); | ||
} | ||
|
||
private async Task OnMembersChangeAsync(NotifyCollectionChangedEventArgs ev) | ||
{ | ||
|
||
} | ||
} | ||
|
||
public class AttendanceTrackerOptions | ||
{ | ||
|
||
/// <summary> | ||
/// The id of the Members Attendance page database in Notion. | ||
/// </summary> | ||
public string MemberAttendanceDatabaseId { 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,59 @@ | ||
using DSharpPlus.Entities; | ||
using Microsoft.Extensions.DependencyInjection; | ||
using Microsoft.Extensions.Hosting; | ||
using Microsoft.Extensions.Options; | ||
using Newtonsoft.Json; | ||
using System.Collections.ObjectModel; | ||
|
||
namespace TrickFireDiscordBot.Services | ||
{ | ||
/// <summary> | ||
/// A class that represents the state of the bot. | ||
/// </summary> | ||
public class BotState : IAutoRegisteredService | ||
{ | ||
/// <summary> | ||
/// The list of members checked in. | ||
/// </summary> | ||
public ObservableCollection<(DiscordMember member, DateTimeOffset time)> Members { get; } = []; | ||
|
||
/// <summary> | ||
/// The id of the message that has the list of members in the shop. | ||
/// </summary> | ||
public ulong ListMessageId { get; set; } = 0; | ||
|
||
/// <summary> | ||
/// The id of the channel that current attendance is sent to. | ||
/// </summary> | ||
public ulong CheckInChannelId { get; set; } = 0; | ||
|
||
private BotStateOptions Options { get; } | ||
|
||
public BotState(IOptions<BotStateOptions> options) | ||
{ | ||
Options = options.Value; | ||
if (!File.Exists(Options.FileLocation)) | ||
{ | ||
File.WriteAllText(Options.FileLocation, "{}"); | ||
} | ||
JsonConvert.PopulateObject(File.ReadAllText(Options.FileLocation), this); | ||
} | ||
|
||
public void Save() | ||
{ | ||
File.WriteAllText(Options.FileLocation, JsonConvert.SerializeObject(this, Formatting.Indented)); | ||
} | ||
|
||
public static void Register(IHostApplicationBuilder builder) | ||
{ | ||
builder.Services | ||
.AddSingleton<BotState>() | ||
.ConfigureTypeSection<BotStateOptions>(builder.Configuration); ; | ||
} | ||
} | ||
|
||
public class BotStateOptions | ||
{ | ||
public string FileLocation { get; set; } = ""; | ||
} | ||
} |
Oops, something went wrong.