warg_api/v1/
ledger.rs

1//! Types relating to the ledger API.
2
3use serde::{Deserialize, Serialize, Serializer};
4use std::borrow::Cow;
5use thiserror::Error;
6use warg_crypto::hash::HashAlgorithm;
7use warg_protocol::registry::RegistryIndex;
8
9/// Represents response a get ledger sources request.
10#[derive(Serialize, Deserialize)]
11#[serde(rename_all = "camelCase")]
12pub struct LedgerSourcesResponse {
13    /// The hash algorithm used by the ledger.
14    pub hash_algorithm: HashAlgorithm,
15    /// The list of ledger sources.
16    pub sources: Vec<LedgerSource>,
17}
18
19/// Ledger source for a specified registry index range. Expected to be sorted in ascending order.
20#[derive(Serialize, Deserialize)]
21#[serde(rename_all = "camelCase")]
22pub struct LedgerSource {
23    /// First registry index that is included in this ledger source.
24    pub first_registry_index: RegistryIndex,
25    /// Last registry index that is included in this ledger source.
26    pub last_registry_index: RegistryIndex,
27    /// The HTTP GET URL location for the ledger source.
28    pub url: String,
29    /// Content type for the ledger source.
30    pub content_type: LedgerSourceContentType,
31    /// Optional, server accepts for HTTP Range header.
32    #[serde(default, skip_serializing_if = "is_false")]
33    pub accept_ranges: bool,
34}
35
36fn is_false(b: &bool) -> bool {
37    !b
38}
39
40/// Content type for the ledger source.
41#[derive(Default, PartialEq, Serialize, Deserialize, Debug)]
42pub enum LedgerSourceContentType {
43    /// The content type is binary representation of the LogId and RecordId hashes without padding.
44    /// In the case of `sha256` hash algorithm, this is a repeating sequence of 64 bytes (32 bytes
45    /// for each the LogId and RecordId) without padding.
46    #[default]
47    #[serde(rename = "application/vnd.warg.ledger.packed")]
48    Packed,
49}
50
51impl LedgerSourceContentType {
52    /// Returns the content type represented as a string.
53    pub fn as_str(&self) -> &'static str {
54        match self {
55            Self::Packed => "application/vnd.warg.ledger.packed",
56        }
57    }
58}
59
60/// Represents a ledger API error.
61#[non_exhaustive]
62#[derive(Debug, Error)]
63pub enum LedgerError {
64    /// An error with a message occurred.
65    #[error("{message}")]
66    Message {
67        /// The HTTP status code.
68        status: u16,
69        /// The error message
70        message: String,
71    },
72}
73
74impl LedgerError {
75    /// Returns the HTTP status code of the error.
76    pub fn status(&self) -> u16 {
77        match self {
78            Self::Message { status, .. } => *status,
79        }
80    }
81}
82
83#[derive(Serialize, Deserialize)]
84#[serde(untagged, rename_all = "camelCase")]
85enum RawError<'a> {
86    Message { status: u16, message: Cow<'a, str> },
87}
88
89impl Serialize for LedgerError {
90    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
91        match self {
92            Self::Message { status, message } => RawError::Message {
93                status: *status,
94                message: Cow::Borrowed(message),
95            }
96            .serialize(serializer),
97        }
98    }
99}
100
101impl<'de> Deserialize<'de> for LedgerError {
102    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
103    where
104        D: serde::Deserializer<'de>,
105    {
106        match RawError::deserialize(deserializer)? {
107            RawError::Message { status, message } => Ok(Self::Message {
108                status,
109                message: message.into_owned(),
110            }),
111        }
112    }
113}