summaryrefslogtreecommitdiff
path: root/src/github
diff options
context:
space:
mode:
Diffstat (limited to 'src/github')
-rw-r--r--src/github/client.c100
-rw-r--r--src/github/client.h17
-rw-r--r--src/github/types.c160
-rw-r--r--src/github/types.h29
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
='13' alt='Gravatar' /> Jarred Sumner 1-1/+1 2022-11-28Allow overriding node:fsGravatar Jarred Sumner 1-0/+9 2022-11-28Add test for processGravatar Jarred Sumner 1-3/+14 2022-11-28Fix process.env and Bun.env object spreadGravatar Jarred Sumner 8-204/+127 2022-11-27Fix `console.log(process.env)`Gravatar Jarred Sumner 2-20/+27