Mercurial
comparison mrjunejune/main.c @ 216:e82b80b24012 default tip
[MrJuneJune] Make webp translate background job.
| author | June Park <parkjune1995@gmail.com> |
|---|---|
| date | Sat, 28 Feb 2026 21:04:43 -0800 |
| parents | 240337164a80 |
| children |
comparison
equal
deleted
inserted
replaced
| 215:c3df85159b31 | 216:e82b80b24012 |
|---|---|
| 22 char content_type[128]; | 22 char content_type[128]; |
| 23 char access_token[256]; | 23 char access_token[256]; |
| 24 char db_path[256]; | 24 char db_path[256]; |
| 25 S3_Config s3_config; | 25 S3_Config s3_config; |
| 26 } Media_Processing_Context; | 26 } Media_Processing_Context; |
| 27 | |
| 28 typedef struct { | |
| 29 char *input_path; | |
| 30 char *output_path; | |
| 31 } File_Converter_Config; | |
| 27 | 32 |
| 28 // Server configuration (loaded from .config) | 33 // Server configuration (loaded from .config) |
| 29 static char g_upload_auth_token[256] = {0}; | 34 static char g_upload_auth_token[256] = {0}; |
| 30 static char g_s3_region[64] = "us-west-2"; | 35 static char g_s3_region[64] = "us-west-2"; |
| 31 static char g_s3_bucket[128] = "mrjunejune"; | 36 static char g_s3_bucket[128] = "mrjunejune"; |
| 288 Seobeo_Render_Html_FilePath(final_body, "/tools/file_converter/index.html", arena); | 293 Seobeo_Render_Html_FilePath(final_body, "/tools/file_converter/index.html", arena); |
| 289 Dowa_HashMap_Push_Arena(resp, "body", final_body, arena); | 294 Dowa_HashMap_Push_Arena(resp, "body", final_body, arena); |
| 290 return resp; | 295 return resp; |
| 291 } | 296 } |
| 292 | 297 |
| 298 // Background thread function for media processing | |
| 299 void *Simple_WebpConverter_Background(void *arg) | |
| 300 { | |
| 301 File_Converter_Config *configuration = (File_Converter_Config *)arg; | |
| 302 | |
| 303 char cmd[1024]; | |
| 304 snprintf(cmd, sizeof(cmd), "ffmpeg -y -i %s -quality 80 %s 2>/tmp/error_log", | |
| 305 configuration->input_path, configuration->output_path); | |
| 306 Seobeo_Log(SEOBEO_INFO, "[MEDIA] Running FFmpeg: %s\n", cmd); | |
| 307 int ffmpeg_result = system(cmd); | |
| 308 | |
| 309 Seobeo_Log(SEOBEO_INFO, "[MEDIA] FFmpeg result: %d\n", ffmpeg_result); | |
| 310 if (ffmpeg_result != 0) | |
| 311 { | |
| 312 Seobeo_Log(SEOBEO_ERROR, "[MEDIA] ERROR: FFmpeg conversion failed\n"); | |
| 313 return NULL; | |
| 314 } | |
| 315 Seobeo_Log(SEOBEO_INFO, "[MEDIA] Successfully converted to webp: %s\n"); | |
| 316 return NULL; | |
| 317 } | |
| 318 | |
| 293 Seobeo_Request_Entry *ConvertImageToWebP(Seobeo_Request_Entry *req, Dowa_Arena *arena) | 319 Seobeo_Request_Entry *ConvertImageToWebP(Seobeo_Request_Entry *req, Dowa_Arena *arena) |
| 294 { | 320 { |
| 295 Seobeo_Request_Entry *resp = NULL; | 321 Seobeo_Request_Entry *resp = NULL; |
| 296 | 322 |
| 297 if (!req) | 323 if (!req) |
| 336 | 362 |
| 337 const char *file_data = ((Seobeo_Request_Entry*)body_kv)->value; | 363 const char *file_data = ((Seobeo_Request_Entry*)body_kv)->value; |
| 338 const char *content_length_str = ((Seobeo_Request_Entry*)cl_kv)->value; | 364 const char *content_length_str = ((Seobeo_Request_Entry*)cl_kv)->value; |
| 339 size_t file_size = atoi(content_length_str); | 365 size_t file_size = atoi(content_length_str); |
| 340 | 366 |
| 341 printf("DEBUG: Converting image, file_size=%zu bytes\n", file_size); | 367 Seobeo_Log(SEOBEO_DEBUG, "Converting image, file_size=%zu bytes\n", file_size); |
| 342 | 368 |
| 343 int open_flags = O_RDWR | O_CREAT | O_EXCL; | 369 int open_flags = O_RDWR | O_CREAT | O_EXCL; |
| 344 | 370 |
| 345 char *uuid4 = (char *)Dowa_Arena_Allocate(arena, UUID_LEN); | 371 char *uuid4 = (char *)Dowa_Arena_Allocate(arena, UUID_LEN); |
| 346 uint32 seed = (uint32)time(NULL) ^ (uint32)pthread_self() ^ counter++; | 372 uint32 seed = (uint32)time(NULL) ^ (uint32)pthread_self() ^ counter++; |
| 363 uuid4 = (char *)Dowa_Arena_Allocate(arena, UUID_LEN); | 389 uuid4 = (char *)Dowa_Arena_Allocate(arena, UUID_LEN); |
| 364 seed = (uint32)time(NULL) ^ (uint32)pthread_self() ^ counter++; | 390 seed = (uint32)time(NULL) ^ (uint32)pthread_self() ^ counter++; |
| 365 Dowa_String_UUID(seed, uuid4); | 391 Dowa_String_UUID(seed, uuid4); |
| 366 char *output_path = (char *)Dowa_Arena_Allocate(arena, TMP_FILE_LENGTH);; | 392 char *output_path = (char *)Dowa_Arena_Allocate(arena, TMP_FILE_LENGTH);; |
| 367 snprintf(output_path, TMP_FILE_LENGTH, "/tmp/%s.webp", uuid4); | 393 snprintf(output_path, TMP_FILE_LENGTH, "/tmp/%s.webp", uuid4); |
| 368 printf("[DEBUG] output_path %s\n", output_path); | 394 Seobeo_Log(SEOBEO_DEBUG, "output_path %s\n", output_path); |
| 369 printf("[DEBUG] open_flags: 0x%x\n", open_flags); | 395 Seobeo_Log(SEOBEO_DEBUG, "open_flags: 0x%x\n", open_flags); |
| 370 printf("[DEBUG] input_path: %s\n", input_path); | 396 Seobeo_Log(SEOBEO_DEBUG, "input_path: %s\n", input_path); |
| 371 int output_fd = open(output_path, open_flags, 0600); | 397 int output_fd = open(output_path, open_flags, 0600); |
| 372 printf("[DEBUG] output_fd: %d\n", output_fd); | 398 Seobeo_Log(SEOBEO_DEBUG, "output_fd: %d\n", output_fd); |
| 373 if (output_fd == -1) | 399 if (output_fd == -1) |
| 374 { | 400 { |
| 375 unlink(input_path); | 401 unlink(input_path); |
| 376 printf("[DEBUG] errno: %d (%s)\n", errno, strerror(errno)); | 402 Seobeo_Log(SEOBEO_DEBUG, "errno: %d (%s)\n", errno, strerror(errno)); |
| 377 char *error_msg = "Failed to create output file"; | 403 char *error_msg = "Failed to create output file"; |
| 378 Dowa_HashMap_Push_Arena(resp, "status", "500", arena); | 404 Dowa_HashMap_Push_Arena(resp, "status", "500", arena); |
| 379 Dowa_HashMap_Push_Arena(resp, "content-type", "text/plain", arena); | 405 Dowa_HashMap_Push_Arena(resp, "content-type", "text/plain", arena); |
| 380 Dowa_HashMap_Push_Arena(resp, "body", error_msg, arena); | 406 Dowa_HashMap_Push_Arena(resp, "body", error_msg, arena); |
| 381 return resp; | 407 return resp; |
| 382 } | 408 } |
| 383 close(output_fd); | 409 close(output_fd); |
| 384 | 410 |
| 385 char cmd[1024]; | 411 File_Converter_Config *configuration = Dowa_Arena_Allocate(arena, sizeof(File_Converter_Config)); |
| 386 snprintf(cmd, sizeof(cmd), "ffmpeg -y -i %s -quality 80 %s 2>/tmp/error_log", | 412 configuration->input_path = input_path; |
| 387 input_path, output_path); | 413 configuration->output_path = output_path; |
| 388 int result = system(cmd); | 414 |
| 389 if (result != 0) | 415 pthread_t thread_id; |
| 416 int thread_result = pthread_create(&thread_id, NULL, Simple_WebpConverter_Background, (void *)configuration); | |
| 417 | |
| 418 if (thread_result != 0) | |
| 390 { | 419 { |
| 391 unlink(input_path); | 420 unlink(input_path); |
| 392 unlink(output_path); | 421 unlink(output_path); |
| 393 char *error_msg = "FFmpeg conversion failed"; | 422 char *error_msg = "FFmpeg conversion failed"; |
| 394 Dowa_HashMap_Push_Arena(resp, "status", "500", arena); | 423 Dowa_HashMap_Push_Arena(resp, "status", "500", arena); |
| 395 Dowa_HashMap_Push_Arena(resp, "content-type", "text/plain", arena); | 424 Dowa_HashMap_Push_Arena(resp, "content-type", "text/plain", arena); |
| 396 Dowa_HashMap_Push_Arena(resp, "body", error_msg, arena); | 425 Dowa_HashMap_Push_Arena(resp, "body", error_msg, arena); |
| 397 return resp; | 426 return resp; |
| 398 } | 427 } |
| 428 else | |
| 429 { | |
| 430 // Detach thread so it cleans up automatically when done | |
| 431 pthread_detach(thread_id); | |
| 432 Seobeo_Log(SEOBEO_INFO, "[MEDIA] Successfully spawned and detached thread\n"); | |
| 433 } | |
| 399 | 434 |
| 400 size_t converted_size = 0; | 435 size_t converted_size = 0; |
| 401 FILE *out_file = fopen(output_path, "rb"); | 436 FILE *out_file = fopen(output_path, "rb"); |
| 402 if (!out_file) | 437 if (!out_file) |
| 403 { | 438 { |
| 410 return resp; | 445 return resp; |
| 411 } | 446 } |
| 412 fclose(out_file); | 447 fclose(out_file); |
| 413 | 448 |
| 414 unlink(input_path); | 449 unlink(input_path); |
| 415 | |
| 416 char *filename = strrchr(output_path, '/') + 1; | 450 char *filename = strrchr(output_path, '/') + 1; |
| 417 char *response_body = Dowa_Arena_Allocate(arena, 512); | 451 char *response_body = Dowa_Arena_Allocate(arena, 512); |
| 418 snprintf(response_body, 512, | 452 snprintf(response_body, 512, |
| 419 "{\"success\":true,\"download_url\":\"/api/download/%s\",\"expires\":\"10 minutes\"}", | 453 "{\"success\":true,\"download_url\":\"/api/download/%s\",\"expires\":\"10 minutes\"}", |
| 420 filename); | 454 filename); |
| 421 Dowa_HashMap_Push_Arena(resp, "status", "200", arena); | 455 Dowa_HashMap_Push_Arena(resp, "status", "200", arena); |
| 422 Dowa_HashMap_Push_Arena(resp, "content-type", "application/json", arena); | 456 Dowa_HashMap_Push_Arena(resp, "content-type", "application/json", arena); |
| 423 Dowa_HashMap_Push_Arena(resp, "body", response_body, arena); | 457 Dowa_HashMap_Push_Arena(resp, "body", response_body, arena); |
| 424 | 458 |
| 425 printf("DEBUG: Image converted, available at /api/download/%s\n", filename); | 459 Seobeo_Log(SEOBEO_DEBUG, "Image converted, available at /api/download/%s\n", filename); |
| 426 | 460 |
| 427 return resp; | 461 return resp; |
| 428 } | 462 } |
| 429 | 463 |
| 430 Seobeo_Request_Entry *ConvertVideoToMP4(Seobeo_Request_Entry *req, Dowa_Arena *arena) | 464 Seobeo_Request_Entry *ConvertVideoToMP4(Seobeo_Request_Entry *req, Dowa_Arena *arena) |