hoprd_api/
types.rs

1// Unified type for PeerId and Address
2//
3// This module provides a unified type for PeerId and Address. This is useful for APIs that accept both PeerId and Address.
4
5use libp2p_identity::PeerId;
6use serde::{Deserialize, Serialize};
7use std::fmt::{Debug, Display, Formatter};
8use std::str::FromStr;
9use utoipa::ToSchema;
10
11use core::result::Result;
12use hopr_crypto_types::types::OffchainPublicKey;
13use hopr_db_api::prelude::HoprDbResolverOperations;
14use hopr_lib::{Address, GeneralError};
15
16use crate::ApiErrorStatus;
17
18#[derive(Debug, Clone, Copy, Eq, Hash, Ord, Serialize, Deserialize, PartialEq, PartialOrd, ToSchema)]
19pub enum PeerOrAddress {
20    #[schema(value_type = String)]
21    PeerId(PeerId),
22    #[schema(value_type = String)]
23    Address(Address),
24}
25
26impl From<PeerId> for PeerOrAddress {
27    fn from(peer_id: PeerId) -> Self {
28        Self::PeerId(peer_id)
29    }
30}
31
32impl From<Address> for PeerOrAddress {
33    fn from(address: Address) -> Self {
34        Self::Address(address)
35    }
36}
37impl FromStr for PeerOrAddress {
38    type Err = GeneralError;
39
40    fn from_str(value: &str) -> Result<PeerOrAddress, GeneralError> {
41        if value.starts_with("0x") {
42            Address::from_str(value)
43                .map(PeerOrAddress::from)
44                .map_err(|_e| GeneralError::ParseError("PeerOrAddress".into()))
45        } else {
46            PeerId::from_str(value)
47                .map(PeerOrAddress::from)
48                .map_err(|_e| GeneralError::ParseError("PeerOrAddress".into()))
49        }
50    }
51}
52
53impl Display for PeerOrAddress {
54    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
55        match self {
56            PeerOrAddress::PeerId(peer_id) => write!(f, "{}", peer_id),
57            PeerOrAddress::Address(address) => write!(f, "{}", address),
58        }
59    }
60}
61
62pub struct HoprIdentifier {
63    pub peer_id: PeerId,
64    pub address: Address,
65}
66
67impl HoprIdentifier {
68    pub async fn new_with<T: HoprDbResolverOperations>(
69        peer_or_address: PeerOrAddress,
70        resolver: &T,
71    ) -> Result<Self, ApiErrorStatus> {
72        match peer_or_address {
73            PeerOrAddress::PeerId(peer_id) => {
74                let offchain_key = match OffchainPublicKey::try_from(peer_id) {
75                    Ok(key) => key,
76                    Err(_) => return Err(ApiErrorStatus::InvalidInput),
77                };
78
79                match resolver.resolve_chain_key(&offchain_key).await {
80                    Ok(Some(address)) => Ok(HoprIdentifier { peer_id, address }),
81                    Ok(None) => Err(ApiErrorStatus::PeerNotFound),
82                    Err(_) => Err(ApiErrorStatus::PeerNotFound),
83                }
84            }
85            PeerOrAddress::Address(address) => match resolver.resolve_packet_key(&address).await {
86                Ok(Some(offchain_key)) => Ok(HoprIdentifier {
87                    peer_id: PeerId::from(offchain_key),
88                    address,
89                }),
90                Ok(None) => Err(ApiErrorStatus::PeerNotFound),
91                Err(_) => Err(ApiErrorStatus::PeerNotFound),
92            },
93        }
94    }
95}