Skip to main content

xet_client/cas_client/simulation/
direct_access_client.rs

1//! Direct Access Client Trait
2//!
3//! This module defines the `DirectAccessClient` trait, which extends the standard
4//! `Client` interface with direct XORB and file access methods. This is used by
5//! the local server and testing utilities to access stored data directly.
6
7use std::ops::Range;
8use std::time::Duration;
9
10use async_trait::async_trait;
11use bytes::Bytes;
12use xet_core_structures::merklehash::MerkleHash;
13use xet_core_structures::xorb_object::XorbObject;
14
15use super::super::interface::Client;
16use crate::cas_types::{
17    FileRange, QueryReconstructionResponse, QueryReconstructionResponseV2, XorbReconstructionFetchInfo,
18};
19use crate::error::Result;
20
21/// A Client with direct access to XORB and file storage.
22///
23/// This trait extends the standard Client interface with methods for:
24/// - Direct XORB access (read, list)
25/// - File data retrieval
26/// - URL expiration control
27/// - API delay simulation
28///
29/// Both `LocalClient` and `MemoryClient` implement this trait, allowing the
30/// local server to work with either backend.
31#[cfg_attr(not(target_family = "wasm"), async_trait)]
32#[cfg_attr(target_family = "wasm", async_trait(?Send))]
33pub trait DirectAccessClient: Client + Send + Sync {
34    /// Sets the expiration duration for fetch term URLs.
35    fn set_fetch_term_url_expiration(&self, expiration: Duration);
36
37    /// Sets a random delay range for all Client API calls.
38    ///
39    /// When set, each Client trait method will sleep for a random duration
40    /// within the specified range before returning. This simulates network latency.
41    ///
42    /// Pass `None` to disable the delay.
43    fn set_api_delay_range(&self, delay_range: Option<Range<Duration>>);
44
45    /// Sets the maximum number of byte ranges per `XorbMultiRangeFetch` entry
46    /// in V2 reconstruction responses.
47    ///
48    /// Default is `usize::MAX` (all ranges in one fetch). When set to N,
49    /// ranges for each xorb are grouped into entries of at most N ranges.
50    /// This simulates the CloudFront URL length limit that forces splitting.
51    fn set_max_ranges_per_fetch(&self, max_ranges: usize);
52
53    /// Sets the expiration duration for global dedup shards.
54    ///
55    /// When set, `query_for_global_dedup_shard` will set the shard footer's
56    /// `shard_key_expiry` to `now + expiration`
57    ///
58    /// Pass `None` to disable (default: returns full shards with no expiration).
59    fn set_global_dedup_shard_expiration(&self, expiration: Option<Duration>);
60
61    /// Disables V2 endpoints (reconstruction and shard upload) with the given HTTP status code.
62    /// When disabled, `/v2/*` handlers return this status, forcing clients to fall back to V1.
63    /// Pass 0 to re-enable.
64    fn disable_v2_endpoints(&self, status_code: u16);
65
66    /// Returns the HTTP status code V2 endpoints should return when disabled,
67    /// or 0 if V2 is enabled.
68    fn v2_disabled_status_code(&self) -> u16 {
69        0
70    }
71
72    /// V1 reconstruction: returns per-range presigned URLs.
73    async fn get_reconstruction_v1(
74        &self,
75        file_id: &MerkleHash,
76        bytes_range: Option<FileRange>,
77    ) -> Result<Option<QueryReconstructionResponse>>;
78
79    /// V2 reconstruction: returns per-xorb multi-range fetch descriptors.
80    async fn get_reconstruction_v2(
81        &self,
82        file_id: &MerkleHash,
83        bytes_range: Option<FileRange>,
84    ) -> Result<Option<QueryReconstructionResponseV2>>;
85
86    /// Applies the configured API delay if set.
87    ///
88    /// This method sleeps for a random duration within the configured delay range.
89    /// If no delay is configured (via `set_api_delay_range`), this returns immediately.
90    async fn apply_api_delay(&self);
91
92    /// Returns all XORB hashes stored in this client.
93    async fn list_xorbs(&self) -> Result<Vec<MerkleHash>>;
94
95    /// Get all uncompressed bytes from a XORB.
96    async fn get_full_xorb(&self, hash: &MerkleHash) -> Result<Bytes>;
97
98    /// Get uncompressed bytes from a XORB within chunk ranges.
99    /// Each tuple represents a chunk index range [start, end).
100    async fn get_xorb_ranges(&self, hash: &MerkleHash, chunk_ranges: Vec<(u32, u32)>) -> Result<Vec<Bytes>>;
101
102    /// Get the length of the uncompressed XORB data.
103    async fn xorb_length(&self, hash: &MerkleHash) -> Result<u32>;
104
105    /// Check if a XORB exists.
106    async fn xorb_exists(&self, hash: &MerkleHash) -> Result<bool>;
107
108    /// Get the XorbObject footer/metadata for a XORB.
109    async fn xorb_footer(&self, hash: &MerkleHash) -> Result<XorbObject>;
110
111    /// Get the file size for a given file hash.
112    async fn get_file_size(&self, hash: &MerkleHash) -> Result<u64>;
113
114    /// Get file data, optionally within a byte range.
115    async fn get_file_data(&self, hash: &MerkleHash, byte_range: Option<FileRange>) -> Result<Bytes>;
116
117    /// Get raw (serialized) bytes from a XORB, optionally within a byte range.
118    ///
119    /// Unlike `get_xorb_ranges` which returns decompressed chunk data, this returns
120    /// the raw bytes as stored (including compression headers). This is used by the
121    /// server's fetch_term endpoint to serve data that clients can then decompress.
122    async fn get_xorb_raw_bytes(&self, hash: &MerkleHash, byte_range: Option<FileRange>) -> Result<Bytes>;
123
124    /// Get the total length of the raw (serialized) XORB data.
125    async fn xorb_raw_length(&self, hash: &MerkleHash) -> Result<u64>;
126
127    /// Fetches term data for a given hash and fetch term.
128    /// Returns (data bytes, chunk byte indices) matching `Client::get_file_term_data`.
129    async fn fetch_term_data(
130        &self,
131        hash: MerkleHash,
132        fetch_term: XorbReconstructionFetchInfo,
133    ) -> Result<(Bytes, Vec<u32>)>;
134}