# HG changeset patch
# User June Park
# Date 1767404830 28800
# Node ID 655ea0b661fdc8dc6c45c2e759aeba65e381dfe8
# Parent 19cccf6e866a8d1c17986a6773ee4ed51e33b823
[Seobeo] Added few endpoints for handling files. [Dowa] Added few functions for random number and generating uuids
diff -r 19cccf6e866a -r 655ea0b661fd color_game/BUILD
--- a/color_game/BUILD Thu Jan 01 16:34:51 2026 -0800
+++ b/color_game/BUILD Fri Jan 02 17:47:10 2026 -0800
@@ -5,7 +5,7 @@
srcs = ["main.c"],
deps = [
"//third_party/raylib:raylib",
- "//dowa:dowa_generic",
+ "//dowa:dowa",
],
static = True
)
diff -r 19cccf6e866a -r 655ea0b661fd dowa/BUILD
--- a/dowa/BUILD Thu Jan 01 16:34:51 2026 -0800
+++ b/dowa/BUILD Fri Jan 02 17:47:10 2026 -0800
@@ -8,12 +8,12 @@
visibility = ["//visibility:public"],
)
-# TODO: Fix so that we can just define in the header instead of defining in the cc_library because this is ass.
cc_library(
- name = "dowa_generic",
+ name = "dowa",
srcs = [
"d_string.c",
"d_memory.c",
+ "d_math.c",
],
hdrs = [
"dowa.h",
@@ -22,20 +22,6 @@
visibility = ["//visibility:public"],
)
-cc_library(
- name = "dowa",
- srcs = [
- "d_string.c",
- "d_memory.c",
- ],
- hdrs = [
- "dowa.h",
- "dowa_internal.h",
- ],
- copts = ["-DDIRECTORY"],
- visibility = ["//visibility:public"],
-)
-
cc_test(
name = "dowa_test",
srcs = ["dowa_test.c"],
@@ -44,7 +30,6 @@
data = glob([
"test_folder/**",
]),
- # TODO: Fix this lmao?
copts = ["-fsanitize=address", "-g"],
linkopts = ["-fsanitize=address"],
)
diff -r 19cccf6e866a -r 655ea0b661fd dowa/d_math.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/dowa/d_math.c Fri Jan 02 17:47:10 2026 -0800
@@ -0,0 +1,13 @@
+#include "dowa.h"
+
+/* Thank you Eskil */
+uint32 Dowa_Math_Random_Uint32(uint32 seed_number)
+{
+ seed_number ^= seed_number << 13;
+ seed_number ^= seed_number >> 17;
+ seed_number ^= seed_number << 5;
+ return seed_number & 0x7fffffff;
+
+ //seed_number = (seed_number << 13) ^ seed_number;
+ //return ((seed_number * (seed_number * seed_number * 15731 + 789221) + 1376312589) & 0x7fffffff);
+}
diff -r 19cccf6e866a -r 655ea0b661fd dowa/d_memory.c
--- a/dowa/d_memory.c Thu Jan 01 16:34:51 2026 -0800
+++ b/dowa/d_memory.c Fri Jan 02 17:47:10 2026 -0800
@@ -1,5 +1,9 @@
#include "dowa.h"
+#ifndef DOWA_ALIGNMENT
+ #define DOWA_ALIGNMENT sizeof(void*) * 2
+#endif
+
// --- Arena --- //
Dowa_Arena *Dowa_Arena_Create(size_t capacity)
{
@@ -23,7 +27,7 @@
void *Dowa_Arena_Allocate(Dowa_Arena *p_arena, size_t size)
{
- return Dowa_Arena_Allocate_Aligned(p_arena, size, sizeof(void*) * 2);
+ return Dowa_Arena_Allocate_Aligned(p_arena, size, DOWA_ALIGNMENT);
}
void Dowa_Arena_Free(Dowa_Arena *p_arena)
@@ -85,9 +89,9 @@
return p_result;
}
-// --- NEW stb_ds-style Array Implementation --- //
+// --- Array Implementation --- //
-void* dowa__array_grow(void* p_array, size_t element_size, size_t minimum_capacity, Dowa_Arena* p_arena)
+void *dowa__array_grow(void* p_array, size_t element_size, size_t minimum_capacity, Dowa_Arena* p_arena)
{
Dowa_Array_Header* p_header;
size_t new_capacity;
@@ -109,7 +113,7 @@
current_capacity = 0;
}
- // Calculate needed capacity: if minimum_capacity is 0, we need room for at least one more element
+ // if minimum_capacity is 0, we need room for at least one more element
size_t needed_capacity = minimum_capacity;
if (p_array && needed_capacity == 0)
needed_capacity = p_header->length + 1;
@@ -127,9 +131,7 @@
if (p_arena)
{
- // Array header and data must be properly aligned
- size_t alignment = element_size >= 16 ? 16 : (element_size >= 8 ? 8 : element_size);
- Dowa_Array_Header* p_new_header = (Dowa_Array_Header*)Dowa_Arena_Allocate_Aligned(p_arena, total_size, alignment);
+ Dowa_Array_Header* p_new_header = (Dowa_Array_Header*)Dowa_Arena_Allocate_Aligned(p_arena, total_size, DOWA_ALIGNMENT);
if (!p_new_header)
return p_array;
@@ -191,7 +193,7 @@
free(p_header);
}
-// --- NEW stb_ds-style HashMap Implementation --- //
+// --- HashMap Implementation --- //
#define DOWA_HASH_EMPTY 0xFFFFFFFF
#define DOWA_HASH_TOMBSTONE 0xFFFFFFFE
@@ -219,7 +221,7 @@
return (Dowa_Hash_Index*)p_header->p_hash;
}
-static void* dowa__hashmap_find_slot(void* p_map, size_t element_size, void* p_key, size_t key_size, uint32 hash, boolean* p_found)
+static void *dowa__hashmap_find_slot(void *p_map, size_t element_size, void *p_key, size_t key_size, uint32 hash, boolean *p_found)
{
Dowa_Hash_Index* p_index = dowa__hashmap_get_index(p_map);
if (!p_index || !p_index->p_buckets)
@@ -247,11 +249,11 @@
if (p_bucket->hash[i] == hash && p_bucket->index[i] != DOWA_HASH_TOMBSTONE)
{
uint32 array_index = p_bucket->index[i];
- char* p_element = (char*)p_map + (array_index * element_size);
+ char *p_element = (char*)p_map + (array_index * element_size);
- char** p_stored_key_ptr = (char**)p_element;
- char* p_stored_key = *p_stored_key_ptr;
- char* p_search_key = (char*)p_key;
+ char **p_stored_key_ptr = (char**)p_element;
+ char *p_stored_key = *p_stored_key_ptr;
+ char *p_search_key = (char*)p_key;
if (memcmp(p_stored_key, p_search_key, key_size) == 0)
{
@@ -272,7 +274,7 @@
return NULL;
}
-void* dowa__hashmap_get_ptr(void* p_map, size_t element_size, void* p_key, size_t key_size)
+void *dowa__hashmap_get_ptr(void *p_map, size_t element_size, void *p_key, size_t key_size)
{
if (!p_map)
return NULL;
@@ -284,21 +286,21 @@
return found ? p_result : NULL;
}
-void* dowa__hashmap_get(void* p_map, size_t element_size, void* p_key, size_t key_size)
+void *dowa__hashmap_get(void *p_map, size_t element_size, void *p_key, size_t key_size)
{
- void* p_kv = dowa__hashmap_get_ptr(p_map, element_size, p_key, key_size);
+ void *p_kv = dowa__hashmap_get_ptr(p_map, element_size, p_key, key_size);
if (!p_kv)
return NULL;
return (char*)p_kv + key_size;
}
-boolean dowa__hashmap_has_key(void* p_map, size_t element_size, void* p_key, size_t key_size)
+boolean dowa__hashmap_has_key(void *p_map, size_t element_size, void *p_key, size_t key_size)
{
return dowa__hashmap_get_ptr(p_map, element_size, p_key, key_size) != NULL;
}
-static void* dowa__hashmap_rehash(void* p_map, size_t element_size, size_t new_bucket_count, Dowa_Arena* p_arena)
+static void* dowa__hashmap_rehash(void *p_map, size_t element_size, size_t new_bucket_count, Dowa_Arena* p_arena)
{
Dowa_Hash_Index* p_old_index = dowa__hashmap_get_index(p_map);
if (!p_old_index)
@@ -397,7 +399,7 @@
return p_map;
}
-void* dowa__hashmap_push(void* p_map, size_t element_size, void* p_key, size_t key_size, Dowa_Arena* p_arena)
+void *dowa__hashmap_push(void *p_map, size_t element_size, void *p_key, size_t key_size, Dowa_Arena* p_arena)
{
uint32 hash = dowa__hash_bytes(p_key, key_size);
@@ -541,7 +543,7 @@
return p_map;
}
-void dowa__hashmap_delete(void* p_map, size_t element_size, void* p_key, size_t key_size)
+void dowa__hashmap_delete(void *p_map, size_t element_size, void *p_key, size_t key_size)
{
if (!p_map)
return;
@@ -592,7 +594,7 @@
}
}
-void dowa__hashmap_clear(void* p_map, size_t element_size)
+void dowa__hashmap_clear(void *p_map, size_t element_size)
{
if (!p_map)
return;
@@ -616,7 +618,7 @@
}
}
-void dowa__hashmap_free(void* p_map)
+void dowa__hashmap_free(void *p_map)
{
if (!p_map)
return;
@@ -632,7 +634,7 @@
dowa__array_free(p_map);
}
-size_t dowa__hashmap_count(void* p_map)
+size_t dowa__hashmap_count(void *p_map)
{
if (!p_map)
return 0;
diff -r 19cccf6e866a -r 655ea0b661fd dowa/d_string.c
--- a/dowa/d_string.c Thu Jan 01 16:34:51 2026 -0800
+++ b/dowa/d_string.c Fri Jan 02 17:47:10 2026 -0800
@@ -141,7 +141,29 @@
{
char *buffer = Dowa_Arena_Allocate(p_arena, sizeof(char*) * strlen(from) + 1);
if (buffer);
- memcpy(buffer, from, strlen(from) + 1);
+ memcpy(buffer, from, strlen(from));
+ buffer[strlen(from)] = '\0';
return buffer;
}
+char *Dowa_String_UUID(uint32 seed, void *buffer)
+{
+ char *res = buffer ? buffer : malloc(sizeof(char)*37);
+ if (!res)
+ return NULL;
+
+ const char *POOL = "abcdef0123456789";
+ int32 i = 0;
+ while (i < 37)
+ {
+ if (i == 8 || i == 13 || i == 18 || i == 23)
+ {
+ res[i++] = '-';
+ continue;
+ }
+ seed = Dowa_Math_Random_Uint32(seed);
+ res[i++] = POOL[seed % 16];
+ }
+ res[36] = '\0';
+ return res;
+}
diff -r 19cccf6e866a -r 655ea0b661fd dowa/dowa.h
--- a/dowa/dowa.h Thu Jan 01 16:34:51 2026 -0800
+++ b/dowa/dowa.h Fri Jan 02 17:47:10 2026 -0800
@@ -1,18 +1,12 @@
#ifndef DOWA
#define DOWA
-#include
+#include // printfs...
#include // strdup, strlen, memcmp, memcpy
#include // malloc, free, realloc
#include // mostly for TODO
#include // size_t
-#ifdef DIRECTORY
-// Only for linux and mac since window do not support.
-// Maybe move this into seobeo file directly?
-#include // some functions loop through files
-#endif
-
#include // I am not re-writing stuff I guess...
#include
@@ -47,7 +41,6 @@
} \
} while (0)
-// Fixed-width integer types
typedef unsigned long long uint64;
typedef long long int64;
typedef unsigned int uint32;
@@ -74,30 +67,26 @@
DLAPI size_t Dowa_Arena_Get_Used(Dowa_Arena *p_arena);
DLAPI size_t Dowa_Arena_Get_Remaining(Dowa_Arena *p_arena);
-// --- New stb_ds-style Data Structures --- //
+// --- Array and HashMap --- //
-// Allocator type enum
typedef enum {
DOWA_ALLOCATOR_MALLOC = 0,
DOWA_ALLOCATOR_ARENA = 1
} Dowa_Allocator_Type;
-// Array header (prefix to actual array data)
typedef struct {
size_t length;
size_t capacity;
uint8 allocator_type;
- Dowa_Arena* p_arena;
- void* p_hash;
+ Dowa_Arena *p_arena;
+ void *p_hash;
} Dowa_Array_Header;
-// Hash bucket (64 bytes for cache line alignment)
typedef struct {
uint32 hash[DOWA_HASH_BUCKET_SIZE];
uint32 index[DOWA_HASH_BUCKET_SIZE];
} Dowa_Hash_Bucket;
-// Hash index structure (separate from value array)
typedef struct {
size_t bucket_count;
size_t item_count;
@@ -107,10 +96,8 @@
Dowa_Hash_Bucket* p_buckets;
} Dowa_Hash_Index;
-// Key-Value pair declaration macro
#define Dowa_KV(K, V) struct { K key; V value; }
-// Internal header accessor
#define dowa__header(a) ((Dowa_Array_Header*)(a) - 1)
// --- Array Macros --- //
@@ -149,7 +136,7 @@
#define Dowa_HashMap_Push(m, k, v) \
do { \
(m) = dowa__hashmap_push((m), sizeof(*(m)), (k), strlen(k) + 1, NULL); \
- void* p_kv_temp = dowa__hashmap_get_ptr((m), sizeof(*(m)), (k), strlen(k) + 1); \
+ void *p_kv_temp = dowa__hashmap_get_ptr((m), sizeof(*(m)), (k), strlen(k) + 1); \
if (p_kv_temp) \
((typeof(m))p_kv_temp)->value = (v); \
} while (0)
@@ -157,7 +144,7 @@
#define Dowa_HashMap_Push_Arena(m, k, v, arena) \
do { \
(m) = dowa__hashmap_push((m), sizeof(*(m)), (k), strlen(k) + 1, (arena)); \
- void* p_kv_temp = dowa__hashmap_get_ptr((m), sizeof(*(m)), (k), strlen(k) + 1); \
+ void *p_kv_temp = dowa__hashmap_get_ptr((m), sizeof(*(m)), (k), strlen(k) + 1); \
if (p_kv_temp) \
((typeof(m))p_kv_temp)->value = (v); \
} while (0)
@@ -183,7 +170,7 @@
#define Dowa_HashMap_Push_Binary(m, k, ksize, v) \
do { \
(m) = dowa__hashmap_push((m), sizeof(*(m)), (k), (ksize), NULL); \
- void* p_kv_temp = dowa__hashmap_get_ptr((m), sizeof(*(m)), (k), (ksize)); \
+ void *p_kv_temp = dowa__hashmap_get_ptr((m), sizeof(*(m)), (k), (ksize)); \
if (p_kv_temp) \
((typeof(m))p_kv_temp)->value = (v); \
} while (0)
@@ -191,37 +178,40 @@
#define Dowa_HashMap_Push_Binary_Arena(m, k, ksize, v, arena) \
do { \
(m) = dowa__hashmap_push((m), sizeof(*(m)), (k), (ksize), (arena)); \
- void* p_kv_temp = dowa__hashmap_get_ptr((m), sizeof(*(m)), (k), (ksize)); \
+ void *p_kv_temp = dowa__hashmap_get_ptr((m), sizeof(*(m)), (k), (ksize)); \
if (p_kv_temp) \
((typeof(m))p_kv_temp)->value = (v); \
} while (0)
// --- Array Core Functions --- //
-DLAPI void* dowa__array_grow(void* p_array, size_t element_size, size_t minimum_capacity, Dowa_Arena* p_arena);
-DLAPI void dowa__array_free(void* p_array);
+DLAPI void *dowa__array_grow(void *p_array, size_t element_size, size_t minimum_capacity, Dowa_Arena* p_arena);
+DLAPI void dowa__array_free(void *p_array);
// --- HashMap Core Functions --- //
-DLAPI uint32 dowa__hash_bytes(void* p_key, size_t key_size);
-DLAPI void* dowa__hashmap_get(void* p_map, size_t element_size, void* p_key, size_t key_size);
-DLAPI void* dowa__hashmap_get_ptr(void* p_map, size_t element_size, void* p_key, size_t key_size);
-DLAPI void* dowa__hashmap_push(void* p_map, size_t element_size, void* p_key, size_t key_size, Dowa_Arena* p_arena);
-DLAPI boolean dowa__hashmap_has_key(void* p_map, size_t element_size, void* p_key, size_t key_size);
-DLAPI void dowa__hashmap_delete(void* p_map, size_t element_size, void* p_key, size_t key_size);
-DLAPI void dowa__hashmap_clear(void* p_map, size_t element_size);
-DLAPI void dowa__hashmap_free(void* p_map);
-DLAPI size_t dowa__hashmap_count(void* p_map);
+DLAPI uint32 dowa__hash_bytes(void *p_key, size_t key_size);
+DLAPI void *dowa__hashmap_get(void *p_map, size_t element_size, void *p_key, size_t key_size);
+DLAPI void *dowa__hashmap_get_ptr(void *p_map, size_t element_size, void *p_key, size_t key_size);
+DLAPI void *dowa__hashmap_push(void *p_map, size_t element_size, void *p_key, size_t key_size, Dowa_Arena* p_arena);
+DLAPI boolean dowa__hashmap_has_key(void *p_map, size_t element_size, void *p_key, size_t key_size);
+DLAPI void dowa__hashmap_delete(void *p_map, size_t element_size, void *p_key, size_t key_size);
+DLAPI void dowa__hashmap_clear(void *p_map, size_t element_size);
+DLAPI void dowa__hashmap_free(void *p_map);
+DLAPI size_t dowa__hashmap_count(void *p_map);
// --- String Manipulation --- //
-DLAPI char *Dowa_String_Slice(char *from, size_t start, size_t end, Dowa_Arena *p_arena);
-DLAPI char **Dowa_String_Split(char *from, char *token, int32 from_length, int32 token_length, Dowa_Arena *p_arena);
-DLAPI char *Dowa_String_Copy_Arena(char *from, Dowa_Arena *p_arena);
+DLAPI char *Dowa_String_Slice(char *from, size_t start, size_t end, Dowa_Arena *p_arena);
+DLAPI char **Dowa_String_Split(char *from, char *token, int32 from_length, int32 token_length, Dowa_Arena *p_arena);
+DLAPI char *Dowa_String_Copy_Arena(char *from, Dowa_Arena *p_arena);
DLAPI int32 Dowa_String_Pos_Find(const char *p_from, const char *p_value, const size_t from_length, const size_t value_length);
DLAPI char *Dowa_String_Find(const char *p_from, const char *p_value, const size_t from_length, const size_t value_length);
DLAPI int32 Dowa_String_Pos_Find_Char(const char *p_from, int c, int32 from_length);
DLAPI char *Dowa_String_Find_Char(const char *p_from, int c, int32 from_length);
+DLAPI char *Dowa_String_UUID(uint32 seed, void *buffer);
+// --- Math --- //
+DLAPI uint32 Dowa_Math_Random_Uint32(uint32 seed_number);
#endif
diff -r 19cccf6e866a -r 655ea0b661fd dowa/dowa_test.c
--- a/dowa/dowa_test.c Thu Jan 01 16:34:51 2026 -0800
+++ b/dowa/dowa_test.c Fri Jan 02 17:47:10 2026 -0800
@@ -2,8 +2,8 @@
#include
#include
#include
-#define DIRECTORY
#include "dowa.h"
+#include
int main(void)
{
@@ -296,6 +296,36 @@
Dowa_Arena_Free(p_arena);
}
+ printf("\n Arena Copy string\n\n");
+ {
+ char *from = "copy_this";
+ Dowa_Arena *p_arena = Dowa_Arena_Create(1024);
+
+ char *value = Dowa_String_Copy_Arena(from, p_arena);
+ assert(strcmp(value, from) == 0);
+ assert(value[9] == '\0');
+
+ Dowa_Arena_Free(p_arena);
+ }
+
+
+ printf("\n UUID\n\n");
+ {
+ char *uuid = Dowa_String_UUID((uint32)time(NULL), NULL);
+ printf("UUID %s\n", uuid);
+ }
+
+ printf("=== Math/Random === \n\n");
+
+ printf("\n RandomNumberGenerator\n\n");
+ {
+ uint32 seed_number = 32;
+ uint32 random_number = Dowa_Math_Random_Uint32(seed_number);
+ uint32 random_number2 = Dowa_Math_Random_Uint32(random_number);
+ printf("randon_number 1: %i\n", random_number);
+ printf("randon_number 2: %i\n", random_number2);
+ }
+
printf("=== All tests passed! ===\n");
return 0;
}
diff -r 19cccf6e866a -r 655ea0b661fd mrjunejune/main.c
--- a/mrjunejune/main.c Thu Jan 01 16:34:51 2026 -0800
+++ b/mrjunejune/main.c Fri Jan 02 17:47:10 2026 -0800
@@ -1,6 +1,12 @@
#include "seobeo/seobeo.h"
+#include
+
+// UUID + /tmp/ + format (max 4)
+#define TMP_FILE_LENGTH 47
+#define UUID_LEN 37
volatile sig_atomic_t stop_server = 0;
+static _Atomic uint32_t counter = 0;
void handle_sigint(int sig)
{
@@ -84,23 +90,348 @@
Seobeo_Request_Entry* GetMDToHTML(Seobeo_Request_Entry *req, Dowa_Arena *arena)
{
- Seobeo_Request_Entry *resp = NULL;
+ Seobeo_Request_Entry *resp = NULL;
char *final_body = Dowa_Arena_Allocate(arena, 50 * 1024);
Seobeo_ServerSideRender(final_body, "/tools/markdown_to_html/index.html", arena);
Dowa_HashMap_Push_Arena(resp, "body", final_body, arena);
return resp;
}
-Seobeo_Request_Entry* GetUser(Seobeo_Request_Entry *req, Dowa_Arena *arena)
+Seobeo_Request_Entry* GetFileConverter(Seobeo_Request_Entry *req, Dowa_Arena *arena)
+{
+ Seobeo_Request_Entry *resp = NULL;
+ char *final_body = Dowa_Arena_Allocate(arena, 50 * 1024);
+ Seobeo_ServerSideRender(final_body, "/tools/file_converter/index.html", arena);
+ Dowa_HashMap_Push_Arena(resp, "body", final_body, arena);
+ return resp;
+}
+
+Seobeo_Request_Entry *ConvertImageToWebP(Seobeo_Request_Entry *req, Dowa_Arena *arena)
{
- void *id_kv = Dowa_HashMap_Get_Ptr(req, ":id");
- const char *user_id = id_kv ? ((Seobeo_Request_Entry*)id_kv)->value : "unknown";
+ Seobeo_Request_Entry *resp = NULL;
+
+ if (!req)
+ {
+ printf("ERROR: Request is NULL\n");
+ char *error_msg = "Internal error: no request data";
+ Dowa_HashMap_Push_Arena(resp, "status", "500", arena);
+ Dowa_HashMap_Push_Arena(resp, "content-type", "text/plain", arena);
+ Dowa_HashMap_Push_Arena(resp, "body", error_msg, arena);
+ return resp;
+ }
+
+ size_t req_length = Dowa_Array_Length(req);
+ printf("Request has %zu entries\n", req_length);
+
+ for (size_t i = 0; i < req_length; i++)
+ {
+ printf(" Key[%zu]: '%s'\n", i, req[i].key);
+ }
+
+ void *body_kv = Dowa_HashMap_Get_Ptr(req, "Body");
+ if (!body_kv)
+ {
+ printf("ERROR: No 'Body' key found in request\n");
+
+ char *error_msg = "No file data provided";
+ Dowa_HashMap_Push_Arena(resp, "status", "400", arena);
+ Dowa_HashMap_Push_Arena(resp, "content-type", "text/plain", arena);
+ Dowa_HashMap_Push_Arena(resp, "body", error_msg, arena);
+ return resp;
+ }
+
+ void *cl_kv = Dowa_HashMap_Get_Ptr(req, "Content-Length");
+ if (!cl_kv)
+ {
+ char *error_msg = "No Content-Length header";
+ Dowa_HashMap_Push_Arena(resp, "status", "400", arena);
+ Dowa_HashMap_Push_Arena(resp, "content-type", "text/plain", arena);
+ Dowa_HashMap_Push_Arena(resp, "body", error_msg, arena);
+ return resp;
+ }
+
+ const char *file_data = ((Seobeo_Request_Entry*)body_kv)->value;
+ const char *content_length_str = ((Seobeo_Request_Entry*)cl_kv)->value;
+ size_t file_size = atoi(content_length_str);
+
+ printf("DEBUG: Converting image, file_size=%zu bytes\n", file_size);
+
+
+ int open_flags = O_RDWR | O_CREAT | O_EXCL;
+
+ char *uuid4 = (char *)Dowa_Arena_Allocate(arena, UUID_LEN);
+ uint32 seed = (uint32)time(NULL) ^ (uint32)pthread_self() ^ counter++;
+ Dowa_String_UUID(seed, uuid4);
+ char *input_path = Dowa_Arena_Allocate(arena, TMP_FILE_LENGTH);;
+ snprintf(input_path, TMP_FILE_LENGTH, "/tmp/%s", uuid4);
+ int input_fd = open(input_path, open_flags, 0600);
+ if (input_fd == -1)
+ {
+ char *error_msg = "Failed to create temporary file";
+ Dowa_HashMap_Push_Arena(resp, "status", "500", arena);
+ Dowa_HashMap_Push_Arena(resp, "content-type", "text/plain", arena);
+ Dowa_HashMap_Push_Arena(resp, "body", error_msg, arena);
+ return resp;
+ }
+ write(input_fd, file_data, file_size);
+ close(input_fd);
+
+
+ uuid4 = (char *)Dowa_Arena_Allocate(arena, UUID_LEN);
+ seed = (uint32)time(NULL) ^ (uint32)pthread_self() ^ counter++;
+ Dowa_String_UUID(seed, uuid4);
+ char *output_path = (char *)Dowa_Arena_Allocate(arena, TMP_FILE_LENGTH);;
+ snprintf(output_path, TMP_FILE_LENGTH, "/tmp/%s.webp", uuid4);
+ printf("[DEBUG] output_path %s\n", output_path);
+ printf("[DEBUG] open_flags: 0x%x\n", open_flags);
+ printf("[DEBUG] input_path: %s\n", input_path);
+ int output_fd = open(output_path, open_flags, 0600);
+ printf("[DEBUG] output_fd: %d\n", output_fd);
+ if (output_fd == -1)
+ {
+ unlink(input_path);
+ printf("[DEBUG] errno: %d (%s)\n", errno, strerror(errno));
+ char *error_msg = "Failed to create output file";
+ Dowa_HashMap_Push_Arena(resp, "status", "500", arena);
+ Dowa_HashMap_Push_Arena(resp, "content-type", "text/plain", arena);
+ Dowa_HashMap_Push_Arena(resp, "body", error_msg, arena);
+ return resp;
+ }
+ close(output_fd);
+
+ char cmd[1024];
+ snprintf(cmd, sizeof(cmd), "ffmpeg -y -i %s -quality 80 %s 2>/tmp/error_log",
+ input_path, output_path);
+ int result = system(cmd);
+ if (result != 0)
+ {
+ unlink(input_path);
+ unlink(output_path);
+ char *error_msg = "FFmpeg conversion failed";
+ Dowa_HashMap_Push_Arena(resp, "status", "500", arena);
+ Dowa_HashMap_Push_Arena(resp, "content-type", "text/plain", arena);
+ Dowa_HashMap_Push_Arena(resp, "body", error_msg, arena);
+ return resp;
+ }
+
+ size_t converted_size = 0;
+ FILE *out_file = fopen(output_path, "rb");
+ if (!out_file)
+ {
+ unlink(input_path);
+ unlink(output_path);
+ char *error_msg = "Failed to read converted file";
+ Dowa_HashMap_Push_Arena(resp, "status", "500", arena);
+ Dowa_HashMap_Push_Arena(resp, "content-type", "text/plain", arena);
+ Dowa_HashMap_Push_Arena(resp, "body", error_msg, arena);
+ return resp;
+ }
+ fclose(out_file);
+
+ unlink(input_path);
+
+ char *filename = strrchr(output_path, '/') + 1;
+ char *response_body = Dowa_Arena_Allocate(arena, 512);
+ snprintf(response_body, 512,
+ "{\"success\":true,\"download_url\":\"/api/download/%s\",\"expires\":\"10 minutes\"}",
+ filename);
+ Dowa_HashMap_Push_Arena(resp, "status", "200", arena);
+ Dowa_HashMap_Push_Arena(resp, "content-type", "application/json", arena);
+ Dowa_HashMap_Push_Arena(resp, "body", response_body, arena);
+
+ printf("DEBUG: Image converted, available at /api/download/%s\n", filename);
+
+ return resp;
+}
+
+Seobeo_Request_Entry *ConvertVideoToMP4(Seobeo_Request_Entry *req, Dowa_Arena *arena)
+{
+ Seobeo_Request_Entry *resp = NULL;
+
+ void *body_kv = Dowa_HashMap_Get_Ptr(req, "Body");
+ if (!body_kv)
+ {
+ char *error_msg = "No file data provided";
+ Dowa_HashMap_Push_Arena(resp, "status", "400", arena);
+ Dowa_HashMap_Push_Arena(resp, "content-type", "text/plain", arena);
+ Dowa_HashMap_Push_Arena(resp, "body", error_msg, arena);
+ return resp;
+ }
+ // Get Content-Length to know the actual binary size
+ void *cl_kv = Dowa_HashMap_Get_Ptr(req, "Content-Length");
+ if (!cl_kv)
+ {
+ char *error_msg = "No Content-Length header";
+ Dowa_HashMap_Push_Arena(resp, "status", "400", arena);
+ Dowa_HashMap_Push_Arena(resp, "content-type", "text/plain", arena);
+ Dowa_HashMap_Push_Arena(resp, "body", error_msg, arena);
+ return resp;
+ }
+
+ const char *file_data = ((Seobeo_Request_Entry*)body_kv)->value;
+ const char *content_length_str = ((Seobeo_Request_Entry*)cl_kv)->value;
+ size_t file_size = atoi(content_length_str);
+
+ printf("DEBUG: Converting video, file_size=%zu bytes\n", file_size);
+
+ char *uuid4 = (char *)Dowa_Arena_Allocate(arena, UUID_LEN);
+ Dowa_String_UUID((uint32)time(NULL), uuid4);
+ char *input_path = Dowa_Arena_Allocate(arena, TMP_FILE_LENGTH);
+ snprintf(input_path, TMP_FILE_LENGTH, "/tmp/%s", uuid4);
+ int input_fd = mkstemp(input_path);
+ if (input_fd == -1)
+ {
+ char *error_msg = "Failed to create temporary file";
+ Dowa_HashMap_Push_Arena(resp, "status", "500", arena);
+ Dowa_HashMap_Push_Arena(resp, "content-type", "text/plain", arena);
+ Dowa_HashMap_Push_Arena(resp, "body", error_msg, arena);
+ return resp;
+ }
+
+ write(input_fd, file_data, file_size);
+ close(input_fd);
+
+ int open_flags = O_RDWR | O_CREAT | O_EXCL;
+
+ uint32 seed = (uint32)time(NULL) ^ (uint32)pthread_self() ^ counter++;;
+ Dowa_String_UUID(seed, uuid4);
+ char *output_path = (char *)Dowa_Arena_Allocate(arena, TMP_FILE_LENGTH);;
+ snprintf(output_path, TMP_FILE_LENGTH, "/tmp/%s.mp4", uuid4);
+ int output_fd = open(output_path, open_flags, 0600);
+ if (output_fd == -1)
+ {
+ unlink(input_path);
+ char *error_msg = "Failed to create output file";
+ Dowa_HashMap_Push_Arena(resp, "status", "500", arena);
+ Dowa_HashMap_Push_Arena(resp, "content-type", "text/plain", arena);
+ Dowa_HashMap_Push_Arena(resp, "body", error_msg, arena);
+ return resp;
+ }
+ close(output_fd);
+
+ char cmd[512];
+ snprintf(cmd, sizeof(cmd),
+ "ffmpeg -y -i %s -c:v libx264 -preset fast -crf 23 -c:a aac %s 2>/tmp/error_log",
+ input_path, output_path);
+ int result = system(cmd);
+ if (result != 0)
+ {
+ unlink(input_path);
+ unlink(output_path);
+ char *error_msg = "FFmpeg conversion failed";
+ Dowa_HashMap_Push_Arena(resp, "status", "500", arena);
+ Dowa_HashMap_Push_Arena(resp, "content-type", "text/plain", arena);
+ Dowa_HashMap_Push_Arena(resp, "body", error_msg, arena);
+ return resp;
+ }
+
+ unlink(input_path);
+ char *filename = strrchr(output_path, '/') + 1;
+ char *response_body = Dowa_Arena_Allocate(arena, 512);
+ snprintf(response_body, 512,
+ "{\"success\":true,\"download_url\":\"/api/download/%s\",\"expires\":\"10 minutes\"}",
+ filename);
+ Dowa_HashMap_Push_Arena(resp, "status", "200", arena);
+ Dowa_HashMap_Push_Arena(resp, "content-type", "application/json", arena);
+ Dowa_HashMap_Push_Arena(resp, "body", response_body, arena);
+
+ printf("DEBUG: Video converted, available at /api/download/%s\n", filename);
+ return resp;
+}
+
+Seobeo_Request_Entry *DownloadConvertedFile(Seobeo_Request_Entry *req, Dowa_Arena *arena)
+{
Seobeo_Request_Entry *resp = NULL;
- char *body = Dowa_Arena_Allocate(arena, 256);
- snprintf(body, 256, "{\"id\":\"%s\",\"name\":\"John Doe\"}", user_id);
+
+ void *filename_kv = Dowa_HashMap_Get_Ptr(req, ":filename");
+ if (!filename_kv)
+ {
+ char *error_msg = "No filename specified";
+ Dowa_HashMap_Push_Arena(resp, "status", "404", arena);
+ Dowa_HashMap_Push_Arena(resp, "content-type", "text/plain", arena);
+ Dowa_HashMap_Push_Arena(resp, "body", error_msg, arena);
+ return resp;
+ }
+
+ const char *filename = ((Seobeo_Request_Entry*)filename_kv)->value;
+
+ // TODO: Maybe check if the uuid is allowed or not?
+ // if (strlen(filename) != TMP_FILE_LENGTH)
+ // {
+ // char *error_msg = "Not Allowed Filename";
+ // Dowa_HashMap_Push_Arena(resp, "status", "404", arena);
+ // Dowa_HashMap_Push_Arena(resp, "content-type", "text/plain", arena);
+ // Dowa_HashMap_Push_Arena(resp, "body", error_msg, arena);
+ // return resp;
+ // }
+ // boolean allowed = FALSE;
+ // for (int i = 0; i < Dowa_Array_Length(g_uuid4_array); i++)
+ // {
+ // if strcmp(g_uuid4_array, filename)
+ // {
+ // allowed = TRUE;
+ // break;
+ // }
+ // g_uuid4_array++;
+ // }
+
+ char filepath[512];
+ snprintf(filepath, sizeof(filepath), "/tmp/%s", filename);
+ FILE *file = fopen(filepath, "rb");
+ if (!file)
+ {
+ char *error_msg = "File not found or expired";
+ Dowa_HashMap_Push_Arena(resp, "status", "404", arena);
+ Dowa_HashMap_Push_Arena(resp, "content-type", "text/plain", arena);
+ Dowa_HashMap_Push_Arena(resp, "body", error_msg, arena);
+ return resp;
+ }
+
+ fseek(file, 0, SEEK_END);
+ size_t file_size = ftell(file);
+ fseek(file, 0, SEEK_SET);
+
+ char *file_data = malloc(file_size + 1);
+ if (!file_data)
+ {
+ fclose(file);
+ char *error_msg = "Memory allocation failed";
+ Dowa_HashMap_Push_Arena(resp, "status", "500", arena);
+ Dowa_HashMap_Push_Arena(resp, "content-type", "text/plain", arena);
+ Dowa_HashMap_Push_Arena(resp, "body", error_msg, arena);
+ return resp;
+ }
+
+ fread(file_data, 1, file_size, file);
+ file_data[file_size] = '\0';
+ fclose(file);
+
+ const char *content_type = "application/octet-stream";
+ if (strstr(filename, ".webp"))
+ content_type = "image/webp";
+ else if (strstr(filename, ".mp4"))
+ content_type = "video/mp4";
+
+ char *body = Dowa_Arena_Allocate(arena, file_size + 1);
+ memcpy(body, file_data, file_size);
+ body[file_size] = '\0';
+ free(file_data);
+
+ unlink(filepath);
+
+ printf("DEBUG: Served and deleted file: %s (%zu bytes)\n", filename, file_size);
+
+ // Set proper Content-Length for binary data
+ char *content_length = Dowa_Arena_Allocate(arena, 32);
+ snprintf(content_length, 32, "%zu", file_size);
+
+ Dowa_HashMap_Push_Arena(resp, "status", "200", arena);
+ Dowa_HashMap_Push_Arena(resp, "content-type", content_type, arena);
+ Dowa_HashMap_Push_Arena(resp, "content-length", content_length, arena);
Dowa_HashMap_Push_Arena(resp, "body", body, arena);
+
return resp;
}
@@ -108,6 +439,7 @@
CREATE_REDIRECT_HANDLER(Resume, "/resume")
CREATE_REDIRECT_HANDLER(Tools, "/tools")
CREATE_REDIRECT_HANDLER(MarkDownToHtml, "/tools/markdown_to_html")
+CREATE_REDIRECT_HANDLER(FileConverter, "/tools/file_converter")
int main(void)
{
@@ -124,5 +456,12 @@
Seobeo_Router_Register("GET", "/tools/markdown_to_html", GetMDToHTML);
Seobeo_Router_Register("GET", "/tools/markdown_to_html/index.html", GetRedirectMarkDownToHtml);
+ Seobeo_Router_Register("GET", "/tools/file_converter", GetFileConverter);
+ Seobeo_Router_Register("GET", "/tools/file_converter/index.html", GetRedirectFileConverter);
+
+ Seobeo_Router_Register("POST", "/api/convert/image-to-webp", ConvertImageToWebP);
+ Seobeo_Router_Register("POST", "/api/convert/video-to-mp4", ConvertVideoToMP4);
+ Seobeo_Router_Register("GET", "/api/download/:filename", DownloadConvertedFile);
+
Seobeo_Web_Server_Start("mrjunejune/src", "6969", SEOBEO_MODE_EDGE, 3);
}
diff -r 19cccf6e866a -r 655ea0b661fd mrjunejune/src/base.css
--- a/mrjunejune/src/base.css Thu Jan 01 16:34:51 2026 -0800
+++ b/mrjunejune/src/base.css Fri Jan 02 17:47:10 2026 -0800
@@ -1,4 +1,26 @@
-/* Base Colors */
+/* Reset CSS: https://meyerweb.com/eric/tools/css/reset/ */
+html, body, div, span, applet, object, iframe,
+h1, h2, h3, h4, h5, h6, p, blockquote, pre,
+a, abbr, acronym, address, big, cite, code,
+del, dfn, em, img, ins, kbd, q, s, samp,
+small, strike, strong, sub, sup, tt, var,
+b, u, i, center,
+dl, dt, dd, ol, ul, li,
+fieldset, form, label, legend,
+table, caption, tbody, tfoot, thead, tr, th, td,
+article, aside, canvas, details, embed,
+figure, figcaption, footer, header, hgroup,
+menu, nav, output, ruby, section, summary,
+time, mark, audio, video {
+ margin: 0;
+ padding: 0;
+ border: 0;
+ font-size: 100%;
+ font: inherit;
+ vertical-align: baseline;
+}
+
+/* --- Colors ---*/
:root {
--white: #ffffff;
--black: hsl(224, 12%, 4%);
@@ -49,11 +71,32 @@
--box-shadow: 0 -2px -6px rgba(159, 140, 96, 25%),
0 -8px -24px rgba(159, 140, 96, 33%), 0 -16px -32px rgba(159, 140, 96, 33%);
}
-
-html {
- background: var(--white);
+@media (prefers-color-scheme: dark) {
+ :root:not(.light-mode) {
+ --white: hsl(224, 10%, 10%);
+ --black: hsl(0, 0%, 90%);
+ --darkgray: #cccccc;
+ --lightgray: #666666;
+ --green: #3d1ea0;
+ --orange: #025ccc;
+ --purple: #2b5b06;
+ --red: #04bb7a;
+ --blue: #932f0e;
+ --darktext: #bebebe;
+ --awesome: #23cade;
+ --accent: #ffcc00;
+ --accent-dark: #ffb275;
+ --gray: 159, 140, 96;
+ --gray-light: 26, 22, 15;
+ --gray-dark: 221, 214, 198;
+ --gray-gradient: rgba(26, 22, 15, 50%), #000;
+ --box-shadow: 0 -2px -6px rgba(159, 140, 96, 25%),
+ 0 -8px -24px rgba(159, 140, 96, 33%), 0 -16px -32px rgba(159, 140, 96, 33%);
+ }
}
+/* --- fonts --- */
+/*
@font-face {
font-family: "Atkinson";
src: url("/public/fonts/atkinson-regular.woff") format("woff");
@@ -66,6 +109,7 @@
font-weight: 700;
font-style: normal;
}
+*/
@font-face {
font-family: "Roboto";
src: url("/public/fonts/Roboto-Regular.ttf");
@@ -83,6 +127,11 @@
src: url("/public/fonts/more-sugar.regular.otf");
}
+/* -- HTML Tags only --*/
+html {
+ background: var(--white);
+}
+
a {
color: inherit; /* blue colors for links too */
text-decoration: inherit; /* no underline */
@@ -120,125 +169,91 @@
color: rgb(var(--black));
line-height: 1.2;
}
+
h1 {
font-size: 3.052em;
}
+
h2 {
font-size: 2.441em;
}
+
h3 {
font-size: 1.953em;
}
+
h4 {
font-size: 1.563em;
}
+
h5 {
font-size: 1.25em;
}
+
strong,
b {
font-weight: 700;
}
+
p {
margin-bottom: 1em;
}
+
.prose p {
margin-bottom: 2em;
}
+
textarea {
width: 100%;
font-size: 16px;
}
+
input {
font-size: 16px;
}
+
table {
width: 100%;
}
+
img {
max-width: 100%;
height: auto;
border-radius: 8px;
}
+
code {
padding: 2px 5px;
background-color: rgb(var(--gray-light));
border-radius: 2px;
}
+
pre {
padding: 1.5em;
border-radius: 8px;
}
+
pre > code {
all: unset;
}
+
blockquote {
border-left: 4px solid var(--accent);
padding: 0 0 0 20px;
margin: 0px;
font-size: 1.333em;
}
+
hr {
border: none;
border-top: 1px solid rgb(var(--gray-light));
}
-@media (max-width: 720px) {
- body {
- font-size: 18px;
- }
- main {
- padding: 1em;
- }
-}
-
-.sr-only {
- border: 0;
- padding: 0;
- margin: 0;
- position: absolute !important;
- height: 1px;
- width: 1px;
- overflow: hidden;
- /* IE6, IE7 - a 0 height clip, off to the bottom right of the visible 1px box */
- clip: rect(1px 1px 1px 1px);
- /* maybe deprecated but we need to support legacy browsers */
- clip: rect(1px, 1px, 1px, 1px);
- /* modern browsers, clip-path works inwards from each corner */
- clip-path: inset(50%);
- /* added line to stop words getting smushed together (as they go onto separate lines and some screen readers do not understand line feeds as a space */
- white-space: nowrap;
-}
.center {
display: flex;
justify-content: center;
}
-/* Auto dark mode based on system preference */
-@media (prefers-color-scheme: dark) {
- :root:not(.light-mode) {
- --white: hsl(224, 10%, 10%);
- --black: hsl(0, 0%, 90%);
- --darkgray: #cccccc;
- --lightgray: #666666;
- --green: #3d1ea0;
- --orange: #025ccc;
- --purple: #2b5b06;
- --red: #04bb7a;
- --blue: #932f0e;
- --darktext: #bebebe;
- --awesome: #23cade;
- --accent: #ffcc00;
- --accent-dark: #ffb275;
- --gray: 159, 140, 96;
- --gray-light: 26, 22, 15;
- --gray-dark: 221, 214, 198;
- --gray-gradient: rgba(26, 22, 15, 50%), #000;
- --box-shadow: 0 -2px -6px rgba(159, 140, 96, 25%),
- 0 -8px -24px rgba(159, 140, 96, 33%), 0 -16px -32px rgba(159, 140, 96, 33%);
- }
-}
-
a {
text-decoration: underline;
}
@@ -250,13 +265,9 @@
height: 1em;
margin-right: 8px;
vertical-align: middle;
-
- /* This treats the paw like a stencil */
- background-color: #FF69B4; /* Change your color here! (e.g., Hot Pink) */
+ background-color: #FF69B4;
-webkit-mask: url('/public/paw.svg') no-repeat center;
mask: url('/public/paw.svg') no-repeat center;
-
- /* Your 2D Animation */
animation: pawStep 0.6s ease-out forwards;
}
@@ -273,3 +284,16 @@
0%, 100% { transform: rotate(-15deg); }
50% { transform: rotate(15deg); }
}
+
+
+/* -- mobile -- */
+@media (max-width: 720px) {
+ body {
+ font-size: 18px;
+ }
+ main {
+ padding: 1em;
+ }
+}
+
+
diff -r 19cccf6e866a -r 655ea0b661fd mrjunejune/src/index.html
--- a/mrjunejune/src/index.html Thu Jan 01 16:34:51 2026 -0800
+++ b/mrjunejune/src/index.html Fri Jan 02 17:47:10 2026 -0800
@@ -7,6 +7,7 @@
.epi-photo {
display: flex;
justify-content: center;
+ margin-bottom: 10px;
}
@@ -22,7 +23,7 @@
- During my free time, I like to write codes mostly in C, typescript and python.
+ During my free time, I like to write codes mostly in C, Python, and Typescript.
This website is hosted using my own server library which I wrote in C.
Links
@@ -30,6 +31,7 @@
Repository - Check out my code (MIT License)
Resume - My professional experiences
Tools - Tools
+
+ {{/parts/header.html}}