Commit 038cc6faeb14
tarball4 files changed+85-25
@@ -107,6 +107,9 @@ pub(crate) struct Service {
107107
unpublished: bool,108108
flush_after: u64,109109
ignored: BTreeSet<OwnedUserId>,110
+ /// kept out of everything the inbox shows, while their entries stay saved for when the111
+ /// room stops being direct112
+ direct: BTreeSet<OwnedRoomId>,110113
leaving: BTreeSet<OwnedRoomId>,111114
timed_out: Arc<AtomicBool>,112115
config: EngineConfig,@@ -282,7 +285,8 @@ impl Service {
282285
for reason in &loaded.gaps {283286
loaded.data.gap(None, *reason, None);284287
}285
- let page = loaded.data.page(&account, None, 50)?;288
+ let direct = direct_rooms(&client);289
+ let page = loaded.data.page(&account, None, 50, &direct)?;286290
let media_scope = MediaScope::bounded(config.max_mention_context_events);287291
media288292
.register(@@ -313,6 +317,7 @@ impl Service {
313317
unpublished: false,314318
flush_after: 0,315319
ignored: BTreeSet::new(),320
+ direct,316321
leaving: BTreeSet::new(),317322
timed_out: timed_out.clone(),318323
config,@@ -347,7 +352,7 @@ impl Service {
347352
348353
async fn publish(&mut self) {349354
self.unpublished = false;350
- let Ok(page) = self.data.page(&self.account, None, 50) else {355
+ let Ok(page) = self.data.page(&self.account, None, 50, &self.direct) else {351356
return;352357
};353358
self.media@@ -518,7 +523,9 @@ impl Service {
518523
async fn command(&mut self, command: MentionsCommand) -> Result<CommandOutput, Error> {519524
match command {520525
MentionsCommand::Page { cursor, limit } => {521
- let page = self.data.page(&self.account, cursor.as_deref(), limit)?;526
+ let page = self527
+ .data528
+ .page(&self.account, cursor.as_deref(), limit, &self.direct)?;522529
self.media523530
.register(524531
&self.media_scope,@@ -569,8 +576,11 @@ impl Service {
569576
}570577
MentionsCommand::SetRead { keys, read } => {571578
let mut next = self.data.clone();572
- for key in keys {573
- if let Some(entry) = next.entries.get_mut(&id(&key)) {579
+ for key in keys580
+ .iter()581
+ .filter(|key| !self.direct.contains(&key.room_id))582
+ {583
+ if let Some(entry) = next.entries.get_mut(&id(key)) {574584
entry.read = read;575585
entry.revision = self.data.revision + 1;576586
}@@ -583,11 +593,10 @@ impl Service {
583593
return Err(invalid("invalid mentions read boundary"));584594
}585595
let mut next = self.data.clone();586
- for entry in next587
- .entries588
- .values_mut()589
- .filter(|entry| entry.discovery_revision <= boundary.revision)590
- {596
+ for entry in next.entries.values_mut().filter(|entry| {597
+ entry.discovery_revision <= boundary.revision598
+ && !self.direct.contains(&entry.key.room_id)599
+ }) {591600
entry.read = true;592601
entry.revision = self.data.revision + 1;593602
}@@ -1200,6 +1209,8 @@ impl Service {
12001209
() = &mut tick => {12011210
tick = Box::pin(matrix_sdk::sleep::sleep(Duration::from_secs(1)));12021211
if now() >= next_scan && !history { self.recovery_budget = 20; self.latest_scan = true; next_scan = now() + 60_000; }1212
+ let direct = direct_rooms(&self.client);1213
+ if direct != self.direct { self.direct = direct; self.dirty = true; self.unpublished = true; }12031214
if now() >= next_expiry { let expired = self.data.expire_candidates(now()); self.dirty |= expired; self.unpublished |= expired; next_expiry = now() + 60_000; }12041215
#[cfg(any(feature = "sqlite", feature = "indexeddb"))]12051216
if self.store.is_none() && self.reopen.is_some() && now() >= self.flush_after { self.reopen().await; }@@ -1385,7 +1396,7 @@ impl Service {
13851396
) {13861397
for (key, entry) in self.data.entries.iter().filter(|(_, entry)| matches!(entry.capture, MentionCaptureState::Pending) || matches!(entry.capture, MentionCaptureState::Failed {retry_at_ms, ..} if retry_at_ms <= now())).take(128) {13871398
if captures.len() >= 2 { break; }1388
- if captures.contains(key) { continue; }1399
+ if captures.contains(key) || self.direct.contains(&entry.key.room_id) { continue; }13891400
let Some(room) = self.client.get_room(&entry.key.room_id).filter(|room| room.state() == RoomState::Joined) else { continue; };13901401
captures.insert(key.clone());13911402
let key = key.clone(); let event_id = entry.key.event_id.clone(); let account = self.account.clone(); let revision = entry.revision;@@ -1649,6 +1660,15 @@ impl Service {
16491660
}16501661
}16511662
1663
+fn direct_rooms(client: &Client) -> BTreeSet<OwnedRoomId> {1664
+ client1665
+ .rooms()1666
+ .into_iter()1667
+ .filter(|room| room.direct_targets_length() > 0)1668
+ .map(|room| room.room_id().to_owned())1669
+ .collect()1670
+}1671
+16521672
fn edited(mut original: Value, edit: &Value) -> Value {16531673
original["content"] = edit["content"]["m.new_content"].clone();16541674
original["unsigned"]["macltok_edited"] = Value::Bool(true);@@ -707,7 +707,9 @@ async fn observing_again_keeps_the_profiles_a_capture_fetched() {
707707
value["origin_server_ts"] = json!(timestamp);708708
value709709
};710
- let factory = EventFactory::new().room(room_id).sender(user_id!("@bob:localhost"));710
+ let factory = EventFactory::new()711
+ .room(room_id)712
+ .sender(user_id!("@bob:localhost"));711713
let mention = raw(712714
factory713715
.text_msg("ping")@@ -738,7 +740,9 @@ async fn observing_again_keeps_the_profiles_a_capture_fetched() {
738740
item739741
};740742
let target = profiled(&data.entries[&ping].event);741
- let mut neighbour = normalise_observed(&following, None, &following_id).unwrap().0;743
+ let mut neighbour = normalise_observed(&following, None, &following_id)744
+ .unwrap()745
+ .0;742746
neighbour = profiled(&neighbour);743747
let revision = data.entries[&ping].revision;744748
service.captured(@@ -768,6 +772,9 @@ async fn observing_again_keeps_the_profiles_a_capture_fetched() {
768772
};769773
assert_eq!(name(&data.entries[&ping].event).as_deref(), Some("Bob"));770774
assert_eq!(name(&data.events[&ping].item).as_deref(), Some("Bob"));771
- assert_eq!(name(&data.events[&following_id].item).as_deref(), Some("Bob"));775
+ assert_eq!(776
+ name(&data.events[&following_id].item).as_deref(),777
+ Some("Bob")778
+ );772779
assert_eq!(data.entries[&ping].capture, capture);773780
}@@ -1,6 +1,6 @@
11
use std::collections::{BTreeMap, BTreeSet};22
3
-use ruma::OwnedUserId;3
+use ruma::{OwnedRoomId, OwnedUserId};44
use serde_json::Value;55
66
use crate::{@@ -304,6 +304,7 @@ impl Data {
304304
account: &OwnedUserId,305305
cursor: Option<&str>,306306
limit: u16,307
+ hidden: &BTreeSet<OwnedRoomId>,307308
) -> Result<MentionsPage, Error> {308309
let (boundary, last) = if let Some(cursor) = cursor {309310
let value: Value =@@ -332,7 +333,8 @@ impl Data {
332333
.entries333334
.iter()334335
.filter(|(key, entry)| {335
- entry.discovery_revision <= boundary336
+ !hidden.contains(&entry.key.room_id)337
+ && entry.discovery_revision <= boundary336338
&& last.as_ref().is_none_or(|last| {337339
(entry.timestamp_ms, key.as_str()) < (last.0, last.1.as_str())338340
})@@ -351,13 +353,26 @@ impl Data {
351353
}).to_string())352354
};353355
let mut coverage = self.coverage.clone();354
- coverage.unresolved_candidates = self.candidates.len();356
+ coverage.gaps.retain(|gap| {357
+ gap.room_id358
+ .as_ref()359
+ .is_none_or(|room_id| !hidden.contains(room_id))360
+ });361
+ coverage.unresolved_candidates = self362
+ .candidates363
+ .values()364
+ .filter(|candidate| !hidden.contains(&candidate.room_id))365
+ .count();355366
Ok(MentionsPage {356367
entries,357368
next_cursor,358369
end_reached,359370
coverage,360
- unread_count: self.entries.values().filter(|entry| !entry.read).count(),371
+ unread_count: self372
+ .entries373
+ .values()374
+ .filter(|entry| !entry.read && !hidden.contains(&entry.key.room_id))375
+ .count(),361376
revision: self.revision,362377
boundary: MentionsBoundary {363378
account: account.clone(),@@ -1,3 +1,5 @@
1
+use std::collections::BTreeSet;2
+13
use ruma::{event_id, user_id};24
35
use super::state::{Data, SavedEvent, Window, id};@@ -90,7 +92,7 @@ async fn pagination_keeps_its_discovery_boundary_and_stable_ties() {
9092
.insert(id(&mention), entry(mention, timestamp, 1, false));9193
}9294
93
- let first = data.page(&account, None, 2).unwrap();95
+ let first = data.page(&account, None, 2, &BTreeSet::new()).unwrap();9496
assert_eq!(9597
first9698
.entries@@ -111,7 +113,9 @@ async fn pagination_keeps_its_discovery_boundary_and_stable_ties() {
111113
.map(|entry| entry.key)112114
.collect::<Vec<_>>();113115
loop {114
- let page = data.page(&account, Some(&cursor), 2).unwrap();116
+ let page = data117
+ .page(&account, Some(&cursor), 2, &BTreeSet::new())118
+ .unwrap();115119
paged.extend(page.entries.into_iter().map(|entry| entry.key));116120
match page.next_cursor {117121
Some(next) => cursor = next,@@ -134,20 +138,34 @@ async fn pagination_rejects_a_forged_account_and_a_future_revision() {
134138
data.entries135139
.insert(id(&mention), entry(mention, 10, 1, false));136140
}137
- let cursor = data.page(&account, None, 1).unwrap().next_cursor.unwrap();141
+ let cursor = data142
+ .page(&account, None, 1, &BTreeSet::new())143
+ .unwrap()144
+ .next_cursor145
+ .unwrap();138146
139147
let mut forged_account: serde_json::Value = serde_json::from_str(&cursor).unwrap();140148
forged_account["account"] = serde_json::Value::String("@mallory:mentions.example".to_owned());141149
assert!(142
- data.page(&account, Some(&forged_account.to_string()), 1)143
- .is_err()150
+ data.page(151
+ &account,152
+ Some(&forged_account.to_string()),153
+ 1,154
+ &BTreeSet::new()155
+ )156
+ .is_err()144157
);145158
146159
let mut future_revision: serde_json::Value = serde_json::from_str(&cursor).unwrap();147160
future_revision["revision"] = serde_json::json!(data.revision + 1);148161
assert!(149
- data.page(&account, Some(&future_revision.to_string()), 1)150
- .is_err()162
+ data.page(163
+ &account,164
+ Some(&future_revision.to_string()),165
+ 1,166
+ &BTreeSet::new()167
+ )168
+ .is_err()151169
);152170
}