use hashtree_core::Hash;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct PeerId {
pub pubkey: String,
pub uuid: String,
}
impl PeerId {
pub fn new(pubkey: String, uuid: String) -> Self {
Self { pubkey, uuid }
}
pub fn to_peer_string(&self) -> String {
format!("{}:{}", self.pubkey, self.uuid)
}
pub fn from_peer_string(s: &str) -> Option<Self> {
let parts: Vec<&str> = s.split(':').collect();
if parts.len() == 2 {
Some(Self {
pubkey: parts[0].to_string(),
uuid: parts[1].to_string(),
})
} else {
None
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "type")]
pub enum SignalingMessage {
#[serde(rename = "hello")]
Hello {
#[serde(rename = "peerId")]
peer_id: String,
roots: Vec<String>,
},
#[serde(rename = "offer")]
Offer {
#[serde(rename = "peerId")]
peer_id: String,
#[serde(rename = "targetPeerId")]
target_peer_id: String,
sdp: String,
},
#[serde(rename = "answer")]
Answer {
#[serde(rename = "peerId")]
peer_id: String,
#[serde(rename = "targetPeerId")]
target_peer_id: String,
sdp: String,
},
#[serde(rename = "candidate")]
Candidate {
#[serde(rename = "peerId")]
peer_id: String,
#[serde(rename = "targetPeerId")]
target_peer_id: String,
candidate: String,
#[serde(rename = "sdpMLineIndex")]
sdp_m_line_index: Option<u16>,
#[serde(rename = "sdpMid")]
sdp_mid: Option<String>,
},
#[serde(rename = "candidates")]
Candidates {
#[serde(rename = "peerId")]
peer_id: String,
#[serde(rename = "targetPeerId")]
target_peer_id: String,
candidates: Vec<IceCandidate>,
},
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct IceCandidate {
pub candidate: String,
#[serde(rename = "sdpMLineIndex")]
pub sdp_m_line_index: Option<u16>,
#[serde(rename = "sdpMid")]
pub sdp_mid: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "type")]
pub enum DataMessage {
#[serde(rename = "req")]
Request {
id: u32,
hash: String,
#[serde(skip_serializing_if = "Option::is_none")]
htl: Option<u8>,
},
#[serde(rename = "res")]
Response {
id: u32,
hash: String,
found: bool,
#[serde(skip_serializing_if = "Option::is_none")]
size: Option<u64>,
},
#[serde(rename = "push")]
Push { hash: String },
#[serde(rename = "have")]
Have { hashes: Vec<String> },
#[serde(rename = "want")]
Want { hashes: Vec<String> },
#[serde(rename = "root")]
RootUpdate {
hash: String,
#[serde(skip_serializing_if = "Option::is_none")]
size: Option<u64>,
},
}
pub const MAX_HTL: u8 = 10;
pub const DECREMENT_AT_MAX_PROB: f64 = 0.5;
pub const DECREMENT_AT_MIN_PROB: f64 = 0.25;
#[derive(Debug, Clone, Copy)]
pub struct PeerHTLConfig {
pub decrement_at_max: bool,
pub decrement_at_min: bool,
}
impl PeerHTLConfig {
pub fn random() -> Self {
use rand::Rng;
let mut rng = rand::thread_rng();
Self {
decrement_at_max: rng.gen::<f64>() < DECREMENT_AT_MAX_PROB,
decrement_at_min: rng.gen::<f64>() < DECREMENT_AT_MIN_PROB,
}
}
pub fn decrement(&self, htl: u8) -> u8 {
if htl == 0 {
return 0;
}
if htl == MAX_HTL {
if self.decrement_at_max {
htl - 1
} else {
htl
}
} else if htl == 1 {
if self.decrement_at_min {
0
} else {
htl
}
} else {
htl - 1
}
}
}
pub fn should_forward(htl: u8) -> bool {
htl > 0
}
use tokio::sync::{mpsc, oneshot};
pub struct ForwardRequest {
pub hash: Hash,
pub exclude_peer_id: String,
pub htl: u8,
pub response: oneshot::Sender<Option<Vec<u8>>>,
}
pub type ForwardTx = mpsc::Sender<ForwardRequest>;
pub type ForwardRx = mpsc::Receiver<ForwardRequest>;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum PeerPool {
Follows,
Other,
}
#[derive(Debug, Clone, Copy)]
pub struct PoolConfig {
pub max_connections: usize,
pub satisfied_connections: usize,
}
impl Default for PoolConfig {
fn default() -> Self {
Self {
max_connections: 10,
satisfied_connections: 5,
}
}
}
#[derive(Debug, Clone)]
pub struct PoolSettings {
pub follows: PoolConfig,
pub other: PoolConfig,
}
impl Default for PoolSettings {
fn default() -> Self {
Self {
follows: PoolConfig {
max_connections: 20,
satisfied_connections: 10,
},
other: PoolConfig {
max_connections: 10,
satisfied_connections: 5,
},
}
}
}
pub struct ClassifyRequest {
pub pubkey: String,
pub response: oneshot::Sender<PeerPool>,
}
pub type ClassifierTx = mpsc::Sender<ClassifyRequest>;
pub type ClassifierRx = mpsc::Receiver<ClassifyRequest>;
pub fn classifier_channel(buffer: usize) -> (ClassifierTx, ClassifierRx) {
mpsc::channel(buffer)
}
#[derive(Clone)]
pub struct WebRTCStoreConfig {
pub relays: Vec<String>,
pub roots: Vec<Hash>,
pub request_timeout_ms: u64,
pub hello_interval_ms: u64,
pub debug: bool,
pub pools: PoolSettings,
pub classifier_tx: Option<ClassifierTx>,
}
impl Default for WebRTCStoreConfig {
fn default() -> Self {
Self {
relays: vec![
"wss://temp.iris.to".to_string(),
"wss://relay.damus.io".to_string(),
],
roots: Vec::new(),
request_timeout_ms: 10000,
hello_interval_ms: 30000,
debug: false,
pools: PoolSettings::default(),
classifier_tx: None,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum PeerState {
New,
Connecting,
Connected,
Ready,
Disconnected,
}
#[derive(Debug, Clone, Default)]
pub struct WebRTCStats {
pub connected_peers: usize,
pub pending_requests: usize,
pub bytes_sent: u64,
pub bytes_received: u64,
pub requests_made: u64,
pub requests_fulfilled: u64,
}
pub const NOSTR_KIND_HASHTREE: u16 = 25050;
pub const DATA_CHANNEL_LABEL: &str = "hashtree";