pub struct ThunderstoreClient { /* private fields */ }Expand description
An async client for a single Thunderstore community.
Build one with ThunderstoreClient::builder.
Implementations§
Source§impl ThunderstoreClient
impl ThunderstoreClient
Sourcepub fn builder() -> ThunderstoreClientBuilder
pub fn builder() -> ThunderstoreClientBuilder
Returns a builder for configuring a ThunderstoreClient.
cache_dir is the only required setting. Nothing is read, written, or sent
over the network until a method such as
get_manifest is awaited, so building is cheap and
infallible apart from configuration validation.
§Examples
use thunderstore_engine::client::ThunderstoreClient;
let client = ThunderstoreClient::builder()
.base_url("https://thunderstore.io")
.community("valheim")
.cache_dir("/var/cache/my-mod-manager")
.build()
.expect("base_url + community compose a valid index URL");
assert_eq!(client.base_url(), "https://thunderstore.io");
assert_eq!(
client.package_index_url(),
"https://thunderstore.io/c/valheim/api/v1/package/"
);Sourcepub fn package_index_url(&self) -> &str
pub fn package_index_url(&self) -> &str
The composed package-index URL this client will query.
Sourcepub fn base_url(&self) -> &str
pub fn base_url(&self) -> &str
The Thunderstore host this client targets, with any trailing slash trimmed.
Sourcepub async fn get_manifest(&self) -> Result<PackageIndex>
pub async fn get_manifest(&self) -> Result<PackageIndex>
Retrieves the package index, loading from cache when it is fresh.
Performs a HEAD request and compares the server’s Last-Modified against
the cached timestamp; if the cache is current it is loaded from disk,
otherwise the index is downloaded and cached.
§Errors
A failed freshness check is not an error on its own: it is logged and a readable cache is served instead, so this succeeds offline once the index has been fetched at least once. Errors therefore mean no usable cache and a failed fetch:
Error::Httpif the download fails or returns a non-success status.Error::SizeLimitExceededif the response exceedsmanifest_max_bytes, or the cached copy exceedsmanifest_max_decompressed_bytes.Error::Jsonif the index is not valid Thunderstore package JSON.Error::Ioif the cache directory cannot be created or written.
Sourcepub async fn refresh_index(&self) -> Result<PackageIndex>
pub async fn refresh_index(&self) -> Result<PackageIndex>
Forces a network refresh of the package index, bypassing the cache.
§Errors
The same set as get_manifest, minus the cache
fallback: because this always goes to the network, any network failure is
fatal here even when a perfectly good cached index exists.
Sourcepub async fn download_files(&self, urls: HashMap<String, String>) -> Result<()>
pub async fn download_files(&self, urls: HashMap<String, String>) -> Result<()>
Downloads multiple package archives concurrently into cache_dir/downloads.
Keys of urls are filenames and values are download URLs. Files that
already exist are skipped. Concurrency is bounded by the configured
download_concurrency, and each archive is bounded by the configured
download_max_bytes. Each archive is written atomically (temp file +
rename) after its full Content-Length is received. Individual download
failures are logged and, if any occurred, surfaced as an aggregate error
rather than silently ignored.
§Errors
Returns a single Error::Download carrying how many of how many files
failed plus the first failure’s message. This is all-or-nothing only in
its reporting, not its effects: files that succeeded are still on disk, so
a caller that retries should expect those to be skipped as already present.
The underlying per-file causes are Error::Http,
Error::SizeLimitExceeded (archive over
download_max_bytes),
Error::IncompleteDownload (body shorter than its Content-Length), and
Error::Io.
Sourcepub async fn create_profile_code(&self, payload: &[u8]) -> Result<String>
pub async fn create_profile_code(&self, payload: &[u8]) -> Result<String>
Uploads a profile-code payload and returns the server-issued key.
payload is sent verbatim as application/octet-stream; composing it (the
#r2modman prefix and base64 body) belongs to
crate::profile::portability. Transient failures are retried per the
client’s RetryPolicy.
§Errors
Error::Httpif the upload fails or the server returns a non-success status, after the retry policy is exhausted.Error::SizeLimitExceededif the response body is implausibly large for a profile key.Error::Jsonif the response is not the expected{ "key": ... }shape.
Sourcepub async fn fetch_profile_code(&self, code: &str) -> Result<Vec<u8>>
pub async fn fetch_profile_code(&self, code: &str) -> Result<Vec<u8>>
Downloads a shared profile by its code, returning the raw response body.
Validating the #r2modman prefix and decoding the base64 body belongs to
crate::profile::portability.
§Errors
Error::Configifcodeis empty or contains anything outside ASCII alphanumerics,-, and_. This is checked before any request, so a malformed code never reaches the network and can never be smuggled into the request path.Error::Httpif the download fails or the code is unknown to the server, after the retry policy is exhausted.Error::SizeLimitExceededif the shared profile exceeds the response cap.