Skip to main content

sfo_cmd_server/
peer_id.rs

1use crate::errors::{CmdError, CmdErrorCode, CmdResult, cmd_err};
2use base58::{FromBase58, ToBase58};
3use bucky_raw_codec::{RawDecode, RawEncode};
4use std::fmt::{Debug, Display, Formatter};
5
6pub trait ToBase36 {
7    fn to_base36(&self) -> String;
8}
9
10pub trait FromBase36 {
11    fn from_base36(&self) -> CmdResult<Vec<u8>>;
12}
13
14const ALPHABET: &[u8] = b"0123456789abcdefghijklmnopqrstuvwxyz";
15
16impl ToBase36 for [u8] {
17    fn to_base36(&self) -> String {
18        base_x::encode(ALPHABET, self)
19    }
20}
21
22impl FromBase36 for str {
23    fn from_base36(&self) -> CmdResult<Vec<u8>> {
24        base_x::decode(ALPHABET, &self.to_ascii_lowercase()).map_err(|e| {
25            let msg = format!("convert string to base36 error! {self}, {e}");
26            CmdError::new(CmdErrorCode::Failed, msg)
27        })
28    }
29}
30
31#[derive(Clone, Eq, PartialEq, Hash, RawDecode, RawEncode)]
32pub struct PeerId(Vec<u8>);
33impl PeerId {
34    pub fn to_base58(&self) -> String {
35        self.0.as_slice().to_base58()
36    }
37
38    pub fn from_base58(base58: &str) -> CmdResult<Self> {
39        Ok(Self(base58.from_base58().map_err(|_| {
40            cmd_err!(CmdErrorCode::InvalidParam, "invalid peer id {}", base58)
41        })?))
42    }
43
44    pub fn as_slice(&self) -> &[u8] {
45        self.0.as_slice()
46    }
47
48    pub fn to_base36(&self) -> String {
49        self.0.to_base36()
50    }
51
52    pub fn from_base36(base36: &str) -> CmdResult<Self> {
53        Ok(Self(base36.from_base36()?))
54    }
55}
56
57impl Display for PeerId {
58    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
59        write!(f, "{}", self.to_base36())
60    }
61}
62
63impl Debug for PeerId {
64    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
65        write!(f, "{}", self.to_base36())
66    }
67}
68
69impl From<&[u8]> for PeerId {
70    fn from(key: &[u8]) -> Self {
71        Self(key.to_vec())
72    }
73}
74
75impl From<Vec<u8>> for PeerId {
76    fn from(key: Vec<u8>) -> Self {
77        Self(key)
78    }
79}
80
81#[cfg(test)]
82mod tests {
83    use super::PeerId;
84
85    #[test]
86    fn base58_round_trip() {
87        let raw = vec![1u8, 2, 3, 4, 5, 250, 251, 252];
88        let id = PeerId::from(raw.clone());
89        let decoded = PeerId::from_base58(&id.to_base58()).unwrap();
90        assert_eq!(decoded.as_slice(), raw.as_slice());
91    }
92
93    #[test]
94    fn base36_round_trip() {
95        let raw = vec![9u8, 8, 7, 6, 5, 4, 3, 2];
96        let id = PeerId::from(raw.clone());
97        let decoded = PeerId::from_base36(&id.to_base36()).unwrap();
98        assert_eq!(decoded.as_slice(), raw.as_slice());
99    }
100
101    #[test]
102    fn invalid_base58_rejected() {
103        assert!(PeerId::from_base58("***invalid***").is_err());
104    }
105
106    #[test]
107    fn invalid_base36_rejected() {
108        assert!(PeerId::from_base36("not@base36").is_err());
109    }
110}