UI only needs concrete client/source info

This commit is contained in:
B. Petersen
2026-08-11 15:27:16 +02:00
parent ee7bfb7937
commit a636f3a36e
3 changed files with 42 additions and 48 deletions
+13 -5
View File
@@ -64,7 +64,7 @@ use self::types::{
JsonrpcMessageListItem, MessageNotificationInfo, MessageSearchResult, MessageViewtype, JsonrpcMessageListItem, MessageNotificationInfo, MessageSearchResult, MessageViewtype,
}, },
}; };
use crate::api::types::appversions::JsonrpcAppVersionInfo; use crate::api::types::appversions::JsonrpcAppSource;
use crate::api::types::chat_list::{ChatListItemFetchResult, get_chat_list_item_by_id}; use crate::api::types::chat_list::{ChatListItemFetchResult, get_chat_list_item_by_id};
use crate::api::types::login_param::TransportListEntry; use crate::api::types::login_param::TransportListEntry;
use crate::api::types::qr::{QrObject, SecurejoinSource, SecurejoinUiPath}; use crate::api::types::qr::{QrObject, SecurejoinSource, SecurejoinUiPath};
@@ -2791,11 +2791,19 @@ impl CommandApi {
} }
} }
/// Get version information of clients. /// Get version information of a specific client and source.
async fn get_app_versions(&self, account_id: u32) -> Result<JsonrpcAppVersionInfo> { async fn get_app_version(
&self,
account_id: u32,
client_id: String,
source_id: String,
) -> Result<Option<JsonrpcAppSource>> {
let ctx = self.get_context(account_id).await?; let ctx = self.get_context(account_id).await?;
let info = deltachat::appversions::get_app_versions(&ctx).await?; Ok(
JsonrpcAppVersionInfo::from_core_type(info) deltachat::appversions::get_app_version(&ctx, &client_id, &source_id)
.await?
.map(|s| JsonrpcAppSource::from_core_type(s)),
)
} }
} }
+8 -28
View File
@@ -1,34 +1,11 @@
use anyhow::Result; use deltachat::appversions::AppSource;
use deltachat::appversions::AppVersionInfo;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use typescript_type_def::TypeDef; use typescript_type_def::TypeDef;
/// Version information of clients.
#[derive(Serialize, Deserialize, TypeDef, schemars::JsonSchema)]
#[serde(rename = "AppVersionInfo", rename_all = "camelCase")]
pub struct JsonrpcAppVersionInfo {
/// Array of clients with version information.
pub clients: Vec<JsonrpcAppClient>,
}
/// Version information of a single client, eg. "deltachat" or "ubuntutouch".
#[derive(Serialize, Deserialize, TypeDef, schemars::JsonSchema)]
#[serde(rename = "AppClient", rename_all = "camelCase")]
pub struct JsonrpcAppClient {
/// ID how the client identifies itself, eg. "deltachat" or "ubuntutouch".
pub client_id: String,
/// Array of sources for that client.
pub sources: Vec<JsonrpcAppSource>,
}
/// Version information of a single source of a client, eg. "gplay" or "fdroid". /// Version information of a single source of a client, eg. "gplay" or "fdroid".
#[derive(Serialize, Deserialize, TypeDef, schemars::JsonSchema)] #[derive(Serialize, Deserialize, TypeDef, schemars::JsonSchema)]
#[serde(rename = "AppSource", rename_all = "camelCase")] #[serde(rename = "AppSource", rename_all = "camelCase")]
pub struct JsonrpcAppSource { pub struct JsonrpcAppSource {
/// ID how the client identifies a source, eg. "gplay" or "fdroid".
pub app_id: String,
/// Always increasing version number. /// Always increasing version number.
pub version_integer: u32, pub version_integer: u32,
@@ -39,9 +16,12 @@ pub struct JsonrpcAppSource {
pub download_url: String, pub download_url: String,
} }
impl JsonrpcAppVersionInfo { impl JsonrpcAppSource {
pub fn from_core_type(info: AppVersionInfo) -> Result<Self> { pub fn from_core_type(source: AppSource) -> Self {
let value = serde_json::to_value(info)?; JsonrpcAppSource {
Ok(serde_json::from_value(value)?) version_integer: source.version_integer,
version_string: source.version_string,
download_url: source.download_url,
}
} }
} }
+21 -15
View File
@@ -10,7 +10,7 @@ use serde::{Deserialize, Serialize};
/// Version information of clients as used on the wire. /// Version information of clients as used on the wire.
#[derive(Debug, Default, Serialize, Deserialize)] #[derive(Debug, Default, Serialize, Deserialize)]
#[serde(rename_all = "camelCase", default)] #[serde(rename_all = "camelCase", default)]
pub struct AppVersionInfo { struct AppVersionInfo {
/// Array clients with version information. /// Array clients with version information.
clients: Vec<AppClient>, clients: Vec<AppClient>,
} }
@@ -18,7 +18,7 @@ pub struct AppVersionInfo {
/// Version infomation of a single client, eg. "deltachat" or "ubuntutouch". /// Version infomation of a single client, eg. "deltachat" or "ubuntutouch".
#[derive(Debug, Default, Serialize, Deserialize)] #[derive(Debug, Default, Serialize, Deserialize)]
#[serde(rename_all = "camelCase", default)] #[serde(rename_all = "camelCase", default)]
pub struct AppClient { struct AppClient {
/// ID how the client identifies itself, eg. "deltachat" or "ubuntutouch" /// ID how the client identifies itself, eg. "deltachat" or "ubuntutouch"
client_id: String, client_id: String,
@@ -34,29 +34,35 @@ pub struct AppSource {
app_id: String, app_id: String,
/// Always increasing version number. /// Always increasing version number.
version_integer: u32, pub version_integer: u32,
/// Any version string. /// Any version string.
version_string: String, pub version_string: String,
/// Where to download that version. /// Where to download that version.
download_url: String, pub download_url: String,
} }
/// Get version information of clients. /// Get version information of a specific client and source.
/// ///
/// If no version information are available, `clients` is set to an empty array. /// If no matching version information are available, `None` is returned.
/// pub async fn get_app_version(
/// The information is coming from the relay via IMAP METADATA and is not cached. context: &Context,
/// A call to `get_app_versions()` is cheap and does not involve network or database calls. client_id: &str,
pub async fn get_app_versions(context: &Context) -> Result<AppVersionInfo> { source_id: &str,
) -> Result<Option<AppSource>> {
if let Some(metadata) = context.metadata.read().await.values().next() if let Some(metadata) = context.metadata.read().await.values().next()
&& let Some(json) = &metadata.app_versions && let Some(json) = &metadata.app_versions
{ {
let app_versions: AppVersionInfo = serde_json::from_str(json)?; let app_versions: AppVersionInfo = serde_json::from_str(json)?;
return Ok(app_versions); let app_version = app_versions
.clients
.into_iter()
.find(|c| c.client_id == client_id)
.and_then(|c| c.sources.into_iter().find(|s| s.app_id == source_id));
return Ok(app_version);
} }
Ok(AppVersionInfo::default()) Ok(None)
} }
#[cfg(test)] #[cfg(test)]
@@ -126,8 +132,8 @@ mod tests {
let mut tcm = TestContextManager::new(); let mut tcm = TestContextManager::new();
let alice = &tcm.alice().await; let alice = &tcm.alice().await;
let versions = get_app_versions(alice).await?; let version = get_app_version(alice, "deltachat", "gplay").await?;
assert!(versions.clients.is_empty()); assert!(version.is_none());
Ok(()) Ok(())
} }