2021-11-22 16:28:30 +00:00
|
|
|
use crate::callback_state_machine::*;
|
2022-05-31 23:54:52 +00:00
|
|
|
use crate::dht::Crypto;
|
2021-11-22 16:28:30 +00:00
|
|
|
use crate::network_manager::*;
|
2022-03-24 14:14:50 +00:00
|
|
|
use crate::routing_table::*;
|
2021-11-22 16:28:30 +00:00
|
|
|
use crate::xx::*;
|
|
|
|
use crate::*;
|
|
|
|
use core::convert::TryFrom;
|
2021-12-21 00:12:30 +00:00
|
|
|
use core::fmt;
|
2022-02-07 02:18:42 +00:00
|
|
|
use serde::*;
|
2021-11-22 16:28:30 +00:00
|
|
|
|
|
|
|
state_machine! {
|
2022-02-07 02:18:42 +00:00
|
|
|
derive(Debug, PartialEq, Eq, Clone, Copy, Serialize, Deserialize)
|
2021-11-22 16:28:30 +00:00
|
|
|
pub Attachment(Detached)
|
|
|
|
//---
|
|
|
|
Detached(AttachRequested) => Attaching [StartAttachment],
|
|
|
|
Attaching => {
|
|
|
|
AttachmentStopped => Detached,
|
|
|
|
WeakPeers => AttachedWeak,
|
|
|
|
GoodPeers => AttachedGood,
|
|
|
|
StrongPeers => AttachedStrong,
|
|
|
|
FullPeers => FullyAttached,
|
|
|
|
TooManyPeers => OverAttached,
|
|
|
|
DetachRequested => Detaching [StopAttachment]
|
|
|
|
},
|
|
|
|
AttachedWeak => {
|
|
|
|
NoPeers => Attaching,
|
|
|
|
GoodPeers => AttachedGood,
|
|
|
|
StrongPeers => AttachedStrong,
|
|
|
|
FullPeers => FullyAttached,
|
|
|
|
TooManyPeers => OverAttached,
|
|
|
|
DetachRequested => Detaching [StopAttachment]
|
|
|
|
},
|
|
|
|
AttachedGood => {
|
|
|
|
NoPeers => Attaching,
|
|
|
|
WeakPeers => AttachedWeak,
|
|
|
|
StrongPeers => AttachedStrong,
|
|
|
|
FullPeers => FullyAttached,
|
|
|
|
TooManyPeers => OverAttached,
|
|
|
|
DetachRequested => Detaching [StopAttachment]
|
|
|
|
},
|
|
|
|
AttachedStrong => {
|
|
|
|
NoPeers => Attaching,
|
|
|
|
WeakPeers => AttachedWeak,
|
|
|
|
GoodPeers => AttachedGood,
|
|
|
|
FullPeers => FullyAttached,
|
|
|
|
TooManyPeers => OverAttached,
|
|
|
|
DetachRequested => Detaching [StopAttachment]
|
|
|
|
},
|
|
|
|
FullyAttached => {
|
|
|
|
NoPeers => Attaching,
|
|
|
|
WeakPeers => AttachedWeak,
|
|
|
|
GoodPeers => AttachedGood,
|
|
|
|
StrongPeers => AttachedStrong,
|
|
|
|
TooManyPeers => OverAttached,
|
|
|
|
DetachRequested => Detaching [StopAttachment]
|
|
|
|
},
|
|
|
|
OverAttached => {
|
|
|
|
NoPeers => Attaching,
|
|
|
|
WeakPeers => AttachedWeak,
|
|
|
|
GoodPeers => AttachedGood,
|
|
|
|
StrongPeers => AttachedStrong,
|
|
|
|
FullPeers => FullyAttached,
|
|
|
|
DetachRequested => Detaching [StopAttachment]
|
|
|
|
},
|
|
|
|
Detaching => {
|
|
|
|
AttachmentStopped => Detached,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
2021-12-21 00:12:30 +00:00
|
|
|
impl fmt::Display for AttachmentState {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
|
|
|
|
let out = match self {
|
2021-11-22 16:28:30 +00:00
|
|
|
AttachmentState::Attaching => "attaching".to_owned(),
|
|
|
|
AttachmentState::AttachedWeak => "attached_weak".to_owned(),
|
|
|
|
AttachmentState::AttachedGood => "attached_good".to_owned(),
|
|
|
|
AttachmentState::AttachedStrong => "attached_strong".to_owned(),
|
|
|
|
AttachmentState::FullyAttached => "fully_attached".to_owned(),
|
|
|
|
AttachmentState::OverAttached => "over_attached".to_owned(),
|
|
|
|
AttachmentState::Detaching => "detaching".to_owned(),
|
|
|
|
AttachmentState::Detached => "detached".to_owned(),
|
2021-12-21 00:12:30 +00:00
|
|
|
};
|
|
|
|
write!(f, "{}", out)
|
2021-11-22 16:28:30 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl TryFrom<String> for AttachmentState {
|
|
|
|
type Error = ();
|
|
|
|
|
|
|
|
fn try_from(s: String) -> Result<Self, Self::Error> {
|
|
|
|
Ok(match s.as_str() {
|
|
|
|
"attaching" => AttachmentState::Attaching,
|
|
|
|
"attached_weak" => AttachmentState::AttachedWeak,
|
|
|
|
"attached_good" => AttachmentState::AttachedGood,
|
|
|
|
"attached_strong" => AttachmentState::AttachedStrong,
|
|
|
|
"fully_attached" => AttachmentState::FullyAttached,
|
|
|
|
"over_attached" => AttachmentState::OverAttached,
|
|
|
|
"detaching" => AttachmentState::Detaching,
|
|
|
|
"detached" => AttachmentState::Detached,
|
|
|
|
_ => return Err(()),
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub struct AttachmentManagerInner {
|
|
|
|
config: VeilidConfig,
|
|
|
|
attachment_machine: CallbackStateMachine<Attachment>,
|
|
|
|
network_manager: NetworkManager,
|
|
|
|
maintain_peers: bool,
|
|
|
|
attach_timestamp: Option<u64>,
|
2022-03-24 14:14:50 +00:00
|
|
|
update_callback: Option<UpdateCallback>,
|
2022-06-13 00:58:02 +00:00
|
|
|
attachment_maintainer_jh: Option<MustJoinHandle<()>>,
|
2021-11-22 16:28:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Clone)]
|
|
|
|
pub struct AttachmentManager {
|
|
|
|
inner: Arc<Mutex<AttachmentManagerInner>>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl AttachmentManager {
|
|
|
|
fn new_inner(
|
|
|
|
config: VeilidConfig,
|
|
|
|
table_store: TableStore,
|
|
|
|
crypto: Crypto,
|
|
|
|
) -> AttachmentManagerInner {
|
|
|
|
AttachmentManagerInner {
|
|
|
|
config: config.clone(),
|
|
|
|
attachment_machine: CallbackStateMachine::new(),
|
2021-12-08 03:09:45 +00:00
|
|
|
network_manager: NetworkManager::new(config, table_store, crypto),
|
2021-11-22 16:28:30 +00:00
|
|
|
maintain_peers: false,
|
|
|
|
attach_timestamp: None,
|
2022-03-24 14:14:50 +00:00
|
|
|
update_callback: None,
|
2021-11-22 16:28:30 +00:00
|
|
|
attachment_maintainer_jh: None,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
pub fn new(config: VeilidConfig, table_store: TableStore, crypto: Crypto) -> Self {
|
|
|
|
Self {
|
|
|
|
inner: Arc::new(Mutex::new(Self::new_inner(config, table_store, crypto))),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn config(&self) -> VeilidConfig {
|
|
|
|
self.inner.lock().config.clone()
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn network_manager(&self) -> NetworkManager {
|
|
|
|
self.inner.lock().network_manager.clone()
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn is_attached(&self) -> bool {
|
|
|
|
let s = self.inner.lock().attachment_machine.state();
|
2021-11-27 17:44:21 +00:00
|
|
|
!matches!(s, AttachmentState::Detached | AttachmentState::Detaching)
|
2021-11-22 16:28:30 +00:00
|
|
|
}
|
|
|
|
pub fn is_detached(&self) -> bool {
|
|
|
|
let s = self.inner.lock().attachment_machine.state();
|
2021-11-27 17:44:21 +00:00
|
|
|
matches!(s, AttachmentState::Detached)
|
2021-11-22 16:28:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn get_attach_timestamp(&self) -> Option<u64> {
|
|
|
|
self.inner.lock().attach_timestamp
|
|
|
|
}
|
|
|
|
|
2022-03-24 14:14:50 +00:00
|
|
|
fn translate_routing_table_health(
|
|
|
|
health: RoutingTableHealth,
|
|
|
|
config: &VeilidConfigRoutingTable,
|
|
|
|
) -> AttachmentInput {
|
|
|
|
if health.reliable_entry_count >= config.limit_over_attached.try_into().unwrap() {
|
2021-11-22 16:28:30 +00:00
|
|
|
return AttachmentInput::TooManyPeers;
|
|
|
|
}
|
2022-03-24 14:14:50 +00:00
|
|
|
if health.reliable_entry_count >= config.limit_fully_attached.try_into().unwrap() {
|
|
|
|
return AttachmentInput::FullPeers;
|
|
|
|
}
|
|
|
|
if health.reliable_entry_count >= config.limit_attached_strong.try_into().unwrap() {
|
|
|
|
return AttachmentInput::StrongPeers;
|
|
|
|
}
|
|
|
|
if health.reliable_entry_count >= config.limit_attached_good.try_into().unwrap() {
|
|
|
|
return AttachmentInput::GoodPeers;
|
2021-11-22 16:28:30 +00:00
|
|
|
}
|
2022-03-24 14:14:50 +00:00
|
|
|
if health.reliable_entry_count >= config.limit_attached_weak.try_into().unwrap()
|
|
|
|
|| health.unreliable_entry_count >= config.limit_attached_weak.try_into().unwrap()
|
|
|
|
{
|
|
|
|
return AttachmentInput::WeakPeers;
|
|
|
|
}
|
|
|
|
AttachmentInput::NoPeers
|
2021-11-22 16:28:30 +00:00
|
|
|
}
|
2022-03-24 14:14:50 +00:00
|
|
|
fn translate_attachment_state(state: &AttachmentState) -> AttachmentInput {
|
2021-11-22 16:28:30 +00:00
|
|
|
match state {
|
|
|
|
AttachmentState::OverAttached => AttachmentInput::TooManyPeers,
|
|
|
|
AttachmentState::FullyAttached => AttachmentInput::FullPeers,
|
|
|
|
AttachmentState::AttachedStrong => AttachmentInput::StrongPeers,
|
|
|
|
AttachmentState::AttachedGood => AttachmentInput::GoodPeers,
|
|
|
|
AttachmentState::AttachedWeak => AttachmentInput::WeakPeers,
|
|
|
|
AttachmentState::Attaching => AttachmentInput::NoPeers,
|
|
|
|
_ => panic!("Invalid state"),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-03-24 14:14:50 +00:00
|
|
|
async fn update_attachment(&self) {
|
2021-11-22 16:28:30 +00:00
|
|
|
let new_peer_state_input = {
|
|
|
|
let inner = self.inner.lock();
|
|
|
|
|
|
|
|
let old_peer_state_input =
|
2022-03-24 14:14:50 +00:00
|
|
|
AttachmentManager::translate_attachment_state(&inner.attachment_machine.state());
|
2021-11-22 16:28:30 +00:00
|
|
|
|
2022-03-24 14:14:50 +00:00
|
|
|
// get reliable peer count from routing table
|
|
|
|
let routing_table = inner.network_manager.routing_table();
|
|
|
|
let health = routing_table.get_routing_table_health();
|
|
|
|
let routing_table_config = &inner.config.get().network.routing_table;
|
2021-11-22 16:28:30 +00:00
|
|
|
|
|
|
|
let new_peer_state_input =
|
2022-03-24 14:14:50 +00:00
|
|
|
AttachmentManager::translate_routing_table_health(health, routing_table_config);
|
2021-11-22 16:28:30 +00:00
|
|
|
|
|
|
|
if old_peer_state_input == new_peer_state_input {
|
|
|
|
None
|
|
|
|
} else {
|
|
|
|
Some(new_peer_state_input)
|
|
|
|
}
|
|
|
|
};
|
|
|
|
if let Some(next_input) = new_peer_state_input {
|
|
|
|
let _ = self.process_input(&next_input).await;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-06-10 21:07:10 +00:00
|
|
|
#[instrument(level = "debug", skip(self))]
|
2021-11-22 16:28:30 +00:00
|
|
|
async fn attachment_maintainer(self) {
|
|
|
|
trace!("attachment starting");
|
|
|
|
let netman = {
|
|
|
|
let mut inner = self.inner.lock();
|
|
|
|
inner.attach_timestamp = Some(intf::get_timestamp());
|
|
|
|
inner.network_manager.clone()
|
|
|
|
};
|
|
|
|
|
|
|
|
let mut started = true;
|
|
|
|
if let Err(err) = netman.startup().await {
|
|
|
|
error!("network startup failed: {}", err);
|
|
|
|
started = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if started {
|
|
|
|
trace!("started maintaining peers");
|
|
|
|
while self.inner.lock().maintain_peers {
|
|
|
|
// tick network manager
|
|
|
|
if let Err(err) = netman.tick().await {
|
|
|
|
error!("Error in network manager: {}", err);
|
|
|
|
self.inner.lock().maintain_peers = false;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2022-03-24 14:14:50 +00:00
|
|
|
self.update_attachment().await;
|
2021-11-22 16:28:30 +00:00
|
|
|
|
|
|
|
// sleep should be at the end in case maintain_peers changes state
|
|
|
|
intf::sleep(1000).await;
|
|
|
|
}
|
|
|
|
trace!("stopped maintaining peers");
|
|
|
|
|
|
|
|
trace!("stopping network");
|
|
|
|
netman.shutdown().await;
|
|
|
|
}
|
|
|
|
|
|
|
|
trace!("stopping attachment");
|
|
|
|
let attachment_machine = self.inner.lock().attachment_machine.clone();
|
|
|
|
let _output = attachment_machine
|
|
|
|
.consume(&AttachmentInput::AttachmentStopped)
|
|
|
|
.await;
|
|
|
|
trace!("attachment stopped");
|
|
|
|
self.inner.lock().attach_timestamp = None;
|
|
|
|
}
|
|
|
|
|
2022-06-10 21:07:10 +00:00
|
|
|
#[instrument(level = "debug", skip_all, err)]
|
2022-03-24 14:14:50 +00:00
|
|
|
pub async fn init(&self, update_callback: UpdateCallback) -> Result<(), String> {
|
2022-03-09 03:32:12 +00:00
|
|
|
trace!("init");
|
2022-02-07 02:18:42 +00:00
|
|
|
let network_manager = {
|
2022-03-24 14:14:50 +00:00
|
|
|
let mut inner = self.inner.lock();
|
|
|
|
inner.update_callback = Some(update_callback.clone());
|
2022-05-16 15:52:48 +00:00
|
|
|
let update_callback2 = update_callback.clone();
|
2022-03-24 14:14:50 +00:00
|
|
|
inner.attachment_machine.set_state_change_callback(Arc::new(
|
|
|
|
move |_old_state: AttachmentState, new_state: AttachmentState| {
|
2022-05-16 15:52:48 +00:00
|
|
|
update_callback2(VeilidUpdate::Attachment(VeilidStateAttachment {
|
|
|
|
state: new_state,
|
|
|
|
}))
|
2022-03-24 14:14:50 +00:00
|
|
|
},
|
|
|
|
));
|
2022-02-07 02:18:42 +00:00
|
|
|
inner.network_manager.clone()
|
|
|
|
};
|
2021-11-22 16:28:30 +00:00
|
|
|
|
2022-05-16 15:52:48 +00:00
|
|
|
network_manager.init(update_callback).await?;
|
2021-11-22 16:28:30 +00:00
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
2022-06-10 21:07:10 +00:00
|
|
|
|
|
|
|
#[instrument(level = "debug", skip(self))]
|
2021-11-22 16:28:30 +00:00
|
|
|
pub async fn terminate(&self) {
|
|
|
|
// Ensure we detached
|
|
|
|
self.detach().await;
|
2022-02-07 02:18:42 +00:00
|
|
|
let network_manager = {
|
|
|
|
let inner = self.inner.lock();
|
|
|
|
inner.network_manager.clone()
|
|
|
|
};
|
|
|
|
network_manager.terminate().await;
|
2022-03-24 14:14:50 +00:00
|
|
|
let mut inner = self.inner.lock();
|
|
|
|
inner.update_callback = None;
|
2021-11-22 16:28:30 +00:00
|
|
|
}
|
|
|
|
|
2022-06-10 21:07:10 +00:00
|
|
|
#[instrument(level = "trace", skip(self))]
|
2021-11-22 16:28:30 +00:00
|
|
|
fn attach(&self) {
|
|
|
|
// Create long-running connection maintenance routine
|
|
|
|
let this = self.clone();
|
|
|
|
self.inner.lock().maintain_peers = true;
|
2022-06-28 03:46:29 +00:00
|
|
|
self.inner.lock().attachment_maintainer_jh =
|
|
|
|
Some(intf::spawn(this.attachment_maintainer()));
|
2021-11-22 16:28:30 +00:00
|
|
|
}
|
|
|
|
|
2022-06-10 21:07:10 +00:00
|
|
|
#[instrument(level = "trace", skip(self))]
|
2021-11-22 16:28:30 +00:00
|
|
|
async fn detach(&self) {
|
|
|
|
let attachment_maintainer_jh = self.inner.lock().attachment_maintainer_jh.take();
|
|
|
|
if let Some(jh) = attachment_maintainer_jh {
|
|
|
|
// Terminate long-running connection maintenance routine
|
|
|
|
self.inner.lock().maintain_peers = false;
|
|
|
|
jh.await;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
async fn handle_output(&self, output: &AttachmentOutput) {
|
|
|
|
match output {
|
|
|
|
AttachmentOutput::StartAttachment => self.attach(),
|
|
|
|
AttachmentOutput::StopAttachment => self.detach().await,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-03-09 03:32:12 +00:00
|
|
|
async fn process_input(&self, input: &AttachmentInput) -> Result<(), String> {
|
2021-11-22 16:28:30 +00:00
|
|
|
let attachment_machine = self.inner.lock().attachment_machine.clone();
|
|
|
|
let output = attachment_machine.consume(input).await;
|
|
|
|
match output {
|
2022-03-09 03:32:12 +00:00
|
|
|
Err(e) => Err(format!(
|
|
|
|
"invalid input '{:?}' for state machine in state '{:?}': {:?}",
|
|
|
|
input,
|
|
|
|
attachment_machine.state(),
|
|
|
|
e
|
|
|
|
)),
|
2021-11-22 16:28:30 +00:00
|
|
|
Ok(v) => {
|
|
|
|
if let Some(o) = v {
|
|
|
|
self.handle_output(&o).await;
|
|
|
|
}
|
2022-03-09 03:32:12 +00:00
|
|
|
Ok(())
|
2021-11-22 16:28:30 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-06-10 21:07:10 +00:00
|
|
|
#[instrument(level = "trace", skip(self), err)]
|
2022-03-09 03:32:12 +00:00
|
|
|
pub async fn request_attach(&self) -> Result<(), String> {
|
|
|
|
self.process_input(&AttachmentInput::AttachRequested)
|
|
|
|
.await
|
|
|
|
.map_err(|e| format!("Attach request failed: {}", e))
|
2021-11-22 16:28:30 +00:00
|
|
|
}
|
|
|
|
|
2022-06-10 21:07:10 +00:00
|
|
|
#[instrument(level = "trace", skip(self), err)]
|
2022-03-09 03:32:12 +00:00
|
|
|
pub async fn request_detach(&self) -> Result<(), String> {
|
|
|
|
self.process_input(&AttachmentInput::DetachRequested)
|
|
|
|
.await
|
2022-06-10 21:07:10 +00:00
|
|
|
.map_err(|e| format!("Detach request failed: {}", e))
|
2021-11-22 16:28:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn get_state(&self) -> AttachmentState {
|
|
|
|
let attachment_machine = self.inner.lock().attachment_machine.clone();
|
|
|
|
attachment_machine.state()
|
|
|
|
}
|
2022-05-16 15:52:48 +00:00
|
|
|
|
|
|
|
pub fn get_veilid_state(&self) -> VeilidStateAttachment {
|
|
|
|
VeilidStateAttachment {
|
|
|
|
state: self.get_state(),
|
|
|
|
}
|
|
|
|
}
|
2021-11-22 16:28:30 +00:00
|
|
|
}
|