mirror of
https://github.com/chatmail/core.git
synced 2026-10-02 11:10:25 +03:00
[might revert] Don't attempt multiple connections at once for now
This commit is contained in:
+27
-94
@@ -6,27 +6,19 @@
|
||||
//! which migrations seed with a list of known chatmail relays.
|
||||
//!
|
||||
//! Status of implementation:
|
||||
//!
|
||||
//! - When the UI uses `init_transports()`, we attempt to add 3 relays.
|
||||
//!
|
||||
//! - Later additions are attempted right before going into IMAP IDLE,
|
||||
//! i.e. only while connected and with nothing more important to do,
|
||||
//! and only if a UI opted in via [`Config::Autorelay`].
|
||||
//! Once a profile has reached `NUM_TRANSPORTS_TARGET` transports,
|
||||
//! [`Config::AutorelayFinished`] is set and nothing is ever added again,
|
||||
//! so deleting a transport later does not pull in a replacement.
|
||||
//! Additions are attempted right before going into IMAP IDLE,
|
||||
//! i.e. only while connected and with nothing more important to do,
|
||||
//! and only if a UI opted in via [`Config::Autorelay`].
|
||||
//! Once a profile has reached `NUM_TRANSPORTS_TARGET` transports,
|
||||
//! [`Config::AutorelayFinished`] is set and nothing is ever added again,
|
||||
//! so deleting a transport later does not pull in a replacement.
|
||||
|
||||
use std::collections::BTreeSet;
|
||||
use std::pin::Pin;
|
||||
use std::sync::Arc;
|
||||
|
||||
use anyhow::{Result, bail};
|
||||
use deltachat_contact_tools::{EmailAddress, addr_normalize};
|
||||
use anyhow::Result;
|
||||
use deltachat_contact_tools::addr_normalize;
|
||||
use rand::distr::{Alphanumeric, SampleString};
|
||||
use rand::rng;
|
||||
use rand::seq::{IndexedRandom, SliceRandom as _};
|
||||
use tokio::sync::Mutex;
|
||||
use tokio::task::JoinSet;
|
||||
use rand::seq::IndexedRandom;
|
||||
|
||||
use crate::config::{self, Config};
|
||||
use crate::log::{LogExt, warn};
|
||||
@@ -64,85 +56,26 @@ pub(crate) async fn init_transports_inner(
|
||||
addrs_from_qr: Vec<String>,
|
||||
skip_network: bool,
|
||||
) -> Result<()> {
|
||||
// If relays were provided via the addresses in the QR code,
|
||||
// then these relays are tried first.
|
||||
let (relays_sender, relays_receiver) = async_channel::unbounded::<String>();
|
||||
let relays_from_qr: BTreeSet<String> = addrs_from_qr
|
||||
.into_iter()
|
||||
.filter_map(|addr| EmailAddress::new(&addr).ok())
|
||||
.map(|email| email.domain)
|
||||
.collect();
|
||||
for relay in &relays_from_qr {
|
||||
relays_sender.try_send(relay.to_string())?;
|
||||
}
|
||||
|
||||
// After the relays from the QR code,
|
||||
// the default relays are tried in a random order.
|
||||
let mut default_relays: Vec<&str> = DEFAULT_RELAY_CANDIDATES.into();
|
||||
default_relays.shuffle(&mut rng());
|
||||
for relay in default_relays {
|
||||
if !relays_from_qr.contains(relay) {
|
||||
relays_sender.try_send(relay.to_string())?;
|
||||
}
|
||||
}
|
||||
|
||||
let last_error: Arc<Mutex<String>> = Default::default();
|
||||
|
||||
// Spawn NUM_TRANSPORTS_TARGET tasks that each add a relay concurrently.
|
||||
let mut join_set = JoinSet::new();
|
||||
for _ in 0..NUM_TRANSPORTS_TARGET {
|
||||
let context = context.clone();
|
||||
let relays_receiver = relays_receiver.clone();
|
||||
let last_error = last_error.clone();
|
||||
join_set.spawn(async move {
|
||||
// Take a lock in order to prevent other relay management code
|
||||
// from running simultaneously
|
||||
let _lock = context.background_task_lock.read().await;
|
||||
// TODO add a back-channel here,
|
||||
// and then the surrounding function has to wait until all tasks took the lock
|
||||
|
||||
loop {
|
||||
let Ok(host) = relays_receiver.try_recv() else {
|
||||
return false; // No more relays to try
|
||||
};
|
||||
let param = login_param_from_host(&host);
|
||||
let res = crate::configure::configure(&context, ¶m, skip_network).await;
|
||||
if let Err(err) = res {
|
||||
warn!(context, "Failed to init transport {host}: {err:#}.");
|
||||
*last_error.lock().await = format!("{err:#}");
|
||||
// Try another relay in the next iteration of the loop
|
||||
} else {
|
||||
info!(context, "Initialized with transport {host}");
|
||||
if context.count_transports().await.unwrap_or(0) >= NUM_TRANSPORTS_TARGET {
|
||||
context
|
||||
.set_config_bool(Config::AutorelayFinished, true)
|
||||
.await
|
||||
.log_err(&context)
|
||||
.ok();
|
||||
info!(context, "Target number of transports reached.");
|
||||
context.restart_io_if_running().await;
|
||||
}
|
||||
return true; // Success
|
||||
}
|
||||
context
|
||||
.sql
|
||||
.transaction(|transaction| {
|
||||
let mut stmt = transaction.prepare("INSERT INTO relay_candidates(host) VALUES(?)")?;
|
||||
for addr in addrs_from_qr {
|
||||
stmt.execute((addr,))?;
|
||||
}
|
||||
});
|
||||
}
|
||||
Ok(())
|
||||
})
|
||||
.await?;
|
||||
|
||||
loop {
|
||||
match join_set.join_next().await {
|
||||
Some(Ok(true)) => break, // Success
|
||||
Some(Ok(false)) => {} // Wait until one of the other tasks is successful
|
||||
Some(Err(e)) => warn!(context, "One of the init_transports tasks failed: {e:#}"),
|
||||
None => bail!(
|
||||
"Could not configure any relay, are you offline? ({})",
|
||||
last_error.try_lock()?
|
||||
),
|
||||
}
|
||||
let host = "nine.testrun.org";
|
||||
let param = login_param_from_host(host);
|
||||
let res = crate::configure::configure(context, ¶m, skip_network).await;
|
||||
if let Err(err) = &res {
|
||||
warn!(context, "Failed to init transports: {err:#}.");
|
||||
} else {
|
||||
info!(context, "Initialized with transport {host}");
|
||||
}
|
||||
|
||||
// Let the other tasks continue running in the background
|
||||
// while the user can already use Delta Chat:
|
||||
join_set.detach_all();
|
||||
res?;
|
||||
|
||||
context.set_config_bool(Config::Autorelay, true).await?;
|
||||
|
||||
@@ -174,7 +107,7 @@ pub(crate) fn maybe_add_additional_relays(
|
||||
async fn maybe_add_additional_relays_inner(context: &Context, skip_network: bool) -> Result<bool> {
|
||||
let now = time();
|
||||
|
||||
let Ok(_lock) = context.background_task_lock.try_write() else {
|
||||
let Ok(_lock) = context.background_task_mutex.try_lock() else {
|
||||
// Housekeeping or automatic relay management is already running in another thread, do nothing.
|
||||
return Ok(false);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user