From a218c53cc2b0f970aab056de2b391489846f41cf Mon Sep 17 00:00:00 2001 From: ThePedroo Date: Sun, 31 Mar 2024 03:32:59 -0300 Subject: [PATCH] improve: organization and internal handling This commit improves the organization of the library and how it handles things internally. --- external/jsonb.c | 8 +- external/jsonb.h | 8 +- include/codecs.h | 51 +++++++----- include/events.h | 16 ++-- include/lavalink.h | 2 +- include/rest.h | 16 ++-- include/utils.h | 8 +- lib/codecs.c | 190 +++++++++++++++++++++++++++++++-------------- lib/rest.c | 146 +++++++++++++++++----------------- lib/utils.c | 17 ++-- lib/websocket.c | 36 +++------ 11 files changed, 289 insertions(+), 209 deletions(-) diff --git a/external/jsonb.c b/external/jsonb.c index 42be42f..70ca5e7 100644 --- a/external/jsonb.c +++ b/external/jsonb.c @@ -97,7 +97,7 @@ void pjsonb_set_string(struct pjsonb *builder, const char *key, const char *valu builder->key_state = PJSONB_TO_CLOSE; } -void pjson_enter_object(struct pjsonb *builder, const char *key) { +void pjsonb_enter_object(struct pjsonb *builder, const char *key) { int key_length = strlen(key); builder->string = realloc(builder->string, builder->position + 5 + key_length); @@ -105,7 +105,7 @@ void pjson_enter_object(struct pjsonb *builder, const char *key) { builder->key_state = PJSONB_NONE; } -void pjson_leave_object(struct pjsonb *builder) { +void pjsonb_leave_object(struct pjsonb *builder) { if (builder->key_state == PJSONB_TO_CLOSE) { builder->string[builder->position - 1] = '}'; builder->string = realloc(builder->string, builder->position + 1); @@ -119,7 +119,7 @@ void pjson_leave_object(struct pjsonb *builder) { builder->key_state = PJSONB_TO_CLOSE; } -void pjson_enter_array(struct pjsonb *builder, const char *key) { +void pjsonb_enter_array(struct pjsonb *builder, const char *key) { int key_length = strlen(key); builder->string = realloc(builder->string, builder->position + 3 + key_length); @@ -127,7 +127,7 @@ void pjson_enter_array(struct pjsonb *builder, const char *key) { builder->key_state = PJSONB_NONE; } -void pjson_leave_array(struct pjsonb *builder) { +void pjsonb_leave_array(struct pjsonb *builder) { if (builder->key_state == PJSONB_TO_CLOSE) { builder->string[builder->position - 1] = ']'; } else { diff --git a/external/jsonb.h b/external/jsonb.h index 40ef742..9c34870 100644 --- a/external/jsonb.h +++ b/external/jsonb.h @@ -26,12 +26,12 @@ void pjsonb_set_bool(struct pjsonb *builder, const char *key, int value); void pjsonb_set_string(struct pjsonb *builder, const char *key, const char *value); -void pjson_enter_object(struct pjsonb *builder, const char *key); +void pjsonb_enter_object(struct pjsonb *builder, const char *key); -void pjson_leave_object(struct pjsonb *builder); +void pjsonb_leave_object(struct pjsonb *builder); -void pjson_enter_array(struct pjsonb *builder, const char *key); +void pjsonb_enter_array(struct pjsonb *builder, const char *key); -void pjson_leave_array(struct pjsonb *builder); +void pjsonb_leave_array(struct pjsonb *builder); #endif \ No newline at end of file diff --git a/include/codecs.h b/include/codecs.h index 8cf5b86..ac709f0 100644 --- a/include/codecs.h +++ b/include/codecs.h @@ -9,53 +9,53 @@ #define COGLINK_PARSE_ERROR -1 -struct coglink_ready_payload { +struct coglink_ready { char *session_id; bool resumed; }; #define COGLINK_READY 0 -struct coglink_player_state_payload { +struct coglink_player_state { int time; int position; bool connected; int ping; }; -struct coglink_player_update_payload { +struct coglink_player_update { u64snowflake guildId; - struct coglink_player_state_payload *state; + struct coglink_player_state *state; }; #define COGLINK_PLAYER_UPDATE 2 -struct coglink_stats_memory_payload { +struct coglink_stats_memory { int free; int used; int allocated; int reservable; }; -struct coglink_stats_cpu_payload { +struct coglink_stats_cpu { int cores; int systemLoad; int lavalinkLoad; }; -struct coglink_stats_frame_stats_payload { +struct coglink_stats_frame_stats { int sent; int nulled; int deficit; }; -struct coglink_stats_payload { +struct coglink_stats { int players; int playingPlayers; int uptime; - struct coglink_stats_memory_payload *memory; - struct coglink_stats_cpu_payload *cpu; - struct coglink_stats_frame_stats_payload *frameStats; + struct coglink_stats_memory *memory; + struct coglink_stats_cpu *cpu; + struct coglink_stats_frame_stats *frameStats; }; #define COGLINK_STATS 3 @@ -84,7 +84,7 @@ struct coglink_tracks { size_t size; }; -struct coglink_track_start_payload { +struct coglink_track_start { u64snowflake guildId; struct coglink_track *track; }; @@ -99,7 +99,7 @@ enum coglink_track_end_reason { COGLINK_TRACK_END_REASON_CLEANUP }; -struct coglink_track_end_payload { +struct coglink_track_end { u64snowflake guildId; struct coglink_track *track; enum coglink_track_end_reason reason; @@ -113,21 +113,21 @@ enum coglink_exception_severity { COGLINK_EXCEPTION_SEVERITY_FAULT }; -struct coglink_exception_payload { +struct coglink_exception { char *message; enum coglink_exception_severity severity; char *cause; }; -struct coglink_track_exception_payload { +struct coglink_track_exception { u64snowflake guildId; struct coglink_track *track; - struct coglink_exception_payload *exception; + struct coglink_exception *exception; }; #define COGLINK_TRACK_EXCEPTION 43 -struct coglink_track_stuck_payload { +struct coglink_track_stuck { u64snowflake guildId; struct coglink_track *track; int thresholdMs; @@ -135,7 +135,7 @@ struct coglink_track_stuck_payload { #define COGLINK_TRACK_STUCK 44 -struct coglink_websocket_closed_payload { +struct coglink_websocket_closed { int code; char *reason; bool byRemote; @@ -283,6 +283,13 @@ struct coglink_node_info { struct coglink_node_info_filters *filters; }; +struct coglink_node_version { + int major; + int minor; + int patch; + char *preRelease; +}; + #define coglink_parse_track(track_info, pairs, json) \ char *path[] = { "encoded", NULL }; \ FIND_FIELD_PATH(json, pairs, encoded, "encoded", 1); \ @@ -340,6 +347,8 @@ int coglink_parse_websocket_data(const char *json, size_t json_length, void **re void coglink_free_track(struct coglink_track *track); +void coglink_free_tracks(struct coglink_tracks *tracks); + int coglink_parse_load_tracks(struct coglink_load_tracks *response, const char *json, size_t json_length); void coglink_free_load_tracks(struct coglink_load_tracks *response); @@ -366,6 +375,10 @@ int coglink_parse_node_info(struct coglink_node_info *response, const char *json void coglink_free_node_info(struct coglink_node_info *node_info); -int coglink_parse_stats(struct coglink_stats_payload *response, const char *json, size_t json_length); +int coglink_parse_stats(struct coglink_stats *response, const char *json, size_t json_length); + +int coglink_parse_version(struct coglink_node_version *response, const char *version, size_t version_length); + +void coglink_free_node_version(struct coglink_node_version *version); #endif diff --git a/include/events.h b/include/events.h index c2e72dd..2c4620c 100644 --- a/include/events.h +++ b/include/events.h @@ -6,15 +6,15 @@ struct coglink_events { int (*on_raw)(struct coglink_client *c_client, const char *data, size_t length); - void (*on_ready)(struct coglink_ready_payload *ready); + void (*on_ready)(struct coglink_ready *ready); void (*on_close)(enum ws_close_reason wscode, const char *reason); - void (*on_track_start)(struct coglink_track_start_payload *trackStart); - void (*on_track_end)(struct coglink_track_end_payload *trackEnd); - void (*on_track_excetion)(struct coglink_track_exception_payload *trackException); - void (*on_track_stuck)(struct coglink_track_stuck_payload *trackStuck); - void (*on_websocket_closed)(struct coglink_websocket_closed_payload *websocketClosed); - void (*on_player_update)(struct coglink_player_update_payload *playerUpdate); - void (*on_stats)(struct coglink_stats_payload *stats); + void (*on_track_start)(struct coglink_track_start *trackStart); + void (*on_track_end)(struct coglink_track_end *trackEnd); + void (*on_track_excetion)(struct coglink_track_exception *trackException); + void (*on_track_stuck)(struct coglink_track_stuck *trackStuck); + void (*on_websocket_closed)(struct coglink_websocket_closed *websocketClosed); + void (*on_player_update)(struct coglink_player_update *playerUpdate); + void (*on_stats)(struct coglink_stats *stats); }; #endif /* COGLINK_LAVALINK_EVENTS_H */ diff --git a/include/lavalink.h b/include/lavalink.h index fcc12ec..733418b 100644 --- a/include/lavalink.h +++ b/include/lavalink.h @@ -16,7 +16,7 @@ struct coglink_node { bool ssl; /* Public info */ char *session_id; - struct coglink_stats_payload *stats; + struct coglink_stats *stats; /* Internal */ uint64_t tstamp; CURLM *mhandle; diff --git a/include/rest.h b/include/rest.h index 942a85d..05aa976 100644 --- a/include/rest.h +++ b/include/rest.h @@ -126,7 +126,9 @@ struct coglink_update_player_params { struct coglink_user *coglink_get_user(struct coglink_client *c_client, u64snowflake user_id); -int coglink_join_voice_channel(struct discord *client, u64snowflake guild_id, u64snowflake channel_id); +int coglink_join_voice_channel(struct coglink_client *c_client, struct discord *client, u64snowflake guild_id, u64snowflake channel_id); + +int coglink_leave_voice_channel(struct coglink_client *c_client, struct discord *client, u64snowflake guild_id); struct coglink_player *coglink_create_player(struct coglink_client *c_client, u64snowflake guild_id); @@ -140,24 +142,20 @@ int coglink_remove_track_from_queue(struct coglink_client *c_client, struct cogl int coglink_remove_player(struct coglink_client *c_client, struct coglink_player *player); -int coglink_decode_track(struct coglink_client *c_client, struct coglink_node *node, char *track, struct coglink_track *response); +int coglink_load_tracks(struct coglink_client *c_client, struct coglink_node *node, char *identifier, struct coglink_load_tracks *response); -void coglink_free_decode_track(struct coglink_track *track); +int coglink_decode_track(struct coglink_client *c_client, struct coglink_node *node, char *track, struct coglink_track *response); int coglink_decode_tracks(struct coglink_client *c_client, struct coglink_node *node, struct coglink_decode_tracks_params *params, struct coglink_tracks *response); -void coglink_free_decode_tracks(struct coglink_tracks *track); - int coglink_update_player(struct coglink_client *c_client, struct coglink_player *player, struct coglink_update_player_params *params, struct coglink_update_player *response); void coglink_destroy_player(struct coglink_client *c_client, struct coglink_player *player); int coglink_get_node_info(struct coglink_client *c_client, struct coglink_node *node, struct coglink_node_info *info); -int coglink_get_node_version(struct coglink_client *c_client, struct coglink_node *node, char **version); - -void coglink_free_node_version(char *version); +int coglink_get_node_version(struct coglink_client *c_client, struct coglink_node *node, struct coglink_node_version *version); -int coglink_get_stats(struct coglink_client *c_client, struct coglink_node *node, struct coglink_stats_payload *stats); +int coglink_get_stats(struct coglink_client *c_client, struct coglink_node *node, struct coglink_stats *stats); #endif \ No newline at end of file diff --git a/include/utils.h b/include/utils.h index 82aa308..45b1d83 100644 --- a/include/utils.h +++ b/include/utils.h @@ -30,8 +30,10 @@ #define PAIR_TO_D_STRING(json, pair, output) \ output = malloc((pair->v.len + 1) * sizeof(char)); \ - memcpy(output, json + pair->v.pos, pair->v.len); \ - output[pair->v.len] = '\0'; + snprintf(output, pair->v.len + 1, "%.*s", (int)pair->v.len, json + pair->v.pos); + +#define FREE_NULLABLE(ptr) \ + if (ptr != NULL) free(ptr); #ifdef COGLINK_DEBUG #define FATAL(...) \ @@ -67,6 +69,6 @@ struct coglink_response { size_t size; }; -int _coglink_perform_request(struct coglink_node *nodeInfo, struct coglink_request_params *req, struct coglink_response *res); +int _coglink_perform_request(struct coglink_node *node_info, struct coglink_request_params *req, struct coglink_response *res); #endif diff --git a/lib/codecs.c b/lib/codecs.c index 53887b2..4a7a5bf 100644 --- a/lib/codecs.c +++ b/lib/codecs.c @@ -47,7 +47,7 @@ int coglink_parse_websocket_data(const char *json, size_t json_length, void **re FIND_FIELD(pairs, json, sessionId, "sessionId"); FIND_FIELD(pairs, json, resumed, "resumed"); - struct coglink_ready_payload *ready = malloc(sizeof(struct coglink_ready_payload)); + struct coglink_ready *ready = malloc(sizeof(struct coglink_ready)); PAIR_TO_D_STRING(json, sessionId, ready->session_id); ready->resumed = json[resumed->v.pos] == 't'; @@ -65,14 +65,16 @@ int coglink_parse_websocket_data(const char *json, size_t json_length, void **re case 'a': { /* TrackStartEvent */ FIND_FIELD(pairs, json, event_track, "track"); - struct coglink_track_start_payload *parsedTrack = malloc(sizeof(struct coglink_track_start_payload)); + struct coglink_track_start *parsedTrack = malloc(sizeof(struct coglink_track_start)); PAIR_TO_SIZET(json, guildId, guildIdStr, parsedTrack->guildId, 18); - struct coglink_track *track_info = malloc(sizeof(struct coglink_track)); - coglink_parse_track(track_info, event_track, json); + struct coglink_track *track = malloc(sizeof(struct coglink_track)); + track->info = malloc(sizeof(struct coglink_track_info)); - parsedTrack->track = track_info; + coglink_parse_track(track, event_track, json); + + parsedTrack->track = track; *response = parsedTrack; *event_type = COGLINK_TRACK_START; @@ -83,14 +85,16 @@ int coglink_parse_websocket_data(const char *json, size_t json_length, void **re FIND_FIELD(pairs, json, reason, "reason"); FIND_FIELD(pairs, json, event_track, "track"); - struct coglink_track_end_payload *parsedTrack = malloc(sizeof(struct coglink_track_end_payload)); + struct coglink_track_end *parsedTrack = malloc(sizeof(struct coglink_track_end)); PAIR_TO_SIZET(json, guildId, guildIdStr, parsedTrack->guildId, 18); - struct coglink_track *track_info = malloc(sizeof(struct coglink_track)); - coglink_parse_track(track_info, event_track, json); + struct coglink_track *track = malloc(sizeof(struct coglink_track)); + track->info = malloc(sizeof(struct coglink_track_info)); + + coglink_parse_track(track, event_track, json); - parsedTrack->track = track_info; + parsedTrack->track = track; switch (json[reason->v.pos]) { case 'f': { @@ -131,15 +135,17 @@ int coglink_parse_websocket_data(const char *json, size_t json_length, void **re FIND_FIELD(pairs, json, cause, "cause"); FIND_FIELD(pairs, json, event_track, "track"); - struct coglink_track_exception_payload *parsedTrack = malloc(sizeof(struct coglink_track_end_payload)); + struct coglink_track_exception *parsedTrack = malloc(sizeof(struct coglink_track_end)); PAIR_TO_SIZET(json, guildId, guildIdStr, parsedTrack->guildId, 18); - struct coglink_track *track_info = malloc(sizeof(struct coglink_track)); - coglink_parse_track(track_info, event_track, json); + struct coglink_track *track = malloc(sizeof(struct coglink_track)); + track->info = malloc(sizeof(struct coglink_track_info)); - parsedTrack->track = track_info; - parsedTrack->exception = malloc(sizeof(struct coglink_exception_payload)); + coglink_parse_track(track, event_track, json); + + parsedTrack->track = track; + parsedTrack->exception = malloc(sizeof(struct coglink_exception)); PAIR_TO_D_STRING(json, message, parsedTrack->exception->message); switch (json[severity->v.pos]) { @@ -171,14 +177,16 @@ int coglink_parse_websocket_data(const char *json, size_t json_length, void **re FIND_FIELD(pairs, json, thresholdMs, "thresholdMs"); FIND_FIELD(pairs, json, event_track, "track"); - struct coglink_track_stuck_payload *parsedTrack = malloc(sizeof(struct coglink_track_end_payload)); + struct coglink_track_stuck *parsedTrack = malloc(sizeof(struct coglink_track_end)); PAIR_TO_SIZET(json, guildId, guildIdStr, parsedTrack->guildId, 18); - struct coglink_track *track_info = malloc(sizeof(struct coglink_track)); - coglink_parse_track(track_info, event_track, json); + struct coglink_track *track = malloc(sizeof(struct coglink_track)); + track->info = malloc(sizeof(struct coglink_track_info)); + + coglink_parse_track(track, event_track, json); - parsedTrack->track = track_info; + parsedTrack->track = track; PAIR_TO_SIZET(json, thresholdMs, thresholdMsStr, parsedTrack->thresholdMs, 8); @@ -187,12 +195,12 @@ int coglink_parse_websocket_data(const char *json, size_t json_length, void **re return COGLINK_SUCCESS; } - case 't': { /* WebSocketClosedEvent */ + case 'e': { /* WebSocketClosedEvent */ FIND_FIELD(pairs, json, code, "code"); FIND_FIELD(pairs, json, reason, "reason"); FIND_FIELD(pairs, json, byRemote, "byRemote"); - struct coglink_websocket_closed_payload *c_info = malloc(sizeof(struct coglink_websocket_closed_payload)); + struct coglink_websocket_closed *c_info = malloc(sizeof(struct coglink_websocket_closed)); PAIR_TO_SIZET(json, code, codeStr, c_info->code, 8); PAIR_TO_D_STRING(json, reason, c_info->reason); @@ -250,10 +258,10 @@ int coglink_parse_websocket_data(const char *json, size_t json_length, void **re path[1] = "nulled"; FIND_FIELD_PATH(json, pairs, nulled, "nulled", 2); - struct coglink_stats_payload *stats = malloc(sizeof(struct coglink_stats_payload)); - stats->memory = malloc(sizeof(struct coglink_stats_memory_payload)); - stats->cpu = malloc(sizeof(struct coglink_stats_cpu_payload)); - stats->frameStats = malloc(sizeof(struct coglink_stats_frame_stats_payload)); + struct coglink_stats *stats = malloc(sizeof(struct coglink_stats)); + stats->memory = malloc(sizeof(struct coglink_stats_memory)); + stats->cpu = malloc(sizeof(struct coglink_stats_cpu)); + stats->frameStats = malloc(sizeof(struct coglink_stats_frame_stats)); PAIR_TO_SIZET(json, players, playersStr, stats->players, 8); PAIR_TO_SIZET(json, playingPlayers, playingPlayersStr, stats->playingPlayers, 16); @@ -289,8 +297,8 @@ int coglink_parse_websocket_data(const char *json, size_t json_length, void **re path[1] = "ping"; FIND_FIELD_PATH(json, pairs, ping, "ping", 2); - struct coglink_player_update_payload *playerUpdate = malloc(sizeof(struct coglink_player_update_payload)); - playerUpdate->state = malloc(sizeof(struct coglink_player_state_payload)); + struct coglink_player_update *playerUpdate = malloc(sizeof(struct coglink_player_update)); + playerUpdate->state = malloc(sizeof(struct coglink_player_state)); PAIR_TO_SIZET(json, guildId, guildIdStr, playerUpdate->guildId, 18); PAIR_TO_SIZET(json, time, timeStr, playerUpdate->state->time, 16); @@ -315,10 +323,20 @@ int coglink_parse_websocket_data(const char *json, size_t json_length, void **re } void coglink_free_track(struct coglink_track *track) { + free(track->encoded); free(track->info); free(track); } +void coglink_free_tracks(struct coglink_tracks *tracks) { + for (size_t i = 0; i < tracks->size; i++) { + coglink_free_track(tracks->array[i]); + } + + free(tracks->array); + free(tracks); +} + int coglink_parse_load_tracks(struct coglink_load_tracks *response, const char *json, size_t json_length) { jsmn_parser parser; jsmntok_t *toks = NULL; @@ -489,7 +507,7 @@ void coglink_free_load_tracks(struct coglink_load_tracks *response) { case COGLINK_LOAD_TYPE_TRACK: { struct coglink_load_tracks_track *data = response->data; - free(data->encoded); + FREE_NULLABLE(data->encoded); free(data->info); free(data); @@ -501,7 +519,7 @@ void coglink_free_load_tracks(struct coglink_load_tracks *response) { free(data->info); for (size_t i = 0; i < data->tracks->size; i++) { - free(data->tracks->array[i]->encoded); + FREE_NULLABLE(data->tracks->array[i]->encoded); free(data->tracks->array[i]->info); free(data->tracks->array[i]); } @@ -515,9 +533,9 @@ void coglink_free_load_tracks(struct coglink_load_tracks *response) { struct coglink_load_tracks_search *data = response->data; for (size_t i = 0; i < data->size; i++) { - free(data->array[i]->encoded); - free(data->array[i]->info); - free(data->array[i]); + FREE_NULLABLE(data->array[i]->encoded); + FREE_NULLABLE(data->array[i]->info); + FREE_NULLABLE(data->array[i]); } free(data->array); @@ -533,8 +551,8 @@ void coglink_free_load_tracks(struct coglink_load_tracks *response) { case COGLINK_LOAD_TYPE_ERROR: { struct coglink_load_tracks_error *data = response->data; - free(data->message); - free(data->cause); + FREE_NULLABLE(data->message); + FREE_NULLABLE(data->cause); free(data); break; @@ -573,19 +591,21 @@ int coglink_parse_voice_state(const char *json, size_t json_length, struct cogli FIND_FIELD(pairs, json, session_id, "session_id"); PAIR_TO_SIZET(json, guild_id, guild_id_str, response->guild_id, 18); - PAIR_TO_SIZET(json, channel_id, channel_id_str, response->channel_id, 18); if (channel_id) { - PAIR_TO_SIZET(json, user_id, user_id_str, response->user_id, 18); + PAIR_TO_SIZET(json, channel_id, channel_id_str, response->channel_id, 18); } else { - response->user_id = 0; + response->channel_id = 0; } - PAIR_TO_D_STRING(json, user_id, response->session_id); + PAIR_TO_SIZET(json, user_id, user_id_str, response->user_id, 18); + PAIR_TO_D_STRING(json, session_id, response->session_id); return COGLINK_SUCCESS; } void coglink_free_voice_state(struct coglink_voice_state *voice_state) { - free(voice_state->session_id); + (void)voice_state; + + /* Nothing to free */ } int coglink_parse_voice_server_update(const char *json, size_t json_length, struct coglink_voice_server_update *response) { @@ -625,8 +645,8 @@ int coglink_parse_voice_server_update(const char *json, size_t json_length, stru } void coglink_free_voice_server_update(struct coglink_voice_server_update *voice_server_update) { - free(voice_server_update->token); - free(voice_server_update->endpoint); + FREE_NULLABLE(voice_server_update->token); + FREE_NULLABLE(voice_server_update->endpoint); } int coglink_parse_guild_create(const char *json, size_t json_length, struct coglink_guild_create *response) { @@ -869,10 +889,10 @@ int coglink_parse_update_player(struct coglink_update_player *response, const ch void coglink_free_update_player(struct coglink_update_player *response) { coglink_free_track(response->track); - free(response->track); - free(response->state); - free(response->filters); - free(response); + FREE_NULLABLE(response->track); + FREE_NULLABLE(response->state); + FREE_NULLABLE(response->filters); + FREE_NULLABLE(response); } int coglink_parse_node_info(struct coglink_node_info *response, const char *json, size_t json_length) { @@ -979,29 +999,29 @@ int coglink_parse_node_info(struct coglink_node_info *response, const char *json } void coglink_free_node_info(struct coglink_node_info *response) { - free(response->version->semver); - free(response->version->preRelease); - free(response->version->build); - free(response->version); - free(response->git->branch); - free(response->git->commit); - free(response->jvm); - free(response->lavaplayer); + FREE_NULLABLE(response->version->semver); + FREE_NULLABLE(response->version->preRelease); + FREE_NULLABLE(response->version->build); + FREE_NULLABLE(response->version); + FREE_NULLABLE(response->git->branch); + FREE_NULLABLE(response->git->commit); + FREE_NULLABLE(response->jvm); + FREE_NULLABLE(response->lavaplayer); for (size_t i = 0; i < response->sourceManagers->size; i++) { - free(response->sourceManagers->array[i]); + FREE_NULLABLE(response->sourceManagers->array[i]); } - free(response->sourceManagers->array); - free(response->sourceManagers); + FREE_NULLABLE(response->sourceManagers->array); + FREE_NULLABLE(response->sourceManagers); for (size_t i = 0; i < response->filters->size; i++) { - free(response->filters->array[i]); + FREE_NULLABLE(response->filters->array[i]); } - free(response->filters->array); - free(response->filters); + FREE_NULLABLE(response->filters->array); + FREE_NULLABLE(response->filters); } -int coglink_parse_stats(struct coglink_stats_payload *response, const char *json, size_t json_length) { +int coglink_parse_stats(struct coglink_stats *response, const char *json, size_t json_length) { jsmn_parser parser; jsmntok_t tokens[128]; @@ -1067,4 +1087,56 @@ int coglink_parse_stats(struct coglink_stats_payload *response, const char *json PAIR_TO_SIZET(json, lavalinkLoad, lavalinkLoadStr,response->cpu->lavalinkLoad, 8); return COGLINK_SUCCESS; +} + +int coglink_parse_version(struct coglink_node_version *response, const char *version, size_t version_length) { + int i = 0; + int dot_count = 0; + int last_info = 0; + /* 0 = major, 1 = minor, 2 = patch, 3 = pre-release */ + int state = 0; + + while (--version_length) { + if (version[i] == '.') { + if (dot_count == 0) { + response->major = atoi(version + last_info); + } else if (dot_count == 1) { + response->minor = atoi(version + last_info); + } else if (dot_count == 2) { + response->patch = atoi(version + last_info); + } else { + return COGLINK_FAILED; + } + + last_info = i + 1; + dot_count++; + } else if (version[i] == '-') { + if (dot_count == 2) { + response->patch = atoi(version + last_info); + } else { + return COGLINK_FAILED; + } + + last_info = i + 1; + state = 3; + } else if (version[i] == '+') { + if (state == 3) { + response->preRelease = malloc(version_length + 1); + memcpy(response->preRelease, version + last_info, version_length); + response->preRelease[version_length] = '\0'; + } else { + return COGLINK_FAILED; + } + + break; + } + + i++; + } + + return COGLINK_SUCCESS; +} + +void coglink_free_node_version(struct coglink_node_version *version) { + FREE_NULLABLE(version->preRelease); } \ No newline at end of file diff --git a/lib/rest.c b/lib/rest.c index aea8c30..947ba2a 100644 --- a/lib/rest.c +++ b/lib/rest.c @@ -47,7 +47,9 @@ struct coglink_user *coglink_get_user(struct coglink_client *c_client, u64snowfl return NULL; } -int coglink_join_voice_channel(struct discord *client, u64snowflake guild_id, u64snowflake channel_id) { +int coglink_join_voice_channel(struct coglink_client *c_client, struct discord *client, u64snowflake guild_id, u64snowflake channel_id) { + (void) c_client; /* Standard */ + char payload[((sizeof("{" "\"op\":4," "\"d\":{" @@ -55,7 +57,7 @@ int coglink_join_voice_channel(struct discord *client, u64snowflake guild_id, u6 "\"channel_id\":\"\"," "\"self_mute\":false," "\"self_deaf\":true" - "}") - 1) + (19 * 2) + 1)]; + "}") - 1) + ((19 * 2) + 1) + 1)]; size_t payload_size = snprintf(payload, sizeof(payload), "{" @@ -71,10 +73,42 @@ int coglink_join_voice_channel(struct discord *client, u64snowflake guild_id, u6 if (!ws_send_text(client->gw.ws, NULL, payload, payload_size)) { FATAL("[coglink:cws] Something went wrong while sending a payload with op 4 to Discord."); - return -1; + return COGLINK_FAILED; + } + + return COGLINK_SUCCESS; +} + +int coglink_leave_voice_channel(struct coglink_client *c_client, struct discord *client, u64snowflake guild_id) { + (void) c_client; /* Standard */ + + char payload[((sizeof("{" + "\"op\":4," + "\"d\":{" + "\"guild_id\":\"\"," + "\"channel_id\":null," + "\"self_mute\":false," + "\"self_deaf\":true" + "}") - 1) + (19 + 1) + 1)]; + + size_t payload_size = snprintf(payload, sizeof(payload), + "{" + "\"op\":4," + "\"d\":{" + "\"guild_id\":%"PRIu64"," + "\"channel_id\":null," + "\"self_mute\":false," + "\"self_deaf\":true" + "}" + "}", guild_id); + + if (!ws_send_text(client->gw.ws, NULL, payload, payload_size)) { + FATAL("[coglink:cws] Something went wrong while sending a payload with op 4 to Discord."); + + return COGLINK_FAILED; } - return 0; + return COGLINK_SUCCESS; } struct coglink_player *coglink_create_player(struct coglink_client *c_client, u64snowflake guild_id) { @@ -105,7 +139,6 @@ struct coglink_player *coglink_create_player(struct coglink_client *c_client, u6 c_client->players->array = realloc(c_client->players->array, sizeof(struct coglink_player) * (c_client->players->size + 1)); c_client->players->size++; - /* todo: (?) use goto to reduce duplicated code */ struct coglink_player *player = &c_client->players->array[c_client->players->size - 1]; player->guild_id = guild_id; player->node = selected_node; @@ -141,9 +174,7 @@ int coglink_add_track_to_queue(struct coglink_client *c_client, struct coglink_p queue->array = realloc(queue->array, sizeof(char *) * (queue->size + 1)); queue->size++; - /* copy */ - queue->array[queue->size - 1] = malloc((strlen(track) + 1) * sizeof(char)); - strcpy(queue->array[queue->size - 1], track); + queue->array[queue->size - 1] = strdup(track); return COGLINK_SUCCESS; } @@ -179,11 +210,7 @@ int coglink_remove_player(struct coglink_client *c_client, struct coglink_player return COGLINK_SUCCESS; } -int coglink_load_tracks(struct coglink_client *c_client, struct coglink_player *player, char *identifier, struct coglink_load_tracks *response) { - struct coglink_node *node = &c_client->nodes->array[player->node]; - - if (node->session_id == NULL) return COGLINK_NODE_OFFLINE; - +int coglink_load_tracks(struct coglink_client *c_client, struct coglink_node *node, char *identifier, struct coglink_load_tracks *response) { size_t endpoint_size = (sizeof("/loadtracks?identifier=") - 1) + strlen(identifier) + 1; char *endpoint = malloc(endpoint_size * sizeof(char)); snprintf(endpoint, endpoint_size * sizeof(char), "/loadtracks?identifier=%s", identifier); @@ -253,11 +280,6 @@ int coglink_decode_track(struct coglink_client *c_client, struct coglink_node *n return COGLINK_SUCCESS; } -void coglink_free_decode_track(struct coglink_track *track) { - free(track->encoded); - free(track->info); -} - int coglink_decode_tracks(struct coglink_client *c_client, struct coglink_node *node, struct coglink_decode_tracks_params *params, struct coglink_tracks *response) { (void) c_client; /* Standard */ @@ -265,13 +287,13 @@ int coglink_decode_tracks(struct coglink_client *c_client, struct coglink_node * struct pjsonb jsonber; pjsonb_init(&jsonber); - pjson_enter_array(&jsonber, "tracks"); + pjsonb_enter_array(&jsonber, "tracks"); for (size_t i = 0; i < params->size; i++) { pjsonb_set_string(&jsonber, NULL, params->array[i]); } - pjson_leave_array(&jsonber); + pjsonb_leave_array(&jsonber); pjsonb_end(&jsonber); @@ -328,16 +350,6 @@ int coglink_decode_tracks(struct coglink_client *c_client, struct coglink_node * return COGLINK_SUCCESS; } -void coglink_free_decode_tracks(struct coglink_tracks *tracks) { - for (size_t i = 0; i < tracks->size; i++) { - free(tracks->array[i]->encoded); - free(tracks->array[i]); - } - - free(tracks->array); - free(tracks); -} - int coglink_update_player(struct coglink_client *c_client, struct coglink_player *player, struct coglink_update_player_params *params, struct coglink_update_player *response) { struct coglink_node *node = &c_client->nodes->array[player->node]; @@ -351,13 +363,13 @@ int coglink_update_player(struct coglink_client *c_client, struct coglink_player pjsonb_init(&jsonber); if (params->track) { - pjson_enter_object(&jsonber, "track"); + pjsonb_enter_object(&jsonber, "track"); if (params->track->encoded) pjsonb_set_string(&jsonber, "encoded", params->track->encoded); if (params->track->identifier) pjsonb_set_string(&jsonber, "identifier", params->track->identifier); if (params->track->userData) pjsonb_set_string(&jsonber, "userData", params->track->userData); - pjson_leave_object(&jsonber); + pjsonb_leave_object(&jsonber); } if (params->position) { @@ -377,77 +389,77 @@ int coglink_update_player(struct coglink_client *c_client, struct coglink_player } if (params->filters) { - pjson_enter_object(&jsonber, "filters"); + pjsonb_enter_object(&jsonber, "filters"); if (params->filters->volume) { pjsonb_set_int(&jsonber, "volume", params->filters->volume); } if (params->filters->equalizer) { - pjson_enter_array(&jsonber, "equalizer"); + pjsonb_enter_array(&jsonber, "equalizer"); for (size_t i = 0; i < 15; i++) { - pjson_enter_object(&jsonber, NULL); + pjsonb_enter_object(&jsonber, NULL); pjsonb_set_int(&jsonber, "band", params->filters->equalizer[i].band); pjsonb_set_int(&jsonber, "gain", params->filters->equalizer[i].gain); - pjson_leave_object(&jsonber); + pjsonb_leave_object(&jsonber); } - pjson_leave_array(&jsonber); + pjsonb_leave_array(&jsonber); } if (params->filters->karaoke) { - pjson_enter_object(&jsonber, "karaoke"); + pjsonb_enter_object(&jsonber, "karaoke"); pjsonb_set_int(&jsonber, "level", params->filters->karaoke->level); pjsonb_set_int(&jsonber, "monoLevel", params->filters->karaoke->monoLevel); pjsonb_set_int(&jsonber, "filterBand", params->filters->karaoke->filterBand); pjsonb_set_int(&jsonber, "filterWidth", params->filters->karaoke->filterWidth); - pjson_leave_object(&jsonber); + pjsonb_leave_object(&jsonber); } if (params->filters->timescale) { - pjson_enter_object(&jsonber, "timescale"); + pjsonb_enter_object(&jsonber, "timescale"); pjsonb_set_int(&jsonber, "speed", params->filters->timescale->speed); pjsonb_set_int(&jsonber, "pitch", params->filters->timescale->pitch); pjsonb_set_int(&jsonber, "rate", params->filters->timescale->rate); - pjson_leave_object(&jsonber); + pjsonb_leave_object(&jsonber); } if (params->filters->tremolo) { - pjson_enter_object(&jsonber, "tremolo"); + pjsonb_enter_object(&jsonber, "tremolo"); pjsonb_set_int(&jsonber, "frequency", params->filters->tremolo->frequency); pjsonb_set_int(&jsonber, "depth", params->filters->tremolo->depth); - pjson_leave_object(&jsonber); + pjsonb_leave_object(&jsonber); } if (params->filters->vibrato) { - pjson_enter_object(&jsonber, "vibrato"); + pjsonb_enter_object(&jsonber, "vibrato"); pjsonb_set_int(&jsonber, "frequency", params->filters->vibrato->frequency); pjsonb_set_int(&jsonber, "depth", params->filters->vibrato->depth); - pjson_leave_object(&jsonber); + pjsonb_leave_object(&jsonber); } if (params->filters->rotation) { - pjson_enter_object(&jsonber, "rotation"); + pjsonb_enter_object(&jsonber, "rotation"); pjsonb_set_int(&jsonber, "frequency", params->filters->rotation->frequency); pjsonb_set_int(&jsonber, "depth", params->filters->rotation->depth); - pjson_leave_object(&jsonber); + pjsonb_leave_object(&jsonber); } if (params->filters->distortion) { - pjson_enter_object(&jsonber, "distortion"); + pjsonb_enter_object(&jsonber, "distortion"); pjsonb_set_int(&jsonber, "sinOffset", params->filters->distortion->sinOffset); pjsonb_set_int(&jsonber, "sinScale", params->filters->distortion->sinScale); @@ -458,29 +470,29 @@ int coglink_update_player(struct coglink_client *c_client, struct coglink_player pjsonb_set_int(&jsonber, "offset", params->filters->distortion->offset); pjsonb_set_int(&jsonber, "scale", params->filters->distortion->scale); - pjson_leave_object(&jsonber); + pjsonb_leave_object(&jsonber); } if (params->filters->channelMix) { - pjson_enter_object(&jsonber, "channelMix"); + pjsonb_enter_object(&jsonber, "channelMix"); pjsonb_set_int(&jsonber, "leftToLeft", params->filters->channelMix->leftToLeft); pjsonb_set_int(&jsonber, "leftToRight", params->filters->channelMix->leftToRight); pjsonb_set_int(&jsonber, "rightToLeft", params->filters->channelMix->rightToLeft); pjsonb_set_int(&jsonber, "rightToRight", params->filters->channelMix->rightToRight); - pjson_leave_object(&jsonber); + pjsonb_leave_object(&jsonber); } if (params->filters->lowPass) { - pjson_enter_object(&jsonber, "lowPass"); + pjsonb_enter_object(&jsonber, "lowPass"); pjsonb_set_int(&jsonber, "smoothing", params->filters->lowPass->smoothing); - pjson_leave_object(&jsonber); + pjsonb_leave_object(&jsonber); } - pjson_leave_object(&jsonber); + pjsonb_leave_object(&jsonber); } pjsonb_end(&jsonber); @@ -495,10 +507,7 @@ int coglink_update_player(struct coglink_client *c_client, struct coglink_player .get_response = true }, &res); - int status = COGLINK_SUCCESS; - - if (response) - status = coglink_parse_update_player(response, res.body, res.size); + int status = coglink_parse_update_player(response, res.body, res.size); free(res.body); pjsonb_free(&jsonber); @@ -547,14 +556,14 @@ int coglink_get_node_info(struct coglink_client *c_client, struct coglink_node * .get_response = true }, &res); - coglink_parse_node_info(info, res.body, res.size); + int status = coglink_parse_node_info(info, res.body, res.size); free(res.body); - return COGLINK_SUCCESS; + return status; } -int coglink_get_node_version(struct coglink_client *c_client, struct coglink_node *node, char **version) { +int coglink_get_node_version(struct coglink_client *c_client, struct coglink_node *node, struct coglink_node_version *version) { (void) c_client; /* Standard */ char endpoint[(sizeof("/version") - 1) + 1]; @@ -571,19 +580,14 @@ int coglink_get_node_version(struct coglink_client *c_client, struct coglink_nod .unversioned = true }, &res); - *version = malloc((res.size + 1) * sizeof(char)); - strcpy(*version, res.body); + int status = coglink_parse_version(version, res.body, res.size); free(res.body); - return COGLINK_SUCCESS; -} - -void coglink_free_node_version(char *version) { - free(version); + return status; } -int coglink_get_stats(struct coglink_client *c_client, struct coglink_node *node, struct coglink_stats_payload *stats) { +int coglink_get_stats(struct coglink_client *c_client, struct coglink_node *node, struct coglink_stats *stats) { (void) c_client; /* Standard */ char endpoint[(sizeof("/stats") - 1) + 1]; @@ -599,11 +603,11 @@ int coglink_get_stats(struct coglink_client *c_client, struct coglink_node *node .get_response = true }, &res); - coglink_parse_stats(stats, res.body, res.size); + int status = coglink_parse_stats(stats, res.body, res.size); free(res.body); - return COGLINK_SUCCESS; + return status; } /* todo: support tunnelbroker endpoints (?) */ \ No newline at end of file diff --git a/lib/utils.c b/lib/utils.c index 3a10c21..0bf55a6 100644 --- a/lib/utils.c +++ b/lib/utils.c @@ -31,21 +31,26 @@ size_t _coglink_fake_write_cb(void *data, size_t size, size_t nmemb, void *userp return size * nmemb; } -int _coglink_perform_request(struct coglink_node *nodeInfo, struct coglink_request_params *req, struct coglink_response *res) { +int _coglink_perform_request(struct coglink_node *node_info, struct coglink_request_params *req, struct coglink_response *res) { CURL *curl = curl_easy_init(); - size_t url_size = (nodeInfo->ssl ? 1 : 0) + (sizeof("http://:") - 1) + (req->unversioned ? 0 : (sizeof("/v4") - 1)) + strlen(nodeInfo->hostname) + 4 + strlen(req->endpoint); + size_t url_size = (node_info->ssl ? 1 : 0) + (sizeof("http://:") - 1) + (req->unversioned ? 0 : (sizeof("/v4") - 1)) + strlen(node_info->hostname) + 4 + strlen(req->endpoint); char *full_url = malloc(url_size + 1); - url_size = snprintf(full_url, url_size + 1, "http%s://%s:%d/v4%s", nodeInfo->ssl ? "s" : "", nodeInfo->hostname, nodeInfo->port, req->endpoint); + + if (req->unversioned) { + url_size = snprintf(full_url, url_size + 1, "http%s://%s:%d%s", node_info->ssl ? "s" : "", node_info->hostname, node_info->port, req->endpoint); + } else { + url_size = snprintf(full_url, url_size + 1, "http%s://%s:%d/v4%s", node_info->ssl ? "s" : "", node_info->hostname, node_info->port, req->endpoint); + } CURLcode c_res = curl_easy_setopt(curl, CURLOPT_URL, full_url); struct curl_slist *chunk = NULL; char *authorization = NULL; - if (nodeInfo->password) { - authorization = malloc(17 + strlen(nodeInfo->password) + 1); - snprintf(authorization, 17 + strlen(nodeInfo->password) + 1, "Authorization: %s", nodeInfo->password); + if (node_info->password) { + authorization = malloc(17 + strlen(node_info->password) + 1); + snprintf(authorization, 17 + strlen(node_info->password) + 1, "Authorization: %s", node_info->password); chunk = curl_slist_append(chunk, authorization); } diff --git a/lib/websocket.c b/lib/websocket.c index 43de548..297e592 100644 --- a/lib/websocket.c +++ b/lib/websocket.c @@ -58,7 +58,7 @@ void _ws_on_text(void *data, struct websockets *ws, struct ws_info *info, const switch (type) { case COGLINK_READY: { - struct coglink_ready_payload *ready = payload; + struct coglink_ready *ready = payload; c_info->c_client->nodes->array[c_info->node_id].session_id = ready->session_id; @@ -67,7 +67,7 @@ void _ws_on_text(void *data, struct websockets *ws, struct ws_info *info, const break; } case COGLINK_PLAYER_UPDATE: { - struct coglink_player_update_payload *player_update = payload; + struct coglink_player_update *player_update = payload; if (c_info->c_client->events->on_player_update) c_info->c_client->events->on_player_update(player_update); @@ -76,7 +76,7 @@ void _ws_on_text(void *data, struct websockets *ws, struct ws_info *info, const break; } case COGLINK_STATS: { - struct coglink_stats_payload *stats = payload; + struct coglink_stats *stats = payload; if (c_info->c_client->events->on_stats) c_info->c_client->events->on_stats(stats); @@ -87,7 +87,7 @@ void _ws_on_text(void *data, struct websockets *ws, struct ws_info *info, const break; } case COGLINK_TRACK_START: { - struct coglink_track_start_payload *track_start = payload; + struct coglink_track_start *track_start = payload; if (c_info->c_client->events->on_track_start) c_info->c_client->events->on_track_start(track_start); @@ -96,7 +96,7 @@ void _ws_on_text(void *data, struct websockets *ws, struct ws_info *info, const break; } case COGLINK_TRACK_END: { - struct coglink_track_end_payload *track_end = payload; + struct coglink_track_end *track_end = payload; struct coglink_player *player = coglink_get_player(c_info->c_client, track_end->guildId); @@ -132,7 +132,7 @@ void _ws_on_text(void *data, struct websockets *ws, struct ws_info *info, const break; } case COGLINK_TRACK_EXCEPTION: { - struct coglink_track_exception_payload *track_exception = payload; + struct coglink_track_exception *track_exception = payload; if (c_info->c_client->events->on_track_excetion) c_info->c_client->events->on_track_excetion(track_exception); @@ -144,7 +144,7 @@ void _ws_on_text(void *data, struct websockets *ws, struct ws_info *info, const break; } case COGLINK_TRACK_STUCK: { - struct coglink_track_stuck_payload *track_stuck = (struct coglink_track_stuck_payload *)payload; + struct coglink_track_stuck *track_stuck = (struct coglink_track_stuck *)payload; if (c_info->c_client->events->on_track_stuck) c_info->c_client->events->on_track_stuck(track_stuck); @@ -153,7 +153,7 @@ void _ws_on_text(void *data, struct websockets *ws, struct ws_info *info, const break; } case COGLINK_WEBSOCKET_CLOSED: { - struct coglink_websocket_closed_payload *websocket_closed = payload; + struct coglink_websocket_closed *websocket_closed = payload; if (c_info->c_client->events->on_websocket_closed) c_info->c_client->events->on_websocket_closed(websocket_closed); @@ -171,7 +171,7 @@ enum discord_event_scheduler _coglink_handle_scheduler(struct discord *client, c switch (event) { case DISCORD_EV_VOICE_STATE_UPDATE: { - struct coglink_voice_state voice_state; + struct coglink_voice_state voice_state = { 0 }; if (coglink_parse_voice_state(data, length, &voice_state) == COGLINK_FAILED) return DISCORD_EVENT_MAIN_THREAD; @@ -179,17 +179,11 @@ enum discord_event_scheduler _coglink_handle_scheduler(struct discord *client, c if (c_client->bot_id == voice_state.user_id) { struct coglink_player *player = coglink_get_player(c_client, voice_state.guild_id); - if (player == NULL) { - coglink_free_voice_state(&voice_state); - - break; - } + if (player == NULL) break; player->voice_data = malloc(sizeof(struct coglink_player_voice_data)); /* todo: is it necessary after being sent to the node? */ player->voice_data->session_id = voice_state.session_id; - - coglink_free_voice_state(&voice_state); } else { size_t i = 0; @@ -197,8 +191,6 @@ enum discord_event_scheduler _coglink_handle_scheduler(struct discord *client, c if (c_client->users->array[i].id == 0) { c_client->users->array[i].channel_id = voice_state.channel_id; - coglink_free_voice_state(&voice_state); - break; } @@ -209,8 +201,6 @@ enum discord_event_scheduler _coglink_handle_scheduler(struct discord *client, c c_client->users->array[c_client->users->size].id = voice_state.user_id; c_client->users->array[c_client->users->size].channel_id = voice_state.channel_id; c_client->users->size++; - - coglink_free_voice_state(&voice_state); } } else { size_t i = 0; @@ -220,21 +210,17 @@ enum discord_event_scheduler _coglink_handle_scheduler(struct discord *client, c c_client->users->array[i].id = 0; c_client->users->array[i].channel_id = 0; - coglink_free_voice_state(&voice_state); - return DISCORD_EVENT_MAIN_THREAD; } i++; } - - coglink_free_voice_state(&voice_state); } break; } case DISCORD_EV_VOICE_SERVER_UPDATE: { - struct coglink_voice_server_update voice_server_update; + struct coglink_voice_server_update voice_server_update = { 0 }; if (coglink_parse_voice_server_update(data, length, &voice_server_update) == COGLINK_FAILED) return DISCORD_EVENT_MAIN_THREAD;