lib.rs (2846B)
1 /* 2 This file is part of TALER 3 Copyright (C) 2025 Taler Systems SA 4 5 TALER is free software; you can redistribute it and/or modify it under the 6 terms of the GNU Affero General Public License as published by the Free Software 7 Foundation; either version 3, or (at your option) any later version. 8 9 TALER is distributed in the hope that it will be useful, but WITHOUT ANY 10 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR 11 A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. 12 13 You should have received a copy of the GNU Affero General Public License along with 14 TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> 15 */ 16 17 use std::{fmt::Display, num::ParseIntError, ops::Deref, str::FromStr}; 18 19 use taler_common::types::payto::{FullPayto, Payto, PaytoErr, PaytoImpl, PaytoURI, TransferPayto}; 20 21 pub mod config; 22 pub mod constants; 23 pub mod cyclos_api; 24 pub mod db; 25 pub mod worker; 26 27 #[derive( 28 Debug, Clone, PartialEq, Eq, serde_with::DeserializeFromStr, serde_with::SerializeDisplay, 29 )] 30 pub struct CyclosId(pub u64); 31 32 impl Deref for CyclosId { 33 type Target = u64; 34 35 fn deref(&self) -> &Self::Target { 36 &self.0 37 } 38 } 39 40 impl Display for CyclosId { 41 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 42 self.0.fmt(f) 43 } 44 } 45 46 #[derive(Debug, thiserror::Error)] 47 #[error("malformed cyclos id: {0}")] 48 pub struct CyclosIdError(ParseIntError); 49 50 impl FromStr for CyclosId { 51 type Err = CyclosIdError; 52 53 fn from_str(s: &str) -> Result<Self, Self::Err> { 54 Ok(Self(u64::from_str(s).map_err(CyclosIdError)?)) 55 } 56 } 57 58 const CYCLOS: &str = "cyclos"; 59 60 #[derive(Debug, thiserror::Error)] 61 #[error("missing cyclos account id in path")] 62 pub struct MissingCyclos; 63 64 impl PaytoImpl for CyclosId { 65 fn as_payto(&self) -> PaytoURI { 66 PaytoURI::from_parts(CYCLOS, format_args!("/{}", self.0)) 67 } 68 69 fn parse(raw: &PaytoURI) -> Result<Self, PaytoErr> { 70 let url = raw.as_ref(); 71 if url.domain() != Some(CYCLOS) { 72 return Err(PaytoErr::UnsupportedKind( 73 CYCLOS, 74 url.domain().unwrap_or_default().to_owned(), 75 )); 76 } 77 let Some(mut segments) = url.path_segments() else { 78 return Err(PaytoErr::custom(MissingCyclos)); 79 }; 80 let Some(first) = segments.next() else { 81 return Err(PaytoErr::custom(MissingCyclos)); 82 }; 83 84 CyclosId::from_str(first).map_err(PaytoErr::custom) 85 } 86 } 87 88 /// Parse a cyclos payto URI, panic if malformed 89 pub fn cyclos_payto(url: impl AsRef<str>) -> FullCyclosPayto { 90 url.as_ref().parse().expect("invalid cyclos payto") 91 } 92 93 pub type CyclosPayto = Payto<CyclosId>; 94 pub type FullCyclosPayto = FullPayto<CyclosId>; 95 pub type TransferCyclosPayto = TransferPayto<CyclosId>;