More flexible responses

This commit is contained in:
Quentin 2022-06-15 10:55:55 +02:00
parent fc5f093564
commit 2c43b7686a
Signed by: quentin
GPG Key ID: E9602264D639FF68
4 changed files with 21 additions and 115 deletions

View File

@ -1,18 +1,22 @@
use miette::{IntoDiagnostic, Result};
use boitalettres::proto::{Request, Response};
use boitalettres::proto::{Request, Response as BalResponse};
use boitalettres::server::accept::addr::{AddrIncoming, AddrStream};
use boitalettres::server::Server;
async fn handle_req(req: Request) -> Result<Response> {
use imap_codec::types::response::{Capability, Data};
use imap_codec::types::response::{Response, Data, Status, Capability};
async fn handle_req(req: Request) -> Result<BalResponse> {
tracing::debug!("Got request: {:#?}", req);
let capabilities = vec![Capability::Imap4Rev1, Capability::Idle];
let body = vec![Data::Capability(capabilities)];
let res = vec![
Response::Data(Data::Capability(capabilities)),
Response::Status(Status::ok(Some(req.tag), None, "Done").unwrap()),
];
Ok(Response::ok("Done")?.with_body(body))
Ok(res)
}
#[tokio::main]

View File

@ -1,104 +1,3 @@
use imap_codec::types::{
core::{Tag, Text},
response::{Code as ImapCode, Status as ImapStatus},
};
use imap_codec::types::response::Response as ImapResponse;
pub type Response = Vec<ImapResponse>;
use super::body::Body;
use crate::errors::{Error, Result};
#[derive(Debug)]
pub struct Response {
pub(crate) status: Status,
pub(crate) body: Option<Body>,
}
impl Response {
pub fn status(code: StatusCode, msg: &str) -> Result<Response> {
Ok(Response {
status: Status::new(code, msg)?,
body: None,
})
}
pub fn ok(msg: &str) -> Result<Response> {
Self::status(StatusCode::Ok, msg)
}
pub fn no(msg: &str) -> Result<Response> {
Self::status(StatusCode::No, msg)
}
pub fn bad(msg: &str) -> Result<Response> {
Self::status(StatusCode::Bad, msg)
}
pub fn bye(msg: &str) -> Result<Response> {
Self::status(StatusCode::Bye, msg)
}
}
impl Response {
pub fn with_extra_code(mut self, extra: ImapCode) -> Self {
self.status.extra = Some(extra);
self
}
pub fn with_body(mut self, body: impl Into<Body>) -> Self {
self.body = Some(body.into());
self
}
}
#[derive(Debug, Clone)]
pub struct Status {
pub(crate) code: StatusCode,
pub(crate) extra: Option<ImapCode>,
pub(crate) text: Text,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum StatusCode {
Ok,
No,
Bad,
PreAuth,
Bye,
}
impl Status {
fn new(code: StatusCode, msg: &str) -> Result<Status> {
Ok(Status {
code,
extra: None,
text: msg.try_into().map_err(Error::text)?,
})
}
pub(crate) fn into_imap(self, tag: Option<Tag>) -> ImapStatus {
match self.code {
StatusCode::Ok => ImapStatus::Ok {
tag,
code: self.extra,
text: self.text,
},
StatusCode::No => ImapStatus::No {
tag,
code: self.extra,
text: self.text,
},
StatusCode::Bad => ImapStatus::Bad {
tag,
code: self.extra,
text: self.text,
},
StatusCode::PreAuth => ImapStatus::PreAuth {
code: self.extra,
text: self.text,
},
StatusCode::Bye => ImapStatus::Bye {
code: self.extra,
text: self.text,
},
}
}
}

View File

@ -11,6 +11,8 @@ use super::pipeline::Connection;
use super::Imap;
use crate::proto::{Request, Response};
use imap_codec::types::response::{Response as ImapResponse, Status};
pub struct Connecting<C, F, S>
where
C: AsyncRead + AsyncWrite + Unpin,
@ -79,8 +81,7 @@ where
{
use futures::SinkExt;
let greeting = Response::ok("Hello").unwrap(); // "Hello" is a valid
// greeting
let greeting = vec![ImapResponse::Status(Status::greeting(None, "Hello").unwrap())]; // "Hello" is a valid greeting
conn.start_send_unpin((None, greeting)).unwrap();
}

View File

@ -6,6 +6,7 @@ use futures::io::{AsyncRead, AsyncWrite};
use futures::sink::Sink;
use futures::stream::Stream;
use imap_codec::types::core::Tag;
use imap_codec::types::response::Response as ImapResponse;
use crate::proto::{Request, Response};
@ -118,13 +119,14 @@ where
let write_buf = &mut self.get_mut().write_buf;
let mut writer = write_buf.writer();
let body = res.body.into_iter().flat_map(|body| body.into_data());
for data in body {
data.encode(&mut writer)?;
for elem in res {
match elem {
ImapResponse::Status(status) => status.encode(&mut writer)?,
ImapResponse::Data(data) => data.encode(&mut writer)?,
_ => (),
}
}
res.status.into_imap(tag).encode(&mut writer)?;
Ok(())
}