Mercurial
view seobeo/snapshot_creator.c @ 106:daf2d393741a
Debugging in server.
| author | June Park <parkjune1995@gmail.com> |
|---|---|
| date | Sat, 03 Jan 2026 10:46:58 -0800 |
| parents | 6626ec933933 |
| children | e7899c93da77 |
line wrap: on
line source
#include "seobeo/snapshot_creator.h" #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/stat.h> #include <unistd.h> #define MAX_RESPONSE_SIZE (1024 * 1024) // Helper: Convert URL path to filename 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: Generate HTTP GET request static int generate_http_get(char *buffer, size_t size, const char *path, const char *host) { return snprintf( buffer, size, "GET %s HTTP/1.1\r\n" "Host: %s\r\n" "Connection: close\r\n" "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n" "User-Agent: SeobeoSnapshotCreator/1.0\r\n" "\r\n", path, host ); } // Helper: Read full HTTP response static char* read_full_response(Seobeo_Handle *client, size_t *len_out) { char *response = malloc(MAX_RESPONSE_SIZE); if (!response) { return NULL; } size_t total = 0; int attempts = 0; const int max_attempts = 100; while (attempts++ < max_attempts && total < MAX_RESPONSE_SIZE - 1) { int n = Seobeo_Handle_Read(client); if (n > 0) { size_t to_copy = client->read_buffer_len; if (total + to_copy > MAX_RESPONSE_SIZE - 1) { to_copy = MAX_RESPONSE_SIZE - 1 - total; } memcpy(response + total, client->read_buffer, to_copy); total += to_copy; Seobeo_Handle_Consume(client, (uint32)to_copy); } else if (n == -2) { break; } else if (n == 0) { usleep(10000); continue; } else { free(response); return NULL; } } response[total] = '\0'; *len_out = total; 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); // Connect to server Seobeo_Handle *client = Seobeo_Stream_Handle_Client_Create(config->host, config->port, FALSE); if (!client || client->socket < 0) { fprintf(stderr, " ✗ Failed to connect to %s:%s\n", config->host, config->port); if (client) { Seobeo_Handle_Destroy(client); } return -1; } // Send GET request char request[4096]; int req_len = generate_http_get(request, sizeof(request), config->path, config->host); Seobeo_Handle_Queue(client, (uint8*)request, (uint32)req_len); if (Seobeo_Handle_Flush(client) < 0) { fprintf(stderr, " ✗ Failed to send request\n"); Seobeo_Handle_Destroy(client); return -1; } // Read response size_t response_len = 0; char *response = read_full_response(client, &response_len); Seobeo_Handle_Destroy(client); if (!response || response_len == 0) { fprintf(stderr, " ✗ Failed to read response\n"); if (response) { free(response); } return -1; } // Parse status code int status = -1; const char *status_line = strstr(response, "HTTP/1.1 "); if (!status_line) { status_line = strstr(response, "HTTP/1.0 "); } if (status_line) { sscanf(status_line + 9, "%d", &status); } if (status != config->expected_status) { fprintf(stderr, " ✗ Status mismatch: expected %d, got %d\n", config->expected_status, status); free(response); return -1; } printf(" ✓ Status: %d\n", status); // 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, response, response_len) == 0) { printf(" ✓ Snapshot saved: %s (%zu bytes)\n", filepath, response_len); free(response); return 0; } else { fprintf(stderr, " ✗ Failed to write snapshot: %s\n", filepath); free(response); return -1; } } 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; }