comparison seobeo/snapshot_creator.c @ 67:6626ec933933

[Seobeo] Separated out Client Server logic. Created test tools.
author June Park <parkjune1995@gmail.com>
date Wed, 24 Dec 2025 09:15:55 -0800
parents
children e7899c93da77
comparison
equal deleted inserted replaced
66:a0f0ad5e42eb 67:6626ec933933
1 #include "seobeo/snapshot_creator.h"
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <string.h>
5 #include <sys/stat.h>
6 #include <unistd.h>
7
8 #define MAX_RESPONSE_SIZE (1024 * 1024)
9
10 // Helper: Convert URL path to filename
11 static void path_to_filename(const char *path, char *filename, size_t max_len)
12 {
13 if (strcmp(path, "/") == 0)
14 {
15 snprintf(filename, max_len, "root.snapshot");
16 return;
17 }
18
19 const char *p = path;
20 if (*p == '/')
21 {
22 p++;
23 }
24
25 char *out = filename;
26 size_t remaining = max_len - 1;
27
28 while (*p && remaining > 0)
29 {
30 if (*p == '/')
31 {
32 *out++ = '_';
33 remaining--;
34 }
35 else
36 {
37 *out++ = *p;
38 remaining--;
39 }
40 p++;
41 }
42
43 snprintf(out, remaining, ".snapshot");
44 }
45
46 // Helper: Create directory recursively
47 static int create_directory(const char *path)
48 {
49 char tmp[1024];
50 char *p = NULL;
51 size_t len;
52
53 snprintf(tmp, sizeof(tmp), "%s", path);
54 len = strlen(tmp);
55 if (tmp[len - 1] == '/')
56 {
57 tmp[len - 1] = 0;
58 }
59
60 for (p = tmp + 1; *p; p++)
61 {
62 if (*p == '/')
63 {
64 *p = 0;
65 mkdir(tmp, 0755);
66 *p = '/';
67 }
68 }
69 return mkdir(tmp, 0755);
70 }
71
72 // Helper: Generate HTTP GET request
73 static int generate_http_get(char *buffer, size_t size, const char *path, const char *host)
74 {
75 return snprintf(
76 buffer, size,
77 "GET %s HTTP/1.1\r\n"
78 "Host: %s\r\n"
79 "Connection: close\r\n"
80 "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n"
81 "User-Agent: SeobeoSnapshotCreator/1.0\r\n"
82 "\r\n",
83 path, host
84 );
85 }
86
87 // Helper: Read full HTTP response
88 static char* read_full_response(Seobeo_Handle *client, size_t *len_out)
89 {
90 char *response = malloc(MAX_RESPONSE_SIZE);
91 if (!response)
92 {
93 return NULL;
94 }
95
96 size_t total = 0;
97 int attempts = 0;
98 const int max_attempts = 100;
99
100 while (attempts++ < max_attempts && total < MAX_RESPONSE_SIZE - 1)
101 {
102 int n = Seobeo_Handle_Read(client);
103
104 if (n > 0)
105 {
106 size_t to_copy = client->read_buffer_len;
107 if (total + to_copy > MAX_RESPONSE_SIZE - 1)
108 {
109 to_copy = MAX_RESPONSE_SIZE - 1 - total;
110 }
111
112 memcpy(response + total, client->read_buffer, to_copy);
113 total += to_copy;
114 Seobeo_Handle_Consume(client, (uint32)to_copy);
115 }
116 else if (n == -2)
117 {
118 break;
119 }
120 else if (n == 0)
121 {
122 usleep(10000);
123 continue;
124 }
125 else
126 {
127 free(response);
128 return NULL;
129 }
130 }
131
132 response[total] = '\0';
133 *len_out = total;
134 return response;
135 }
136
137 // Helper: Write snapshot to file
138 static int write_snapshot(const char *filepath, const char *data, size_t size)
139 {
140 // Create directory if needed
141 char dir_copy[1024];
142 snprintf(dir_copy, sizeof(dir_copy), "%s", filepath);
143
144 char *last_slash = strrchr(dir_copy, '/');
145 if (last_slash)
146 {
147 *last_slash = '\0';
148 create_directory(dir_copy);
149 }
150
151 FILE *f = fopen(filepath, "wb");
152 if (!f)
153 {
154 perror("fopen");
155 return -1;
156 }
157
158 size_t written = fwrite(data, 1, size, f);
159 fclose(f);
160
161 return (written == size) ? 0 : -1;
162 }
163
164 int Seobeo_Snapshot_Create(const SnapshotConfig *config)
165 {
166 if (!config || !config->path || !config->snapshot_dir || !config->host || !config->port)
167 {
168 fprintf(stderr, "Invalid snapshot config\n");
169 return -1;
170 }
171
172 printf("Creating snapshot: %s (expecting %d)\n", config->path, config->expected_status);
173
174 // Connect to server
175 Seobeo_Handle *client = Seobeo_Stream_Handle_Client_Create(config->host, config->port, FALSE);
176 if (!client || client->socket < 0)
177 {
178 fprintf(stderr, " ✗ Failed to connect to %s:%s\n", config->host, config->port);
179 if (client)
180 {
181 Seobeo_Handle_Destroy(client);
182 }
183 return -1;
184 }
185
186 // Send GET request
187 char request[4096];
188 int req_len = generate_http_get(request, sizeof(request), config->path, config->host);
189 Seobeo_Handle_Queue(client, (uint8*)request, (uint32)req_len);
190
191 if (Seobeo_Handle_Flush(client) < 0)
192 {
193 fprintf(stderr, " ✗ Failed to send request\n");
194 Seobeo_Handle_Destroy(client);
195 return -1;
196 }
197
198 // Read response
199 size_t response_len = 0;
200 char *response = read_full_response(client, &response_len);
201 Seobeo_Handle_Destroy(client);
202
203 if (!response || response_len == 0)
204 {
205 fprintf(stderr, " ✗ Failed to read response\n");
206 if (response)
207 {
208 free(response);
209 }
210 return -1;
211 }
212
213 // Parse status code
214 int status = -1;
215 const char *status_line = strstr(response, "HTTP/1.1 ");
216 if (!status_line)
217 {
218 status_line = strstr(response, "HTTP/1.0 ");
219 }
220 if (status_line)
221 {
222 sscanf(status_line + 9, "%d", &status);
223 }
224
225 if (status != config->expected_status)
226 {
227 fprintf(stderr, " ✗ Status mismatch: expected %d, got %d\n",
228 config->expected_status, status);
229 free(response);
230 return -1;
231 }
232
233 printf(" ✓ Status: %d\n", status);
234
235 // Generate snapshot filename
236 char filename[256];
237 path_to_filename(config->path, filename, sizeof(filename));
238
239 char filepath[1024];
240 snprintf(filepath, sizeof(filepath), "%s/%s", config->snapshot_dir, filename);
241
242 // Write snapshot
243 if (write_snapshot(filepath, response, response_len) == 0)
244 {
245 printf(" ✓ Snapshot saved: %s (%zu bytes)\n", filepath, response_len);
246 free(response);
247 return 0;
248 }
249 else
250 {
251 fprintf(stderr, " ✗ Failed to write snapshot: %s\n", filepath);
252 free(response);
253 return -1;
254 }
255 }
256
257 int Seobeo_Snapshots_Create_Batch(const SnapshotConfig configs[], int count)
258 {
259 int failed = 0;
260 int passed = 0;
261
262 for (int i = 0; i < count; i++)
263 {
264 if (Seobeo_Snapshot_Create(&configs[i]) == 0)
265 {
266 passed++;
267 }
268 else
269 {
270 failed++;
271 }
272 printf("\n");
273 }
274
275 printf("=== Summary ===\n");
276 printf("Created: %d\n", passed);
277 printf("Failed: %d\n", failed);
278
279 return (failed == 0) ? 0 : -1;
280 }