mirror of
https://github.com/chatmail/core.git
synced 2026-10-02 11:10:25 +03:00
feat: try fasted relays to attempt first configure on
This commit is contained in:
@@ -546,7 +546,7 @@ impl CommandApi {
|
|||||||
ctx.add_transport_from_qr(&qr).await
|
ctx.add_transport_from_qr(&qr).await
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Adds an initial transport on a randomly chosen chatmail relay
|
/// Adds an initial transport on the chatmail relay that answers fastest
|
||||||
/// and lets the profile add further ones in the background.
|
/// and lets the profile add further ones in the background.
|
||||||
///
|
///
|
||||||
/// A `DCACCOUNT:` or `DCLOGIN:` `qr` code adds a single transport
|
/// A `DCACCOUNT:` or `DCLOGIN:` `qr` code adds a single transport
|
||||||
|
|||||||
@@ -141,7 +141,7 @@ class Account:
|
|||||||
|
|
||||||
@futuremethod
|
@futuremethod
|
||||||
def init_transports(self, qr: Optional[str] = None):
|
def init_transports(self, qr: Optional[str] = None):
|
||||||
"""Add an initial transport on a randomly chosen chatmail relay.
|
"""Add an initial transport on the chatmail relay that answers fastest.
|
||||||
|
|
||||||
The profile then adds further ones in the background.
|
The profile then adds further ones in the background.
|
||||||
A ``DCACCOUNT:`` or ``DCLOGIN:`` ``qr`` code adds a single transport
|
A ``DCACCOUNT:`` or ``DCLOGIN:`` ``qr`` code adds a single transport
|
||||||
|
|||||||
+29
-5
@@ -11,11 +11,13 @@ use deltachat_contact_tools::addr_normalize;
|
|||||||
use rand::distr::{Alphanumeric, SampleString};
|
use rand::distr::{Alphanumeric, SampleString};
|
||||||
use rand::seq::{IndexedRandom, SliceRandom};
|
use rand::seq::{IndexedRandom, SliceRandom};
|
||||||
use rusqlite::Transaction;
|
use rusqlite::Transaction;
|
||||||
|
use tokio::task::JoinSet;
|
||||||
|
|
||||||
use crate::config::{self, Config};
|
use crate::config::{self, Config};
|
||||||
use crate::configure::{EnteredLoginParam, configure};
|
use crate::configure::{EnteredLoginParam, configure};
|
||||||
use crate::log::{LogExt, warn};
|
use crate::log::{LogExt, warn};
|
||||||
use crate::login_param::{EnteredCertificateChecks, EnteredImapLoginParam};
|
use crate::login_param::{EnteredCertificateChecks, EnteredImapLoginParam};
|
||||||
|
use crate::net::{connect_tcp, proxy::ProxyConfig};
|
||||||
use crate::{context::Context, tools::time};
|
use crate::{context::Context, tools::time};
|
||||||
|
|
||||||
/// The target number of transports.
|
/// The target number of transports.
|
||||||
@@ -57,19 +59,41 @@ pub(crate) async fn add_relay_candidates(context: &Context, addrs: &[String]) ->
|
|||||||
/// All candidates are probed at once with a TCP connection to their HTTPS port
|
/// All candidates are probed at once with a TCP connection to their HTTPS port
|
||||||
/// and configured in the order in which the connections complete,
|
/// and configured in the order in which the connections complete,
|
||||||
/// stopping at the first success. Candidates that fail the probe are skipped.
|
/// stopping at the first success. Candidates that fail the probe are skipped.
|
||||||
|
/// Answering TCP fastest is used as a network proximity measure,
|
||||||
|
/// which keeps latency low for initial onboarding,
|
||||||
|
/// and it avoids relays that are down or black-holing traffic.
|
||||||
pub(crate) async fn add_transport_from_candidates(
|
pub(crate) async fn add_transport_from_candidates(
|
||||||
context: &Context,
|
context: &Context,
|
||||||
skip_network: bool,
|
skip_network: bool,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let mut candidates = triable_relay_candidates(context, time()).await?;
|
let mut candidates = triable_relay_candidates(context, time()).await?;
|
||||||
candidates.shuffle(&mut rand::rng());
|
candidates.shuffle(&mut rand::rng());
|
||||||
let mut last_err = format_err!("No relay candidates");
|
let mut probes = JoinSet::new();
|
||||||
|
let proxy_config = ProxyConfig::load(context).await?;
|
||||||
|
let load_cache = false;
|
||||||
|
for host in candidates {
|
||||||
|
let ctx = context.clone();
|
||||||
|
let proxy_config = proxy_config.clone();
|
||||||
|
probes.spawn(async move {
|
||||||
|
let res = match proxy_config {
|
||||||
|
_ if skip_network => Ok(()),
|
||||||
|
Some(proxy) => proxy.connect(&ctx, &host, 443, load_cache).await.map(drop),
|
||||||
|
None => connect_tcp(&ctx, &host, 443, load_cache).await.map(drop),
|
||||||
|
};
|
||||||
|
(host, res)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// We patiently try each candidate in turn which might take a while
|
let mut last_err = format_err!("No relay candidates");
|
||||||
// if many hosts are unreachable but eventually succeeds if one candidate works.
|
|
||||||
let mark_as_autorelay = true;
|
let mark_as_autorelay = true;
|
||||||
for host in &candidates {
|
while let Some(res) = probes.join_next().await {
|
||||||
let param = login_param_from_host(host, mark_as_autorelay);
|
let (host, res) = res?;
|
||||||
|
if let Err(err) = res {
|
||||||
|
warn!(context, "Failed to connect to relay {host}: {err:#}.");
|
||||||
|
last_err = err;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let param = login_param_from_host(&host, mark_as_autorelay);
|
||||||
match configure(context, ¶m, skip_network).await {
|
match configure(context, ¶m, skip_network).await {
|
||||||
Ok(()) => {
|
Ok(()) => {
|
||||||
info!(context, "Added a transport on relay {host}.");
|
info!(context, "Added a transport on relay {host}.");
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ async fn test_add_transport_from_candidates_failure() -> Result<()> {
|
|||||||
mark_defaults_tried(t, time()).await?;
|
mark_defaults_tried(t, time()).await?;
|
||||||
save_relay_candidates(t, &["bad host", "worse host"], 0).await?;
|
save_relay_candidates(t, &["bad host", "worse host"], 0).await?;
|
||||||
|
|
||||||
let skip_network = false;
|
let skip_network = true;
|
||||||
let err = add_transport_from_candidates(t, skip_network)
|
let err = add_transport_from_candidates(t, skip_network)
|
||||||
.await
|
.await
|
||||||
.unwrap_err();
|
.unwrap_err();
|
||||||
|
|||||||
+1
-1
@@ -189,7 +189,7 @@ impl Context {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Adds an initial transport on a randomly chosen chatmail relay
|
/// Adds an initial transport on the chatmail relay that answers fastest
|
||||||
/// and lets the profile add further ones in the background.
|
/// and lets the profile add further ones in the background.
|
||||||
///
|
///
|
||||||
/// A `DCACCOUNT:` or `DCLOGIN:` `qr` code adds a single transport
|
/// A `DCACCOUNT:` or `DCLOGIN:` `qr` code adds a single transport
|
||||||
|
|||||||
Reference in New Issue
Block a user