From 5164aed19dec10f1c861cca2c49a9ebe4cd2da67 Mon Sep 17 00:00:00 2001 From: Will Brown Date: Mon, 30 Dec 2024 14:32:13 -0500 Subject: [PATCH] Do something special on Tuesday Optional feature, can be enabled for a certain channel with a config flag. ![Happy Tuesday](https://tenor.com/view/happy-tuesday-its-tuesday-tuesday-dance-default-mario-gif-15064439) --- config.c | 31 +++++++++++++++++++++++++++--- config.h | 15 ++++++++++++++- main.c | 57 ++++++++++++++++++++++++++++++++++++++++++++++++-------- 3 files changed, 91 insertions(+), 12 deletions(-) diff --git a/config.c b/config.c index c09882f..612cd20 100644 --- a/config.c +++ b/config.c @@ -1,5 +1,9 @@ #define _GNU_SOURCE +#include #include +#include +#include +#include #include @@ -7,11 +11,32 @@ struct zblock_config zblock_config; -int zblock_config_load(struct discord *client) { +static const char *ZBLOCK_CONFIG_ERRORS[] = { + "OK", + "Error loading conninfo from config", + "No channel id was provided for the tuesday event" +}; +static_assert(sizeof(ZBLOCK_CONFIG_ERRORS) / sizeof(*ZBLOCK_CONFIG_ERRORS) == ZBLOCK_CONFIG_ERRORCOUNT, "Not all config errors implemented"); + +zblock_config_err zblock_config_load(struct discord *client) { struct ccord_szbuf_readonly conninfo = discord_config_get_field(client, (char *[2]){"zblock", "conninfo"}, 2); if (asprintf(&zblock_config.conninfo, "%.*s", (int)conninfo.size, conninfo.start) < 0) { - return 1; + return ZBLOCK_CONFIG_CONNINFO_ERROR; + } + + struct ccord_szbuf_readonly tuesday_enable = discord_config_get_field(client, (char *[3]){"zblock", "tuesday", "enable"}, 3); + if (!strncmp(tuesday_enable.start, "true", tuesday_enable.size)) { + zblock_config.tuesday_enable = true; + struct ccord_szbuf_readonly tuesday_channel = discord_config_get_field(client, (char *[3]){"zblock", "tuesday", "channel"}, 3); + zblock_config.tuesday_channel = 0; // initialize it with something + if (tuesday_channel.size > 0) zblock_config.tuesday_channel = strtoull(tuesday_channel.start, NULL, 10); + if (!zblock_config.tuesday_channel) return ZBLOCK_CONFIG_NO_TUESDAY_CHANNEL; } - return 0; + return ZBLOCK_CONFIG_OK; +} + +// returns a string about the result of a config function +const char *zblock_config_strerror(zblock_config_err error) { + return error < 0 || error >= ZBLOCK_CONFIG_ERRORCOUNT ? "Unspecified error" : ZBLOCK_CONFIG_ERRORS[error]; } diff --git a/config.h b/config.h index 15f8542..85e3a55 100644 --- a/config.h +++ b/config.h @@ -6,8 +6,21 @@ // the current zblock config extern struct zblock_config { char *conninfo; + u64snowflake tuesday_channel; + bool tuesday_enable; } zblock_config; -int zblock_config_load(struct discord *client); +typedef enum { + ZBLOCK_CONFIG_OK, + ZBLOCK_CONFIG_CONNINFO_ERROR, + ZBLOCK_CONFIG_NO_TUESDAY_CHANNEL, + ZBLOCK_CONFIG_ERRORCOUNT +} zblock_config_err; + +// load config entries for zblock +zblock_config_err zblock_config_load(struct discord *client); + +// returns a string about the result of a config function +const char *zblock_config_strerror(zblock_config_err error); #endif diff --git a/main.c b/main.c index 7646303..42cc427 100644 --- a/main.c +++ b/main.c @@ -218,6 +218,17 @@ static void timer_retrieve_feeds(struct discord *client, struct discord_timer *t pthread_create(&retrieve_thread, NULL, &thread_retrieve_feeds, client); } +static void timer_tuesday_event(struct discord *client, struct discord_timer *timer) { + // not doing anything with the timer + (void) timer; + + struct discord_create_message msg = { + .content = "https://tenor.com/view/happy-tuesday-its-tuesday-tuesday-dance-default-mario-gif-15064439" + }; + + discord_create_message(client, zblock_config.tuesday_channel, &msg, NULL); +} + static void bot_command_add(struct discord *client, const struct discord_interaction *event) { char msg[DISCORD_MAX_MESSAGE_LEN]; zblock_feed_info feed; @@ -505,6 +516,18 @@ static struct bot_command commands[] = { } }; +// delay before the first feed retrieval (in ms) +#define FEED_TIMER_DELAY 15000 + +// interval for the feed retrieval timer (in ms) +#define FEED_TIMER_INTERVAL 600000 + +// seconds in a day +#define ONE_DAY_SEC 86400 + +// milliseconds in a week +#define ONE_WEEK_MS 604800000 + static void on_ready(struct discord *client, const struct discord_ready *event) { log_info("Logged in as %s!", event->user->username); @@ -512,6 +535,25 @@ static void on_ready(struct discord *client, const struct discord_ready *event) for (struct bot_command *i = commands; i < commands + sizeof(commands) / sizeof(*commands); ++i) { discord_create_global_application_command(client, event->application->id, &i->cmd, NULL); } + + // feed timer + discord_timer_interval(client, timer_retrieve_feeds, NULL, NULL, FEED_TIMER_DELAY, FEED_TIMER_INTERVAL, -1); + + // find the next tueday and start the timer for the tuesday event + if (zblock_config.tuesday_enable) { + time_t current_time = time(NULL); + struct tm midnight_tm; + gmtime_r(¤t_time, &midnight_tm); + // set it to midnight + midnight_tm.tm_sec = 0; + midnight_tm.tm_min = 0; + midnight_tm.tm_hour = 0; + time_t midnight_time = timegm(&midnight_tm); + // find next tuesday and add it to the time + time_t next_tuesday = midnight_time + ONE_DAY_SEC * (((1 - midnight_tm.tm_wday + 7) % 7) + 1); + // set a timer that starts midnight next tuesday and triggers every week + discord_timer_interval(client, timer_tuesday_event, NULL, NULL, (next_tuesday - current_time) * 1000, ONE_WEEK_MS, -1); + } } static void on_interaction(struct discord *client, const struct discord_interaction *event) { @@ -549,12 +591,6 @@ static void on_guild_delete(struct discord *client, const struct discord_guild * } } -// delay before the first feed retrieval (in ms) -#define FEED_TIMER_DELAY 15000 - -// interval for the feed retrieval timer (in ms) -#define FEED_TIMER_INTERVAL 600000 - int main(void) { int exit_code = 0; @@ -562,7 +598,13 @@ int main(void) { setlocale(LC_ALL, "C"); srand(time(NULL)); struct discord *client = discord_config_init("config.json"); - zblock_config_load(client); + + zblock_config_err config_err = zblock_config_load(client); + if (config_err) { + log_fatal("Error loading zblock config: %s\n", zblock_config_strerror(config_err)); + exit_code = 1; + goto cleanup; + } // connect to database database_conn = PQconnectdb(zblock_config.conninfo); @@ -575,7 +617,6 @@ int main(void) { discord_set_on_ready(client, &on_ready); discord_set_on_interaction_create(client, &on_interaction); discord_set_on_guild_delete(client, &on_guild_delete); - discord_timer_interval(client, timer_retrieve_feeds, NULL, NULL, FEED_TIMER_DELAY, FEED_TIMER_INTERVAL, -1); discord_run(client); PQfinish(database_conn);