use std::ffi::c_char;
use tokio::sync::oneshot;
use crate::ffi::OnStatus;
use crate::{Error, Id, NonZeroSlab, State, moq_string};
struct ServerEntry {
close: Option<oneshot::Sender<()>>,
callback: OnStatus,
addr: String,
fingerprints: Vec<String>,
}
#[derive(Default)]
pub struct Server {
task: NonZeroSlab<Option<ServerEntry>>,
request: NonZeroSlab<moq_tokio::server::Request>,
}
impl Server {
pub fn listen(&mut self, server: moq_tokio::Server, callback: OnStatus) -> Result<Id, Error> {
let addr = server.local_addr()?.to_string();
let fingerprints = server.certificates().fingerprints();
let (close, closed) = oneshot::channel();
let id = self.task.insert(Some(ServerEntry {
close: Some(close),
callback,
addr,
fingerprints,
}))?;
tokio::spawn(async move {
let res = Self::run(server, callback, closed).await;
let entry = State::lock().server.task.remove(id).flatten();
if let Some(entry) = entry {
entry.callback.call(res);
}
});
Ok(id)
}
async fn run(server: moq_tokio::Server, callback: OnStatus, mut close: oneshot::Receiver<()>) -> Result<(), Error> {
let mut listener = server.listen().await?;
let res = loop {
let request = tokio::select! {
biased;
_ = &mut close => break Ok(()),
request = listener.accept() => match request {
Some(request) => request,
None => break Ok(()),
},
};
let request = match State::lock().server.request.insert(request) {
Ok(request) => request,
Err(err) => break Err(err),
};
callback.call(request);
};
listener.close().await;
res
}
pub fn close(&mut self, server: Id) -> Result<(), Error> {
self.task
.get_mut(server)
.and_then(|entry| entry.as_mut())
.ok_or(Error::NotFound)?
.close
.take()
.ok_or(Error::NotFound)?;
Ok(())
}
fn entry(&self, server: Id) -> Result<&ServerEntry, Error> {
self.task
.get(server)
.and_then(|entry| entry.as_ref())
.ok_or(Error::NotFound)
}
pub fn addr(&self, server: Id, dst: &mut moq_string) -> Result<(), Error> {
*dst = borrow(&self.entry(server)?.addr);
Ok(())
}
pub fn fingerprints(&self, server: Id, dst: &mut [moq_string]) -> Result<usize, Error> {
let fingerprints = &self.entry(server)?.fingerprints;
for (dst, fingerprint) in dst.iter_mut().zip(fingerprints) {
*dst = borrow(fingerprint);
}
Ok(fingerprints.len())
}
fn request(&self, request: Id) -> Result<&moq_tokio::server::Request, Error> {
self.request.get(request).ok_or(Error::NotFound)
}
pub fn request_path(&self, request: Id, dst: &mut moq_string) -> Result<(), Error> {
*dst = borrow(self.request(request)?.path());
Ok(())
}
pub fn request_query(&self, request: Id, dst: &mut moq_string) -> Result<(), Error> {
*dst = match self.request(request)?.query() {
Some(query) => borrow(query),
None => moq_string {
data: std::ptr::null(),
len: 0,
},
};
Ok(())
}
pub fn request_take(&mut self, request: Id) -> Result<moq_tokio::server::Request, Error> {
self.request.remove(request).ok_or(Error::NotFound)
}
}
fn borrow(value: &str) -> moq_string {
moq_string {
data: value.as_ptr().cast::<c_char>(),
len: value.len(),
}
}