fix: Only emit TransportsModified if transports are really modified

Otherwise it's not possible to write tests reliably because sync messages may be executed multiple
times if they arrive from different transports. This should fix flaky
`test_transport_synchronization`.

Also always emit `TransportsModified` if the primary transport is changed by a sync message, even if
it doesn't contain `SyncData::Transports`.

Also don't decrease `add_timestamp` in `save_transport()` if nothing else changes, this doesn't make
sense.
This commit is contained in:
iequidoo
2026-01-10 23:07:16 -03:00
committed by iequidoo
parent ed300b6f97
commit fe3b1ea16d
3 changed files with 25 additions and 13 deletions

View File

@@ -417,12 +417,12 @@ pub enum EventType {
chat_id: ChatId,
},
/// One or more transports has changed.
/// One or more transports has changed or another transport is primary now.
///
/// UI should update the list.
///
/// This event is emitted when transport
/// synchronization messages arrives,
/// This event is emitted when a transport
/// synchronization message modifies transports,
/// but not when the UI modifies the transport list by itself.
TransportsModified,

View File

@@ -832,7 +832,9 @@ pub(crate) async fn receive_imf_inner(
let transport_changed = if transport_exists {
transaction.execute(
"UPDATE config SET value=? WHERE keyname='configured_addr'",
"
UPDATE config SET value=? WHERE keyname='configured_addr' AND value!=?1
",
(from_addr,),
)? > 0
} else {
@@ -848,6 +850,7 @@ pub(crate) async fn receive_imf_inner(
if transport_changed {
info!(context, "Primary transport changed to {from_addr:?}.");
context.sql.uncache_raw_config("configured_addr").await;
context.emit_event(EventType::TransportsModified);
}
} else {
warn!(context, "Sync items are not encrypted.");

View File

@@ -621,16 +621,17 @@ impl From<ConfiguredLoginParam> for ConfiguredLoginParamJson {
}
/// Saves transport to the database.
/// Returns whether transports are modified.
pub(crate) async fn save_transport(
context: &Context,
entered_param: &EnteredLoginParam,
configured: &ConfiguredLoginParamJson,
add_timestamp: i64,
) -> Result<()> {
) -> Result<bool> {
let addr = addr_normalize(&configured.addr);
let configured_addr = context.get_config(Config::ConfiguredAddr).await?;
context
let mut modified = context
.sql
.execute(
"INSERT INTO transports (addr, entered_param, configured_param, add_timestamp)
@@ -638,7 +639,10 @@ pub(crate) async fn save_transport(
ON CONFLICT (addr)
DO UPDATE SET entered_param=excluded.entered_param,
configured_param=excluded.configured_param,
add_timestamp=excluded.add_timestamp",
add_timestamp=excluded.add_timestamp
WHERE entered_param != excluded.entered_param
OR configured_param != excluded.configured_param
OR add_timestamp < excluded.add_timestamp",
(
&addr,
serde_json::to_string(entered_param)?,
@@ -646,7 +650,8 @@ pub(crate) async fn save_transport(
add_timestamp,
),
)
.await?;
.await?
> 0;
if configured_addr.is_none() {
// If there is no transport yet, set the new transport as the primary one
@@ -654,8 +659,9 @@ pub(crate) async fn save_transport(
.sql
.set_raw_config(Config::ConfiguredAddr.as_ref(), Some(&addr))
.await?;
modified = true;
}
Ok(())
Ok(modified)
}
/// Sends a sync message to synchronize transports across devices.
@@ -721,24 +727,25 @@ pub(crate) async fn sync_transports(
transports: &[TransportData],
removed_transports: &[RemovedTransportData],
) -> Result<()> {
let mut modified = false;
for TransportData {
configured,
entered,
timestamp,
} in transports
{
save_transport(context, entered, configured, *timestamp).await?;
modified |= save_transport(context, entered, configured, *timestamp).await?;
}
context
.sql
.transaction(|transaction| {
for RemovedTransportData { addr, timestamp } in removed_transports {
transaction.execute(
modified |= transaction.execute(
"DELETE FROM transports
WHERE addr=? AND add_timestamp<=?",
(addr, timestamp),
)?;
)? > 0;
transaction.execute(
"INSERT INTO removed_transports (addr, remove_timestamp)
VALUES (?, ?)
@@ -752,7 +759,9 @@ pub(crate) async fn sync_transports(
})
.await?;
context.emit_event(EventType::TransportsModified);
if modified {
context.emit_event(EventType::TransportsModified);
}
Ok(())
}