diff --git a/TrickFireDiscordBot/Discord/Bot.cs b/TrickFireDiscordBot/Discord/DiscordBot.cs
similarity index 99%
rename from TrickFireDiscordBot/Discord/Bot.cs
rename to TrickFireDiscordBot/Discord/DiscordBot.cs
index 4a30ea1..c08f90a 100644
--- a/TrickFireDiscordBot/Discord/Bot.cs
+++ b/TrickFireDiscordBot/Discord/DiscordBot.cs
@@ -14,7 +14,7 @@ namespace TrickFireDiscordBot.Discord
/// A class representing the Discord bot.
///
/// The token of the bot
- public class Bot
+ public class DiscordBot
{
private const string SadCatASCII =
" />----フ\r\n" +
@@ -34,7 +34,7 @@ public class Bot
private bool _needToUpdateEmbed = true;
- public Bot(string token)
+ public DiscordBot(string token)
{
DiscordClientBuilder builder = DiscordClientBuilder
.CreateDefault(token, DiscordIntents.None)
diff --git a/TrickFireDiscordBot/Notion/Automation.cs b/TrickFireDiscordBot/Notion/Automation.cs
new file mode 100644
index 0000000..ba2570b
--- /dev/null
+++ b/TrickFireDiscordBot/Notion/Automation.cs
@@ -0,0 +1,33 @@
+using Newtonsoft.Json;
+using Notion.Client;
+
+namespace TrickFireDiscordBot.Notion
+{
+ public class Automation
+ {
+ [JsonProperty("source")]
+ public AutomationSource? Source { get; set; } = null;
+
+ [JsonProperty("data")]
+ public IObject? Data { get; set; } = null;
+ }
+
+ public class AutomationSource
+ {
+ [JsonProperty("type")]
+ public string Type { get; set; } = "";
+
+ [JsonProperty("automation_id")]
+ public string AutomationId { get; set; } = "";
+
+
+ [JsonProperty("action_id")]
+ public string ActionId { get; set; } = "";
+
+ [JsonProperty("event_id")]
+ public string EventId { get; set; } = "";
+
+ [JsonProperty("attempt")]
+ public int Attempt { get; set; } = 0;
+ }
+}
diff --git a/TrickFireDiscordBot/Program.cs b/TrickFireDiscordBot/Program.cs
index 8ded268..6e1be1b 100644
--- a/TrickFireDiscordBot/Program.cs
+++ b/TrickFireDiscordBot/Program.cs
@@ -1,4 +1,5 @@
-using TrickFireDiscordBot.Discord;
+using Notion.Client;
+using TrickFireDiscordBot.Discord;
namespace TrickFireDiscordBot
{
@@ -6,21 +7,37 @@ internal class Program
{
static async Task Main(string[] args)
{
- // The token is on the first line of the secrets.txt file
- string token;
+ string[] lines;
if (args.Length == 1)
{
- token = File.ReadAllLines(args[0])[0];
+ lines = File.ReadAllLines(args[0]);
}
else
{
- token = File.ReadAllLines("secrets.txt")[0];
+ lines = File.ReadAllLines("secrets.txt");
}
// Start the bot
- Bot bot = new(token);
+ DiscordBot bot = new(lines[0]);
await bot.Start();
+ // Start notion client
+ //NotionClient notionClient = NotionClientFactory.Create(new ClientOptions()
+ //{
+ // AuthToken = lines[1]
+ //});
+
+ // Start the webhook listener
+
+ // 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(bot.Client.Logger, "http://*:8080/");
+ webhookListener.Start();
+
+ // Start role syncer
+ RoleSyncer syncer = new(null, bot, webhookListener);
+ syncer.Start();
+
// Hang the process forever so it doesn't quit after the bot
// connects
await Task.Delay(-1);
diff --git a/TrickFireDiscordBot/RoleSyncer.cs b/TrickFireDiscordBot/RoleSyncer.cs
new file mode 100644
index 0000000..e18d762
--- /dev/null
+++ b/TrickFireDiscordBot/RoleSyncer.cs
@@ -0,0 +1,44 @@
+using Newtonsoft.Json;
+using Notion.Client;
+using System.Net;
+using TrickFireDiscordBot.Discord;
+using TrickFireDiscordBot.Notion;
+
+namespace TrickFireDiscordBot
+{
+ public class RoleSyncer(NotionClient notionClient, DiscordBot discordBot, WebhookListener listener)
+ {
+ public const string WebhookEndpoint = "/members";
+
+ public NotionClient NotionClient { get; } = notionClient;
+ public DiscordBot DiscordBot { get; } = discordBot;
+ public WebhookListener WebhookListener { get; } = listener;
+
+ public void Start()
+ {
+ WebhookListener.OnWebhookReceived += OnWebhook;
+ }
+
+ public void Stop()
+ {
+ WebhookListener.OnWebhookReceived -= OnWebhook;
+ }
+
+ private void OnWebhook(HttpListenerRequest request)
+ {
+ if (request.RawUrl == null || !request.RawUrl.StartsWith(WebhookEndpoint))
+ {
+ return;
+ }
+
+ using StreamReader reader = new(request.InputStream);
+ Automation? automation = JsonConvert.DeserializeObject(reader.ReadToEnd());
+ if (automation == null || automation.Data is not Page page)
+ {
+ return;
+ }
+
+ Console.WriteLine(JsonConvert.SerializeObject(page, Formatting.Indented));
+ }
+ }
+}
diff --git a/TrickFireDiscordBot/TrickFireDiscordBot.csproj b/TrickFireDiscordBot/TrickFireDiscordBot.csproj
index acb6975..6c6d530 100644
--- a/TrickFireDiscordBot/TrickFireDiscordBot.csproj
+++ b/TrickFireDiscordBot/TrickFireDiscordBot.csproj
@@ -10,6 +10,7 @@
+
diff --git a/TrickFireDiscordBot/WebhookListener.cs b/TrickFireDiscordBot/WebhookListener.cs
new file mode 100644
index 0000000..836f524
--- /dev/null
+++ b/TrickFireDiscordBot/WebhookListener.cs
@@ -0,0 +1,82 @@
+using Microsoft.Extensions.Logging;
+using System.Net;
+using System.Text;
+
+namespace TrickFireDiscordBot
+{
+ public class WebhookListener : IDisposable
+ {
+ public event Action? OnWebhookReceived;
+ public ILogger Logger { get; }
+
+ private readonly HttpListener _listener = new();
+ private bool _isRunning = false;
+
+ public WebhookListener(ILogger logger, params string[] prefixes)
+ {
+ Logger = logger;
+ foreach (string prefix in prefixes)
+ {
+ _listener.Prefixes.Add(prefix);
+ }
+ }
+
+ public void Start()
+ {
+ _ = Task.Run(async () =>
+ {
+ try
+ {
+ await LongThread();
+ }
+ catch (Exception ex)
+ {
+ Logger.LogError(ex, "Webhook Listener error");
+ }
+ });
+ }
+
+ public void Stop()
+ {
+ _listener.Stop();
+ }
+
+ void IDisposable.Dispose()
+ {
+ GC.SuppressFinalize(this);
+ _listener.Close();
+ }
+
+ public void Close()
+ {
+ ((IDisposable)this).Dispose();
+ }
+
+ private async Task LongThread()
+ {
+ _isRunning = true;
+ _listener.Start();
+
+ while (_isRunning)
+ {
+ try
+ {
+ // Wait for request
+ HttpListenerContext ctx = await _listener.GetContextAsync();
+
+ // Read request body
+ OnWebhookReceived?.Invoke(ctx.Request);
+
+ // Return ok response on request
+ ctx.Response.StatusCode = (int)HttpStatusCode.OK;
+ ctx.Response.OutputStream.Write(Encoding.UTF8.GetBytes("Ok"));
+ ctx.Response.OutputStream.Close();
+ }
+ catch (Exception ex)
+ {
+ Logger.LogError(ex, "Webhook Listener loop error");
+ }
+ }
+ }
+ }
+}