Skip to content

Commit

Permalink
feat(timers): add timers support
Browse files Browse the repository at this point in the history
  • Loading branch information
Anotra committed Mar 25, 2022
1 parent 5dcc700 commit 18a528d
Show file tree
Hide file tree
Showing 5 changed files with 166 additions and 1 deletion.
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ DISCORD_OBJS = $(OBJDIR)/$(SRC_DIR)/concord-once.o \
$(OBJDIR)/$(SRC_DIR)/discord-ratelimit.o \
$(OBJDIR)/$(SRC_DIR)/discord-client.o \
$(OBJDIR)/$(SRC_DIR)/discord-gateway.o \
$(OBJDIR)/$(SRC_DIR)/discord-timer.o \
$(OBJDIR)/$(SRC_DIR)/discord-misc.o \
$(OBJDIR)/$(SRC_DIR)/application_command.o \
$(OBJDIR)/$(SRC_DIR)/interaction.o \
Expand Down
19 changes: 19 additions & 0 deletions include/discord-internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
#include "uthash.h"
#include "queue.h"
#include "heap-inl.h"
#include "priority_queue.h"

/** @brief Return 1 if string isn't considered empty */
#define NOT_EMPTY_STR(str) ((str) && *(str))
Expand Down Expand Up @@ -684,6 +685,19 @@ void discord_gateway_send_presence_update(struct discord_gateway *gw);

/** @} DiscordInternalGateway */

struct discord_timers {
priority_queue *q;
};


void discord_timers_init(struct discord *client);
void discord_timers_cleanup(struct discord *client);
void discord_timers_run(struct discord *client, struct discord_timers *timer);
unsigned _discord_timer_ctl(
struct discord *client,
struct discord_timers *timers,
struct discord_timer *timer);

/**
* @brief The Discord client handler
*
Expand All @@ -707,6 +721,11 @@ struct discord {
/** the client's user structure */
struct discord_user self;

struct {
struct discord_timers internal;
struct discord_timers user;
} timers;

/** wakeup timer handle */
struct {
/** callback to be triggered on timer's timeout */
Expand Down
29 changes: 29 additions & 0 deletions include/discord.h
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,35 @@ struct logconf *discord_get_logconf(struct discord *client);
*/
struct io_poller *discord_get_io_poller(struct discord *client);

struct discord_timer;
typedef void (*discord_ev_timer)
(struct discord *client, struct discord_timer *ev);

enum discord_timer_flags {
DISCORD_TIMER_MILLISECONDS = 0,
DISCORD_TIMER_MICROSECONDS = 1 << 0,
DISCORD_TIMER_DELETE = 1 << 1,
DISCORD_TIMER_DELETE_AUTO = 1 << 2,
DISCORD_TIMER_CANCELED = 1 << 3,
};

struct discord_timer {
unsigned id;
discord_ev_timer cb;
void *data;
int64_t start_after;
int64_t interval;
int64_t repeat;
int flags;
};


unsigned discord_timer_ctl(struct discord *client, struct discord_timer *timer);


unsigned discord_timer(struct discord *client, discord_ev_timer cb,
void *data, int64_t start_after);

/** @} Discord */

#endif /* DISCORD_H */
5 changes: 4 additions & 1 deletion src/discord-client.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ static void
_discord_init(struct discord *new_client)
{
ccord_global_init();

discord_timers_init(new_client);
new_client->io_poller = io_poller_create();
discord_adapter_init(&new_client->adapter, &new_client->conf,
&new_client->token);
Expand Down Expand Up @@ -97,6 +97,7 @@ void
discord_cleanup(struct discord *client)
{
if (client->is_original) {
discord_timers_cleanup(client);
logconf_cleanup(&client->conf);
discord_adapter_cleanup(&client->adapter);
discord_gateway_cleanup(&client->gw);
Expand Down Expand Up @@ -355,6 +356,8 @@ discord_run(struct discord *client)
break;

now = (int64_t)cog_timestamp_ms();
discord_timers_run(client, &client->timers.internal);
discord_timers_run(client, &client->timers.user);

/* check for pending wakeup timers */
if (client->wakeup_timer.next != -1
Expand Down
113 changes: 113 additions & 0 deletions src/discord-timer.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@

#include "discord.h"
#include "discord-internal.h"

static int
cmp_timers(const void *a, const void *b)
{
const int64_t l = *(int64_t *)a;
const int64_t r = *(int64_t *)b;
if (l == r || (l < 0 && r < 0))
return 0;
if (l < 0) return 1;
if (r < 0) return -1;
return l > r ? 1 : -1;
}

void
discord_timers_init(struct discord *client)
{
client->timers.internal.q =
priority_queue_create(sizeof(int64_t), sizeof(struct discord_timer),
cmp_timers, 0);
client->timers.user.q =
priority_queue_create(sizeof(int64_t), sizeof(struct discord_timer),
cmp_timers, 0);
}

static void
discord_timers_cancel_all(struct discord *client, priority_queue *q)
{
struct discord_timer timer;
while ((timer.id = priority_queue_pop(q, NULL, &timer))) {
timer.flags |= DISCORD_TIMER_CANCELED;
if (timer.cb) timer.cb(client, &timer);
}
}

void
discord_timers_cleanup(struct discord *client)
{
discord_timers_cancel_all(client, client->timers.user.q);
priority_queue_destroy(client->timers.user.q);

discord_timers_cancel_all(client, client->timers.internal.q);
priority_queue_destroy(client->timers.internal.q);
}

unsigned
_discord_timer_ctl(
struct discord *client,
struct discord_timers *timers,
struct discord_timer *timer)
{
int64_t now = -1;
if (timer->start_after >= 0)
now = (int64_t)discord_timestamp_us(client) + timer->start_after * 1000;
if (!timer->id) {
return priority_queue_push(timers->q, &now, timer);
} else {
if (priority_queue_update(timers->q, timer->id, &now, &timer))
return timer->id;
return 0;
}
}

void
discord_timers_run(struct discord *client, struct discord_timers *timers)
{
int64_t now = (int64_t)discord_timestamp_us(client);
struct discord_timer timer;
for (int64_t trigger;
(timer.id = priority_queue_peek(timers->q, &trigger, &timer));)
{
if (trigger > now || trigger == -1) return;

if (timer.flags & DISCORD_TIMER_DELETE && timer.repeat <= 0) {
priority_queue_pop(timers->q, NULL, NULL);
continue;
}
if (timer.flags & DISCORD_TIMER_DELETE_AUTO) {
timer.flags |= DISCORD_TIMER_DELETE;
priority_queue_update(timers->q, timer.id, &now, &timer);
}

if (timer.cb) timer.cb(client, &timer);

if (timer.repeat != 0) {
int64_t next = -1;
if (timer.repeat > 0)
timer.repeat--;
if (timer.interval > 0)
next = now + timer.interval * 1000;
priority_queue_update(timers->q, timer.id, &next, &timer);
}
}
}
unsigned
discord_timer_ctl(struct discord *client, struct discord_timer *timer)
{
return _discord_timer_ctl(client, &client->timers.user, timer);
}

unsigned discord_timer(struct discord *client, discord_ev_timer cb,
void *data, int64_t start_after)
{
struct discord_timer timer = {
.cb = cb,
.data = data,
.start_after = start_after,
.flags = DISCORD_TIMER_DELETE_AUTO,
};
return discord_timer_ctl(client, &timer);
}

0 comments on commit 18a528d

Please sign in to comment.