27typedef enum : uint16_t {
32typedef enum : uint32_t {
84 return (a > b) ? a : b;
111 struct timespec ts = {};
112 if (clock_gettime(CLOCK_MONOTONIC, &ts) != 0) {
149 .page_index = page_index,
151 .page_bytes = out->
bytes,
204 const int n = snprintf(out, cap,
"page_%04zu.%s", page_no, ext);
205 return (n > 0) && ((size_t)n < cap);
230 const char* target_abs,
231 const char* target_rel)
234 if (held ==
nullptr) {
237 char src_abs[PATH_MAX];
239 if ((sn < 0) || ((
size_t)sn >=
sizeof(src_abs))) {
247 char act_abs[PATH_MAX];
249 (void)snprintf(act_abs,
sizeof(act_abs),
"%s", target_abs);
250 (void)snprintf(act_rel,
sizeof(act_rel),
"%s", target_rel);
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,
261 (
int)(tab_dot - target_abs),
264 (void)snprintf(act_rel,
267 (
int)(tre_dot - target_rel),
310 const char* guessed_abs,
311 const char* actual_abs)
313 if ((storage ==
nullptr) || (guessed_abs ==
nullptr) || (actual_abs ==
nullptr)) {
316 if (
strcmp(guessed_abs, actual_abs) == 0) {
353 const char* chapter_url,
355 const char* target_abs,
356 const char* target_rel,
371 .referer = chapter_url,
421 const char* target_abs,
422 const char* target_rel,
434 if ((tx->
held !=
nullptr) &&
436 const time_t observed = time(
nullptr);
439 (observed < (time_t)0) ? 0 : (int64_t)observed,
490 const char* target_abs,
497 error = (aborted ==
k_ra8_ok) ? error : aborted;
501 const char* held_etag = (tx->
held !=
nullptr) ? tx->
held->
etag :
"";
504 const char* modified =
519 const time_t observed = time(
nullptr);
532 (observed < (time_t)0) ? 0 : (int64_t)observed,
537 if (out_bytes !=
nullptr) {
538 *out_bytes = tx->
got;
564 const char* chapter_url,
566 const char* target_abs,
567 const char* target_rel,
571 if (out_bytes !=
nullptr) {
574 if (out_resp !=
nullptr) {
581 if (out_resp !=
nullptr) {
588 if (out_resp !=
nullptr) {
622 const char* chapter_url,
623 const char* dest_abs,
624 const char* dest_rel,
636 char target_abs[PATH_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))) {
646 const bool has_validator =
647 (held !=
nullptr) && ((held->
etag[0] !=
'\0') || (held->
last_modified[0] !=
'\0'));
648 if (!ctx->
refetch && !has_validator &&
681 const char* chapter_url,
682 const char* dest_abs,
683 const char* dest_rel,
690 const size_t page_no = base + i + 1U;
707 return progress_error;
@ k_ms_per_sec
Milliseconds per second.
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.
ra8_err_t fw_fs_unlink(const fw_fs_namespace_t *names, const char *path)
Remove one regular file; directories require fw_fs_rmdir.
@ 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.
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.
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.
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.
uint64_t mdl_hash_str(const char *s)
FNV-1a 64 hash of a NUL-terminated string (excluding the NUL).
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).
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.
@ k_mdl_relpath_max
Page path relative to the series dir.
@ k_mdl_max_page_recs
Per-page content records per series.
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.
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).
@ k_ra8_fail
Generic unspecified failure.
@ k_ra8_err_invalid_state
Module in wrong state for requested operation.
@ k_ra8_err_validation_failed
Validation rule failed (caller-supplied invariant not satisfied).
@ k_ra8_ok
Success – operation completed with all postconditions satisfied.
@ k_ra8_err_protocol_error
Protocol-level error (e.g.
ra8_err_codes_t ra8_err_t
Canonical error-return type used by every ra8-firmware API.
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.
uint16_t pages_done
Pages fetched and verified.
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.
mdl_state_t * state
Persistent state, read and updated.
mdl_url_list_t * images
Extracted-image scratch (caller-owned).
const mdl_site_t * site
Selectors + politeness bounds.
void * progress_ctx
Context passed to progress_fn.
mdl_storage_t * storage
Portable storage binding + workspaces.
const char * series_abs_dir
Absolute series dir (paths resolve here).
bool refetch
Ignore local page reuse and hit network.
mdl_session_t * session
Identity + robots + net backend.
mdl_progress_fn progress_fn
Per-page progress sink, or NULL (silent).
uint32_t timeout_ms
Per-request time budget.
ra8_err_t progress_error
First callback failure from this run.
One per-page progress event the run emits through mdl_progress_fn.
Tallies a fetch run reports back (all zero-initialised by the run).
size_t pages_fetched
Pages transferred over the network.
size_t pages_reused
Pages served from an already-held verified file.
size_t pages_failed
Page fetches that failed or robots refused.
Caller-owned lifecycle and write seam for one response body.
Per-request session parameters.
const char * if_none_match
If-None-Match conditional header (ETag), or NULL.
const char * if_modified_since
If-Modified-Since header (Last-Modified), or NULL.
Per-transfer response metadata surfaced to the politeness governor.
long status
Finished transfer's HTTP status, 0 if none.
char etag[k_mdl_etag_max]
Raw ETag value, "" when absent.
char last_modified[k_mdl_last_mod_max]
Raw Last-Modified value, "" when absent.
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.
char etag[k_mdl_etag_max]
Cached ETag for conditional GET.
char last_modified[k_mdl_last_mod_max]
Cached Last-Modified response value.
uint64_t content_hash
FNV-1a 64 of the fetched bytes.
char rel_path[k_mdl_relpath_max]
Path under the series directory.
uint16_t response_status
Most recent HTTP status; zero if legacy.
int64_t fetched_at
Most recent HTTP result time (epoch s).
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).
uint32_t img_delay_max
Per-image spacing ceiling.
uint32_t img_delay_min
Per-image spacing floor.
uint32_t page_rec_count
Page records recorded.
One non-reentrant downloader filesystem dependency bundle.
const fw_fs_t * fs
Injected portable filesystem.
uint64_t hash
Running FNV-1a identity.
char urls[k_mdl_max_urls][k_mdl_url_max]
Absolute, NUL-terminated.
size_t count
Number of valid entries.