diff options
Diffstat (limited to 'src/github')
-rw-r--r-- | src/github/client.c | 100 | ||||
-rw-r--r-- | src/github/client.h | 17 | ||||
-rw-r--r-- | src/github/types.c | 160 | ||||
-rw-r--r-- | src/github/types.h | 29 |
4 files changed, 306 insertions, 0 deletions
diff --git a/src/github/client.c b/src/github/client.c new file mode 100644 index 0000000..0c0034e --- /dev/null +++ b/src/github/client.c @@ -0,0 +1,100 @@ +// +// Created by Anshul Gupta on 4/4/25. +// + +#include "client.h" + +#include <stdlib.h> + +#include <cjson/cJSON.h> +#include <curl/curl.h> + +#include "queries/github/gh_identity.h" +#include "queries/github/gh_list_repos.h" + +#include "../buffer.h" +#include "types.h" + +char *github_identity(const gql_client *client) +{ + char *login = NULL; + buffer_t buf = buffer_new(4096); + + const CURLcode ret = gql_client_send(client, gh_identity, NULL, &buf); + if (ret != CURLE_OK) { + fprintf(stderr, "Failed to send request: %s\n", + curl_easy_strerror(ret)); + goto fail; + } + + // Parse the response + cJSON *root = cJSON_Parse((const char *) buf.data); + if (!root) { + const char *err = cJSON_GetErrorPtr(); + if (err) + fprintf(stderr, "Error parsing response: %s\n", err); + goto fail; + } + + // Check for errors + if (gql_handle_error(root) < 0) + goto fail1; + + // Get login from json + login = identity_from_json(root); + +fail1: + cJSON_Delete(root); +fail: + buffer_free(buf); + return login; +} + +int github_list_user_repos(const gql_client *client, const char *username, + const char *after, struct gh_list_repos_res *res) +{ + int status = 0; + buffer_t buf = buffer_new(4096); + + cJSON *args = cJSON_CreateObject(); + if (!args) { + status = -1; + goto end; + } + cJSON_AddItemToObject(args, "username", cJSON_CreateString(username)); + cJSON_AddItemToObject(args, "after", cJSON_CreateString(after)); + + const CURLcode ret = gql_client_send(client, gh_list_repos, args, &buf); + if (ret != CURLE_OK) { + fprintf(stderr, "Failed to send request: %s\n", + curl_easy_strerror(ret)); + status = -1; + goto end; + } + + // Parse the response + cJSON *root = cJSON_Parse((const char *) buf.data); + if (!root) { + const char *err = cJSON_GetErrorPtr(); + if (err) + fprintf(stderr, "Error parsing response: %s\n", err); + status = -1; + goto end; + } + + // Check for errors + if (gql_handle_error(root) < 0) { + status = -1; + goto end; + } + + // Convert json to struct + if (gh_list_repos_from_json(root, res) < 0) { + fprintf(stderr, "Failed to parse response\n"); + status = -1; + } + +end: + buffer_free(buf); + return status; +} diff --git a/src/github/client.h b/src/github/client.h new file mode 100644 index 0000000..723c24c --- /dev/null +++ b/src/github/client.h @@ -0,0 +1,17 @@ +// +// Created by Anshul Gupta on 4/4/25. +// + +#ifndef GITHUB_CLIENT_H +#define GITHUB_CLIENT_H + +#include "../client.h" + +#include "types.h" + +char *github_identity(const gql_client *client); + +int github_list_user_repos(const gql_client *client, const char *username, + const char *after, struct gh_list_repos_res *res); + +#endif // GITHUB_CLIENT_H diff --git a/src/github/types.c b/src/github/types.c new file mode 100644 index 0000000..ce9441e --- /dev/null +++ b/src/github/types.c @@ -0,0 +1,160 @@ +// +// Created by Anshul Gupta on 4/4/25. +// + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <cjson/cJSON.h> + +#include "types.h" + + +char *identity_from_json(const cJSON *root) +{ + cJSON *data = cJSON_GetObjectItemCaseSensitive(root, "data"); + if (!data || !cJSON_IsObject(data)) { + fprintf(stderr, "Error: data object not found\n"); + return NULL; + } + cJSON *viewer = cJSON_GetObjectItemCaseSensitive(data, "viewer"); + if (!viewer || !cJSON_IsObject(viewer)) { + fprintf(stderr, "Error: viewer object not found\n"); + return NULL; + } + cJSON *login = cJSON_GetObjectItemCaseSensitive(viewer, "login"); + if (!login || !cJSON_IsString(login)) { + fprintf(stderr, "Error: login not found\n"); + return NULL; + } + + return strdup(login->valuestring); +} + +int gh_list_repos_from_json(cJSON *root, struct gh_list_repos_res *res) +{ + int status = 0; + cJSON *repo; + + // Initialize the response structure + memset(res, 0, sizeof(*res)); + + // Get the data object + cJSON *data = cJSON_GetObjectItemCaseSensitive(root, "data"); + if (!data || !cJSON_IsObject(data)) { + fprintf(stderr, "Error: data object not found\n"); + status = -1; + goto end; + } + + // Get the repositoryOwner object + cJSON *repositoryOwner = cJSON_GetObjectItemCaseSensitive( + data, "repositoryOwner"); + if (!repositoryOwner || !cJSON_IsObject(repositoryOwner)) { + fprintf(stderr, "Error: repositoryOwner object not found\n"); + status = -1; + goto end; + } + + // Get the repositories object + cJSON *repositories = cJSON_GetObjectItemCaseSensitive(repositoryOwner, + "repositories"); + if (!repositories || !cJSON_IsObject(repositories)) { + fprintf(stderr, "Error: repositories object not found\n"); + status = -1; + goto end; + } + + // Get the pageInfo object + cJSON *page_info = cJSON_GetObjectItemCaseSensitive(repositories, + "pageInfo"); + if (!page_info || !cJSON_IsObject(page_info)) { + fprintf(stderr, "Error: pageInfo object not found\n"); + status = -1; + goto end; + } + + // Get the hasNextPage and endCursor values + cJSON *has_next_page = cJSON_GetObjectItemCaseSensitive(page_info, + "hasNextPage"); + if (!has_next_page || !cJSON_IsBool(has_next_page)) { + fprintf(stderr, "Error: hasNextPage not found\n"); + status = -1; + goto end; + } + res->has_next_page = cJSON_IsTrue(has_next_page); + + cJSON *end_cursor = cJSON_GetObjectItemCaseSensitive(page_info, + "endCursor"); + if (!end_cursor || !cJSON_IsString(end_cursor)) { + fprintf(stderr, "Error: endCursor not found\n"); + status = -1; + goto end; + } + res->end_cursor = strdup(end_cursor->valuestring); + + // Get the nodes array + cJSON *nodes = cJSON_GetObjectItemCaseSensitive(repositories, "nodes"); + if (!nodes || !cJSON_IsArray(nodes)) { + fprintf(stderr, "Error: nodes array not found\n"); + status = -1; + goto end; + } + + // Iterate over the nodes array + size_t len = cJSON_GetArraySize(nodes); + res->repos = malloc(sizeof(*res->repos) * len); + cJSON_ArrayForEach(repo, nodes) + { + cJSON *name = cJSON_GetObjectItemCaseSensitive(repo, "name"); + if (!name || !cJSON_IsString(name)) { + fprintf(stderr, "Error: name not found\n"); + status = -1; + goto end; + } + cJSON *url = cJSON_GetObjectItemCaseSensitive(repo, "url"); + if (!url || !cJSON_IsString(url)) { + fprintf(stderr, "Error: url not found\n"); + status = -1; + goto end; + } + cJSON *is_fork = cJSON_GetObjectItemCaseSensitive(repo, + "isFork"); + if (!is_fork || !cJSON_IsBool(is_fork)) { + fprintf(stderr, "Error: isFork not found\n"); + status = -1; + goto end; + } + cJSON *is_private = cJSON_GetObjectItemCaseSensitive( + repo, "isPrivate"); + if (!is_private || !cJSON_IsBool(is_private)) { + fprintf(stderr, "Error: isPrivate not found\n"); + status = -1; + goto end; + } + + res->repos[res->repos_len].name = strdup(name->valuestring); + res->repos[res->repos_len].url = strdup(url->valuestring); + res->repos[res->repos_len].is_fork = cJSON_IsTrue(is_fork); + res->repos[res->repos_len].is_private = + cJSON_IsTrue(is_private); + res->repos_len++; + } + +end: + cJSON_Delete(root); + if (status != 0) + gh_list_repos_res_free(*res); + return status; +} + +void gh_list_repos_res_free(struct gh_list_repos_res res) +{ + free(res.end_cursor); + for (size_t i = 0; i < res.repos_len; i++) { + free(res.repos[i].name); + free(res.repos[i].url); + } + free(res.repos); +} diff --git a/src/github/types.h b/src/github/types.h new file mode 100644 index 0000000..dec3551 --- /dev/null +++ b/src/github/types.h @@ -0,0 +1,29 @@ +// +// Created by Anshul Gupta on 4/4/25. +// + +#ifndef GITHUB_TYPES_H +#define GITHUB_TYPES_H + +#include <cjson/cJSON.h> + +char *identity_from_json(const cJSON *root); + +struct gh_list_repos_res { + int has_next_page; + char *end_cursor; + + struct { + char *name; + char *url; + int is_fork; + int is_private; + } *repos; + + size_t repos_len; +}; + +int gh_list_repos_from_json(cJSON *root, struct gh_list_repos_res *res); +void gh_list_repos_res_free(struct gh_list_repos_res res); + +#endif // GITHUB_TYPES_H |