use crate::respond::ExchangeHandler;
use super::nego::abort;
use super::*;
pub enum BdxResponder<'a> {
Download(BdxDownloadResponder<'a>),
Upload(BdxUploadResponder<'a>),
}
impl BdxResponder<'_> {
pub fn fd(&self) -> &[u8] {
match self {
Self::Download(responder) => responder.fd(),
Self::Upload(responder) => responder.fd(),
}
}
pub async fn reject(self, status: BdxStatus) -> Result<(), Error> {
match self {
Self::Download(responder) => responder.reject(status).await,
Self::Upload(responder) => responder.reject(status).await,
}
}
}
pub trait BdxHandler {
async fn handles(&self, _responder: &BdxResponder<'_>) -> bool {
false
}
async fn handle(&self, responder: BdxResponder<'_>) -> Result<(), Error> {
responder.reject(BdxStatus::FileDesignatorUnknown).await
}
}
impl<T> BdxHandler for &T
where
T: BdxHandler,
{
async fn handles(&self, responder: &BdxResponder<'_>) -> bool {
T::handles(self, responder).await
}
async fn handle(&self, responder: BdxResponder<'_>) -> Result<(), Error> {
T::handle(self, responder).await
}
}
pub struct EmptyBdxHandler;
impl BdxHandler for EmptyBdxHandler {}
pub struct ChainedBdxHandler<H, T> {
pub handler: H,
pub next: T,
}
impl<H, T> ChainedBdxHandler<H, T> {
pub const fn new(handler: H, next: T) -> Self {
Self { handler, next }
}
}
impl<H, T> BdxHandler for ChainedBdxHandler<H, T>
where
H: BdxHandler,
T: BdxHandler,
{
async fn handles(&self, responder: &BdxResponder<'_>) -> bool {
self.handler.handles(responder).await || self.next.handles(responder).await
}
async fn handle(&self, responder: BdxResponder<'_>) -> Result<(), Error> {
if self.handler.handles(&responder).await {
self.handler.handle(responder).await
} else {
self.next.handle(responder).await
}
}
}
pub struct Bdx<T>(T);
impl<T> Bdx<T> {
pub const fn new(handler: T) -> Self {
Self(handler)
}
pub fn handler(&self) -> &T {
&self.0
}
}
impl<T: BdxHandler> ExchangeHandler for Bdx<T> {
async fn handle(&self, mut exchange: Exchange<'_>) -> Result<(), Error> {
exchange.recv_fetch().await?;
let meta = exchange.rx()?.meta();
let responder = match opcode(&meta) {
Some(OpCode::ReceiveInit) => {
BdxResponder::Download(BdxDownloadResponder::accept(exchange).await?)
}
Some(OpCode::SendInit) => {
BdxResponder::Upload(BdxUploadResponder::accept(exchange).await?)
}
_ => {
exchange.rx_done()?;
return abort(&mut exchange, BdxStatus::UnexpectedMessage).await;
}
};
if self.0.handles(&responder).await {
self.0.handle(responder).await
} else {
responder.reject(BdxStatus::FileDesignatorUnknown).await
}
}
}