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)
This commit is contained in:
2024-12-30 14:32:13 -05:00
parent 6cce5e129e
commit 5164aed19d
3 changed files with 91 additions and 12 deletions

View File

@ -1,5 +1,9 @@
#define _GNU_SOURCE #define _GNU_SOURCE
#include <assert.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <concord/discord.h> #include <concord/discord.h>
@ -7,11 +11,32 @@
struct zblock_config zblock_config; 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); 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) { 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];
} }

View File

@ -6,8 +6,21 @@
// the current zblock config // the current zblock config
extern struct zblock_config { extern struct zblock_config {
char *conninfo; char *conninfo;
u64snowflake tuesday_channel;
bool tuesday_enable;
} zblock_config; } 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 #endif

57
main.c
View File

@ -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); 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) { static void bot_command_add(struct discord *client, const struct discord_interaction *event) {
char msg[DISCORD_MAX_MESSAGE_LEN]; char msg[DISCORD_MAX_MESSAGE_LEN];
zblock_feed_info feed; 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) { static void on_ready(struct discord *client, const struct discord_ready *event) {
log_info("Logged in as %s!", event->user->username); 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) { 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); 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(&current_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) { 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 main(void) {
int exit_code = 0; int exit_code = 0;
@ -562,7 +598,13 @@ int main(void) {
setlocale(LC_ALL, "C"); setlocale(LC_ALL, "C");
srand(time(NULL)); srand(time(NULL));
struct discord *client = discord_config_init("config.json"); 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 // connect to database
database_conn = PQconnectdb(zblock_config.conninfo); database_conn = PQconnectdb(zblock_config.conninfo);
@ -575,7 +617,6 @@ int main(void) {
discord_set_on_ready(client, &on_ready); discord_set_on_ready(client, &on_ready);
discord_set_on_interaction_create(client, &on_interaction); discord_set_on_interaction_create(client, &on_interaction);
discord_set_on_guild_delete(client, &on_guild_delete); 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); discord_run(client);
PQfinish(database_conn); PQfinish(database_conn);