[main.c] Attempt to fix feed retrieval

This commit is contained in:
2024-11-24 11:47:01 -05:00
parent 56ae903c41
commit e1bbea325c

157
main.c
View File

@ -43,9 +43,6 @@ struct bot_command {
discord_create_interaction_response(client, event->id, event->token, &res, NULL); \ discord_create_interaction_response(client, event->id, event->token, &res, NULL); \
} while (0) } while (0)
// default interval for the feed retrieval timer
#define TIMER_INTERVAL 600
typedef struct { typedef struct {
zblock_feed_info_minimal info; zblock_feed_info_minimal info;
FILE *fp; FILE *fp;
@ -69,24 +66,8 @@ static void timer_retrieve_feeds(struct discord *client, struct discord_timer *t
); );
if (PQresultStatus(database_res) != PGRES_TUPLES_OK) { if (PQresultStatus(database_res) != PGRES_TUPLES_OK) {
log_error("Unable to retrieve feed list: %s", PQresultErrorMessage(database_res)); log_error("Unable to retrieve feed list: %s", PQresultErrorMessage(database_res));
PQclear(database_res); goto all_done;
return; }
}
// get all the required feed info to send messages
int nfeeds = PQntuples(database_res);
zblock_feed_buffer *feed_list = malloc(nfeeds * sizeof(*feed_list));
if (!feed_list) {
log_error("Unable to retrieve feed list: %s", strerror(errno));
PQclear(database_res);
return;
}
for (int i = 0; i < nfeeds; ++i) {
feed_list[i].info.url = PQgetvalue(database_res, i, 0);
feed_list[i].info.last_pubDate = PQgetvalue(database_res, i, 1);
feed_list[i].info.channel_id = be64toh(*(uint64_t *) PQgetvalue(database_res, i, 2));
}
// get all those feeds // get all those feeds
CURLM *multi = curl_multi_init(); CURLM *multi = curl_multi_init();
@ -96,89 +77,97 @@ static void timer_retrieve_feeds(struct discord *client, struct discord_timer *t
goto all_done; goto all_done;
} }
// put running handles up here so we can start transfers now instead of later
int running_handles;
// get all the required feed info to send messages
int nfeeds = PQntuples(database_res);
for (int i = 0; i < nfeeds; ++i) { for (int i = 0; i < nfeeds; ++i) {
feed_list[i].fp = open_memstream(&feed_list[i].buf, &feed_list[i].bufsize); zblock_feed_buffer *feed_buffer = malloc(sizeof(*feed_buffer));
if (!feed_list[i].fp) continue; // fail gracefully if (!feed_buffer) {
log_error("Failure allocating feed buffer: %s", strerror(errno));
continue;
}
feed_buffer->info.url = PQgetvalue(database_res, i, 0);
feed_buffer->info.last_pubDate = PQgetvalue(database_res, i, 1);
feed_buffer->info.channel_id = be64toh(*(uint64_t *) PQgetvalue(database_res, i, 2));
feed_buffer->fp = open_memstream(&feed_buffer->buf, &feed_buffer->bufsize);
if (!feed_buffer->fp) continue; // fail gracefully
CURL *feed_handle = curl_easy_init(); CURL *feed_handle = curl_easy_init();
if (!feed_handle) { if (!feed_handle) {
fclose(feed_list[i].fp); fclose(feed_buffer->fp);
free(feed_list[i].buf); free(feed_buffer->buf);
continue; continue;
} }
curl_easy_setopt(feed_handle, CURLOPT_URL, feed_list[i].info.url); curl_easy_setopt(feed_handle, CURLOPT_URL, feed_buffer->info.url);
curl_easy_setopt(feed_handle, CURLOPT_WRITEDATA, feed_list[i].fp); curl_easy_setopt(feed_handle, CURLOPT_WRITEDATA, feed_buffer->fp);
curl_easy_setopt(feed_handle, CURLOPT_PRIVATE, &feed_list[i]); curl_easy_setopt(feed_handle, CURLOPT_PRIVATE, feed_buffer);
CURLMcode mc = curl_multi_add_handle(multi, feed_handle); CURLMcode mc = curl_multi_add_handle(multi, feed_handle);
if (mc) { if (mc) {
log_error("Unable to retrieve feed list: %s", curl_multi_strerror(mc)); log_error("Unable to retrieve feed list: %s", curl_multi_strerror(mc));
curl_easy_cleanup(feed_handle); curl_easy_cleanup(feed_handle);
fclose(feed_list[i].fp); fclose(feed_buffer->fp);
free(feed_list[i].buf); free(feed_buffer->buf);
continue; continue;
} }
curl_multi_perform(multi, &running_handles);
} }
// it's time // it's time
int running_handles_prev = 0;
int running_handles;
do { do {
CURLMcode mc = curl_multi_perform(multi, &running_handles); CURLMcode mc = curl_multi_perform(multi, &running_handles);
if (running_handles < running_handles_prev) { CURLMsg *msg;
running_handles_prev = running_handles; int msgs_in_queue;
do {
CURLMsg *msg; msg = curl_multi_info_read(multi, &msgs_in_queue);
int msgs_in_queue; if (msg && msg->msg == CURLMSG_DONE) {
do { CURL *handle = msg->easy_handle;
msg = curl_multi_info_read(multi, &msgs_in_queue); // get our buffer out
if (msg && msg->msg == CURLMSG_DONE) { zblock_feed_buffer *feed_buffer;
CURL *handle = msg->easy_handle; curl_easy_getinfo(handle, CURLINFO_PRIVATE, &feed_buffer);
// get our buffer out fclose(feed_buffer->fp); // close the file descriptor for the buffer (also flushes buffer)
zblock_feed_buffer *feed_buffer; if (!msg->data.result) {
curl_easy_getinfo(handle, CURLINFO_PRIVATE, &feed_buffer); // hell yeah parse that RSS feed
fclose(feed_buffer->fp); // close the file descriptor for the buffer (also flushes buffer) mrss_t *mrss_feed;
if (!msg->data.result) { mrss_error_t mrss_err = mrss_parse_buffer(feed_buffer->buf, feed_buffer->bufsize, &mrss_feed);
// hell yeah parse that RSS feed if (!mrss_err) {
mrss_t *mrss_feed; // get publication date of entries and send any new ones
mrss_error_t mrss_err = mrss_parse_buffer(feed_buffer->buf, feed_buffer->bufsize, &mrss_feed); mrss_item_t *item = mrss_feed->item;
if (!mrss_err) { time_t last_pubDate_time = pubDate_to_time_t(feed_buffer->info.last_pubDate);
// get publication date of entries send any new ones bool update_pubDate = false;
time_t last_pubDate_time = pubDate_to_time_t(feed_buffer->info.last_pubDate); while (item && pubDate_to_time_t(item->pubDate) > last_pubDate_time) {
mrss_item_t *item = mrss_feed->item; update_pubDate = true;
bool update_pubDate = false;
while (item && pubDate_to_time_t(item->pubDate) > last_pubDate_time) {
update_pubDate = true;
// Send new entry in the feed
char msg[DISCORD_MAX_MESSAGE_LEN];
snprintf(msg, sizeof(msg), "### %s\n[%s](%s)", mrss_feed->title, mrss_feed->item->title, mrss_feed->item->link);
struct discord_create_message res = { .content = msg };
discord_create_message(client, feed_buffer->info.channel_id, &res, NULL);
item = item->next;
}
if (update_pubDate) { // Send new entry in the feed
feed_buffer->info.last_pubDate = mrss_feed->item->pubDate; char msg[DISCORD_MAX_MESSAGE_LEN];
zblock_feed_info_update(database_conn, &feed_buffer->info); snprintf(msg, sizeof(msg), "### %s\n[%s](%s)", mrss_feed->title, mrss_feed->item->title, mrss_feed->item->link);
} struct discord_create_message res = { .content = msg };
discord_create_message(client, feed_buffer->info.channel_id, &res, NULL);
// done with our feed! item = item->next;
mrss_free(mrss_feed);
} else {
log_error("Error parsing feed: %s\n", mrss_strerror(mrss_err));
} }
if (update_pubDate) {
feed_buffer->info.last_pubDate = mrss_feed->item->pubDate;
zblock_feed_info_update(database_conn, &feed_buffer->info);
}
// done with our feed!
mrss_free(mrss_feed);
} else { } else {
log_error("Error downloading RSS feed: %s\n", curl_easy_strerror(msg->data.result)); log_error("Error parsing feed: %s\n", mrss_strerror(mrss_err));
} }
} else {
// free our buffers log_error("Error downloading RSS feed: %s\n", curl_easy_strerror(msg->data.result));
curl_multi_remove_handle(multi, handle);
curl_easy_cleanup(handle);
free(feed_buffer->buf);
} }
} while (msg);
} // free our buffers
curl_multi_remove_handle(multi, handle);
curl_easy_cleanup(handle);
free(feed_buffer->buf);
free(feed_buffer);
}
} while (msg);
if (!mc && running_handles) { if (!mc && running_handles) {
mc = curl_multi_poll(multi, NULL, 0, 300, NULL); mc = curl_multi_poll(multi, NULL, 0, 300, NULL);
@ -188,15 +177,12 @@ static void timer_retrieve_feeds(struct discord *client, struct discord_timer *t
log_fatal("curl_multi_poll(): %s", curl_multi_strerror(mc)); log_fatal("curl_multi_poll(): %s", curl_multi_strerror(mc));
exit(1); exit(1);
} }
running_handles_prev = running_handles;
} while (running_handles); } while (running_handles);
curl_multi_cleanup(multi); curl_multi_cleanup(multi);
// processing is done // processing is done
all_done: all_done:
free(feed_list);
PQclear(database_res); PQclear(database_res);
} }
@ -373,6 +359,9 @@ static void on_interaction(struct discord *client, const struct discord_interact
discord_create_interaction_response(client, event->id, event->token, &res, NULL); discord_create_interaction_response(client, event->id, event->token, &res, NULL);
} }
// default interval for the feed retrieval timer (in ms)
#define TIMER_INTERVAL 600000
int main(void) { int main(void) {
int exit_code = 0; int exit_code = 0;