use std::sync::Arc;
use futures::future::BoxFuture;
use ntk_proto::v1::method_call::Call;
use ntk_proto::v1::{Auth, CallerContext, MethodCall, RemoteError, ResponsePayload, TypedValue};
use ntk_rpc::RpcHandler;
use tokio::sync::RwLock;
#[derive(Debug)]
pub struct IdentityStack {
pub qspn: ntk_qspn::QspnRpcHandler,
pub peers: ntk_peerservices::PeersRpcHandler,
pub coordinator: ntk_coordinator::CoordinatorRpcHandler,
pub hooking: ntk_hooking::HookingRpcHandler,
}
pub struct Dispatcher {
neighborhood: ntk_neighborhood::NeighborhoodRpcHandler,
identity: ntk_identities::IdentityRpcHandler,
identity_stack: RwLock<Arc<IdentityStack>>,
}
impl Dispatcher {
#[must_use]
pub fn new(
neighborhood: ntk_neighborhood::NeighborhoodRpcHandler,
identity: ntk_identities::IdentityRpcHandler,
stack: IdentityStack,
) -> Self {
Self {
neighborhood,
identity,
identity_stack: RwLock::new(Arc::new(stack)),
}
}
pub async fn replace_identity_stack(&self, stack: IdentityStack) {
*self.identity_stack.write().await = Arc::new(stack);
}
}
impl std::fmt::Debug for Dispatcher {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Dispatcher").finish_non_exhaustive()
}
}
fn misrouted() -> RemoteError {
RemoteError {
domain: ntk_proto::v1::ErrorDomain::Deserialize as i32,
message: "MethodCall with no oneof arm set".to_owned(),
}
}
impl RpcHandler for Dispatcher {
fn handle<'a>(
&'a self,
caller: CallerContext,
unicast_id: TypedValue,
call: MethodCall,
auth: Option<Auth>,
) -> BoxFuture<'a, Result<ResponsePayload, RemoteError>> {
Box::pin(async move {
let Some(arm) = &call.call else {
return Err(misrouted());
};
match arm {
Call::NeighborhoodHereIAm(_)
| Call::NeighborhoodRequestArc(_)
| Call::NeighborhoodCanYouExport(_)
| Call::NeighborhoodRemoveArc(_)
| Call::NeighborhoodNop(_) => {
self.neighborhood
.handle(caller, unicast_id, call, auth)
.await
}
Call::IdentityMatchDuplication(_)
| Call::IdentityGetPeerMainId(_)
| Call::IdentityNotifyIdentityArcRemoved(_) => {
self.identity.handle(caller, unicast_id, call, auth).await
}
Call::QspnGetFullEtp(_)
| Call::QspnSendEtp(_)
| Call::QspnGotPrepareDestroy(_)
| Call::QspnGotDestroy(_) => {
let stack = self.identity_stack.read().await.clone();
stack.qspn.handle(caller, unicast_id, call, auth).await
}
Call::PeersForwardPeerMessage(_)
| Call::PeersGetRequest(_)
| Call::PeersSetResponse(_)
| Call::PeersSetRefuseMessage(_)
| Call::PeersSetRedoFromStart(_)
| Call::PeersSetNextDestination(_)
| Call::PeersSetFailure(_)
| Call::PeersSetNonParticipant(_)
| Call::PeersSetMissingOptionalMaps(_)
| Call::PeersSetParticipant(_)
| Call::PeersGiveParticipantMaps(_)
| Call::PeersAskParticipantMaps(_) => {
let stack = self.identity_stack.read().await.clone();
stack.peers.handle(caller, unicast_id, call, auth).await
}
Call::CoordinatorExecutePrepareMigration(_)
| Call::CoordinatorExecuteFinishMigration(_)
| Call::CoordinatorExecutePrepareEnter(_)
| Call::CoordinatorExecuteFinishEnter(_)
| Call::CoordinatorExecuteWeHaveSplitted(_) => {
let stack = self.identity_stack.read().await.clone();
stack
.coordinator
.handle(caller, unicast_id, call, auth)
.await
}
Call::HookingRetrieveNetworkData(_)
| Call::HookingSearchMigrationPath(_)
| Call::HookingRouteSearchRequest(_)
| Call::HookingRouteSearchError(_)
| Call::HookingRouteSearchResponse(_)
| Call::HookingRouteExploreRequest(_)
| Call::HookingRouteExploreResponse(_)
| Call::HookingRouteDeleteReserveRequest(_)
| Call::HookingRouteMigRequest(_)
| Call::HookingRouteMigResponse(_) => {
let stack = self.identity_stack.read().await.clone();
stack.hooking.handle(caller, unicast_id, call, auth).await
}
}
})
}
}