mod blocks;
mod endpoint;
mod handle;
mod server_session;
mod staging;
mod state;
mod initiator;
mod messages;
mod responder;
pub mod transport;
pub use blocks::BlockHolder;
pub use endpoint::{SessionEndpoint, SessionMessageTx, session_message_channel};
pub use server_session::{
ServerSession, ServerSessionCommand, ServerSessionHandle, ServerSessionOptions,
create_server_session,
};
pub use server_session::ServerSessionCommand as EndpointSessionCommand;
pub use server_session::ServerSessionHandle as EndpointSessionHandle;
pub use handle::{SessionHandle, SessionHandleStateTx, session_handle_state_channel};
pub use state::{AttachmentState, ControlRole, SessionPhase};
pub use messages::{BlockInfo, SessionMessage, SessionStateSnapshot};
pub use initiator::InitiatorSession;
pub use responder::ResponderSession;
pub use server_session::ServerSessionOptions as ControllableSessionOptions;
#[derive(Debug, Clone)]
pub struct ControllableSessionResult {
pub session_id: super::SessionId,
pub local_g2_count: usize,
pub local_g3_count: usize,
}
pub use messages::{BlockMatch, OnboardMessage};
pub use transport::{LocalTransport, MessageTransport, VeloTransport};
use anyhow::Result;
use dashmap::DashMap;
use tokio::sync::mpsc;
pub type SessionId = uuid::Uuid;
pub type OnboardSessionTx = mpsc::Sender<OnboardMessage>;
pub async fn dispatch_onboard_message(
sessions: &DashMap<SessionId, OnboardSessionTx>,
message: OnboardMessage,
) -> Result<()> {
let session_id = message.session_id();
let sender = sessions.get(&session_id).map(|entry| entry.value().clone());
if let Some(sender) = sender {
sender
.send(message)
.await
.map_err(|e| anyhow::anyhow!("failed to send to session {session_id}: {e}"))?;
return Ok(());
}
anyhow::bail!("no session task registered for session {session_id}");
}
pub async fn dispatch_session_message(
sessions: &DashMap<SessionId, SessionMessageTx>,
message: SessionMessage,
) -> Result<()> {
let session_id = message.session_id();
let sender = sessions.get(&session_id).map(|entry| entry.value().clone());
if let Some(sender) = sender {
sender
.send(message)
.await
.map_err(|e| anyhow::anyhow!("failed to send to session {session_id}: {e}"))?;
return Ok(());
}
anyhow::bail!("no session registered for session {session_id}");
}
#[cfg(test)]
mod tests {
use super::*;
#[tokio::test]
async fn test_dispatch_onboard_message() {
let sessions: DashMap<SessionId, OnboardSessionTx> = DashMap::new();
let session_id = SessionId::new_v4();
let (tx, mut rx) = mpsc::channel(16);
sessions.insert(session_id, tx);
let msg = OnboardMessage::CloseSession {
requester: crate::InstanceId::new_v4(),
session_id,
};
dispatch_onboard_message(&sessions, msg).await.unwrap();
let received = rx.recv().await.unwrap();
assert_eq!(received.session_id(), session_id);
}
#[tokio::test]
async fn test_dispatch_session_message() {
let sessions: DashMap<SessionId, SessionMessageTx> = DashMap::new();
let session_id = SessionId::new_v4();
let (tx, mut rx) = mpsc::channel(16);
sessions.insert(session_id, tx);
let msg = SessionMessage::Close { session_id };
dispatch_session_message(&sessions, msg).await.unwrap();
let received = rx.recv().await.unwrap();
assert_eq!(received.session_id(), session_id);
}
#[tokio::test]
async fn test_dispatch_missing_onboard_session() {
let sessions: DashMap<SessionId, OnboardSessionTx> = DashMap::new();
let session_id = SessionId::new_v4();
let msg = OnboardMessage::CloseSession {
requester: crate::InstanceId::new_v4(),
session_id,
};
let result = dispatch_onboard_message(&sessions, msg).await;
assert!(result.is_err());
}
#[tokio::test]
async fn test_dispatch_missing_session_message() {
let sessions: DashMap<SessionId, SessionMessageTx> = DashMap::new();
let session_id = SessionId::new_v4();
let msg = SessionMessage::Close { session_id };
let result = dispatch_session_message(&sessions, msg).await;
assert!(result.is_err());
}
}