1use hashtree_network::DataMessage as SharedDataMessage;
4pub use hashtree_network::{
5 decrement_htl_with_policy, should_forward_htl, validate_mesh_frame, DataQuoteRequest,
6 DataQuoteResponse, DataRequest, DataResponse, HtlMode, HtlPolicy, IceCandidate, MeshNostrFrame,
7 MeshNostrPayload, PeerHTLConfig, PeerId, PeerPool, PoolConfig, PoolSettings,
8 RequestDispatchConfig, SelectionStrategy, SignalingMessage, TimedSeenSet, BLOB_REQUEST_POLICY,
9 DECREMENT_AT_MAX_PROB, DECREMENT_AT_MIN_PROB, MAX_HTL, MESH_DEFAULT_HTL, MESH_EVENT_POLICY,
10 MESH_MAX_HTL, MESH_PROTOCOL, MESH_PROTOCOL_VERSION, MSG_TYPE_QUOTE_REQUEST,
11 MSG_TYPE_QUOTE_RESPONSE, MSG_TYPE_REQUEST, MSG_TYPE_RESPONSE,
12};
13use serde::{Deserialize, Serialize};
14
15pub fn decrement_htl(htl: u8, config: &PeerHTLConfig) -> u8 {
17 decrement_htl_with_policy(htl, &BLOB_REQUEST_POLICY, config)
18}
19
20pub fn should_forward(htl: u8) -> bool {
22 should_forward_htl(htl)
23}
24
25pub const WEBRTC_KIND: u64 = 25050;
28
29pub const HELLO_TAG: &str = "hello";
31
32pub const WEBRTC_TAG: &str = "webrtc";
34
35#[derive(Clone)]
37pub struct WebRTCConfig {
38 pub relays: Vec<String>,
40 pub signaling_enabled: bool,
42 pub max_outbound: usize,
44 pub max_inbound: usize,
46 pub hello_interval_ms: u64,
48 pub message_timeout_ms: u64,
50 pub stun_servers: Vec<String>,
52 pub debug: bool,
54 pub multicast: super::multicast::MulticastConfig,
56 pub wifi_aware: super::wifi_aware::WifiAwareConfig,
58 pub bluetooth: super::bluetooth::BluetoothConfig,
60 pub pools: PoolSettings,
62 pub request_selection_strategy: SelectionStrategy,
64 pub request_fairness_enabled: bool,
66 pub request_dispatch: RequestDispatchConfig,
68}
69
70impl Default for WebRTCConfig {
71 fn default() -> Self {
72 Self {
73 relays: vec![
74 "wss://relay.damus.io".to_string(),
75 "wss://relay.primal.net".to_string(),
76 "wss://temp.iris.to".to_string(),
77 "wss://relay.snort.social".to_string(),
78 ],
79 signaling_enabled: true,
80 max_outbound: 6,
81 max_inbound: 6,
82 hello_interval_ms: 3000,
83 message_timeout_ms: 15000,
84 stun_servers: vec![
85 "stun:stun.iris.to:3478".to_string(),
86 "stun:stun.l.google.com:19302".to_string(),
87 "stun:stun.cloudflare.com:3478".to_string(),
88 ],
89 debug: false,
90 multicast: super::multicast::MulticastConfig::default(),
91 wifi_aware: super::wifi_aware::WifiAwareConfig::default(),
92 bluetooth: super::bluetooth::BluetoothConfig::default(),
93 pools: PoolSettings::default(),
94 request_selection_strategy: SelectionStrategy::TitForTat,
95 request_fairness_enabled: true,
96 request_dispatch: RequestDispatchConfig {
97 initial_fanout: 2,
98 hedge_fanout: 1,
99 max_fanout: 8,
100 hedge_interval_ms: 120,
101 },
102 }
103 }
104}
105
106#[derive(Debug, Clone)]
108pub struct PeerStatus {
109 pub peer_id: String,
110 pub pubkey: String,
111 pub state: String,
112 pub direction: PeerDirection,
113 pub connected_at: Option<std::time::Instant>,
114 pub pool: PeerPool,
115}
116
117#[derive(Debug, Clone, Copy, PartialEq, Eq)]
119pub enum PeerDirection {
120 Inbound,
121 Outbound,
122}
123
124#[derive(Debug, Clone)]
126pub enum PeerStateEvent {
127 Connected(PeerId),
129 Failed(PeerId),
131 Disconnected(PeerId),
133}
134
135impl std::fmt::Display for PeerDirection {
136 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
137 match self {
138 PeerDirection::Inbound => write!(f, "inbound"),
139 PeerDirection::Outbound => write!(f, "outbound"),
140 }
141 }
142}
143
144pub const MSG_TYPE_PAYMENT: u8 = 0x04;
145pub const MSG_TYPE_PAYMENT_ACK: u8 = 0x05;
146pub const MSG_TYPE_CHUNK: u8 = 0x06;
147
148#[derive(Debug, Clone, Serialize, Deserialize)]
161pub struct DataPayment {
162 #[serde(with = "serde_bytes")]
163 pub h: Vec<u8>,
164 pub q: u64,
165 pub c: u32,
166 pub p: u64,
167 #[serde(skip_serializing_if = "Option::is_none")]
168 pub m: Option<String>,
169 pub tok: String,
170}
171
172#[derive(Debug, Clone, Serialize, Deserialize)]
173pub struct DataPaymentAck {
174 #[serde(with = "serde_bytes")]
175 pub h: Vec<u8>,
176 pub q: u64,
177 pub c: u32,
178 pub a: bool,
179 #[serde(skip_serializing_if = "Option::is_none")]
180 pub e: Option<String>,
181}
182
183#[derive(Debug, Clone, Serialize, Deserialize)]
184pub struct DataChunk {
185 #[serde(with = "serde_bytes")]
186 pub h: Vec<u8>,
187 pub q: u64,
188 pub c: u32,
189 pub n: u32,
190 pub p: u64,
191 #[serde(with = "serde_bytes")]
192 pub d: Vec<u8>,
193}
194
195#[derive(Debug, Clone)]
196pub enum DataMessage {
197 Request(DataRequest),
198 Response(DataResponse),
199 QuoteRequest(DataQuoteRequest),
200 QuoteResponse(DataQuoteResponse),
201 Payment(DataPayment),
202 PaymentAck(DataPaymentAck),
203 Chunk(DataChunk),
204}
205
206pub fn encode_request(req: &DataRequest) -> Result<Vec<u8>, rmp_serde::encode::Error> {
209 Ok(hashtree_network::encode_request(req))
210}
211
212pub fn encode_response(res: &DataResponse) -> Result<Vec<u8>, rmp_serde::encode::Error> {
215 Ok(hashtree_network::encode_response(res))
216}
217
218pub fn encode_quote_request(req: &DataQuoteRequest) -> Result<Vec<u8>, rmp_serde::encode::Error> {
220 Ok(hashtree_network::encode_quote_request(req))
221}
222
223pub fn encode_quote_response(res: &DataQuoteResponse) -> Result<Vec<u8>, rmp_serde::encode::Error> {
225 Ok(hashtree_network::encode_quote_response(res))
226}
227
228pub fn encode_payment(req: &DataPayment) -> Result<Vec<u8>, rmp_serde::encode::Error> {
229 let body = rmp_serde::to_vec_named(req)?;
230 let mut result = Vec::with_capacity(1 + body.len());
231 result.push(MSG_TYPE_PAYMENT);
232 result.extend(body);
233 Ok(result)
234}
235
236pub fn encode_payment_ack(res: &DataPaymentAck) -> Result<Vec<u8>, rmp_serde::encode::Error> {
237 let body = rmp_serde::to_vec_named(res)?;
238 let mut result = Vec::with_capacity(1 + body.len());
239 result.push(MSG_TYPE_PAYMENT_ACK);
240 result.extend(body);
241 Ok(result)
242}
243
244pub fn encode_chunk(chunk: &DataChunk) -> Result<Vec<u8>, rmp_serde::encode::Error> {
245 let body = rmp_serde::to_vec_named(chunk)?;
246 let mut result = Vec::with_capacity(1 + body.len());
247 result.push(MSG_TYPE_CHUNK);
248 result.extend(body);
249 Ok(result)
250}
251
252pub fn parse_message(data: &[u8]) -> Result<DataMessage, rmp_serde::decode::Error> {
254 if data.is_empty() {
255 return Err(rmp_serde::decode::Error::LengthMismatch(0));
256 }
257
258 let msg_type = data[0];
259
260 match msg_type {
261 MSG_TYPE_REQUEST | MSG_TYPE_RESPONSE | MSG_TYPE_QUOTE_REQUEST | MSG_TYPE_QUOTE_RESPONSE => {
262 match hashtree_network::parse_message(data) {
263 Some(SharedDataMessage::Request(req)) => Ok(DataMessage::Request(req)),
264 Some(SharedDataMessage::Response(res)) => Ok(DataMessage::Response(res)),
265 Some(SharedDataMessage::QuoteRequest(req)) => Ok(DataMessage::QuoteRequest(req)),
266 Some(SharedDataMessage::QuoteResponse(res)) => Ok(DataMessage::QuoteResponse(res)),
267 None => Err(rmp_serde::decode::Error::LengthMismatch(msg_type as u32)),
268 }
269 }
270 MSG_TYPE_PAYMENT => {
271 let req: DataPayment = rmp_serde::from_slice(&data[1..])?;
272 Ok(DataMessage::Payment(req))
273 }
274 MSG_TYPE_PAYMENT_ACK => {
275 let res: DataPaymentAck = rmp_serde::from_slice(&data[1..])?;
276 Ok(DataMessage::PaymentAck(res))
277 }
278 MSG_TYPE_CHUNK => {
279 let chunk: DataChunk = rmp_serde::from_slice(&data[1..])?;
280 Ok(DataMessage::Chunk(chunk))
281 }
282 _ => Err(rmp_serde::decode::Error::LengthMismatch(msg_type as u32)),
283 }
284}
285
286pub fn hash_to_hex(hash: &[u8]) -> String {
288 hashtree_network::hash_to_key(hash)
289}
290
291pub fn encode_message(msg: &DataMessage) -> Result<Vec<u8>, rmp_serde::encode::Error> {
293 match msg {
294 DataMessage::Request(req) => encode_request(req),
295 DataMessage::Response(res) => encode_response(res),
296 DataMessage::QuoteRequest(req) => encode_quote_request(req),
297 DataMessage::QuoteResponse(res) => encode_quote_response(res),
298 DataMessage::Payment(req) => encode_payment(req),
299 DataMessage::PaymentAck(res) => encode_payment_ack(res),
300 DataMessage::Chunk(chunk) => encode_chunk(chunk),
301 }
302}