Abstract out the last remaining SQL queries in timer_retrieve_feeds()

This commit is contained in:
2024-11-25 00:36:40 -05:00
parent 23ed4a7d96
commit 69be63aa2e
3 changed files with 87 additions and 47 deletions

View File

@ -23,10 +23,24 @@ static const char *ZBLOCK_FEED_INFO_ERRORS[] = {
"Invalid arguments provided", "Invalid arguments provided",
"An error was encountered with the feed database", "An error was encountered with the feed database",
"The feed already exists", "The feed already exists",
"The feed does not exist" "The feed does not exist",
"Finished getting feed info",
"Out of memory"
}; };
static_assert(sizeof(ZBLOCK_FEED_INFO_ERRORS) / sizeof(*ZBLOCK_FEED_INFO_ERRORS) == ZBLOCK_FEED_INFO_ERRORCOUNT, "Not all feed info errors implemented"); static_assert(sizeof(ZBLOCK_FEED_INFO_ERRORS) / sizeof(*ZBLOCK_FEED_INFO_ERRORS) == ZBLOCK_FEED_INFO_ERRORCOUNT, "Not all feed info errors implemented");
// free all information associated with a minimal feed info struct (does not assume the struct was allocated using malloc)
void zblock_feed_info_minimal_free(zblock_feed_info_minimal *feed_info) {
free(feed_info->last_pubDate);
free(feed_info->url);
}
// free all information associated with a feed info struct (does not assume the struct was allocated using malloc)
void zblock_feed_info_free(zblock_feed_info *feed_info) {
free(feed_info->title);
zblock_feed_info_minimal_free((zblock_feed_info_minimal *) feed_info);
}
// returns a string about the result of a feed_info function // returns a string about the result of a feed_info function
const char *zblock_feed_info_strerror(zblock_feed_info_err error) { const char *zblock_feed_info_strerror(zblock_feed_info_err error) {
return error < 0 || error >= ZBLOCK_FEED_INFO_ERRORCOUNT ? "Unspecified error" : ZBLOCK_FEED_INFO_ERRORS[error]; return error < 0 || error >= ZBLOCK_FEED_INFO_ERRORCOUNT ? "Unspecified error" : ZBLOCK_FEED_INFO_ERRORS[error];
@ -43,6 +57,49 @@ time_t pubDate_to_time_t(char *s) {
return timegm(&tm); return timegm(&tm);
} }
// Begin retrieval of feed info objects.
zblock_feed_info_err zblock_feed_info_retrieve_list_begin(PGconn *conn) {
if (!conn) return ZBLOCK_FEED_INFO_INVALID_ARGS;
if (!PQsendQueryParams(
conn, "SELECT url, last_pubDate, channel_id from feeds",
0, NULL, NULL, NULL, NULL, 1
)) {
return ZBLOCK_FEED_INFO_DBERROR;
}
PQsetSingleRowMode(conn);
return ZBLOCK_FEED_INFO_OK;
}
// Retrieve the next feed list object.
// On error, no more objects can be retrieved and the returned object is invalid.
zblock_feed_info_err zblock_feed_info_retrieve_list_item(PGconn *conn, zblock_feed_info_minimal *feed_info) {
if (!conn || !feed_info) return ZBLOCK_FEED_INFO_INVALID_ARGS;
PGresult *res = PQgetResult(conn);
if (PQresultStatus(res) != PGRES_SINGLE_TUPLE) {
if (PQresultStatus(res) != PGRES_TUPLES_OK) {
log_error("Unable to retrieve feeds: %s", PQresultErrorMessage(res));
PQclear(res);
return ZBLOCK_FEED_INFO_DBERROR;
} else {
PQclear(res);
return ZBLOCK_FEED_INFO_FINISHED;
}
}
feed_info->url = strdup(PQgetvalue(res, 0, 0));
feed_info->last_pubDate = strdup(PQgetvalue(res, 0, 1));
if (!feed_info->url || !feed_info->last_pubDate) {
PQclear(res);
return ZBLOCK_FEED_INFO_NOMEM;
}
feed_info->channel_id = be64toh(*(uint64_t *) PQgetvalue(res, 0, 2));
PQclear(res);
return ZBLOCK_FEED_INFO_OK;
}
// check if the feed currently exists. the result is in the exists pointer. // check if the feed currently exists. the result is in the exists pointer.
zblock_feed_info_err zblock_feed_info_exists(PGconn *conn, const char *url, u64snowflake channel_id, int *exists) { zblock_feed_info_err zblock_feed_info_exists(PGconn *conn, const char *url, u64snowflake channel_id, int *exists) {
if (!conn || !exists) return ZBLOCK_FEED_INFO_INVALID_ARGS; if (!conn || !exists) return ZBLOCK_FEED_INFO_INVALID_ARGS;
@ -149,11 +206,7 @@ zblock_feed_info_err zblock_feed_info_update(PGconn *conn, zblock_feed_info_mini
); );
zblock_feed_info_err result = ZBLOCK_FEED_INFO_OK; zblock_feed_info_err result = ZBLOCK_FEED_INFO_OK;
if (PQresultStatus(update_res) != PGRES_COMMAND_OK) { if (PQresultStatus(update_res) != PGRES_COMMAND_OK) result = ZBLOCK_FEED_INFO_DBERROR;
log_error("Failed to update feed: %s", PQresultErrorMessage(update_res));
result = ZBLOCK_FEED_INFO_DBERROR;
}
PQclear(update_res); PQclear(update_res);
return result; return result;
} }

View File

@ -27,15 +27,30 @@ typedef enum {
ZBLOCK_FEED_INFO_DBERROR, ZBLOCK_FEED_INFO_DBERROR,
ZBLOCK_FEED_INFO_EXISTS, ZBLOCK_FEED_INFO_EXISTS,
ZBLOCK_FEED_INFO_NOT_EXIST, ZBLOCK_FEED_INFO_NOT_EXIST,
ZBLOCK_FEED_INFO_FINISHED,
ZBLOCK_FEED_INFO_NOMEM,
ZBLOCK_FEED_INFO_ERRORCOUNT ZBLOCK_FEED_INFO_ERRORCOUNT
} zblock_feed_info_err; } zblock_feed_info_err;
// free all information associated with a minimal feed info struct (does not assume the struct was allocated using malloc)
void zblock_feed_info_minimal_free(zblock_feed_info_minimal *feed_info);
// free all information associated with a feed info struct (does not assume the struct was allocated using malloc)
void zblock_feed_info_free(zblock_feed_info *feed_info);
// maybe change the function signature so you can actually do error handling with the result? // maybe change the function signature so you can actually do error handling with the result?
time_t pubDate_to_time_t(char *s); time_t pubDate_to_time_t(char *s);
// returns a string about the result of a feed_info function // returns a string about the result of a feed_info function
const char *zblock_feed_info_strerror(zblock_feed_info_err error); const char *zblock_feed_info_strerror(zblock_feed_info_err error);
// Begin retrieval of feed info objects.
zblock_feed_info_err zblock_feed_info_retrieve_list_begin(PGconn *conn);
// Retrieve the next feed list object.
// On error, no more objects can be retrieved and the returned object is invalid.
zblock_feed_info_err zblock_feed_info_retrieve_list_item(PGconn *conn, zblock_feed_info_minimal *feed_info);
// check if the feed currently exists. the result is in the exists pointer. // check if the feed currently exists. the result is in the exists pointer.
zblock_feed_info_err zblock_feed_info_exists(PGconn *conn, const char *url, u64snowflake channel_id, int *exists); zblock_feed_info_err zblock_feed_info_exists(PGconn *conn, const char *url, u64snowflake channel_id, int *exists);

54
main.c
View File

@ -70,64 +70,40 @@ static void timer_retrieve_feeds(struct discord *client, struct discord_timer *t
return; return;
} }
if (!PQsendQueryParams( // Begin retrieval of feed list objects.
database_conn, "SELECT url, last_pubDate, channel_id from feeds", if (zblock_feed_info_retrieve_list_begin(database_conn)) {
0, NULL, NULL, NULL, NULL, 1
)) {
log_error("Unable to retrieve feed list: %s", PQerrorMessage(database_conn)); log_error("Unable to retrieve feed list: %s", PQerrorMessage(database_conn));
curl_multi_cleanup(multi);
return; return;
} }
PQsetSingleRowMode(database_conn);
// put running handles up here so we can start transfers now instead of later // put running handles up here so we can start transfers now instead of later
int running_handles, total_feeds = 0; int running_handles, total_feeds = 0;
// get all the required feed info to send messages // get all the required feed info to send messages
PGresult *database_res; zblock_feed_info_minimal feed_info;
while ((database_res = PQgetResult(database_conn))) { while (!zblock_feed_info_retrieve_list_item(database_conn, &feed_info)) {
if (PQresultStatus(database_res) != PGRES_SINGLE_TUPLE) {
if (PQresultStatus(database_res) != PGRES_TUPLES_OK) {
log_error("Unable to retrieve feeds: %s", PQresultErrorMessage(database_res));
}
goto db_loop_end;
}
++total_feeds; ++total_feeds;
zblock_feed_buffer *feed_buffer = malloc(sizeof(*feed_buffer)); zblock_feed_buffer *feed_buffer = malloc(sizeof(*feed_buffer));
if (!feed_buffer) { if (!feed_buffer) {
log_error("Failure allocating feed buffer: %s", strerror(errno)); log_error("Failure allocating feed buffer: %s", strerror(errno));
goto db_loop_end; continue;
} }
feed_buffer->info.url = strdup(PQgetvalue(database_res, 0, 0)); feed_buffer->info = feed_info;
if (!feed_buffer->info.url) {
log_error("Failure allocating feed buffer: %s", strerror(errno));
free(feed_buffer);
goto db_loop_end;
}
feed_buffer->info.last_pubDate = strdup(PQgetvalue(database_res, 0, 1));
if (!feed_buffer->info.url) {
log_error("Failure allocating feed buffer: %s", strerror(errno));
free(feed_buffer->info.url);
free(feed_buffer);
goto db_loop_end;
}
feed_buffer->info.channel_id = be64toh(*(uint64_t *) PQgetvalue(database_res, 0, 2));
feed_buffer->fp = open_memstream(&feed_buffer->buf, &feed_buffer->bufsize); feed_buffer->fp = open_memstream(&feed_buffer->buf, &feed_buffer->bufsize);
if (!feed_buffer->fp) { if (!feed_buffer->fp) {
log_error("Unable to retrieve feed: %s", strerror(errno)); log_error("Unable to retrieve feed: %s", strerror(errno));
free(feed_buffer->info.last_pubDate); zblock_feed_info_minimal_free(&feed_buffer->info);
free(feed_buffer->info.url);
free(feed_buffer); free(feed_buffer);
goto db_loop_end; continue;
} }
CURL *feed_handle = curl_easy_init(); CURL *feed_handle = curl_easy_init();
if (!feed_handle) { if (!feed_handle) {
fclose(feed_buffer->fp); fclose(feed_buffer->fp);
free(feed_buffer->buf); free(feed_buffer->buf);
free(feed_buffer->info.last_pubDate); zblock_feed_info_minimal_free(&feed_buffer->info);
free(feed_buffer->info.url);
free(feed_buffer); free(feed_buffer);
goto db_loop_end; continue;
} }
curl_easy_setopt(feed_handle, CURLOPT_URL, feed_buffer->info.url); curl_easy_setopt(feed_handle, CURLOPT_URL, feed_buffer->info.url);
@ -139,15 +115,11 @@ static void timer_retrieve_feeds(struct discord *client, struct discord_timer *t
curl_easy_cleanup(feed_handle); curl_easy_cleanup(feed_handle);
fclose(feed_buffer->fp); fclose(feed_buffer->fp);
free(feed_buffer->buf); free(feed_buffer->buf);
free(feed_buffer->info.last_pubDate); zblock_feed_info_minimal_free(&feed_buffer->info);
free(feed_buffer->info.url);
free(feed_buffer); free(feed_buffer);
goto db_loop_end; continue;
} }
curl_multi_perform(multi, &running_handles); curl_multi_perform(multi, &running_handles);
db_loop_end:
PQclear(database_res);
} }
int successful_feeds = 0; int successful_feeds = 0;