Mercurial
view seobeo/snapshot_creator.c @ 173:827c6ac504cd hg-web
Merged in default here.
| author | MrJuneJune <me@mrjunejune.com> |
|---|---|
| date | Mon, 19 Jan 2026 18:59:10 -0800 |
| parents | 7eb79fd91c7e |
| children |
line wrap: on
line source
#include "seobeo/snapshot_creator.h" #include "seobeo/seobeo_internal.h" #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/stat.h> #include <unistd.h> static void path_to_filename(const char *path, char *filename, size_t max_len) { if (strcmp(path, "/") == 0) { snprintf(filename, max_len, "root.snapshot"); return; } const char *p = path; if (*p == '/') p++; char *out = filename; size_t remaining = max_len - 1; while (*p && remaining > 0) { if (*p == '/') { *out++ = '_'; remaining--; } else { *out++ = *p; remaining--; } p++; } snprintf(out, remaining, ".snapshot"); } // Helper: Create directory recursively static int create_directory(const char *path) { char tmp[1024]; char *p = NULL; size_t len; snprintf(tmp, sizeof(tmp), "%s", path); len = strlen(tmp); if (tmp[len - 1] == '/') { tmp[len - 1] = 0; } for (p = tmp + 1; *p; p++) { if (*p == '/') { *p = 0; mkdir(tmp, 0755); *p = '/'; } } return mkdir(tmp, 0755); } // Helper: Build full HTTP response from Seobeo_Client_Response static char* build_full_response(Seobeo_Client_Response *p_resp, size_t *len_out) { if (!p_resp) return NULL; // Calculate total response size size_t status_line_len = 100; // "HTTP/1.1 200 OK\r\n" size_t headers_len = 0; size_t body_len = p_resp->body_length; // Estimate header size if (p_resp->headers) { size_t header_count = Dowa_Array_Length(p_resp->headers); for (size_t i = 0; i < header_count; i++) { headers_len += strlen(p_resp->headers[i].key) + strlen(p_resp->headers[i].value) + 4; // ": " + "\r\n" } } size_t total_size = status_line_len + headers_len + 2 + body_len + 1; // +2 for "\r\n", +1 for null terminator char *response = malloc(total_size); if (!response) return NULL; // Build status line int offset = snprintf(response, total_size, "HTTP/1.1 %d %s\r\n", p_resp->status_code, p_resp->status_text ? p_resp->status_text : "OK"); // Add headers if (p_resp->headers) { size_t header_count = Dowa_Array_Length(p_resp->headers); for (size_t i = 0; i < header_count; i++) { offset += snprintf(response + offset, total_size - offset, "%s: %s\r\n", p_resp->headers[i].key, p_resp->headers[i].value); } } // End of headers offset += snprintf(response + offset, total_size - offset, "\r\n"); // Add body if (p_resp->body && body_len > 0) { memcpy(response + offset, p_resp->body, body_len); offset += body_len; } response[offset] = '\0'; *len_out = offset; return response; } // Helper: Write snapshot to file static int write_snapshot(const char *filepath, const char *data, size_t size) { // Create directory if needed char dir_copy[1024]; snprintf(dir_copy, sizeof(dir_copy), "%s", filepath); char *last_slash = strrchr(dir_copy, '/'); if (last_slash) { *last_slash = '\0'; create_directory(dir_copy); } FILE *f = fopen(filepath, "wb"); if (!f) { perror("fopen"); return -1; } size_t written = fwrite(data, 1, size, f); fclose(f); return (written == size) ? 0 : -1; } int Seobeo_Snapshot_Create(const SnapshotConfig *config) { if (!config || !config->path || !config->snapshot_dir || !config->host || !config->port) { fprintf(stderr, "Invalid snapshot config\n"); return -1; } printf("Creating snapshot: %s (expecting %d)\n", config->path, config->expected_status); // Build URL char url[2048]; snprintf(url, sizeof(url), "http://%s:%s%s", config->host, config->port, config->path); // Create HTTP request Seobeo_Client_Request *p_req = Seobeo_Client_Request_Create(url); if (!p_req) { fprintf(stderr, " ✗ Failed to create request for %s\n", url); return -1; } // Execute request Seobeo_Client_Response *p_resp = Seobeo_Client_Request_Execute(p_req); if (!p_resp) { fprintf(stderr, " ✗ Failed to get response\n"); Seobeo_Client_Request_Destroy(p_req); return -1; } // Check status code if (p_resp->status_code != config->expected_status) { fprintf(stderr, " ✗ Status mismatch: expected %d, got %d\n", config->expected_status, p_resp->status_code); // fprintf(stderr, "%s", p_resp->body); Seobeo_Client_Response_Destroy(p_resp); Seobeo_Client_Request_Destroy(p_req); return -1; } printf(" ✓ Status: %d\n", p_resp->status_code); // Generate snapshot filename char filename[256]; path_to_filename(config->path, filename, sizeof(filename)); char filepath[1024]; snprintf(filepath, sizeof(filepath), "%s/%s", config->snapshot_dir, filename); // Write snapshot if (write_snapshot(filepath, p_resp->body, p_resp->body_length) == 0) { printf(" ✓ Snapshot saved: %s (%zu bytes)\n", filepath, p_resp->body_length); return 0; } else { fprintf(stderr, " ✗ Failed to write snapshot: %s\n", filepath); return -1; } Seobeo_Client_Response_Destroy(p_resp); Seobeo_Client_Request_Destroy(p_req); } int Seobeo_Snapshots_Create_Batch(const SnapshotConfig configs[], int count) { int failed = 0; int passed = 0; for (int i = 0; i < count; i++) { if (Seobeo_Snapshot_Create(&configs[i]) == 0) passed++; else failed++; printf("\n"); } printf("=== Summary ===\n"); printf("Created: %d\n", passed); printf("Failed: %d\n", failed); return (failed == 0) ? 0 : -1; }