ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
mdl_fetch_page.c
Go to the documentation of this file.
1
9#include <limits.h>
10#include <stdint.h>
11#include <stdio.h>
12#include <string.h>
13#include <time.h>
14
15#include "mdl_fetch.h"
17#include "mdl_fetch_internal.h"
18#include "mdl_hash.h"
19#include "mdl_net.h"
20#include "mdl_storage.h"
21#include "mdl_url_guard.h"
22#include "mdl_urlname.h"
23#include "ra8_attributes.h"
24#include "ra8_err.h"
25
27typedef enum : uint16_t {
30
32typedef enum : uint32_t {
36 k_ms_per_sec = 1000U,
37 k_ns_per_ms = 1000000U,
39
45typedef struct {
46 uint64_t bytes;
47 uint32_t elapsed_ms;
48 bool reused;
50
67
82RA8_INTERNAL static uint32_t internal_mdl_fetch_page_max_u32(uint32_t a, uint32_t b)
83{
84 return (a > b) ? a : b;
85}
86
88RA8_INTERNAL static const char* internal_mdl_fetch_page_host(const char* url, char* buf, size_t cap)
89{
90 return mdl_url_host(url, buf, cap) ? buf : nullptr;
91}
92
107{
108 if (ctx->progress_fn == nullptr) {
109 return 0;
110 }
111 struct timespec ts = {};
112 if (clock_gettime(CLOCK_MONOTONIC, &ts) != 0) {
113 return 0;
114 }
115 return ((int64_t)ts.tv_sec * (int64_t)k_ms_per_sec) +
116 ((int64_t)ts.tv_nsec / (int64_t)k_ns_per_ms);
117}
118
139 const mdl_run_pos_t* pos,
140 size_t page_index,
141 const mdl_page_outcome_t* out)
142{
143 if (ctx->progress_fn == nullptr) {
144 return k_ra8_ok;
145 }
146 const mdl_fetch_progress_t ev = {.chapter_index = pos->chapter_index,
147 .chapter_total = pos->chapter_total,
148 .chapter_id = pos->chapter_id,
149 .page_index = page_index,
150 .page_total = ctx->images->count,
151 .page_bytes = out->bytes,
152 .elapsed_ms = out->elapsed_ms,
153 .reused = out->reused};
154 return ctx->progress_fn(ctx->progress_ctx, &ev);
155}
156
175RA8_INTERNAL static bool
176internal_mdl_fetch_copy_file(mdl_storage_t* storage, const char* src, const char* dst)
177{
178 return mdl_storage_copy_atomic(storage, src, dst) == k_ra8_ok;
179}
180
199RA8_INTERNAL static bool
200internal_mdl_fetch_page_leaf(size_t page_no, const char* url, char* out, size_t cap)
201{
202 char ext[8];
203 mdl_urlname_ext(url, ext, sizeof(ext));
204 const int n = snprintf(out, cap, "page_%04zu.%s", page_no, ext);
205 return (n > 0) && ((size_t)n < cap);
206}
207
229 uint64_t url_hash,
230 const char* target_abs,
231 const char* target_rel)
232{
233 const mdl_page_rec_t* held = mdl_state_find_page(ctx->state, url_hash);
234 if (held == nullptr) {
235 return false;
236 }
237 char src_abs[PATH_MAX];
238 const int sn = snprintf(src_abs, sizeof(src_abs), "%s/%s", ctx->series_abs_dir, held->rel_path);
239 if ((sn < 0) || ((size_t)sn >= sizeof(src_abs))) {
240 return false;
241 }
242 uint64_t have = 0U;
243 if ((mdl_hash_file(ctx->storage, src_abs, &have) != k_ra8_ok) || (have != held->content_hash)) {
244 return false; /* the held file is gone or torn: refetch */
245 }
246
247 char act_abs[PATH_MAX];
248 char act_rel[k_mdl_relpath_max];
249 (void)snprintf(act_abs, sizeof(act_abs), "%s", target_abs);
250 (void)snprintf(act_rel, sizeof(act_rel), "%s", target_rel);
251
252 const char* held_dot = strrchr(held->rel_path, '.');
253 const char* tab_dot = strrchr(act_abs, '.');
254 const char* tre_dot = strrchr(act_rel, '.');
255 if ((held_dot != nullptr) && (tab_dot != nullptr) && (tre_dot != nullptr)) {
256 const char* held_ext = held_dot + 1;
257 if (strcmp(tab_dot + 1, held_ext) != 0) {
258 (void)snprintf(act_abs,
259 sizeof(act_abs),
260 "%.*s.%s",
261 (int)(tab_dot - target_abs),
262 target_abs,
263 held_ext);
264 (void)snprintf(act_rel,
265 sizeof(act_rel),
266 "%.*s.%s",
267 (int)(tre_dot - target_rel),
268 target_rel,
269 held_ext);
270 }
271 }
272
273 if (strcmp(held->rel_path, act_rel) == 0) {
274 return true; /* already in place (same-chapter resume) */
275 }
276 if (!internal_mdl_fetch_copy_file(ctx->storage, src_abs, act_abs)) {
277 return false;
278 }
279 return mdl_state_add_page(ctx->state,
280 url_hash,
281 held->content_hash,
282 act_rel,
283 held->etag,
284 held->last_modified,
285 held->fetched_at,
286 held->response_status);
287}
288
310 const char* guessed_abs,
311 const char* actual_abs)
312{
313 if ((storage == nullptr) || (guessed_abs == nullptr) || (actual_abs == nullptr)) {
314 return false;
315 }
316 if (strcmp(guessed_abs, actual_abs) == 0) {
317 return true;
318 }
319 fw_fs_stat_t state = {};
320 const ra8_err_t error = fw_fs_stat(&storage->fs->names, guessed_abs, &state);
321 if (error != k_ra8_ok) {
322 return false;
323 }
324 if (!state.exists) {
325 return true;
326 }
327 if (state.type != k_fw_fs_node_file) {
328 return false;
329 }
330 return fw_fs_unlink(&storage->fs->names, guessed_abs) == k_ra8_ok;
331}
332
353 const char* chapter_url,
354 const char* url,
355 const char* target_abs,
356 const char* target_rel,
358{
359 uint32_t crawl = 0U;
360 if (!mdl_session_url_allowed(ctx->session, url, &crawl)) {
362 return k_ra8_fail;
363 }
365 tx->held = ctx->refetch ? nullptr : tx->recorded;
366 const char* host = internal_mdl_fetch_page_host(url, tx->host, sizeof(tx->host));
369 tx->req = (mdl_net_req_t){
370 .user_agent = ctx->session->user_agent,
371 .referer = chapter_url,
372 .if_none_match = (tx->held != nullptr && tx->held->etag[0] != '\0') ? tx->held->etag : nullptr,
373 .if_modified_since = (tx->held != nullptr && tx->held->last_modified[0] != '\0')
374 ? tx->held->last_modified
375 : nullptr,
376 .timeout_ms = ctx->timeout_ms,
377 };
378 ra8_err_t rc = priv_mdl_fetch_body_init_image(&tx->body, ctx->storage, target_abs, target_rel);
380 if (rc == k_ra8_ok) {
382 host,
383 url,
384 &tx->req,
385 &sink,
386 tx->jmin,
387 tx->jmax,
388 &tx->resp,
389 &tx->got);
390 }
391 if (rc != k_ra8_ok) {
392 const ra8_err_t aborted = priv_mdl_fetch_body_abort(&tx->body);
393 const ra8_err_t failure = (aborted == k_ra8_ok) ? rc : aborted;
394 priv_mdl_fetch_record_fail(ctx, url, tx->resp.status, failure);
395 return failure;
396 }
397 return k_ra8_ok;
398}
399
420 const char* url,
421 const char* target_abs,
422 const char* target_rel,
424 bool* out_done)
425{
426 *out_done = false;
427 if (tx->resp.status != (long)k_http_not_modified) {
428 return k_ra8_ok;
429 }
431 if (cleanup != k_ra8_ok) {
432 return cleanup;
433 }
434 if ((tx->held != nullptr) &&
435 internal_mdl_fetch_try_reuse(ctx, mdl_hash_str(url), target_abs, target_rel)) {
436 const time_t observed = time(nullptr);
438 mdl_hash_str(url),
439 (observed < (time_t)0) ? 0 : (int64_t)observed,
440 (uint16_t)k_http_not_modified)) {
442 }
443 *out_done = true;
444 return k_ra8_ok;
445 }
446 tx->req.if_none_match = nullptr;
447 tx->req.if_modified_since = nullptr;
448 tx->resp = (mdl_net_resp_t){};
449 tx->got = 0U;
452 tx->host,
453 url,
454 &tx->req,
455 &sink,
456 tx->jmin,
457 tx->jmax,
458 &tx->resp,
459 &tx->got);
460 if ((rc == k_ra8_ok) && (tx->resp.status != (long)k_http_not_modified)) {
461 return k_ra8_ok;
462 }
463 cleanup = priv_mdl_fetch_body_abort(&tx->body);
464 const ra8_err_t failure_fallback = (rc != k_ra8_ok) ? rc : k_ra8_err_validation_failed;
465 const ra8_err_t failure = (cleanup != k_ra8_ok) ? cleanup : failure_fallback;
466 priv_mdl_fetch_record_fail(ctx, url, tx->resp.status, failure);
467 return failure;
468}
469
489 const char* url,
490 const char* target_abs,
492 size_t* out_bytes)
493{
495 if (error != k_ra8_ok) {
496 const ra8_err_t aborted = priv_mdl_fetch_body_abort(&tx->body);
497 error = (aborted == k_ra8_ok) ? error : aborted;
498 priv_mdl_fetch_record_fail(ctx, url, tx->resp.status, error);
499 return error;
500 }
501 const char* held_etag = (tx->held != nullptr) ? tx->held->etag : "";
502 const char* etag = (tx->resp.etag[0] != '\0') ? tx->resp.etag : held_etag;
503 const char* held_modified = (tx->held != nullptr) ? tx->held->last_modified : "";
504 const char* modified =
505 (tx->resp.last_modified[0] != '\0') ? tx->resp.last_modified : held_modified;
506 if ((ctx->state->page_rec_count >= (uint32_t)k_mdl_max_page_recs) && (tx->recorded == nullptr)) {
507 error = priv_mdl_fetch_body_abort(&tx->body);
508 error = (error == k_ra8_ok) ? k_ra8_err_no_mem : error;
509 priv_mdl_fetch_record_fail(ctx, url, tx->resp.status, error);
510 return error;
511 }
512 if ((tx->resp.status < (long)k_http_status_min) || (tx->resp.status > (long)k_http_status_max)) {
513 error = priv_mdl_fetch_body_abort(&tx->body);
514 error = (error == k_ra8_ok) ? k_ra8_err_protocol_error : error;
515 priv_mdl_fetch_record_fail(ctx, url, tx->resp.status, error);
516 return error;
517 }
518 const uint64_t content = tx->body.writer.hash;
519 const time_t observed = time(nullptr);
520 error = priv_mdl_fetch_body_commit(&tx->body);
521 if (error != k_ra8_ok) {
522 priv_mdl_fetch_record_fail(ctx, url, tx->resp.status, error);
523 return error;
524 }
525 if (!internal_mdl_fetch_discard_stale_page(ctx->storage, target_abs, tx->body.actual_abs) ||
527 mdl_hash_str(url),
528 content,
529 tx->body.actual_rel,
530 etag,
531 modified,
532 (observed < (time_t)0) ? 0 : (int64_t)observed,
533 (uint16_t)tx->resp.status)) {
535 return k_ra8_fail;
536 }
537 if (out_bytes != nullptr) {
538 *out_bytes = tx->got;
539 }
540 return k_ra8_ok;
541}
542
564 const char* chapter_url,
565 const char* url,
566 const char* target_abs,
567 const char* target_rel,
568 size_t* out_bytes,
569 mdl_net_resp_t* out_resp)
570{
571 if (out_bytes != nullptr) {
572 *out_bytes = 0U;
573 }
574 if (out_resp != nullptr) {
575 *out_resp = (mdl_net_resp_t){};
576 }
577 mdl_page_transfer_t tx = {};
578 ra8_err_t rc =
579 internal_mdl_fetch_prepare_page(ctx, chapter_url, url, target_abs, target_rel, &tx);
580 if (rc != k_ra8_ok) {
581 if (out_resp != nullptr) {
582 *out_resp = tx.resp;
583 }
584 return rc;
585 }
586 bool reused = false;
587 rc = internal_mdl_fetch_resolve_not_modified(ctx, url, target_abs, target_rel, &tx, &reused);
588 if (out_resp != nullptr) {
589 *out_resp = tx.resp;
590 }
591 if ((rc != k_ra8_ok) || reused) {
592 return rc;
593 }
594 return internal_mdl_fetch_publish_page(ctx, url, target_abs, &tx, out_bytes);
595}
596
622 const char* chapter_url,
623 const char* dest_abs,
624 const char* dest_rel,
625 size_t page_no,
626 size_t idx,
628 mdl_fetch_stats_t* stats,
630{
631 const char* url = ctx->images->urls[idx];
632 char leaf[k_fetch_leaf_bytes];
633 if (!internal_mdl_fetch_page_leaf(page_no, url, leaf, sizeof(leaf))) {
634 return k_ra8_fail;
635 }
636 char target_abs[PATH_MAX];
637 char target_rel[k_mdl_relpath_max];
638 const int an = snprintf(target_abs, sizeof(target_abs), "%s/%s", dest_abs, leaf);
639 const int rn = snprintf(target_rel, sizeof(target_rel), "%s/%s", dest_rel, leaf);
640 if ((an < 0) || ((size_t)an >= sizeof(target_abs)) || (rn < 0) ||
641 ((size_t)rn >= sizeof(target_rel))) {
642 return k_ra8_fail;
643 }
644 const uint64_t url_hash = mdl_hash_str(url);
645 const mdl_page_rec_t* held = mdl_state_find_page(ctx->state, url_hash);
646 const bool has_validator =
647 (held != nullptr) && ((held->etag[0] != '\0') || (held->last_modified[0] != '\0'));
648 if (!ctx->refetch && !has_validator &&
649 internal_mdl_fetch_try_reuse(ctx, url_hash, target_abs, target_rel)) {
650 stats->pages_reused += 1U;
651 *out = (mdl_page_outcome_t){.bytes = 0U, .elapsed_ms = 0U, .reused = true};
652 } else {
653 const int64_t t0 = internal_mdl_fetch_mono_ms(ctx);
654 size_t got = 0U;
655 mdl_net_resp_t resp = {};
656 const ra8_err_t rc =
657 internal_mdl_fetch_do_fetch_page(ctx, chapter_url, url, target_abs, target_rel, &got, &resp);
658 if (rc != k_ra8_ok) {
659 stats->pages_failed += 1U;
660 return rc;
661 }
662 if (resp.status == (long)k_http_not_modified) {
663 stats->pages_reused += 1U;
664 *out = (mdl_page_outcome_t){.bytes = 0U,
665 .elapsed_ms = (uint32_t)(internal_mdl_fetch_mono_ms(ctx) - t0),
666 .reused = true};
667 } else {
668 stats->pages_fetched += 1U;
669 *out = (mdl_page_outcome_t){.bytes = (uint64_t)got,
670 .elapsed_ms = (uint32_t)(internal_mdl_fetch_mono_ms(ctx) - t0),
671 .reused = false};
672 }
673 }
674 rec->pages_done = (uint16_t)(idx + 1U);
675 return priv_mdl_fetch_checkpoint(ctx);
676}
677
681 const char* chapter_url,
682 const char* dest_abs,
683 const char* dest_rel,
684 size_t base,
686 mdl_fetch_stats_t* stats,
687 const mdl_run_pos_t* pos)
688{
689 for (size_t i = 0U; i < ctx->images->count; ++i) {
690 const size_t page_no = base + i + 1U;
691 mdl_page_outcome_t out = {};
693 chapter_url,
694 dest_abs,
695 dest_rel,
696 page_no,
697 i,
698 rec,
699 stats,
700 &out);
701 if (rc != k_ra8_ok) {
702 return rc;
703 }
704 const ra8_err_t progress_error = internal_mdl_fetch_emit_progress(ctx, pos, i + 1U, &out);
705 if (progress_error != k_ra8_ok) {
706 ctx->progress_error = progress_error;
707 return progress_error;
708 }
709 }
710 return k_ra8_ok;
711}
712
#define nullptr
@ k_ms_per_sec
Milliseconds per second.
Definition main.c:51
ra8_err_t fw_fs_stat(const fw_fs_namespace_t *names, const char *path, fw_fs_stat_t *out)
Query a path; a miss is success with out->exists == false.
Definition fw_if_fs.c:480
ra8_err_t fw_fs_unlink(const fw_fs_namespace_t *names, const char *path)
Remove one regular file; directories require fw_fs_rmdir.
Definition fw_if_fs.c:575
@ k_fw_fs_node_file
Regular byte stream.
ra8_err_t priv_mdl_fetch_checkpoint(const mdl_fetch_ctx_t *ctx)
Persist state atomically when a checkpoint target is configured.
Definition mdl_fetch.c:193
ra8_err_t priv_mdl_fetch_with_retry(mdl_fetch_ctx_t *ctx, const char *host, const char *url, const mdl_net_req_t *req, mdl_net_body_sink_t *sink, uint32_t jmin, uint32_t jmax, mdl_net_resp_t *out_resp, size_t *out_bytes)
Bounded, governed retry of one image transfer; last status latched.
Definition mdl_fetch.c:264
void priv_mdl_fetch_record_fail(const mdl_fetch_ctx_t *ctx, const char *url, long status, ra8_err_t err)
Append one failure to the run's log (when set); always tally total.
Definition mdl_fetch.c:175
State-aware chapter/page download orchestrator for the media downloader.
ra8_err_t priv_mdl_fetch_body_commit(mdl_fetch_body_t *body)
Validate exact size/hash and publish one prepared body.
mdl_net_body_sink_t priv_mdl_fetch_body_sink(mdl_fetch_body_t *body)
Return the network sink view of one body state.
ra8_err_t priv_mdl_fetch_body_prepare(mdl_fetch_body_t *body)
Finish prefix classification and make a nonempty stage commit-ready.
ra8_err_t priv_mdl_fetch_body_init_image(mdl_fetch_body_t *body, mdl_storage_t *storage, const char *target_abs, const char *target_rel)
Initialize a magic-typed image body sink.
ra8_err_t priv_mdl_fetch_body_abort(mdl_fetch_body_t *body)
Abort any private stage owned by a body sink.
Portable single-transaction response-body sink for media fetches.
Module-private fetch-loop decisions promoted for host unit tests and the CLI's end-of-run reporting.
ra8_err_t priv_mdl_fetch_chapter_pages(mdl_fetch_ctx_t *ctx, const char *chapter_url, const char *dest_abs, const char *dest_rel, size_t base, mdl_chapter_rec_t *rec, mdl_fetch_stats_t *stats, const mdl_run_pos_t *pos)
Fetch every page of one chapter; fail (partial) on the first bad page.
static ra8_err_t internal_mdl_fetch_prepare_page(mdl_fetch_ctx_t *ctx, const char *chapter_url, const char *url, const char *target_abs, const char *target_rel, mdl_page_transfer_t *tx)
Prepare and execute the initial conditional page request.
static ra8_err_t internal_mdl_fetch_resolve_not_modified(mdl_fetch_ctx_t *ctx, const char *url, const char *target_abs, const char *target_rel, mdl_page_transfer_t *tx, bool *out_done)
Resolve HTTP 304 by verified reuse or one unconditional retry.
static bool internal_mdl_fetch_discard_stale_page(mdl_storage_t *storage, const char *guessed_abs, const char *actual_abs)
Remove a superseded URL-derived page only after its replacement committed.
mdl_fetch_page_size_t
Local page-path buffer size.
@ k_fetch_leaf_bytes
page_NNNN.ext leaf-name bytes.
static bool internal_mdl_fetch_copy_file(mdl_storage_t *storage, const char *src, const char *dst)
Copy one file through the validated portable storage transaction.
mdl_fetch_page_bound_t
Status and time conversions used by page accounting.
@ k_ns_per_ms
Nanoseconds per millisecond.
@ k_http_status_min
Smallest valid HTTP response status.
@ k_http_status_max
Largest valid HTTP response status.
static ra8_err_t internal_mdl_fetch_one_page(mdl_fetch_ctx_t *ctx, const char *chapter_url, const char *dest_abs, const char *dest_rel, size_t page_no, size_t idx, mdl_chapter_rec_t *rec, mdl_fetch_stats_t *stats, mdl_page_outcome_t *out)
Reuse or fetch page idx and checkpoint its outcome.
static ra8_err_t internal_mdl_fetch_publish_page(mdl_fetch_ctx_t *ctx, const char *url, const char *target_abs, mdl_page_transfer_t *tx, size_t *out_bytes)
Validate and atomically publish a nonempty staged page.
static bool internal_mdl_fetch_try_reuse(mdl_fetch_ctx_t *ctx, uint64_t url_hash, const char *target_abs, const char *target_rel)
Reuse an already-held byte-identical page instead of fetching it.
static int64_t internal_mdl_fetch_mono_ms(const mdl_fetch_ctx_t *ctx)
Perform the mono ms step.
static bool internal_mdl_fetch_page_leaf(size_t page_no, const char *url, char *out, size_t cap)
Compose the page_NNNN.ext leaf for one page; false if it overran.
static uint32_t internal_mdl_fetch_page_max_u32(uint32_t a, uint32_t b)
Larger of two unsigned delay values.
static ra8_err_t internal_mdl_fetch_do_fetch_page(mdl_fetch_ctx_t *ctx, const char *chapter_url, const char *url, const char *target_abs, const char *target_rel, size_t *out_bytes, mdl_net_resp_t *out_resp)
Perform the do fetch page step.
static ra8_err_t internal_mdl_fetch_emit_progress(const mdl_fetch_ctx_t *ctx, const mdl_run_pos_t *pos, size_t page_index, const mdl_page_outcome_t *out)
Emit one per-page progress event through the injected sink, if any.
static const char * internal_mdl_fetch_page_host(const char *url, char *buf, size_t cap)
Governor host key for one page URL.
Content-identity hashing (FNV-1a 64) for the media downloader's persistent library state.
ra8_err_t mdl_hash_file(mdl_storage_t *storage, const char *path, uint64_t *out)
FNV-1a 64 hash of a file's full contents.
Definition mdl_hash.c:103
uint64_t mdl_hash_str(const char *s)
FNV-1a 64 hash of a NUL-terminated string (excluding the NUL).
Definition mdl_hash.c:40
Streaming HTTP(S) GET seam (a real function-pointer vtable) for the host manga downloader (v0).
@ k_http_not_modified
Conditional GET reused the held entity.
@ k_mdl_gov_host_max
Host-key buffer bytes (matches config).
bool mdl_session_url_allowed(mdl_session_t *session, const char *url, uint32_t *crawl_delay_ms)
Decide whether url may be fetched under robots.txt, and its delay.
const mdl_page_rec_t * mdl_state_find_page(const mdl_state_t *st, uint64_t url_hash)
Find a page record by its source-URL hash (the dedup lookup).
Definition mdl_state.c:334
bool mdl_state_note_page_response(mdl_state_t *st, uint64_t url_hash, int64_t fetched_at, uint16_t response_status)
Refresh the observed HTTP result for one existing URL cache entry.
Definition mdl_state.c:393
@ k_mdl_relpath_max
Page path relative to the series dir.
Definition mdl_state.h:102
@ k_mdl_max_page_recs
Per-page content records per series.
Definition mdl_state.h:115
bool mdl_state_add_page(mdl_state_t *st, uint64_t url_hash, uint64_t content_hash, const char *rel_path, const char *etag, const char *last_modified, int64_t fetched_at, uint16_t response_status)
Add or replace a URL-keyed page cache record.
Definition mdl_state.c:347
Injected portable storage resources for downloader domain code.
ra8_err_t mdl_storage_copy_atomic(mdl_storage_t *storage, const char *source, const char *destination)
Copy a regular file through a validated atomic transaction.
Pure URL / address safety predicates for the libcurl backend.
bool mdl_url_host(const char *url, char *out, size_t cap)
Extract the authority (host and optional port) from an http(s) URL.
Bounded URL naming and portable image-classification helpers.
void mdl_urlname_ext(const char *url, char *out, size_t cap)
Choose a lower-case image file extension from a URL.
Annotation-attribute framework macros for ra8-firmware.
#define RA8_PRIV
Module-private helper: shared across TUs but only inside one library.
#define RA8_INTERNAL
Marker that a function is intended to be static (file-local).
Error Code Definitions for ra8-firmware.
@ k_ra8_err_no_mem
Static buffer exhausted (no dynamic memory on this project).
Definition ra8_err.h:142
@ k_ra8_fail
Generic unspecified failure.
Definition ra8_err.h:133
@ k_ra8_err_invalid_state
Module in wrong state for requested operation.
Definition ra8_err.h:161
@ k_ra8_err_validation_failed
Validation rule failed (caller-supplied invariant not satisfied).
Definition ra8_err.h:459
@ k_ra8_ok
Success – operation completed with all postconditions satisfied.
Definition ra8_err.h:119
@ k_ra8_err_protocol_error
Protocol-level error (e.g.
Definition ra8_err.h:429
ra8_err_codes_t ra8_err_t
Canonical error-return type used by every ra8-firmware API.
Definition ra8_err.h:546
int strcmp(const char *s1, const char *s2)
Compare two null-terminated strings.
char * strrchr(const char *s, int c)
Locate last occurrence of character in string.
Result of a portable metadata query.
bool exists
False means a clean lookup miss.
fw_fs_node_type_t type
Kind of node at the path.
fw_fs_namespace_t names
Namespace operations.
One chapter's coverage in library state.
Definition mdl_state.h:128
uint16_t pages_done
Pages fetched and verified.
Definition mdl_state.h:135
Caller-owned state for one retryable streamed fetch.
mdl_storage_txn_t writer
Single private output stage.
char actual_rel[k_mdl_relpath_max]
Magic-derived relative path.
char actual_abs[PATH_MAX]
Magic-derived final path.
Everything mdl_fetch_run needs, injected for testability.
Definition mdl_fetch.h:164
mdl_state_t * state
Persistent state, read and updated.
Definition mdl_fetch.h:167
mdl_url_list_t * images
Extracted-image scratch (caller-owned).
Definition mdl_fetch.h:177
const mdl_site_t * site
Selectors + politeness bounds.
Definition mdl_fetch.h:172
void * progress_ctx
Context passed to progress_fn.
Definition mdl_fetch.h:183
mdl_storage_t * storage
Portable storage binding + workspaces.
Definition mdl_fetch.h:166
const char * series_abs_dir
Absolute series dir (paths resolve here).
Definition mdl_fetch.h:170
bool refetch
Ignore local page reuse and hit network.
Definition mdl_fetch.h:179
mdl_session_t * session
Identity + robots + net backend.
Definition mdl_fetch.h:165
mdl_progress_fn progress_fn
Per-page progress sink, or NULL (silent).
Definition mdl_fetch.h:182
uint32_t timeout_ms
Per-request time budget.
Definition mdl_fetch.h:174
ra8_err_t progress_error
First callback failure from this run.
Definition mdl_fetch.h:184
One per-page progress event the run emits through mdl_progress_fn.
Definition mdl_fetch.h:125
Tallies a fetch run reports back (all zero-initialised by the run).
Definition mdl_fetch.h:65
size_t pages_fetched
Pages transferred over the network.
Definition mdl_fetch.h:69
size_t pages_reused
Pages served from an already-held verified file.
Definition mdl_fetch.h:70
size_t pages_failed
Page fetches that failed or robots refused.
Definition mdl_fetch.h:71
Caller-owned lifecycle and write seam for one response body.
Definition mdl_net.h:162
Per-request session parameters.
Definition mdl_net.h:43
const char * if_none_match
If-None-Match conditional header (ETag), or NULL.
Definition mdl_net.h:46
const char * if_modified_since
If-Modified-Since header (Last-Modified), or NULL.
Definition mdl_net.h:47
Per-transfer response metadata surfaced to the politeness governor.
Definition mdl_net.h:120
long status
Finished transfer's HTTP status, 0 if none.
Definition mdl_net.h:121
char etag[k_mdl_etag_max]
Raw ETag value, "" when absent.
Definition mdl_net.h:123
char last_modified[k_mdl_last_mod_max]
Raw Last-Modified value, "" when absent.
Definition mdl_net.h:124
Transfer outcome used to produce one progress event.
uint64_t bytes
Bytes transferred, zero when reused.
uint32_t elapsed_ms
Monotonic elapsed milliseconds.
bool reused
Whether verified local bytes won.
One page's dedup/verify record in the series-wide pool.
Definition mdl_state.h:151
char etag[k_mdl_etag_max]
Cached ETag for conditional GET.
Definition mdl_state.h:155
char last_modified[k_mdl_last_mod_max]
Cached Last-Modified response value.
Definition mdl_state.h:157
uint64_t content_hash
FNV-1a 64 of the fetched bytes.
Definition mdl_state.h:153
char rel_path[k_mdl_relpath_max]
Path under the series directory.
Definition mdl_state.h:154
uint16_t response_status
Most recent HTTP status; zero if legacy.
Definition mdl_state.h:159
int64_t fetched_at
Most recent HTTP result time (epoch s).
Definition mdl_state.h:158
Mutable state for one conditional page transfer.
const mdl_page_rec_t * held
Record eligible for conditional reuse.
uint32_t jmin
Governed minimum image delay.
size_t got
Body bytes accepted by the sink.
const mdl_page_rec_t * recorded
URL-keyed record, including refetch runs.
mdl_net_resp_t resp
Most recent response metadata.
char host[k_mdl_gov_host_max]
Parsed governor host key.
uint32_t jmax
Governed maximum image delay.
mdl_net_req_t req
Request metadata and validators.
mdl_fetch_body_t body
Single portable transaction body sink.
Stable chapter position carried into per-page progress events.
size_t chapter_total
Total chapters in the run.
size_t chapter_index
1-based chapter position in the run.
const char * chapter_id
Stable chapter identifier.
const char * user_agent
Full UA header (caller-owned).
Definition mdl_session.h:41
uint32_t img_delay_max
Per-image spacing ceiling.
Definition mdl_config.h:88
uint32_t img_delay_min
Per-image spacing floor.
Definition mdl_config.h:87
uint32_t page_rec_count
Page records recorded.
Definition mdl_state.h:193
One non-reentrant downloader filesystem dependency bundle.
Definition mdl_storage.h:40
const fw_fs_t * fs
Injected portable filesystem.
Definition mdl_storage.h:41
uint64_t hash
Running FNV-1a identity.
Definition mdl_storage.h:62
char urls[k_mdl_max_urls][k_mdl_url_max]
Absolute, NUL-terminated.
Definition mdl_extract.h:30
size_t count
Number of valid entries.
Definition mdl_extract.h:31