Add 'myliststats' command

This commit is contained in:
x3 2023-08-09 17:26:53 +02:00
parent 9ddafb8240
commit be61d8dabc
Signed by: x3
GPG Key ID: 7E9961E8AD0E240E
8 changed files with 161 additions and 17 deletions

102
src/api.c
View File

@ -484,27 +484,34 @@ static enum error api_ratelimit()
/* /*
* Returns the written byte count * Returns the written byte count
* Or -1 on error, and -2 if errno was EINTR * Or negative errno value on error
*/ */
static ssize_t api_send(char *buffer, size_t data_len, size_t buf_size) static ssize_t api_send(char *buffer, size_t data_len, size_t buf_size)
{ {
pthread_mutex_lock(&api_work_mx);
ssize_t read_len; ssize_t read_len;
int en; int en;
if (api_ratelimit() == ERR_SHOULD_EXIT) if (api_ratelimit() == ERR_SHOULD_EXIT) {
return -2; read_len = -2;
goto end;
}
uio_debug("{Api}: Sending: %.*s", (int)data_len, buffer); uio_debug("{Api}: Sending: %.*s", (int)data_len, buffer);
if (api_encryption) if (api_encryption)
data_len = api_encrypt(buffer, data_len); data_len = api_encrypt(buffer, data_len);
en = net_send(buffer, data_len); en = net_send(buffer, data_len);
if (en < 0) if (en < 0) {
return en; read_len = en;
goto end;
}
read_len = net_read(buffer, buf_size); read_len = net_read(buffer, buf_size);
if (read_len < 0) { if (read_len < 0) {
if (read_len == -EINTR)
uio_error("!!! BAD PLACE EINTR !!! report pls"); uio_error("!!! BAD PLACE EINTR !!! report pls");
return read_len; /* This could lead so some problems if we also want to goto end; /* This could lead so some problems if we also want to
log out. If we hit this, the msg got sent, but we log out. If we hit this, the msg got sent, but we
couldn't read the response. That means, in the couldn't read the response. That means, in the
logout call, this msg's data will be read logout call, this msg's data will be read
@ -516,6 +523,8 @@ static ssize_t api_send(char *buffer, size_t data_len, size_t buf_size)
read_len = api_decrypt(buffer, read_len); read_len = api_decrypt(buffer, read_len);
uio_debug("{Api}: Reading: %.*s", (int)read_len, buffer); uio_debug("{Api}: Reading: %.*s", (int)read_len, buffer);
end:
pthread_mutex_unlock(&api_work_mx);
return read_len; return read_len;
} }
@ -686,7 +695,6 @@ static enum error api_cmd_base_pref(char buffer[API_BUFSIZE], int send_len,
enum error err = NOERR; enum error err = NOERR;
int retry_count = 0; int retry_count = 0;
pthread_mutex_lock(&api_work_mx);
api_g_retry_count = 0; api_g_retry_count = 0;
while (retry_count < API_MAX_TRYAGAIN && while (retry_count < API_MAX_TRYAGAIN &&
@ -701,7 +709,7 @@ static enum error api_cmd_base_pref(char buffer[API_BUFSIZE], int send_len,
res_len = api_send(buffer, send_len, API_BUFSIZE); res_len = api_send(buffer, send_len, API_BUFSIZE);
if (res_len < 0) { if (res_len < 0) {
if (res_len == -2 && should_exit) if (res_len == -EINTR && should_exit)
err = ERR_SHOULD_EXIT; err = ERR_SHOULD_EXIT;
else else
err = ERR_API_COMMFAIL; err = ERR_API_COMMFAIL;
@ -742,10 +750,24 @@ static enum error api_cmd_base_pref(char buffer[API_BUFSIZE], int send_len,
} }
if (err == ERR_API_NOLOGIN || err == ERR_API_INV_SESSION) { if (err == ERR_API_NOLOGIN || err == ERR_API_INV_SESSION) {
if (api_authed == false) {
/* If this happens and we are not logged in, don't retry */
err = ERR_API_COMMFAIL;
break;
}
api_g_retry_count++; api_g_retry_count++;
if (api_g_retry_count < API_MAX_TRYAGAIN) { if (api_g_retry_count < API_MAX_TRYAGAIN) {
uio_debug("Let's try loggin in agane"); struct timespec ts;
MS_TO_TIMESPEC_L(ts, 30000);
uio_debug("Let's try loggin in agane after waiting some");
api_authed = false; /* We got logged out probably */ api_authed = false; /* We got logged out probably */
if (nanosleep(&ts, NULL) == -1) {
if (errno == EINTR && should_exit) {
err = ERR_SHOULD_EXIT;
goto end;
}
}
err = api_auth(); /* -> will call this function */ err = api_auth(); /* -> will call this function */
if (api_g_retry_count < API_MAX_TRYAGAIN) { if (api_g_retry_count < API_MAX_TRYAGAIN) {
memcpy(buffer, l_buff, send_len); memcpy(buffer, l_buff, send_len);
@ -764,7 +786,6 @@ static enum error api_cmd_base_pref(char buffer[API_BUFSIZE], int send_len,
} }
end: end:
pthread_mutex_unlock(&api_work_mx);
return err; return err;
} }
static enum error api_cmd_base(char buffer[API_BUFSIZE], struct api_result *res, static enum error api_cmd_base(char buffer[API_BUFSIZE], struct api_result *res,
@ -1022,4 +1043,65 @@ enum error api_cmd_mylistmod(uint64_t lid, struct api_mylistadd_opts *opts,
return err; return err;
} }
static enum error api_cmd_myliststats_resp_parse(const char *buffer, struct api_myliststats_result *stats)
{
/* all int
*
* {animes}|{eps}|{files}|{size of files}|{added animes}|{added eps}|
* {added files}|{added groups}|{leech %}|{glory %}|{viewed % of db}|
* {mylist % of db}|{viewed % of mylist}|{number of viewed eps}|
* {votes}|{reviews}|{viewed length in minutes}
*/
bool glr;
char *line;
size_t line_len;
int fc;
glr = api_get_line(buffer, 2, &line, &line_len);
if (!glr)
return ERR_API_RESP_INVALID;
fc = api_field_parse(line,
"%lu", &stats->animes,
"%lu", &stats->eps,
"%lu", &stats->files,
"%lu", &stats->size_of_files,
"%lu", &stats->added_animes,
"%lu", &stats->added_eps,
"%lu", &stats->added_files,
"%lu", &stats->added_groups,
"%lu", &stats->leech_prcnt,
"%lu", &stats->glory_prcnt,
"%lu", &stats->viewed_prcnt_of_db,
"%lu", &stats->mylist_prcnt_of_db,
"%lu", &stats->viewed_prcnt_of_mylist,
"%lu", &stats->num_of_viewed_eps,
"%lu", &stats->votes,
"%lu", &stats->reviews,
"%lu", &stats->viewed_minutes,
NULL);
if (fc != 17) {
uio_error("Scanf only parsed %d", fc);
return ERR_API_RESP_INVALID;
}
return NOERR;
}
enum error api_cmd_myliststats(struct api_result *res)
{
char buffer[API_BUFSIZE];
enum error err = NOERR;
err = api_cmd_base(buffer, res, "MYLISTSTATS s=%s", api_session);
//err = api_cmd_base(buffer, res, "MYLISTSTATS");
if (err != NOERR)
return err;
if (res->code == APICODE_MYLIST_STATS)
return api_cmd_myliststats_resp_parse(buffer, &res->myliststats);
else
return ERR_API_RESP_INVALID;
}
#pragma GCC diagnostic pop #pragma GCC diagnostic pop

View File

@ -2,6 +2,7 @@
#define _API_H #define _API_H
#include <stdint.h> #include <stdint.h>
#include <time.h> #include <time.h>
#include <stdbool.h>
#include "error.h" #include "error.h"
@ -243,6 +244,15 @@ struct api_mylistadd_result {
struct api_mylistmod_result { struct api_mylistmod_result {
uint32_t n_edits; uint32_t n_edits;
}; };
/* The largest struct probably lul 136 bytes */
struct api_myliststats_result {
uint64_t animes, eps, files, size_of_files;
uint64_t added_animes, added_eps, added_files;
uint64_t added_groups, leech_prcnt, glory_prcnt;
uint64_t viewed_prcnt_of_db, mylist_prcnt_of_db;
uint64_t viewed_prcnt_of_mylist, num_of_viewed_eps;
uint64_t votes, reviews, viewed_minutes;
};
#define e(n) struct api_##n##_result n #define e(n) struct api_##n##_result n
struct api_result { struct api_result {
@ -255,6 +265,7 @@ struct api_result {
e(mylistadd); e(mylistadd);
e(encrypt); e(encrypt);
e(mylistmod); e(mylistmod);
e(myliststats);
}; };
}; };
#undef e #undef e
@ -269,5 +280,6 @@ enum error api_cmd_mylistadd(int64_t size, const uint8_t *hash,
struct api_mylistadd_opts *opts, struct api_result *res); struct api_mylistadd_opts *opts, struct api_result *res);
enum error api_cmd_mylistmod(uint64_t lid, struct api_mylistadd_opts *opts, enum error api_cmd_mylistmod(uint64_t lid, struct api_mylistadd_opts *opts,
struct api_result *res); struct api_result *res);
enum error api_cmd_myliststats(struct api_result *res);
#endif /* _API_H */ #endif /* _API_H */

View File

@ -23,8 +23,10 @@ static const struct cmd_entry ents[] = {
{ .arg_name = "server-version", .fn = cmd_server_version, .need_api = true }, { .arg_name = "server-version", .fn = cmd_server_version, .need_api = true },
{ .arg_name = "uptime", .fn = cmd_server_uptime, .need_auth = true }, { .arg_name = "uptime", .fn = cmd_server_uptime, .need_auth = true },
{ .arg_name = "ed2k", .fn = cmd_ed2k, }, { .arg_name = "ed2k", .fn = cmd_ed2k, },
{ .arg_name = "add", .fn = cmd_add, .argcheck = cmd_add_argcheck, .need_auth = true, .need_cache = true, }, { .arg_name = "add", .fn = cmd_add, .argcheck = cmd_add_argcheck, .need_auth = true, .need_cache = true, },
{ .arg_name = "modify", .fn = cmd_modify, .argcheck = cmd_modify_argcheck, .need_auth = true, .need_cache = true, }, { .arg_name = "modify", .fn = cmd_modify, .argcheck = cmd_modify_argcheck, .need_auth = true, .need_cache = true, },
{ .arg_name = "stats", .fn = cmd_stats, .need_auth = true, .need_cache = false, },
}; };
static const int32_t ents_len = sizeof(ents)/sizeof(*ents); static const int32_t ents_len = sizeof(ents)/sizeof(*ents);

View File

@ -42,4 +42,9 @@ enum error cmd_prog_version(void *);
enum error cmd_modify(void *data); enum error cmd_modify(void *data);
enum error cmd_modify_argcheck(); enum error cmd_modify_argcheck();
/*
* Request the mylist stats
*/
enum error cmd_stats(void *data);
#endif /* _CMD_H */ #endif /* _CMD_H */

40
src/cmd_stats.c Normal file
View File

@ -0,0 +1,40 @@
#include <stdio.h>
#include "error.h"
#include "api.h"
#include "util.h"
#include "uio.h"
enum error cmd_stats(void *data)
{
enum error err = NOERR;
struct api_result res;
struct api_myliststats_result *stats = &res.myliststats;
err = api_cmd_myliststats(&res);
if (err != NOERR) {
uio_error("Failed to request stats from API server");
return err;
}
printf("Mylist status:\n"
"Anime: %lu\n"
"Episodes: %lu\n"
"Files: %lu\n"
"Size of files: %lu\n"
"Added groups: %lu\n"
"leech%%: %lu\n"
"Glory%%: %lu\n"
"Viewed%%/DB: %lu\n"
"Mylist%%/DB: %lu\n"
"Viewed%%/Mylist: %lu\n"
"Viewed eps: %lu\n"
"Votes: %lu\n"
"Reviews: %lu\n"
"Viewed minutes: %lu\n",
stats->animes, stats->eps, stats->files, stats->size_of_files, stats->added_groups,
stats->leech_prcnt, stats->glory_prcnt, stats->viewed_prcnt_of_db,
stats->mylist_prcnt_of_db, stats->viewed_prcnt_of_mylist, stats->num_of_viewed_eps,
stats->votes, stats->reviews, stats->viewed_minutes);
return NOERR;
}

View File

@ -171,6 +171,12 @@ static struct conf_entry options[] = {
.subopts_count = sizeof(modify_add_subopts) / sizeof(modify_add_subopts[0]), .subopts_count = sizeof(modify_add_subopts) / sizeof(modify_add_subopts[0]),
}, },
{ .l_name = "stats", .s_name = UCHAR_MAX + 10,
.has_arg = no_argument, .set_func = config_set_bool, .in_args = true,
.type = OTYPE_SUBCOMMAND, .handle_order = 1,
.h_desc = "Get the mylist status",
},
/*{ .l_name = "stats", .s_name = UCHAR_MAX + 5, /*{ .l_name = "stats", .s_name = UCHAR_MAX + 5,
.has_arg = no_argument, .set_func = config_set_bool, .in_args = true, .has_arg = no_argument, .set_func = config_set_bool, .in_args = true,
.type = OTYPE_B, .handle_order = 1, .value_is_set = true },*/ .type = OTYPE_B, .handle_order = 1, .value_is_set = true },*/

View File

@ -265,9 +265,7 @@ ssize_t net_read(void* out_data, size_t read_size)
int en = errno; int en = errno;
uio_error("{net} Read failed: %s", strerror(errno)); uio_error("{net} Read failed: %s", strerror(errno));
if (en == EINTR) return -en;
return -2;
return -1;
} }
if (read == read_size) if (read == read_size)
uio_warning("{net} Data may have been discarded!"); uio_warning("{net} Data may have been discarded!");

View File

@ -12,9 +12,8 @@ enum error net_init();
/* /*
* Send and read data to and from the api * Send and read data to and from the api
* Returns the number of bytes sent/read or -1 on error * Returns the number of bytes sent/read or
* If the error is EINTR, it returns -2 * a negative value which is the errno */
*/
ssize_t net_send(const void *msg, size_t msg_len); ssize_t net_send(const void *msg, size_t msg_len);
ssize_t net_read(void *out_data, size_t read_size); ssize_t net_read(void *out_data, size_t read_size);