1use crate::dto::prelude::*;
2
3#[cfg(feature = "blob-storage-billing")]
4pub use crate::domain::blob_storage::{
5 BlobStorageBillingWarning, BlobStorageFundingStatus, BlobStorageGatewayPrincipalSyncAction,
6 BlobStoragePaymentModelStatus, BlobStorageReadinessBlocker,
7};
8#[cfg(feature = "blob-storage-billing")]
9use candid::Int;
10
11#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
18pub struct CreateCertificateResult {
19 pub method: String,
20 pub blob_hash: String,
21}
22
23#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
30pub struct BlobStorageLocalCounters {
31 pub stored_blobs: u64,
32 pub pending_deletions: u64,
33 pub gateway_principals: u64,
34}
35
36impl BlobStorageLocalCounters {
37 #[must_use]
38 pub const fn new(stored_blobs: u64, pending_deletions: u64, gateway_principals: u64) -> Self {
39 Self {
40 stored_blobs,
41 pending_deletions,
42 gateway_principals,
43 }
44 }
45}
46
47#[cfg(feature = "blob-storage-billing")]
54#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
55pub enum BlobStorageCashierDebtTarget {
56 Prepaid,
57 Ledger,
58}
59
60#[cfg(feature = "blob-storage-billing")]
67#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
68pub struct BlobStorageCashierAccountCycleBalances {
69 pub total: Int,
70 pub cycles_prepaid: Int,
71 pub cycles_promo: Int,
72 pub debt_target: BlobStorageCashierDebtTarget,
73 pub cycles_ledger: Int,
74}
75
76#[cfg(feature = "blob-storage-billing")]
83#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
84pub struct BlobStorageCashierAccountBalanceGetRequest {
85 pub account: Principal,
86}
87
88#[cfg(feature = "blob-storage-billing")]
95#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
96pub struct BlobStorageCashierAccountBalanceGetOk {
97 pub account_cycle_balances: BlobStorageCashierAccountCycleBalances,
98 pub account: Principal,
99}
100
101#[cfg(feature = "blob-storage-billing")]
108#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
109pub enum BlobStorageCashierAccountBalanceGetError {
110 AccountNotFound,
111 InternalError(String),
112}
113
114#[cfg(feature = "blob-storage-billing")]
121#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
122pub enum BlobStorageCashierAccountBalanceGetResult {
123 Ok(BlobStorageCashierAccountBalanceGetOk),
124 Err(BlobStorageCashierAccountBalanceGetError),
125}
126
127#[cfg(feature = "blob-storage-billing")]
134#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
135pub struct BlobStorageCashierAccountTopUpRequest {
136 pub target_balance: Option<Nat>,
137 pub account: Option<Principal>,
138}
139
140#[cfg(feature = "blob-storage-billing")]
147#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
148pub struct BlobStorageCashierAccountTopUpOk {
149 pub balance: BlobStorageCashierAccountCycleBalances,
150 pub message: String,
151}
152
153#[cfg(feature = "blob-storage-billing")]
160#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
161pub enum BlobStorageCashierAccountTopUpError {
162 NotAuthorized(Principal),
163 AccountBalanceOverflow,
164 InternalError(String),
165 TopUpWithoutCycles,
166}
167
168#[cfg(feature = "blob-storage-billing")]
175#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
176pub enum BlobStorageCashierAccountTopUpResult {
177 Ok(BlobStorageCashierAccountTopUpOk),
178 Err(BlobStorageCashierAccountTopUpError),
179}
180
181#[cfg(feature = "blob-storage-billing")]
188#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
189pub struct BlobStorageBillingConfig {
190 pub cashier_canister_id: Principal,
191 pub project_cycles_reserve: Nat,
192 pub min_upload_balance: Nat,
193 pub target_upload_balance: Nat,
194 pub gateway_principal_limit: u64,
195}
196
197#[cfg(feature = "blob-storage-billing")]
204#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
205pub struct BlobProjectCyclesTopUpReport {
206 pub requested_cycles: Nat,
207 pub attached_cycles: Nat,
208 pub project_cycles_before: Nat,
209 pub project_cycles_after: Nat,
210 pub reserve_cycles: Nat,
211 pub cashier_total_after: Nat,
212 pub skipped_reason: Option<String>,
213}
214
215#[cfg(feature = "blob-storage-billing")]
222#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
223pub struct BlobStorageStatusRequest {
224 pub sync_gateway_principals: bool,
225}
226
227#[cfg(feature = "blob-storage-billing")]
234#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
235pub struct BlobStorageStatusResponse {
236 pub payment_model: BlobStoragePaymentModelStatus,
237 pub cashier_canister_id: Option<Principal>,
238 pub payment_account: Option<Principal>,
239 pub cashier_balance: Option<Nat>,
240 pub min_upload_balance: Option<Nat>,
241 pub target_upload_balance: Option<Nat>,
242 pub project_cycles_reserve: Option<Nat>,
243 pub project_cycles_available: Nat,
244 pub gateway_principal_count: u64,
245 pub last_gateway_principal_sync_at_ns: Option<u64>,
246 pub gateway_principal_sync_action: BlobStorageGatewayPrincipalSyncAction,
247 pub funding_status: BlobStorageFundingStatus,
248 pub ready: bool,
249 pub blockers: Vec<BlobStorageReadinessBlocker>,
250 pub warnings: Vec<BlobStorageBillingWarning>,
251}
252
253#[cfg(all(test, feature = "blob-storage-billing"))]
254mod tests {
255 use super::*;
256 use candid::{CandidType, Decode, Encode};
257 use serde::de::DeserializeOwned;
258 use std::fmt::Debug;
259
260 #[test]
261 fn billing_status_enums_roundtrip_candid_through_dto_path() {
262 assert_enum_candid_contract(BlobStoragePaymentModelStatus::ProjectAsPaymentAccount);
263 assert_enum_candid_contract(BlobStorageGatewayPrincipalSyncAction::SkippedReadOnlyStatus);
264 assert_enum_candid_contract(BlobStorageFundingStatus::FundingRequired {
265 requested_cycles: Nat::from(42_u64),
266 });
267 assert_enum_candid_contract(BlobStorageReadinessBlocker::InsufficientCashierBalance);
268 assert_enum_candid_contract(BlobStorageBillingWarning::SyncRequestedButStatusIsReadOnly);
269 }
270
271 fn assert_enum_candid_contract<T>(value: T)
272 where
273 T: CandidType + Clone + Debug + DeserializeOwned + Eq,
274 {
275 let bytes = Encode!(&value).expect("encode blob-storage status enum");
276 let decoded = Decode!(&bytes, T).expect("decode blob-storage status enum");
277
278 assert_eq!(decoded, value);
279 }
280}