mirror of
https://github.com/chatmail/core.git
synced 2026-04-27 10:26:29 +03:00
back to stable async-std + use surf instead of reqwest
removes tokio from our dependency tree, now only one async executor
This commit is contained in:
@@ -94,12 +94,12 @@ fn parse_xml(in_emailaddr: &str, xml_raw: &str) -> Result<LoginParam, Error> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn moz_autoconfigure(
|
||||
pub async fn moz_autoconfigure(
|
||||
context: &Context,
|
||||
url: &str,
|
||||
param_in: &LoginParam,
|
||||
) -> Result<LoginParam, Error> {
|
||||
let xml_raw = read_url(context, url)?;
|
||||
let xml_raw = read_url(context, url).await?;
|
||||
|
||||
let res = parse_xml(¶m_in.addr, &xml_raw);
|
||||
if let Err(err) = &res {
|
||||
|
||||
@@ -112,7 +112,7 @@ fn parse_xml(xml_raw: &str) -> Result<ParsingResult, Error> {
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
pub fn outlk_autodiscover(
|
||||
pub async fn outlk_autodiscover(
|
||||
context: &Context,
|
||||
url: &str,
|
||||
_param_in: &LoginParam,
|
||||
@@ -120,7 +120,7 @@ pub fn outlk_autodiscover(
|
||||
let mut url = url.to_string();
|
||||
/* Follow up to 10 xml-redirects (http-redirects are followed in read_url() */
|
||||
for _i in 0..10 {
|
||||
let xml_raw = read_url(context, &url)?;
|
||||
let xml_raw = read_url(context, &url).await?;
|
||||
let res = parse_xml(&xml_raw);
|
||||
if let Err(err) = &res {
|
||||
warn!(context, "{}", err);
|
||||
|
||||
@@ -248,7 +248,7 @@ async fn exec_step(
|
||||
"https://autoconfig.{}/mail/config-v1.1.xml?emailaddress={}",
|
||||
param_domain, param_addr_urlencoded
|
||||
);
|
||||
*param_autoconfig = moz_autoconfigure(ctx, &url, ¶m).ok();
|
||||
*param_autoconfig = moz_autoconfigure(ctx, &url, ¶m).await.ok();
|
||||
}
|
||||
}
|
||||
6 => {
|
||||
@@ -259,7 +259,7 @@ async fn exec_step(
|
||||
"https://{}/.well-known/autoconfig/mail/config-v1.1.xml?emailaddress={}",
|
||||
param_domain, param_addr_urlencoded
|
||||
);
|
||||
*param_autoconfig = moz_autoconfigure(ctx, &url, ¶m).ok();
|
||||
*param_autoconfig = moz_autoconfigure(ctx, &url, ¶m).await.ok();
|
||||
}
|
||||
}
|
||||
/* Outlook section start ------------- */
|
||||
@@ -268,7 +268,7 @@ async fn exec_step(
|
||||
progress!(ctx, 310);
|
||||
if param_autoconfig.is_none() {
|
||||
let url = format!("https://{}/autodiscover/autodiscover.xml", param_domain);
|
||||
*param_autoconfig = outlk_autodiscover(ctx, &url, ¶m).ok();
|
||||
*param_autoconfig = outlk_autodiscover(ctx, &url, ¶m).await.ok();
|
||||
}
|
||||
}
|
||||
8 => {
|
||||
@@ -278,7 +278,7 @@ async fn exec_step(
|
||||
"https://{}{}/autodiscover/autodiscover.xml",
|
||||
"autodiscover.", param_domain
|
||||
);
|
||||
*param_autoconfig = outlk_autodiscover(ctx, &url, ¶m).ok();
|
||||
*param_autoconfig = outlk_autodiscover(ctx, &url, ¶m).await.ok();
|
||||
}
|
||||
}
|
||||
/* ----------- Outlook section end */
|
||||
@@ -289,7 +289,7 @@ async fn exec_step(
|
||||
"http://autoconfig.{}/mail/config-v1.1.xml?emailaddress={}",
|
||||
param_domain, param_addr_urlencoded
|
||||
);
|
||||
*param_autoconfig = moz_autoconfigure(ctx, &url, ¶m).ok();
|
||||
*param_autoconfig = moz_autoconfigure(ctx, &url, ¶m).await.ok();
|
||||
}
|
||||
}
|
||||
10 => {
|
||||
@@ -300,7 +300,7 @@ async fn exec_step(
|
||||
"http://{}/.well-known/autoconfig/mail/config-v1.1.xml",
|
||||
param_domain
|
||||
);
|
||||
*param_autoconfig = moz_autoconfigure(ctx, &url, ¶m).ok();
|
||||
*param_autoconfig = moz_autoconfigure(ctx, &url, ¶m).await.ok();
|
||||
}
|
||||
}
|
||||
/* B. If we have no configuration yet, search configuration in Thunderbird's centeral database */
|
||||
@@ -309,7 +309,7 @@ async fn exec_step(
|
||||
if param_autoconfig.is_none() {
|
||||
/* always SSL for Thunderbird's database */
|
||||
let url = format!("https://autoconfig.thunderbird.net/v1.1/{}", param_domain);
|
||||
*param_autoconfig = moz_autoconfigure(ctx, &url, ¶m).ok();
|
||||
*param_autoconfig = moz_autoconfigure(ctx, &url, ¶m).await.ok();
|
||||
}
|
||||
}
|
||||
/* C. Do we have any autoconfig result?
|
||||
|
||||
@@ -3,17 +3,13 @@ use crate::context::Context;
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
pub enum Error {
|
||||
#[error("URL request error")]
|
||||
GetError(#[from] reqwest::Error),
|
||||
GetError(surf::Error),
|
||||
}
|
||||
|
||||
pub fn read_url(context: &Context, url: &str) -> Result<String, Error> {
|
||||
pub async fn read_url(context: &Context, url: &str) -> Result<String, Error> {
|
||||
info!(context, "Requesting URL {}", url);
|
||||
|
||||
match reqwest::blocking::Client::new()
|
||||
.get(url)
|
||||
.send()
|
||||
.and_then(|res| res.text())
|
||||
{
|
||||
match surf::get(url).recv_string().await {
|
||||
Ok(res) => Ok(res),
|
||||
Err(err) => {
|
||||
info!(context, "Can\'t read URL {}", url);
|
||||
|
||||
@@ -161,10 +161,7 @@ pub async fn dc_get_oauth2_access_token(
|
||||
}
|
||||
|
||||
// ... and POST
|
||||
let response = reqwest::blocking::Client::new()
|
||||
.post(post_url)
|
||||
.form(&post_param)
|
||||
.send();
|
||||
let response = surf::post(post_url).body_form(&post_param);
|
||||
if response.is_err() {
|
||||
warn!(
|
||||
context,
|
||||
@@ -172,19 +169,8 @@ pub async fn dc_get_oauth2_access_token(
|
||||
);
|
||||
return None;
|
||||
}
|
||||
let response = response.unwrap();
|
||||
if !response.status().is_success() {
|
||||
warn!(
|
||||
context,
|
||||
"Unsuccessful response when calling OAuth2 at {}: {:?}",
|
||||
token_url,
|
||||
response.status()
|
||||
);
|
||||
return None;
|
||||
}
|
||||
|
||||
// generate new token: parse returned json
|
||||
let parsed: reqwest::Result<Response> = response.json();
|
||||
let parsed: Result<Response, _> = response.unwrap().recv_json().await;
|
||||
if parsed.is_err() {
|
||||
warn!(
|
||||
context,
|
||||
@@ -192,7 +178,6 @@ pub async fn dc_get_oauth2_access_token(
|
||||
);
|
||||
return None;
|
||||
}
|
||||
println!("response: {:?}", &parsed);
|
||||
|
||||
// update refresh_token if given, typically on the first round, but we update it later as well.
|
||||
let response = parsed.unwrap();
|
||||
@@ -260,12 +245,12 @@ pub async fn dc_get_oauth2_addr(
|
||||
if let Some(access_token) =
|
||||
dc_get_oauth2_access_token(context, addr.as_ref(), code.as_ref(), false).await
|
||||
{
|
||||
let addr_out = oauth2.get_addr(context, access_token);
|
||||
let addr_out = oauth2.get_addr(context, access_token).await;
|
||||
if addr_out.is_none() {
|
||||
// regenerate
|
||||
if let Some(access_token) = dc_get_oauth2_access_token(context, addr, code, true).await
|
||||
{
|
||||
oauth2.get_addr(context, access_token)
|
||||
oauth2.get_addr(context, access_token).await
|
||||
} else {
|
||||
None
|
||||
}
|
||||
@@ -295,7 +280,7 @@ impl Oauth2 {
|
||||
}
|
||||
}
|
||||
|
||||
fn get_addr(&self, context: &Context, access_token: impl AsRef<str>) -> Option<String> {
|
||||
async fn get_addr(&self, context: &Context, access_token: impl AsRef<str>) -> Option<String> {
|
||||
let userinfo_url = self.get_userinfo.unwrap_or_else(|| "");
|
||||
let userinfo_url = replace_in_uri(&userinfo_url, "$ACCESS_TOKEN", access_token);
|
||||
|
||||
@@ -306,41 +291,25 @@ impl Oauth2 {
|
||||
// "verified_email": true,
|
||||
// "picture": "https://lh4.googleusercontent.com/-Gj5jh_9R0BY/AAAAAAAAAAI/AAAAAAAAAAA/IAjtjfjtjNA/photo.jpg"
|
||||
// }
|
||||
let response = reqwest::blocking::Client::new().get(&userinfo_url).send();
|
||||
let response: Result<HashMap<String, serde_json::Value>, surf::Error> =
|
||||
surf::get(userinfo_url).recv_json().await;
|
||||
if response.is_err() {
|
||||
warn!(context, "Error getting userinfo: {:?}", response);
|
||||
return None;
|
||||
}
|
||||
let response = response.unwrap();
|
||||
if !response.status().is_success() {
|
||||
warn!(context, "Error getting userinfo: {:?}", response.status());
|
||||
return None;
|
||||
}
|
||||
|
||||
let parsed: reqwest::Result<HashMap<String, serde_json::Value>> = response.json();
|
||||
if parsed.is_err() {
|
||||
warn!(
|
||||
context,
|
||||
"Failed to parse userinfo JSON response: {:?}", parsed
|
||||
);
|
||||
return None;
|
||||
}
|
||||
if let Ok(response) = parsed {
|
||||
// CAVE: serde_json::Value.as_str() removes the quotes of json-strings
|
||||
// but serde_json::Value.to_string() does not!
|
||||
if let Some(addr) = response.get("email") {
|
||||
if let Some(s) = addr.as_str() {
|
||||
Some(s.to_string())
|
||||
} else {
|
||||
warn!(context, "E-mail in userinfo is not a string: {}", addr);
|
||||
None
|
||||
}
|
||||
let parsed = response.unwrap();
|
||||
// CAVE: serde_json::Value.as_str() removes the quotes of json-strings
|
||||
// but serde_json::Value.to_string() does not!
|
||||
if let Some(addr) = parsed.get("email") {
|
||||
if let Some(s) = addr.as_str() {
|
||||
Some(s.to_string())
|
||||
} else {
|
||||
warn!(context, "E-mail missing in userinfo.");
|
||||
warn!(context, "E-mail in userinfo is not a string: {}", addr);
|
||||
None
|
||||
}
|
||||
} else {
|
||||
warn!(context, "Failed to parse userinfo.");
|
||||
warn!(context, "E-mail missing in userinfo.");
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
22
src/qr.rs
22
src/qr.rs
@@ -2,7 +2,6 @@
|
||||
|
||||
use lazy_static::lazy_static;
|
||||
use percent_encoding::percent_decode_str;
|
||||
use reqwest::Url;
|
||||
use serde::Deserialize;
|
||||
|
||||
use crate::chat;
|
||||
@@ -193,7 +192,7 @@ fn decode_account(_context: &Context, qr: &str) -> Lot {
|
||||
|
||||
let mut lot = Lot::new();
|
||||
|
||||
if let Ok(url) = Url::parse(payload) {
|
||||
if let Ok(url) = url::Url::parse(payload) {
|
||||
if url.scheme() == "https" {
|
||||
lot.state = LotState::QrAccount;
|
||||
lot.text1 = url.host_str().map(|x| x.to_string());
|
||||
@@ -221,25 +220,12 @@ struct CreateAccountResponse {
|
||||
pub async fn set_config_from_qr(context: &Context, qr: &str) -> Result<(), Error> {
|
||||
let url_str = &qr[DCACCOUNT_SCHEME.len()..];
|
||||
|
||||
let response = reqwest::blocking::Client::new().post(url_str).send();
|
||||
let response: Result<CreateAccountResponse, surf::Error> =
|
||||
surf::post(url_str).recv_json().await;
|
||||
if response.is_err() {
|
||||
bail!("Cannot create account, request to {} failed", url_str);
|
||||
}
|
||||
let response = response.unwrap();
|
||||
if !response.status().is_success() {
|
||||
bail!("Request to {} unsuccessful: {:?}", url_str, response);
|
||||
}
|
||||
|
||||
let parsed: reqwest::Result<CreateAccountResponse> = response.json();
|
||||
if parsed.is_err() {
|
||||
bail!(
|
||||
"Failed to parse JSON response from {}: error: {:?}",
|
||||
url_str,
|
||||
parsed
|
||||
);
|
||||
}
|
||||
println!("response: {:?}", &parsed);
|
||||
let parsed = parsed.unwrap();
|
||||
let parsed = response.unwrap();
|
||||
|
||||
context
|
||||
.set_config(Config::Addr, Some(&parsed.email))
|
||||
|
||||
@@ -341,12 +341,10 @@ impl Scheduler {
|
||||
// wait for all loops to be started
|
||||
inbox_start_recv
|
||||
.recv()
|
||||
.try_join(mvbox_start_recv.recv())
|
||||
.try_join(sentbox_start_recv.recv())
|
||||
.try_join(smtp_start_recv.recv())
|
||||
.await
|
||||
.map(|_| ())
|
||||
.unwrap_or_else(|err| error!(ctx, "failed to start scheduler: {}", err));
|
||||
.join(mvbox_start_recv.recv())
|
||||
.join(sentbox_start_recv.recv())
|
||||
.join(smtp_start_recv.recv())
|
||||
.await;
|
||||
|
||||
info!(ctx, "scheduler is running");
|
||||
}
|
||||
@@ -384,36 +382,28 @@ impl Scheduler {
|
||||
|
||||
async fn interrupt_inbox(&self) {
|
||||
match self {
|
||||
Scheduler::Running { ref inbox, .. } => {
|
||||
inbox.interrupt().await.ok();
|
||||
}
|
||||
Scheduler::Running { ref inbox, .. } => inbox.interrupt().await,
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
async fn interrupt_mvbox(&self) {
|
||||
match self {
|
||||
Scheduler::Running { ref mvbox, .. } => {
|
||||
mvbox.interrupt().await.ok();
|
||||
}
|
||||
Scheduler::Running { ref mvbox, .. } => mvbox.interrupt().await,
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
async fn interrupt_sentbox(&self) {
|
||||
match self {
|
||||
Scheduler::Running { ref sentbox, .. } => {
|
||||
sentbox.interrupt().await.ok();
|
||||
}
|
||||
Scheduler::Running { ref sentbox, .. } => sentbox.interrupt().await,
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
async fn interrupt_smtp(&self) {
|
||||
match self {
|
||||
Scheduler::Running { ref smtp, .. } => {
|
||||
smtp.interrupt().await.ok();
|
||||
}
|
||||
Scheduler::Running { ref smtp, .. } => smtp.interrupt().await,
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
@@ -492,12 +482,14 @@ impl ConnectionState {
|
||||
// Trigger shutdown of the run loop.
|
||||
self.stop_sender.send(()).await;
|
||||
// Wait for a notification that the run loop has been shutdown.
|
||||
self.shutdown_receiver.recv().await.ok();
|
||||
self.shutdown_receiver.recv().await;
|
||||
}
|
||||
|
||||
async fn interrupt(&self) -> Result<(), async_std::sync::TrySendError<()>> {
|
||||
// Use try_send to avoid blocking on interrupts.
|
||||
self.idle_interrupt_sender.try_send(())
|
||||
async fn interrupt(&self) {
|
||||
if !self.idle_interrupt_sender.is_full() {
|
||||
// Use try_send to avoid blocking on interrupts.
|
||||
self.idle_interrupt_sender.send(()).await;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -531,8 +523,8 @@ impl SmtpConnectionState {
|
||||
}
|
||||
|
||||
/// Interrupt any form of idle.
|
||||
async fn interrupt(&self) -> Result<(), async_std::sync::TrySendError<()>> {
|
||||
self.state.interrupt().await
|
||||
async fn interrupt(&self) {
|
||||
self.state.interrupt().await;
|
||||
}
|
||||
|
||||
/// Shutdown this connection completely.
|
||||
@@ -579,8 +571,8 @@ impl ImapConnectionState {
|
||||
}
|
||||
|
||||
/// Interrupt any form of idle.
|
||||
async fn interrupt(&self) -> Result<(), async_std::sync::TrySendError<()>> {
|
||||
self.state.interrupt().await
|
||||
async fn interrupt(&self) {
|
||||
self.state.interrupt().await;
|
||||
}
|
||||
|
||||
/// Shutdown this connection completely.
|
||||
|
||||
Reference in New Issue
Block a user