Mercurial
diff s3/s3_uploader.h @ 196:83f16548ba41
[AI] Adding s3 bucket uploader code using Seobeo.
| author | MrJuneJune <me@mrjunejune.com> |
|---|---|
| date | Sat, 14 Feb 2026 16:08:15 -0800 |
| parents | |
| children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/s3/s3_uploader.h Sat Feb 14 16:08:15 2026 -0800 @@ -0,0 +1,150 @@ +#ifndef S3_UPLOADER_H +#define S3_UPLOADER_H + +/** + * S3 Uploader + * ----------- + * + * Generic S3 bucket uploader using AWS Signature Version 4. + * Built on top of seobeo HTTP client. + * + * ## Examples + * + * ### 1. Upload a file from disk + * + * ```c + * S3_Config config = { + * .access_key_id = "AKIAIOSFODNN7EXAMPLE", + * .secret_access_key = "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", + * .region = "us-east-1", + * .bucket = "my-bucket" + * }; + * + * S3_Result result = S3_Upload_File(&config, "/path/to/local/file.txt", "uploads/file.txt"); + * if (result.success) + * { + * printf("Uploaded successfully!\n"); + * } + * else + * { + * printf("Error: %s\n", result.error_message); + * } + * S3_Result_Destroy(&result); + * ``` + * + * ### 2. Upload raw data from memory + * + * ```c + * const char *data = "Hello, S3!"; + * S3_Result result = S3_Upload_Data(&config, (const uint8 *)data, strlen(data), + * "hello.txt", "text/plain"); + * S3_Result_Destroy(&result); + * ``` + * + * ### 3. Upload with custom content type + * + * ```c + * S3_Result result = S3_Upload_File_With_Content_Type(&config, + * "/path/to/image.png", + * "images/photo.png", + * "image/png"); + * S3_Result_Destroy(&result); + * ``` + */ + +#include <stddef.h> + +#include "dowa/dowa.h" + +// S3 configuration +typedef struct { + const char *access_key_id; // AWS access key ID + const char *secret_access_key; // AWS secret access key + const char *region; // AWS region (e.g., "us-east-1") + const char *bucket; // S3 bucket name + const char *endpoint; // Optional custom endpoint (NULL for default AWS) + boolean use_path_style; // Use path-style URLs (bucket in path, not subdomain) +} S3_Config; + +// Upload result +typedef struct { + boolean success; // TRUE if upload succeeded + int32 status_code; // HTTP status code + char *error_message; // Error message (NULL on success) + char *etag; // ETag of uploaded object (on success) + Dowa_Arena *p_arena; // Internal arena (do not modify) +} S3_Result; + +// --- Core API --- // + +/* Upload file from disk to S3. Content-Type is auto-detected. */ +extern S3_Result S3_Upload_File(const S3_Config *p_config, + const char *local_path, + const char *s3_key); + +/* Upload file with explicit content type. */ +extern S3_Result S3_Upload_File_With_Content_Type(const S3_Config *p_config, + const char *local_path, + const char *s3_key, + const char *content_type); + +/* Upload raw data from memory to S3. */ +extern S3_Result S3_Upload_Data(const S3_Config *p_config, + const uint8 *data, + size_t data_length, + const char *s3_key, + const char *content_type); + +/* Free resources associated with result. */ +extern void S3_Result_Destroy(S3_Result *p_result); + +// --- Presigned URLs --- // + +// Presigned URL result +typedef struct { + boolean success; // TRUE if generation succeeded + char *url; // The presigned URL (on success) + char *error_message; // Error message (on failure) + Dowa_Arena *p_arena; // Internal arena (do not modify) +} S3_Presigned_URL; + +/* Generate a presigned URL for uploading (PUT) a file. + * + * The client can use this URL to upload directly to S3 without credentials. + * + * Example: + * S3_Presigned_URL url = S3_Presign_Put(&config, "uploads/file.txt", "image/png", 3600); + * if (url.success) { + * printf("Upload URL: %s\n", url.url); + * // Client does: curl -X PUT -H "Content-Type: image/png" --data-binary @file.png "$URL" + * } + * S3_Presigned_URL_Destroy(&url); + */ +extern S3_Presigned_URL S3_Presign_Put(const S3_Config *p_config, + const char *s3_key, + const char *content_type, + int32 expires_seconds); + +/* Generate a presigned URL for downloading (GET) a file. + * + * Example: + * S3_Presigned_URL url = S3_Presign_Get(&config, "uploads/file.txt", 3600); + * if (url.success) { + * printf("Download URL: %s\n", url.url); + * // Client does: curl "$URL" -o file.txt + * } + * S3_Presigned_URL_Destroy(&url); + */ +extern S3_Presigned_URL S3_Presign_Get(const S3_Config *p_config, + const char *s3_key, + int32 expires_seconds); + +/* Free resources associated with presigned URL result. */ +extern void S3_Presigned_URL_Destroy(S3_Presigned_URL *p_url); + +// --- Utility Functions --- // + +/* Guess content type from file extension. Returns "application/octet-stream" if unknown. */ +extern const char *S3_Guess_Content_Type(const char *filename); + +#endif