Mercurial
view postdog/main.c @ 113:7a4e942814bc
[MrJuneJune] Fixed static assets
| author | June Park <parkjune1995@gmail.com> |
|---|---|
| date | Sun, 04 Jan 2026 14:42:54 -0800 |
| parents | d6d578b49a19 |
| children | e2a73e64e8e6 |
line wrap: on
line source
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <time.h> #include <sys/stat.h> #include <dirent.h> #include "dowa/dowa.h" #include <curl/curl.h> #include "third_party/raylib/include/raylib.h" #define RAYGUI_IMPLEMENTATION #include "third_party/raylib/include/raygui.h" #define SCREEN_WIDTH 1280 #define SCREEN_HEIGHT 780 #define TEXT_SIZE 10 #define JSON_INPUT_BUFFER_LEN 8192 #define HEADER_INPUT_BUFFER_LEN 4096 #define PARAM_INPUT_BUFFER_LEN 4096 #define MAX_HISTORY_ITEMS 100 #define HEADER_BUFFER_LENGTH 1024 * 4 #define DEFAULT_TEXT_BUFFER_LENGTH 1024 * 4 #define URL_TEXT_BUFFER 1024 * 10 #define BODY_BUFFER_LENGTH 1024 * 1025 * 5 #define RESULT_BUFFER_LENGTH 1024 * 1025 * 5 #define AREANA_BUFFER_LENGTH 1024 * 1025 * 15 typedef Dowa_KV(char*, char*) INPUT_HASHMAP; typedef struct { char *data; size_t size; } ResponseBuffer; typedef struct { char filename[256]; char displayName[128]; char method[16]; time_t timestamp; } HistoryItem; char *PostDog_Enum_To_String(int active_enum) { switch(active_enum) { case 0: return "GET"; case 1: return "POST"; case 2: return "PUT"; case 3: return "DELETE"; } } static size_t Postdog_Curl_Callback(void *contents, size_t size, size_t nmemb, void *userp) { size_t real_size = size * nmemb; ResponseBuffer *buf = (ResponseBuffer *)userp; char *ptr = realloc(buf->data, buf->size + real_size + 1); if (ptr == NULL) { printf("Not enough memory for response\n"); return 0; } buf->data = ptr; memcpy(&(buf->data[buf->size]), contents, real_size); buf->size += real_size; buf->data[buf->size] = 0; return real_size; } int PostDog_Make_HttpRequest( const char *url, const char *method, const char *headers, const char *body, char *response, size_t responseSize) { CURL *curl; CURLcode res; ResponseBuffer buffer = { .data = malloc(1), .size = 0 }; response[0] = '\n'; if (buffer.data == NULL) { snprintf(response, responseSize, "Error: Failed to allocate memory"); return -1; } buffer.data[0] = '\0'; curl_global_init(CURL_GLOBAL_DEFAULT); curl = curl_easy_init(); if (curl) { struct curl_slist *headerList = NULL; // Set URL curl_easy_setopt(curl, CURLOPT_URL, url); // Set HTTP method if (strcmp(method, "POST") == 0) { curl_easy_setopt(curl, CURLOPT_POST, 1L); if (body && strlen(body) > 0) { curl_easy_setopt(curl, CURLOPT_POSTFIELDS, body); } } else if (strcmp(method, "PUT") == 0) { curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "PUT"); if (body && strlen(body) > 0) { curl_easy_setopt(curl, CURLOPT_POSTFIELDS, body); } } else if (strcmp(method, "DELETE") == 0) { curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "DELETE"); } // Default is GET // Parse and add headers if (headers && strlen(headers) > 0) { char *headersCopy = strdup(headers); char *line = strtok(headersCopy, "\n"); while (line != NULL) { // Trim whitespace while (*line == ' ' || *line == '\t') line++; if (strlen(line) > 0) { headerList = curl_slist_append(headerList, line); } line = strtok(NULL, "\n"); } curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headerList); free(headersCopy); } // Set write callback curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, Postdog_Curl_Callback); curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&buffer); // Follow redirects curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L); // Set timeout curl_easy_setopt(curl, CURLOPT_TIMEOUT, 30L); // Perform request res = curl_easy_perform(curl); if (res != CURLE_OK) snprintf(response, responseSize, "Error: %s\n", curl_easy_strerror(res)); else { long response_code; curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code); snprintf(response, responseSize, "HTTP Status: %ld\n\n%s", response_code, buffer.data ? buffer.data : ""); } // Cleanup if (headerList) curl_slist_free_all(headerList); curl_easy_cleanup(curl); } else { snprintf(response, responseSize, "Error: Failed to initialize curl"); } free(buffer.data); curl_global_cleanup(); return 0; } typedef struct { Rectangle rectangle; char *label; bool active; } TabItem; typedef enum { TAB_HEADER = 0, TAB_BODY, TAB_GET_PARAMS, TAB_BAR, } PostDog_Tab_Enum; void PostDog_Update_URL(char **p_url_input_text, char* get_params) { char *url_input_text = *p_url_input_text; // Reset char *question_mark = strchr(url_input_text, '?'); if (question_mark) *question_mark = '\0'; int get_params_length = (int)strlen(get_params) ; if (get_params_length == 0) return; char *separator = "?"; Dowa_Arena *arena = Dowa_Arena_Create(1024*1024); char **lines = Dowa_String_Split(get_params, "\n", get_params_length, 1, arena); size_t url_len = strlen(url_input_text); size_t url_capacity = URL_TEXT_BUFFER; for (int i = 0; i < Dowa_Array_Length(lines); i++) { char *line = lines[i]; char **key_value = Dowa_String_Split(line, " ", (int)strlen(line), 1, arena); if (Dowa_Array_Length(key_value) < 2) continue; // Skip this line, not break entire loop // Check buffer capacity before each append size_t needed = url_len + strlen(separator) + strlen(key_value[0]) + 1 + 10; // +10 for "=" and safety if (needed >= url_capacity) break; strcat(url_input_text, separator); strcat(url_input_text, key_value[0]); strcat(url_input_text, "="); url_len = strlen(url_input_text); for (int i = 1; i < Dowa_Array_Length(key_value); i++) { if (!key_value[i] || key_value[i][0] == '\0') break; size_t value_len = strlen(key_value[i]); needed = url_len + value_len + 4; // +4 for "%20" if needed if (needed >= url_capacity) break; printf("\n\n------\n\n"); printf("key_value[%i]: %s, p = %p\n", i, key_value[i], key_value[i]); printf("\n\n------\n\n"); if (i > 1) strcat(url_input_text, "%20"); strcat(url_input_text, key_value[i]); url_len = strlen(url_input_text); } separator = "&"; } Dowa_Arena_Free(arena); } int main() { // -- initizlied --// InitWindow(SCREEN_WIDTH, SCREEN_HEIGHT, "PostDog"); SetWindowState(FLAG_WINDOW_RESIZABLE); SetTargetFPS(60); Dowa_Arena *arena = Dowa_Arena_Create(AREANA_BUFFER_LENGTH); // -- Starting pos ---// float side_bar_x = 10; float side_bar_y = 10; Rectangle history_sidebar = { .x = side_bar_x, .y = side_bar_y, .width = 0, .height = 0 }; Rectangle url_area = { 0 }; Rectangle textBounds = { 0 }; Rectangle url_input_bounds = { 0 }; bool url_input_bool = false; Rectangle url_text_bounds = { 0 }; Rectangle url_enter_button = { 0 }; Rectangle method_dropdown = { 0 }; char *url_input_text = (char *)Dowa_Arena_Allocate(arena, URL_TEXT_BUFFER); snprintf(url_input_text, URL_TEXT_BUFFER, "https://httpbin.org/get"); INPUT_HASHMAP *url_body_map = NULL; Dowa_HashMap_Push_Arena(url_body_map, "Header", (char *)Dowa_Arena_Allocate(arena, HEADER_BUFFER_LENGTH), arena); Dowa_HashMap_Push_Arena(url_body_map, "Body", (char *)Dowa_Arena_Allocate(arena, BODY_BUFFER_LENGTH), arena); Dowa_HashMap_Push_Arena(url_body_map, "Get Param", (char *)Dowa_Arena_Allocate(arena, DEFAULT_TEXT_BUFFER_LENGTH), arena); Dowa_HashMap_Push_Arena(url_body_map, "Bar", (char *)Dowa_Arena_Allocate(arena, DEFAULT_TEXT_BUFFER_LENGTH), arena); snprintf(url_body_map[0].value, HEADER_BUFFER_LENGTH, "Content-Type: application/json"); snprintf(url_body_map[1].value, HEADER_BUFFER_LENGTH, ""); char *url_result_text = (char *)Dowa_Arena_Allocate(arena, RESULT_BUFFER_LENGTH); int active_method_dropdown = 0; bool method_edit = false; int sendRequest; // -- input --// Rectangle input_area = { 0 }; Rectangle input_tab = { 0 }; Rectangle input_tab_item = { 0 }; Rectangle input_body = { 0 }; bool input_body_bool = false; // -- result --// Rectangle result_area = { 0 }; Rectangle result_body = { 0 }; // General styling. int padding = 10; // TODO make it % based? int active_input_tab = 0; while (!WindowShouldClose()) { int screen_width = GetScreenWidth(); int screen_height = GetScreenHeight(); history_sidebar.width = screen_width * 0.15; history_sidebar.height = screen_width - 10; // -- URL Area --// url_area.x = (side_bar_x + history_sidebar.width); url_area.y = (side_bar_y); url_area.width = (screen_width - history_sidebar.width) * 0.9; url_area.height = (screen_height) * 0.1; url_text_bounds.x = url_area.x + padding; url_text_bounds.y = (url_area.height) / 2; url_text_bounds.width = 7 * (TEXT_SIZE / 2); url_text_bounds.height = TEXT_SIZE * 2; url_input_bounds.x = url_text_bounds.x + url_text_bounds.width + padding; url_input_bounds.y = (url_area.height) / 2; url_input_bounds.width = (url_area.width - padding) * 0.7; url_input_bounds.height = TEXT_SIZE * 2; url_enter_button.x = url_input_bounds.x + url_input_bounds.width + padding; url_enter_button.y = (url_area.height) / 2; url_enter_button.width = (url_area.width - padding) * 0.1; url_enter_button.height = TEXT_SIZE * 2; method_dropdown.x = url_enter_button.x + url_enter_button.width + padding; method_dropdown.y = (url_area.height) / 2; method_dropdown.width = (url_area.width - padding) * 0.1; method_dropdown.height = TEXT_SIZE * 2; // -- Input Area --// input_area.x = (side_bar_x + history_sidebar.width); input_area.y = (side_bar_y + url_area.height); input_area.width = url_area.width * 0.5; input_area.height = screen_height - url_area.height; input_tab.x = (side_bar_x + history_sidebar.width) + padding; input_tab.y = (side_bar_y + url_area.height) + padding; input_tab.width = url_area.width * 0.49 - padding; input_tab.height = input_area.height * 0.1; input_tab_item = input_tab; input_tab_item.width = input_tab.width / 4; input_body.x = input_tab.x; input_body.y = input_tab.y + input_tab.height; input_body.width = url_area.width * 0.49 - padding; input_body.height = input_area.height - input_tab.height - padding; // -- Result Area --// result_area.x = (input_area.x + input_area.width); result_area.y = (side_bar_y + url_area.height); result_area.width = url_area.width * 0.49; result_area.height = screen_height - url_area.height; result_body.x = result_area.x + padding; result_body.y = result_area.y + input_tab.height + padding; result_body.width = url_area.width * 0.49 - padding; result_body.height = result_area.height - input_tab.height - padding; BeginDrawing(); ClearBackground(GetColor(GuiGetStyle(DEFAULT, BACKGROUND_COLOR))); // Sidebar Rect DrawRectangleRec(history_sidebar, Fade(GRAY, 0.1f)); // URL area Rect GuiDrawText("URL: ", url_text_bounds, TEXT_ALIGN_CENTER, RED); DrawRectangleRec(url_area, Fade(RED, 0.1f)); if (GuiTextBox(url_input_bounds, url_input_text, DEFAULT_TEXT_BUFFER_LENGTH, url_input_bool)) url_input_bool = !url_input_bool; sendRequest = GuiButton(url_enter_button, "ENTER"); if (sendRequest) PostDog_Make_HttpRequest( url_input_text, PostDog_Enum_To_String(active_method_dropdown), url_body_map[0].value, url_body_map[1].value, url_result_text, RESULT_BUFFER_LENGTH ); if (GuiDropdownBox(method_dropdown, "GET;POST;PUT;DELETE", &active_method_dropdown, method_edit)) method_edit = !method_edit; // Input Tabs Rect DrawRectangleRec(input_area, Fade(BLUE, 0.1f)); DrawRectangleRec(input_tab, Fade(DARKBLUE, 0.1f)); GuiSetStyle(TOGGLE, GROUP_PADDING, 0); if (JUNE_GuiTextBox(input_body, url_body_map[active_input_tab].value, DEFAULT_TEXT_BUFFER_LENGTH, input_body_bool)) input_body_bool = !input_body_bool; GuiToggleGroup(input_tab_item, "Header;Body;Get Param;Bar", &active_input_tab); PostDog_Update_URL(&url_input_text, url_body_map[TAB_GET_PARAMS].value); // Result Rect DrawRectangleRec(result_area, Fade(GREEN, 0.1f)); DrawRectangleRec(result_body, Fade(DARKGREEN, 0.1f)); GuiTextBoxMulti(result_body, url_result_text, RESULT_BUFFER_LENGTH, false); EndDrawing(); } CloseWindow(); return 0; }