110 if ((sink ==
nullptr) || (sink->
storage ==
nullptr) || (sink->
destination ==
nullptr)) {
143 const uint8_t* bytes,
145 uint32_t* out_written)
148 if ((sink ==
nullptr) || (out_written ==
nullptr) || ((bytes ==
nullptr) && (length != 0U))) {
154 *out_written = length;
176 return (a > b) ? a : b;
197 static const char*
const alternate_exts[] = {
"jpg",
"jpeg",
"png",
"webp",
"gif",
"bmp"};
198 for (
size_t ext_idx = 0U; ext_idx < (
sizeof(alternate_exts) /
sizeof(alternate_exts[0]));
200 if (
strcmp(alternate_exts[ext_idx], true_ext) == 0) {
204 const int alternate_len = snprintf(alternate_leaf,
205 sizeof(alternate_leaf),
208 alternate_exts[ext_idx]);
210 if ((alternate_len <= 0) || ((
size_t)alternate_len >=
sizeof(alternate_leaf)) ||
211 !
mdl_path_join(out_dir, alternate_leaf, alternate_path,
sizeof(alternate_path))) {
213 "mdl: warning: cannot resolve stale page "
222 bool removed =
false;
229 "mdl: warning: cannot safely remove stale "
275 " -- unsupported image signature\n");
280 if ((dot ==
nullptr) || (dot[1] ==
'\0')) {
285 const int extension = snprintf(true_ext,
sizeof(true_ext),
"%s", dot + 1);
286 if ((extension <= 0) || ((
size_t)extension >=
sizeof(true_ext))) {
297 " FAILED -- atomic publication failed\n");
344 const int holding_len =
345 snprintf(holding_leaf,
sizeof(holding_leaf),
"page_%04zu.download", idx + 1U);
347 if ((holding_len < 0) || ((
size_t)holding_len >=
sizeof(holding_leaf)) ||
348 !
mdl_path_join(out_dir, holding_leaf, holding,
sizeof(holding))) {
353 .timeout_ms = timeout};
467 "mdl: cannot create output directory '",
472 const int copied = snprintf(out_abs, (
size_t)
k_fw_fs_path_cap,
"%s", out_dir);
475 "mdl: output path is not a directory: '",
508 "mdl: cannot create output directory '",
515 "mdl: unsafe or unresolved output directory '",
556 "mdl: downloaded artifact failed structural "
563 "mdl: artifact fetch failed -- ",
591 const char* final_path,
601 "mdl: network init failed\n"));
615 .timeout_ms = timeout};
618 .destination = final_path,
625 bool published =
false;
628 if ((rc ==
k_ra8_ok) && !published) {
646 "mdl: direct artifact '",
648 "' has no supported structural validator "
649 "(cbz|cbt|cbt.gz|epub|jof|rabook)\n"));
668 "downloaded and verified ",
673 return (output_error ==
k_ra8_ok) ? 0 : 1;
676 "downloaded and verified ",
684 return (output_error ==
k_ra8_ok) ? 0 : 1;
710 .timeout_ms = timeout};
724 "mdl: fetch failed -- ",
740 "mdl: page contains no supported image URLs\n"));
760 "mdl: network init failed\n"));
827 return (output_error ==
k_ra8_ok) ? 0 : 1;
850 const int length = snprintf(out,
sizeof(out),
"%s.%s", dir, ext);
851 if ((length < 0) || ((
size_t)length >=
sizeof(out))) {
853 "mdl: output path for '",
871 return (output_error ==
k_ra8_ok) ? 0 : 1;
879 "mdl: --pack needs a --format "
880 "(cbz|cbt|cbt.gz|epub|jof|rabook)\n");
881 return (output_error ==
k_ra8_ok) ? 2 : 1;
884 if ((dir ==
nullptr) || (dir[0] !=
'/') ||
888 "mdl: cannot resolve '",
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.
@ k_fw_fs_node_directory
Directory.
@ k_fw_fs_path_cap
Largest portable path including its NUL.
mdl_app_context_t * priv_mdl_app_context(void)
The working set the composition root bound with mdl_app_bind.
int mdl_app_run_artifact(const char *url, const char *out_dir, uint32_t timeout, const mdl_run_opts_t *opts)
Download, validate and atomically publish one direct artifact.
static ra8_err_t internal_direct_pack_failure(const char *dir, const char *ext, ra8_err_t failure)
Report one pack exporter failure with its exact hexadecimal status.
static ra8_err_t internal_direct_artifact_write(void *context, const uint8_t *bytes, uint32_t length, uint32_t *out_written)
Append one complete response chunk to the portable artifact stage.
static int internal_pack_directory_output(const char *dir, const char *ext, mdl_format_t format)
Package a directory-output format and report its wildcard destination.
static ra8_err_t internal_direct_text3(ra8_io_stream_t *stream, const char *first, const char *second, const char *third)
Append three borrowed direct-action fragments to one stream.
static size_t internal_download_page_image(const char *url, const char *out_dir, uint32_t dmin, uint32_t dmax, uint32_t timeout, mdl_politeness_t *pol, size_t idx)
Gate, space, and download one page-mode image.
static size_t internal_publish_page_image(mdl_fetch_body_t *body, const char *out_dir, size_t idx)
Validate and publish one staged page-mode image.
static bool internal_finish_artifact_fetch(mdl_direct_artifact_sink_t *state, ra8_err_t error, long status)
Finalize or abort one direct artifact transfer.
static ra8_err_t internal_direct_artifact_reset(void *context)
Abort a prior attempt and begin a fresh artifact transaction.
static bool internal_extract_page_images(const char *url, const char *attr, uint32_t timeout)
Fetch one page and populate the shared extracted-image list.
int mdl_app_run_page(const char *url, const char *out_dir, const char *attr, uint32_t max_imgs, uint64_t seed, uint32_t timeout, const mdl_run_opts_t *opts)
Download image resources from one direct page URL.
static int internal_pack_file_output(const char *dir, const char *ext, mdl_format_t format)
Package a file-output format beside its source directory.
static bool internal_prepare_artifact_path(const char *out_dir, const char *leaf, char *final_path)
Prepare the exact final path for one direct artifact.
static bool internal_prepare_output_dir(const char *out_dir, char *out_abs)
Create and canonicalize one direct-action output directory.
int mdl_app_run_pack(const char *dir, mdl_format_t format)
Package an existing image directory without network access.
static size_t internal_download_page_images(const char *url, const char *out_dir, uint32_t max_imgs, uint64_t seed, uint32_t timeout, bool polite)
Download the extracted page images into an output directory.
static uint32_t internal_max_u32(uint32_t a, uint32_t b)
Return the larger of two unsigned values.
static void internal_direct_latch(ra8_err_t error)
Latch the first direct presenter failure for loop cancellation.
static void internal_remove_stale_page_variants(const char *out_dir, size_t page_no, const char *true_ext)
Remove stale page files whose extensions differ from verified bytes.
static bool internal_fetch_artifact(const char *url, const char *final_path, mdl_format_t format, uint32_t timeout, const mdl_run_opts_t *opts, size_t *got)
Fetch one policy-approved artifact into an atomic holding path.
Module-private contract shared by the application-mode translation units.
ra8_err_t priv_mdl_app_start_session(mdl_net_iface_t *net, const mdl_run_opts_t *opts, const char *cfg_contact, char *ua, size_t ua_cap)
Initialize one bounded network-policy session.
@ k_polite_img_min_ms
Polite per-image floor.
@ k_polite_img_max_ms
Polite per-image ceiling.
@ k_ext_bytes
Image-extension buffer.
@ k_page_img_delay_max
page-mode per-image ceiling, ms.
@ k_page_img_delay_min
page-mode per-image floor, ms.
@ k_file_path_bytes
File-path buffer.
@ k_leaf_name_bytes
Composed archive/dir leaf name.
ra8_err_t priv_mdl_app_storage_unlink_regular(mdl_storage_t *storage, const char *path, bool *out_removed)
Remove one regular file while refusing symbolic or special nodes.
ra8_err_t priv_mdl_app_storage_ensure_directory(mdl_storage_t *storage, const char *path)
Ensure one canonical portable path names a real directory.
bool mdl_format_is_dir_output(mdl_format_t fmt)
Whether fmt writes per-page sibling files rather than one container.
const char * mdl_format_ext(mdl_format_t fmt)
File extension (without dot) for a format, e.g.
ra8_err_t mdl_export_chapter_ws(mdl_storage_t *storage, mdl_format_t fmt, const char *chapter_dir, const char *out_path, mdl_export_workspace_t *ws)
Package a chapter after auto-loading bounded local metadata.
ra8_err_t priv_mdl_export_output_abort(mdl_export_output_t *output)
Abort one unpublished export stage, retaining cleanup failure.
ra8_err_t priv_mdl_export_output_commit(mdl_export_output_t *output, mdl_export_workspace_t *workspace, bool *out_published)
Structurally validate and publish one completed export stage.
ra8_err_t priv_mdl_export_output_begin(mdl_export_output_t *output, mdl_storage_t *storage, const char *destination, mdl_format_t format)
Bind a validated publication transaction to one destination.
ra8_err_t priv_mdl_export_output_write(mdl_export_output_t *output, const uint8_t *bytes, uint32_t length)
Append one complete byte span to an active export stage.
Private portable byte-stream contracts for media exporters.
void priv_mdl_fetch_reason(ra8_err_t err, long status, char *buf, size_t cap)
Render a human-readable reason for a transfer result and HTTP status.
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.
@ k_mdl_reason_max
Failure-reason string buffer bytes.
ra8_err_t mdl_net_get_buf(mdl_net_iface_t *net, const char *url, const mdl_net_req_t *req, char *buf, size_t cap, size_t *out_len, mdl_net_resp_t *resp)
GET url fully into a caller buffer (used for HTML pages).
void mdl_net_destroy(mdl_net_iface_t *net)
Deinitialise a caller-owned network interface.
ra8_err_t mdl_net_get_body(mdl_net_iface_t *net, const char *url, const mdl_net_req_t *req, mdl_net_body_sink_t *sink, size_t *out_len, mdl_net_resp_t *resp)
GET url and stream its body through a caller-owned sink.
ra8_err_t mdl_net_provider_open(const mdl_net_provider_t *provider, const mdl_net_policy_t *policy, mdl_net_iface_t *out_net)
Open a transport through an injected provider.
void mdl_politeness_init(mdl_politeness_t *p, uint64_t seed)
Seed the jitter source, using the real host clock for sleeps.
uint32_t mdl_politeness_wait(mdl_politeness_t *p, uint32_t min_ms, uint32_t max_ms)
Sleep a jittered delay in [min_ms, max_ms] and return it.
bool mdl_path_join(const char *parent, const char *seg, char *out, size_t cap)
Join one safe child segment under a parent directory path.
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.
@ k_mdl_ua_max
Built User-Agent buffer bytes.
ra8_err_t priv_mdl_stream_hex(ra8_err_t prior, ra8_io_stream_t *stream, uint32_t value)
Append one hexadecimal error/status value after prior success.
ra8_err_t priv_mdl_stream_text(ra8_err_t prior, ra8_io_stream_t *stream, const char *text)
Append text unless an earlier operation already failed.
ra8_err_t priv_mdl_stream_u64(ra8_err_t prior, ra8_io_stream_t *stream, uint64_t value)
Append one unsigned integer unless an earlier append failed.
void mdl_urlname_last_segment(const char *url, char *out, size_t cap)
Sanitised last non-empty path segment of a URL.
ra8_err_t mdl_verify_file(mdl_storage_t *storage, mdl_format_t format, const char *path, mdl_export_workspace_t *workspace, mdl_verify_report_t *report)
Validate a completed artifact using caller-owned scratch only.
bool mdl_format_is_verifiable(mdl_format_t format)
Report whether a format has an in-process structural validator.
ra8_err_t mdl_format_from_path(const char *path, mdl_format_t *out_format)
Infer an artifact format from its complete path suffix.
#define RA8_INTERNAL
Marker that a function is intended to be static (file-local).
@ k_ra8_err_invalid_arg
Invalid function argument.
@ 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.
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.
bool active
Begin succeeded.
mdl_session_t session
Network policy session.
ra8_err_t io_error
First presenter sink failure.
mdl_url_list_t images
Prepared page image URLs.
mdl_storage_t storage
Injected filesystem facade.
ra8_io_stream_t * diagnostic
Borrowed diagnostic sink.
Transactional body sink for one directly downloaded artifact.
mdl_export_output_t output
Structurally validated output stage.
mdl_storage_t * storage
Exclusive portable storage binding.
const char * destination
Canonical final artifact path.
mdl_format_t format
Exact canonical verifier selection.
One validated staged publication, including random ZIP backfill.
mdl_storage_txn_t writer
Active storage transaction.
Caller-owned state for one retryable streamed fetch.
char actual_abs[PATH_MAX]
Magic-derived final path.
Caller-owned lifecycle and write seam for one response body.
A network backend handle: an immutable method table plus its state.
Per-request session parameters.
Per-transfer response metadata surfaced to the politeness governor.
long status
Finished transfer's HTTP status, 0 if none.
Deterministic jitter source plus its (optional) injected clock.
Cross-cutting policy and injected transport threaded into every mode.
mdl_net_policy_t policy
Backend security policy.
bool polite
True to raise per-host delays.
const mdl_net_provider_t * net
Injected transport factory.
const char * user_agent
Full UA header (caller-owned).
One non-reentrant downloader filesystem dependency bundle.
fw_fs_transaction_t transaction
Active private filesystem stage.
size_t count
Number of valid entries.
Caller-allocated byte-stream handle binding a sink to its context.