feat: disable background io per account, available apis in rust and jsonrpc

api: rust: add `set_disable_background_io` and `get_disable_background_io` to a `Accounts` (the account manager)

api: jsonrpc: add `set_disable_background_io` method and `Account::Configured.background_io_disabled` property

api: select account now starts and stops io for "background disabled" accounts

This is partly a port of the desktop "disable sync all" option, the other part is making it per account.
So you can define that an account should be excluded from background syncing. This can be useful for advanced users that want to control their network traffic (don't connect a specific account in the background unless it is actively selected, like when the network is monitored and you want to hide your other accounts by disabling their background syncing.)
This commit is contained in:
Simon Laux
2024-03-02 01:04:03 +01:00
parent 4e8979f7c8
commit 3ca294c434
3 changed files with 133 additions and 32 deletions

View File

@@ -210,16 +210,16 @@ impl CommandApi {
/// Get a list of all configured accounts.
async fn get_all_accounts(&self) -> Result<Vec<Account>> {
let mut accounts = Vec::new();
for id in self.accounts.read().await.get_all() {
let context_option = self.accounts.read().await.get_account(id);
if let Some(ctx) = context_option {
accounts.push(Account::from_context(&ctx, id).await?)
}
let manager = self.accounts.read().await;
for id in manager.get_all() {
accounts.push(Account::load(&manager, id).await?)
}
Ok(accounts)
}
/// Starts background tasks for all accounts.
///
/// Acounts with `disable_background_io` are not started, unless the account is the selected one
async fn start_io_for_all_accounts(&self) -> Result<()> {
self.accounts.write().await.start_io().await;
Ok(())
@@ -236,6 +236,8 @@ impl CommandApi {
/// The `AccountsBackgroundFetchDone` event is emitted at the end even in case of timeout.
/// Process all events until you get this one and you can safely return to the background
/// without forgetting to create notifications caused by timing race conditions.
///
/// Acounts with `disable_background_io` are not fetched
async fn accounts_background_fetch(&self, timeout_in_seconds: f64) -> Result<()> {
self.accounts
.write()
@@ -245,6 +247,22 @@ impl CommandApi {
Ok(())
}
/// Set disable_background_io for an account, when enabled,
/// io is stopped unless the account is selected and background fetch is also disabled for the account
///
/// This automatically stops/starts io when account is in the background
pub async fn set_disable_background_io(
&self,
account_id: u32,
disable_background_io: bool,
) -> Result<()> {
self.accounts
.write()
.await
.set_disable_background_io(account_id, disable_background_io)
.await
}
// ---------------------------------------------
// Methods that work on individual accounts
// ---------------------------------------------
@@ -265,15 +283,8 @@ impl CommandApi {
/// Get top-level info for an account.
async fn get_account_info(&self, account_id: u32) -> Result<Account> {
let context_option = self.accounts.read().await.get_account(account_id);
if let Some(ctx) = context_option {
Ok(Account::from_context(&ctx, account_id).await?)
} else {
Err(anyhow!(
"account with id {} doesn't exist anymore",
account_id
))
}
let manager = &self.accounts.read().await;
Account::load(manager, account_id).await
}
/// Get the combined filesize of an account in bytes

View File

@@ -1,4 +1,4 @@
use anyhow::Result;
use anyhow::{anyhow, Result};
use deltachat::config::Config;
use deltachat::contact::{Contact, ContactId};
use serde::Serialize;
@@ -17,29 +17,43 @@ pub enum Account {
// size: u32,
profile_image: Option<String>, // TODO: This needs to be converted to work with blob http server.
color: String,
/// Account IO is disabled when this account is not selected
///
/// this means IO is stopped unless this account is selected
/// and background fetch is also disabled for this account
background_io_disabled: bool,
},
#[serde(rename_all = "camelCase")]
Unconfigured { id: u32 },
}
impl Account {
pub async fn from_context(ctx: &deltachat::context::Context, id: u32) -> Result<Self> {
if ctx.is_configured().await? {
let display_name = ctx.get_config(Config::Displayname).await?;
let addr = ctx.get_config(Config::Addr).await?;
let profile_image = ctx.get_config(Config::Selfavatar).await?;
let color = color_int_to_hex_string(
Contact::get_by_id(ctx, ContactId::SELF).await?.get_color(),
);
Ok(Account::Configured {
id,
display_name,
addr,
profile_image,
color,
})
pub async fn load(accounts: &deltachat::accounts::Accounts, id: u32) -> Result<Self> {
if let Some(ctx) = &accounts.get_account(id) {
if ctx.is_configured().await? {
let display_name = ctx.get_config(Config::Displayname).await?;
let addr = ctx.get_config(Config::Addr).await?;
let profile_image = ctx.get_config(Config::Selfavatar).await?;
let color = color_int_to_hex_string(
Contact::get_by_id(ctx, ContactId::SELF).await?.get_color(),
);
Ok(Account::Configured {
id: ctx.get_id(),
display_name,
addr,
profile_image,
color,
background_io_disabled: accounts.get_disable_background_io(id).unwrap_or(false),
})
} else {
Ok(Account::Unconfigured { id })
}
} else {
Ok(Account::Unconfigured { id })
Err(anyhow!(
"account with id {} doesn't exist anymore",
id
))
}
}
}