use super::Service;
use crate::{
Error,
model::{BookEntry, OverlayStatus},
peer::SyncPeers,
peer_discovery::Discovery,
peer_sync::{PeerSync, Scheduler},
recorded::{record, unix_seconds},
retrieval::RecordSource,
};
use std::sync::{Arc, atomic::Ordering};
impl Service {
pub fn with_record_peers(mut self, peers: SyncPeers) -> Self {
self.record_peers = Some(peers);
self
}
pub(super) fn record_sources(&self) -> Vec<Arc<dyn RecordSource + Send + Sync>> {
let mut sources = self.sources.clone();
let peers = self.record_peers.iter().flat_map(SyncPeers::record_sources);
sources.extend(peers.map(|peer| -> Arc<dyn RecordSource + Send + Sync> { Arc::new(peer) }));
sources
}
pub(super) fn record_source_count(&self) -> usize {
let peers = self
.record_peers
.as_ref()
.map_or(0, SyncPeers::record_count);
self.sources.len() + peers
}
pub fn with_peer_sync(mut self, sync: PeerSync) -> Result<Self, Error> {
self.peer_sync = Some(Scheduler::new(sync)?);
Ok(self)
}
pub fn with_discovery(mut self, discovery: Discovery) -> Result<Self, Error> {
self.discovery = Some(discovery);
Ok(self)
}
pub(super) fn discover_peers(&self) {
let Some(discovery) = &self.discovery else {
return;
};
if self.stop.load(Ordering::Acquire) {
return;
}
let result = self
.share_sync_backoff(discovery)
.and_then(|()| discovery.step(&self.engine, &self.stop));
if self.stop.load(Ordering::Acquire) {
return;
}
record(&self.discovery_error, &result);
}
fn share_sync_backoff(&self, discovery: &Discovery) -> Result<(), Error> {
let Some(scheduler) = &self.peer_sync else {
return Ok(());
};
discovery.hold_off(scheduler.backed_off(unix_seconds()?)?)
}
pub(super) fn sync_next_inventory(&self) {
let Some(scheduler) = &self.peer_sync else {
return;
};
if self.stop.load(Ordering::Acquire) {
return;
}
let result = scheduler
.step(&self.engine, &self.stop)
.and_then(|()| self.penalize_in_book(scheduler));
if self.stop.load(Ordering::Acquire) {
return;
}
record(&self.inventory_error, &result);
}
fn penalize_in_book(&self, scheduler: &Scheduler) -> Result<(), Error> {
let penalized = scheduler.drain_penalized()?;
match &self.discovery {
Some(discovery) => discovery.penalize(&penalized),
None => Ok(()),
}
}
pub(super) fn overlay_status(&self) -> Result<Option<OverlayStatus>, Error> {
let Some(scheduler) = &self.peer_sync else {
return Ok(None);
};
let mut overlay = scheduler.status(&self.engine)?;
if let Some(discovery) = &self.discovery {
overlay.discovery = Some(discovery.status()?);
}
Ok(Some(overlay))
}
pub(super) fn overlay_book(&self) -> Result<Option<Vec<BookEntry>>, Error> {
self.discovery.as_ref().map(Discovery::book).transpose()
}
}