feat: client version information (#8557)

> we aim to inform about updates for installations outside of any
appstore soon.
>
> there is already a PR on android at
https://github.com/deltachat/deltachat-android/pull/4582, however, the
information about "update available" is a mockup there.
>
> in general, there are 3 ideas around about how to gather the "update
available" infomation - (1) checking a central url, (2) let contacts
provide information, (3) let relay provide information. on various
one-to-one discussions, outcome is that (3) is the most reasonable way
to go.

this PR is about reading update information via IMAP metadata from the
relay.

it is up to the UI to call `get_app_version()` at a reasonable time and
frequency, see comment in the code. when called, `get_app_version()`
iterates over all known profiles and relays and checks for version
information, returning the newest for the given scope.

we do not use an event, as that is tricky wrt changes - we do not know
if other relays report later a newer version. we also do not cache
anything, to prevent bad relays avoiding us to update permanently. also
it is easier :)

<details>
<summary>outdated notes and questions</summary>

- ~~it is up to the clients to get the needed information, we could let
core filter, but it seems easy enough the other way round, and may have
debug advantages, one can iterate etc.~~ EDIT: we now filter in core,
this also makes the jsonrpc part easier, see review comments

- when is IMAP METADATA actually read? when are they ready? is that
really the correct place? i am up to change that, but beware, this is
not really my expertise, so someone else may need to take over :)
EDIT: see below, IMAP METADATA is read on connection, before fetching
starts, usually fast enough

- relay part is missing. once the format is settled and discussed
shortly here, that should be done soon as well. but this is definitely
not my expertise and needed to be done by someone else :)

- key for IMAP METADATA is `/shared/vendor/deltachat/appversions` -
shall we continue use `deltachat` for compatibility or so? `chatmail`
seems to be more correct
EDIT: we stay with the current
</details>

relay counterpart issue: https://github.com/chatmail/relay/issues/1037

cc @link2xt @Hocuri @hpk42

---------

Co-authored-by: holger krekel <holger@merlinux.eu>
This commit is contained in:
biørn
2026-08-13 16:45:58 +02:00
committed by GitHub
parent 1edbfa1024
commit c1e961d37f
6 changed files with 430 additions and 2 deletions

View File

@@ -140,6 +140,10 @@ pub(crate) struct ServerMetadata {
/// should be fetched from the server
/// to be ready for WebRTC calls.
pub ice_servers_expiration_timestamp: i64,
/// App versions, as raw JSON string.
/// Consumed by get_app_versions().
pub app_versions: Option<String>,
}
struct UidGrouper<T: Iterator<Item = (i64, u32, String)>> {
@@ -1292,6 +1296,10 @@ impl Session {
let now = time();
// Refresh TURN server credentials if they expire in 12 hours.
//
// Moreover, Take the chance to update `app_versions` as well.
// As best effort, even checking every some days is good enough -
// and saves one additional time get get_metadata() call.
if now + 3600 * 12 < old_metadata.ice_servers_expiration_timestamp {
return Ok(());
}
@@ -1302,7 +1310,11 @@ impl Session {
let mailbox = "";
let options = "";
let metadata = self
.get_metadata(mailbox, options, "(/shared/vendor/deltachat/turn)")
.get_metadata(
mailbox,
options,
"(/shared/vendor/deltachat/turn /shared/vendor/deltachat/appversions)",
)
.await?;
for m in metadata {
if m.entry == "/shared/vendor/deltachat/turn"
@@ -1318,6 +1330,8 @@ impl Session {
warn!(context, "Failed to parse TURN server metadata: {err:#}.");
}
}
} else if m.entry == "/shared/vendor/deltachat/appversions" {
old_metadata.app_versions = m.value;
}
}
}
@@ -1341,6 +1355,7 @@ impl Session {
let mut max_smtp_rcpt_to = None;
let mut ice_servers = None;
let mut ice_servers_expiration_timestamp = 0;
let mut app_versions = None;
let mailbox = "";
let options = "";
@@ -1348,7 +1363,7 @@ impl Session {
.get_metadata(
mailbox,
options,
"(/shared/comment /shared/admin /shared/vendor/deltachat/irohrelay /shared/vendor/deltachat/turn /shared/vendor/deltachat/maxsmtprecipients)",
"(/shared/comment /shared/admin /shared/vendor/deltachat/irohrelay /shared/vendor/deltachat/turn /shared/vendor/deltachat/maxsmtprecipients /shared/vendor/deltachat/appversions)",
)
.await?;
for m in metadata {
@@ -1396,6 +1411,9 @@ impl Session {
}
}
}
"/shared/vendor/deltachat/appversions" => {
app_versions = m.value;
}
_ => {}
}
}
@@ -1417,6 +1435,7 @@ impl Session {
supports_push: max_smtp_rcpt_to.is_some() || self.capabilities.has_xdeltapush,
ice_servers,
ice_servers_expiration_timestamp,
app_versions,
},
);
Ok(())