1use po_crypto::identity::Identity;
23use po_session::channel::channels;
24use po_session::state::Session;
25use po_transport::quic::{QuicConfig, QuicListener, QuicTransport};
26use std::net::SocketAddr;
27
28use crate::peer::PeerInfo;
29
30pub struct Po {
35 session: Session,
36 transport: QuicTransport,
37 identity: Identity,
38 peer_info: Option<PeerInfo>,
39}
40
41impl Po {
42 pub async fn connect(addr: &str) -> Result<Self, PoError> {
54 let socket_addr: SocketAddr = addr
55 .parse()
56 .map_err(|e| PoError::Config(format!("invalid address '{addr}': {e}")))?;
57
58 let identity = Identity::generate();
59 let mut transport = QuicTransport::connect(socket_addr)
60 .await
61 .map_err(|e| PoError::Transport(e.to_string()))?;
62
63 let mut session = Session::new(Identity::from_bytes(&identity.secret_key_bytes()));
64 session
65 .handshake_initiator(&mut transport)
66 .await
67 .map_err(|e| PoError::Handshake(e.to_string()))?;
68
69 let peer_info = session.peer_node_id().map(|id| PeerInfo {
70 node_id: *id,
71 addr: socket_addr,
72 pubkey: [0u8; 32], });
74
75 Ok(Self {
76 session,
77 transport,
78 identity,
79 peer_info,
80 })
81 }
82
83 pub async fn bind(port: u16) -> Result<Self, PoError> {
96 let identity = Identity::generate();
97
98 let config = QuicConfig {
99 bind_addr: format!("0.0.0.0:{port}").parse().unwrap(),
100 };
101 let listener = QuicListener::bind(config)
102 .await
103 .map_err(|e| PoError::Transport(e.to_string()))?;
104
105 let mut transport = listener
106 .accept()
107 .await
108 .map_err(|e| PoError::Transport(e.to_string()))?;
109
110 let mut session = Session::new(Identity::from_bytes(&identity.secret_key_bytes()));
111 session
112 .handshake_responder(&mut transport)
113 .await
114 .map_err(|e| PoError::Handshake(e.to_string()))?;
115
116 let peer_info = session.peer_node_id().map(|id| PeerInfo {
117 node_id: *id,
118 addr: format!("0.0.0.0:{port}").parse().unwrap(),
119 pubkey: [0u8; 32],
120 });
121
122 Ok(Self {
123 session,
124 transport,
125 identity,
126 peer_info,
127 })
128 }
129
130 pub async fn send(&mut self, data: &[u8]) -> Result<(), PoError> {
132 self.session
133 .send(&mut self.transport, channels::DEFAULT, data)
134 .await
135 .map_err(|e| PoError::Session(e.to_string()))
136 }
137
138 pub async fn recv(&mut self) -> Result<Option<(u32, Vec<u8>)>, PoError> {
142 self.session
143 .recv(&mut self.transport)
144 .await
145 .map_err(|e| PoError::Session(e.to_string()))
146 }
147
148 pub fn node_id(&self) -> String {
150 self.session.node_id().to_hex()
151 }
152
153 pub fn public_key(&self) -> [u8; 32] {
155 self.identity.public_key_bytes()
156 }
157
158 pub fn peer_node_id(&self) -> Option<String> {
160 self.session.peer_node_id().map(|id| id.to_hex())
161 }
162
163 pub fn peer_info(&self) -> Option<&PeerInfo> {
165 self.peer_info.as_ref()
166 }
167
168 pub async fn close(&mut self) -> Result<(), PoError> {
170 self.session
171 .close(&mut self.transport)
172 .await
173 .map_err(|e| PoError::Session(e.to_string()))
174 }
175}
176
177#[derive(Debug)]
179pub enum PoError {
180 Config(String),
181 Transport(String),
182 Handshake(String),
183 Session(String),
184}
185
186impl std::fmt::Display for PoError {
187 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
188 match self {
189 Self::Config(e) => write!(f, "config: {e}"),
190 Self::Transport(e) => write!(f, "transport: {e}"),
191 Self::Handshake(e) => write!(f, "handshake: {e}"),
192 Self::Session(e) => write!(f, "session: {e}"),
193 }
194 }
195}
196
197impl std::error::Error for PoError {}