sfo_cmd_server/
peer_id.rs1use 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}