JMAP eventsource WIP

Manos Pitsidianakis 2020-04-03 08:27:00 +03:00
parent c5a99a9cf9
commit 2a001ee2ef
Signed by: Manos Pitsidianakis
GPG Key ID: 73627C2F690DF710
2 changed files with 66 additions and 11 deletions

View File

@ -28,6 +28,7 @@ use crate::email::*;
use crate::error::{MeliError, Result};
use fnv::FnvHashMap;
use reqwest::blocking::Client;
use reqwest::Url;
use std::collections::BTreeMap;
use std::str::FromStr;
use std::sync::{Arc, Mutex, RwLock};
@ -75,6 +76,7 @@ pub mod mailbox;
use mailbox::*;
pub mod eventsource;
use eventsource::client::EventSourceClient;
#[derive(Debug, Default)]
pub struct EnvelopeCache {
@ -236,9 +238,39 @@ impl MailBackend for JmapType {
fn watch(
&self,
_sender: RefreshEventConsumer,
_work_context: WorkContext,
work_context: WorkContext,
) -> Result<std::thread::ThreadId> {
Err(MeliError::from("JMAP watch for updates is unimplemented"))
let connection = JmapConnection::new(&self.server_conf, self.online.clone())?;
let handle = std::thread::Builder::new()
.name(format!("{} jmap connection", self.account_name.as_str(),))
.spawn(move || {
let thread = std::thread::current();
work_context
.set_status
.send((thread.id(), "watching".to_string()))
.unwrap();
let event_source_url = connection.session.event_source_url.clone();
debug!(&event_source_url);
let client = EventSourceClient::new(
Url::parse(&event_source_url).unwrap(),
vec![
(
"types".to_string(),
"Email,EmailDelivery,Mailbox".to_string(),
),
("closeafter".to_string(), "no".to_string()),
("ping".to_string(), "1".to_string()),
],
connection,
);
for event in client {
debug!(&event);
println!("{}", event.unwrap());
}
})?;
Ok(handle.thread().id())
}
fn mailboxes(&self) -> Result<FnvHashMap<MailboxHash, Mailbox>> {

View File

@ -23,6 +23,7 @@
//! # Reqwest-based EventSource client
use super::event::{parse_event_line, Event, ParseResult};
use crate::backends::jmap::JmapConnection;
use crate::error::*;
use reqwest;
use reqwest::header::{HeaderMap, HeaderValue, ACCEPT, CONTENT_TYPE};
@ -56,10 +57,11 @@ impl MeliError {
/// A client for a Server-Sent Events endpoint.
///
/// Read events by iterating over the client.
pub struct Client {
client: reqwest::blocking::Client,
pub struct EventSourceClient {
connection: JmapConnection,
response: Option<BufReader<reqwest::blocking::Response>>,
url: reqwest::Url,
query: Vec<(String, String)>,
last_event_id: Option<String>,
last_try: Option<Instant>,
@ -68,15 +70,23 @@ pub struct Client {
pub retry: Duration,
}
impl Client {
impl EventSourceClient {
/// Constructs a new EventSource client for the given URL.
///
/// This does not start an HTTP request.
pub fn new(url: reqwest::Url) -> Client {
Client {
client: reqwest::blocking::Client::new(),
pub fn new(
url: reqwest::Url,
query: Vec<(String, String)>,
connection: JmapConnection,
) -> EventSourceClient {
debug!("&url = {:#?}", &url);
debug!("&connection.session = {:#?}", &connection.session);
debug!("&connection.server_conf = {:#?}", &connection.server_conf);
EventSourceClient {
connection,
response: None,
url: url,
url,
query,
last_event_id: None,
last_try: None,
retry: Duration::from_millis(DEFAULT_RETRY),
@ -90,7 +100,20 @@ impl Client {
headers.insert("Last-Event-ID", HeaderValue::from_str(id).unwrap());
}
let res = self.client.get(self.url.clone()).headers(headers).send()?;
let res = debug!(self
.connection
.client
.lock()
.unwrap()
.get(self.url.clone())
.basic_auth(
&self.connection.server_conf.server_username,
Some(&self.connection.server_conf.server_password),
)
.query(&self.query)
.headers(headers))
.send()?;
debug!(&res);
// Check status code and Content-Type.
{
@ -128,7 +151,7 @@ macro_rules! try_option {
/// Iterate over the client to get events.
///
/// HTTP requests are made transparently while iterating.
impl Iterator for Client {
impl Iterator for EventSourceClient {
type Item = Result<Event>;
fn next(&mut self) -> Option<Result<Event>> {