summaryrefslogtreecommitdiff
path: root/src/github.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/github.c')
-rw-r--r--src/github.c290
1 files changed, 0 insertions, 290 deletions
diff --git a/src/github.c b/src/github.c
deleted file mode 100644
index 38c28a0..0000000
--- a/src/github.c
+++ /dev/null
@@ -1,290 +0,0 @@
-//
-// Created by Anshul Gupta on 4/4/25.
-//
-
-#include "github.h"
-
-#include <stddef.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <cjson/cJSON.h>
-#include <curl/curl.h>
-
-#include "queries/identity.h"
-#include "queries/list_repos.h"
-
-#include "buffer.h"
-#include "github_types.h"
-
-struct gh_impl {
- struct github_ctx ctx;
- CURL *curl;
-};
-
-static CURLcode gh_impl_send(const struct gh_impl *client, const char *query,
- cJSON *args, buffer_t *buf);
-
-static int gh_handle_error(const cJSON *root);
-
-github_client *github_client_new(const struct github_ctx ctx)
-{
- struct gh_impl *c = malloc(sizeof(*c));
- if (!c)
- return NULL;
-
- c->ctx.endpoint = strdup(ctx.endpoint);
- c->ctx.token = strdup(ctx.token);
- c->ctx.user_agent = strdup(ctx.user_agent);
- c->curl = curl_easy_init();
- return c;
-}
-
-github_client *github_client_dup(github_client *client)
-{
- struct gh_impl *c = client;
- if (!c)
- return NULL;
-
- struct gh_impl *dup = malloc(sizeof(*dup));
- if (!dup)
- return NULL;
-
- dup->ctx.endpoint = strdup(c->ctx.endpoint);
- dup->ctx.token = strdup(c->ctx.token);
- dup->ctx.user_agent = strdup(c->ctx.user_agent);
- dup->curl = curl_easy_duphandle(c->curl);
-
- return dup;
-}
-
-void github_client_free(github_client *client)
-{
- struct gh_impl *c = client;
- if (!c)
- return;
- curl_easy_cleanup(c->curl);
- free((char *) c->ctx.endpoint);
- free((char *) c->ctx.token);
- free((char *) c->ctx.user_agent);
- free(c);
-}
-
-char *github_client_identity(const github_client *client)
-{
- char *login = NULL;
- const struct gh_impl *c = client;
- buffer_t buf = buffer_new(4096);
-
- const CURLcode ret = gh_impl_send(c, 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 (gh_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_client_list_user_repos(const github_client *client,
- const char *username, const char *after,
- struct list_repos_res *res)
-{
- int status = 0;
- const struct gh_impl *c = client;
- 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 = gh_impl_send(c, 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 (gh_handle_error(root) < 0) {
- status = -1;
- goto end;
- }
-
- // Convert json to struct
- if (list_repos_from_json(root, res) < 0) {
- fprintf(stderr, "Failed to parse response\n");
- status = -1;
- }
-
-end:
- buffer_free(buf);
- return status;
-}
-
-/**
- * Wraps the query in a JSON object with a "query" key and an optional
- * "variables" key
- * @param query GraphQL query
- * @param args GraphQL arguments
- * @return JSON string
- */
-static char *wrap_query(const char *query, cJSON *args)
-{
- cJSON *root = NULL, *query_str = NULL;
- char *str = NULL;
-
- root = cJSON_CreateObject();
- if (!root)
- return NULL;
-
- query_str = cJSON_CreateString(query);
- if (!query_str)
- goto end;
-
- // Transfer ownership of the string to root
- cJSON_AddItemToObject(root, "query", query_str);
-
- // Add the args object if it exists
- if (args)
- cJSON_AddItemToObject(root, "variables", args);
-
- str = cJSON_Print(root);
-end:
- cJSON_Delete(root);
- return str;
-}
-
-static size_t write_data(const void *ptr, const size_t size, size_t nmemb,
- void *stream)
-{
- (void) size; // unused
-
- buffer_t *buf = stream;
- buffer_append(buf, ptr, nmemb);
- return nmemb;
-}
-
-/**
- * Send a GraphQL query to the GitHub API
- * @param client Github Client
- * @param query GraphQL query
- * @return CURLcode
- */
-static CURLcode gh_impl_send(const struct gh_impl *client, const char *query,
- cJSON *args, buffer_t *buf)
-{
- struct curl_slist *headers = NULL;
- char auth[1024];
-
- // Set the URL
- curl_easy_setopt(client->curl, CURLOPT_URL, client->ctx.endpoint);
-
- // Set the authorization header
- snprintf(auth, sizeof(auth), "Authorization: bearer %s",
- client->ctx.token);
- headers = curl_slist_append(headers, auth);
- // Set the content type to JSON
- headers = curl_slist_append(headers, "Content-Type: application/json");
- curl_easy_setopt(client->curl, CURLOPT_HTTPHEADER, headers);
-
- // Set user agent
- curl_easy_setopt(client->curl, CURLOPT_USERAGENT,
- client->ctx.user_agent);
-
- // Set the request type to POST
- curl_easy_setopt(client->curl, CURLOPT_CUSTOMREQUEST, "POST");
-
- // Prepare request body
- char *wrapped_query = wrap_query(query, args);
-
- // Set the request body
- curl_easy_setopt(client->curl, CURLOPT_POSTFIELDS, wrapped_query);
- curl_easy_setopt(client->curl, CURLOPT_POSTFIELDSIZE,
- strlen(wrapped_query));
-
- // Set the write function to capture the response
- curl_easy_setopt(client->curl, CURLOPT_WRITEFUNCTION, write_data);
- curl_easy_setopt(client->curl, CURLOPT_WRITEDATA, (void *) buf);
-
- // Perform the request
- const CURLcode ret = curl_easy_perform(client->curl);
-
- // Append null terminator to the buffer
- if (ret == CURLE_OK)
- buffer_append(buf, "\0", 1);
-
- // Cleanup
- free(wrapped_query);
- curl_slist_free_all(headers);
-
- return ret;
-}
-
-/**
- * Handle errors in the response.
- * Will check for the "errors" key in the response and print the error messages.
- * Returns failure if any errors are found.
- * @param root Parsed JSON response
- * @return 0 on success (no errors), -1 on failure
- */
-static int gh_handle_error(const cJSON *root)
-{
- // Check for errors
- cJSON *errors = cJSON_GetObjectItemCaseSensitive(root, "errors");
- if (!errors || !cJSON_IsArray(errors)) {
- // No errors
- return 0;
- }
-
- cJSON *err;
- cJSON_ArrayForEach(err, errors)
- {
- // Get the error message
- cJSON *message = cJSON_GetObjectItemCaseSensitive(err,
- "message");
- if (message && cJSON_IsString(message)) {
- fprintf(stderr, "Github Error: %s\n",
- message->valuestring);
- } else {
- fprintf(stderr, "Github Error: Unknown error\n");
- }
- }
-
- return -1;
-}