feat: search pdus
This commit is contained in:
parent
27d35f5ab4
commit
e457e19088
7 changed files with 193 additions and 17 deletions
13
Cargo.lock
generated
13
Cargo.lock
generated
|
@ -1560,7 +1560,6 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "ruma"
|
||||
version = "0.0.1"
|
||||
source = "git+https://github.com/timokoesters/ruma?branch=timo-fixes#7f8c78e8ba4be7fda450285e62493f6b33cb085a"
|
||||
dependencies = [
|
||||
"ruma-api",
|
||||
"ruma-client-api",
|
||||
|
@ -1574,7 +1573,6 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "ruma-api"
|
||||
version = "0.17.0-alpha.1"
|
||||
source = "git+https://github.com/timokoesters/ruma?branch=timo-fixes#7f8c78e8ba4be7fda450285e62493f6b33cb085a"
|
||||
dependencies = [
|
||||
"http",
|
||||
"percent-encoding",
|
||||
|
@ -1589,7 +1587,6 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "ruma-api-macros"
|
||||
version = "0.17.0-alpha.1"
|
||||
source = "git+https://github.com/timokoesters/ruma?branch=timo-fixes#7f8c78e8ba4be7fda450285e62493f6b33cb085a"
|
||||
dependencies = [
|
||||
"proc-macro-crate",
|
||||
"proc-macro2",
|
||||
|
@ -1600,7 +1597,6 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "ruma-client-api"
|
||||
version = "0.10.0-alpha.1"
|
||||
source = "git+https://github.com/timokoesters/ruma?branch=timo-fixes#7f8c78e8ba4be7fda450285e62493f6b33cb085a"
|
||||
dependencies = [
|
||||
"assign",
|
||||
"http",
|
||||
|
@ -1618,7 +1614,6 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "ruma-common"
|
||||
version = "0.2.0"
|
||||
source = "git+https://github.com/timokoesters/ruma?branch=timo-fixes#7f8c78e8ba4be7fda450285e62493f6b33cb085a"
|
||||
dependencies = [
|
||||
"js_int",
|
||||
"ruma-identifiers",
|
||||
|
@ -1631,7 +1626,6 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "ruma-events"
|
||||
version = "0.22.0-alpha.1"
|
||||
source = "git+https://github.com/timokoesters/ruma?branch=timo-fixes#7f8c78e8ba4be7fda450285e62493f6b33cb085a"
|
||||
dependencies = [
|
||||
"js_int",
|
||||
"ruma-common",
|
||||
|
@ -1646,7 +1640,6 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "ruma-events-macros"
|
||||
version = "0.22.0-alpha.1"
|
||||
source = "git+https://github.com/timokoesters/ruma?branch=timo-fixes#7f8c78e8ba4be7fda450285e62493f6b33cb085a"
|
||||
dependencies = [
|
||||
"proc-macro-crate",
|
||||
"proc-macro2",
|
||||
|
@ -1657,7 +1650,6 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "ruma-federation-api"
|
||||
version = "0.0.3"
|
||||
source = "git+https://github.com/timokoesters/ruma?branch=timo-fixes#7f8c78e8ba4be7fda450285e62493f6b33cb085a"
|
||||
dependencies = [
|
||||
"js_int",
|
||||
"ruma-api",
|
||||
|
@ -1672,7 +1664,6 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "ruma-identifiers"
|
||||
version = "0.17.4"
|
||||
source = "git+https://github.com/timokoesters/ruma?branch=timo-fixes#7f8c78e8ba4be7fda450285e62493f6b33cb085a"
|
||||
dependencies = [
|
||||
"rand",
|
||||
"ruma-identifiers-macros",
|
||||
|
@ -1684,7 +1675,6 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "ruma-identifiers-macros"
|
||||
version = "0.17.4"
|
||||
source = "git+https://github.com/timokoesters/ruma?branch=timo-fixes#7f8c78e8ba4be7fda450285e62493f6b33cb085a"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
@ -1695,7 +1685,6 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "ruma-identifiers-validation"
|
||||
version = "0.1.1"
|
||||
source = "git+https://github.com/timokoesters/ruma?branch=timo-fixes#7f8c78e8ba4be7fda450285e62493f6b33cb085a"
|
||||
dependencies = [
|
||||
"ruma-serde",
|
||||
"serde",
|
||||
|
@ -1706,7 +1695,6 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "ruma-serde"
|
||||
version = "0.2.3"
|
||||
source = "git+https://github.com/timokoesters/ruma?branch=timo-fixes#7f8c78e8ba4be7fda450285e62493f6b33cb085a"
|
||||
dependencies = [
|
||||
"form_urlencoded",
|
||||
"itoa",
|
||||
|
@ -1718,7 +1706,6 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "ruma-signatures"
|
||||
version = "0.6.0-dev.1"
|
||||
source = "git+https://github.com/timokoesters/ruma?branch=timo-fixes#7f8c78e8ba4be7fda450285e62493f6b33cb085a"
|
||||
dependencies = [
|
||||
"base64 0.12.3",
|
||||
"ring",
|
||||
|
|
|
@ -17,8 +17,8 @@ edition = "2018"
|
|||
rocket = { git = "https://github.com/timokoesters/Rocket.git", branch = "empty_parameters", features = ["tls"] }
|
||||
|
||||
#ruma = { git = "https://github.com/ruma/ruma", features = ["rand", "client-api", "federation-api", "unstable-pre-spec", "unstable-synapse-quirks"], rev = "987d48666cf166cf12100b5dbc61b5e3385c4014" } # Used for matrix spec type definitions and helpers
|
||||
ruma = { git = "https://github.com/timokoesters/ruma", features = ["rand", "client-api", "federation-api", "unstable-pre-spec", "unstable-synapse-quirks"], branch = "timo-fixes" } # Used for matrix spec type definitions and helpers
|
||||
#ruma = { path = "../ruma/ruma", features = ["rand", "client-api", "federation-api", "unstable-pre-spec", "unstable-synapse-quirks"] }
|
||||
#ruma = { git = "https://github.com/timokoesters/ruma", features = ["rand", "client-api", "federation-api", "unstable-pre-spec", "unstable-synapse-quirks"], branch = "timo-fixes" } # Used for matrix spec type definitions and helpers
|
||||
ruma = { path = "../ruma/ruma", features = ["rand", "client-api", "federation-api", "unstable-pre-spec", "unstable-synapse-quirks"] }
|
||||
tokio = "0.2.22" # Used for long polling
|
||||
sled = "0.32.0" # Used for storing data permanently
|
||||
log = "0.4.8" # Used for emitting log entries
|
||||
|
|
|
@ -17,6 +17,7 @@ mod push;
|
|||
mod read_marker;
|
||||
mod redact;
|
||||
mod room;
|
||||
mod search;
|
||||
mod session;
|
||||
mod state;
|
||||
mod sync;
|
||||
|
@ -47,6 +48,7 @@ pub use push::*;
|
|||
pub use read_marker::*;
|
||||
pub use redact::*;
|
||||
pub use room::*;
|
||||
pub use search::*;
|
||||
pub use session::*;
|
||||
pub use state::*;
|
||||
pub use sync::*;
|
||||
|
|
93
src/client_server/search.rs
Normal file
93
src/client_server/search.rs
Normal file
|
@ -0,0 +1,93 @@
|
|||
use super::State;
|
||||
use crate::{ConduitResult, Database, Error, Ruma};
|
||||
use js_int::uint;
|
||||
use ruma::api::client::{error::ErrorKind, r0::search::search_events};
|
||||
|
||||
#[cfg(feature = "conduit_bin")]
|
||||
use rocket::post;
|
||||
use search_events::{ResultCategories, ResultRoomEvents, SearchResult};
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
#[cfg_attr(
|
||||
feature = "conduit_bin",
|
||||
post("/_matrix/client/r0/search", data = "<body>")
|
||||
)]
|
||||
pub fn search_events_route(
|
||||
db: State<'_, Database>,
|
||||
body: Ruma<search_events::Request>,
|
||||
) -> ConduitResult<search_events::Response> {
|
||||
let sender_id = body.sender_id.as_ref().expect("user is authenticated");
|
||||
|
||||
let search_criteria = body.search_categories.room_events.as_ref().unwrap();
|
||||
let filter = search_criteria
|
||||
.filter
|
||||
.as_ref()
|
||||
.unwrap();
|
||||
|
||||
let room_id = filter.rooms
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.first()
|
||||
.unwrap();
|
||||
|
||||
let limit = filter.limit.map_or(10, |l| u64::from(l) as usize);
|
||||
|
||||
if !db.rooms.is_joined(sender_id, &room_id)? {
|
||||
return Err(Error::BadRequest(
|
||||
ErrorKind::Forbidden,
|
||||
"You don't have permission to view this room.",
|
||||
));
|
||||
}
|
||||
|
||||
let skip = match body.next_batch.as_ref().map(|s| s.parse()) {
|
||||
Some(Ok(s)) => s,
|
||||
Some(Err(_)) => {
|
||||
return Err(Error::BadRequest(
|
||||
ErrorKind::InvalidParam,
|
||||
"Invalid next_batch token.",
|
||||
))
|
||||
}
|
||||
None => 0, // Default to the start
|
||||
};
|
||||
|
||||
let search = db
|
||||
.rooms
|
||||
.search_pdus(&room_id, &search_criteria.search_term)?;
|
||||
|
||||
let results = search
|
||||
.0
|
||||
.map(|result| {
|
||||
Ok::<_, Error>(SearchResult {
|
||||
context: None,
|
||||
rank: None,
|
||||
result: dbg!(db
|
||||
.rooms
|
||||
.get_pdu_from_id(dbg!(&result))?
|
||||
.map(|pdu| pdu.to_room_event())),
|
||||
})
|
||||
})
|
||||
.filter_map(|r| r.ok())
|
||||
.skip(skip)
|
||||
.take(limit)
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let next_batch = if results.len() < limit as usize {
|
||||
None
|
||||
} else {
|
||||
Some((skip + limit).to_string())
|
||||
};
|
||||
|
||||
Ok(search_events::Response {
|
||||
search_categories: ResultCategories {
|
||||
room_events: Some(ResultRoomEvents {
|
||||
count: uint!(0), // TODO
|
||||
groups: BTreeMap::new(), // TODO
|
||||
next_batch,
|
||||
results,
|
||||
state: BTreeMap::new(), // TODO
|
||||
highlights: search.1,
|
||||
}),
|
||||
},
|
||||
}
|
||||
.into())
|
||||
}
|
|
@ -104,6 +104,8 @@ impl Database {
|
|||
aliasid_alias: db.open_tree("alias_roomid")?,
|
||||
publicroomids: db.open_tree("publicroomids")?,
|
||||
|
||||
tokenids: db.open_tree("tokenids")?,
|
||||
|
||||
userroomid_joined: db.open_tree("userroomid_joined")?,
|
||||
roomuserid_joined: db.open_tree("roomuserid_joined")?,
|
||||
userroomid_invited: db.open_tree("userroomid_invited")?,
|
||||
|
|
|
@ -35,6 +35,8 @@ pub struct Rooms {
|
|||
pub(super) aliasid_alias: sled::Tree, // AliasId = RoomId + Count
|
||||
pub(super) publicroomids: sled::Tree,
|
||||
|
||||
pub(super) tokenids: sled::Tree, // TokenId = RoomId + Token + PduId
|
||||
|
||||
pub(super) userroomid_joined: sled::Tree,
|
||||
pub(super) roomuserid_joined: sled::Tree,
|
||||
pub(super) userroomid_invited: sled::Tree,
|
||||
|
@ -562,7 +564,7 @@ impl Rooms {
|
|||
self.pduid_pdu.insert(&pdu_id, &*pdu_json.to_string())?;
|
||||
|
||||
self.eventid_pduid
|
||||
.insert(pdu.event_id.to_string(), pdu_id)?;
|
||||
.insert(pdu.event_id.to_string(), pdu_id.clone())?;
|
||||
|
||||
if let Some(state_key) = pdu.state_key {
|
||||
let mut key = room_id.to_string().as_bytes().to_vec();
|
||||
|
@ -573,7 +575,7 @@ impl Rooms {
|
|||
self.roomstateid_pdu.insert(key, &*pdu_json.to_string())?;
|
||||
}
|
||||
|
||||
match event_type {
|
||||
match dbg!(event_type) {
|
||||
EventType::RoomRedaction => {
|
||||
if let Some(redact_id) = &redacts {
|
||||
// TODO: Reason
|
||||
|
@ -616,6 +618,21 @@ impl Rooms {
|
|||
)?;
|
||||
}
|
||||
}
|
||||
EventType::RoomMessage => {
|
||||
if let Some(body) = dbg!(content).get("body").and_then(|b| b.as_str()) {
|
||||
for word in body
|
||||
.split_terminator(|c: char| !c.is_alphanumeric())
|
||||
.map(str::to_lowercase)
|
||||
{
|
||||
let mut key = room_id.to_string().as_bytes().to_vec();
|
||||
key.push(0xff);
|
||||
key.extend_from_slice(word.as_bytes());
|
||||
key.push(0xff);
|
||||
key.extend_from_slice(&pdu_id);
|
||||
self.tokenids.insert(key, &[])?;
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
self.edus.room_read_set(&room_id, &sender, index)?;
|
||||
|
@ -928,6 +945,80 @@ impl Rooms {
|
|||
})
|
||||
}
|
||||
|
||||
pub fn search_pdus(
|
||||
&self,
|
||||
room_id: &RoomId,
|
||||
search_string: &str,
|
||||
) -> Result<(impl Iterator<Item = IVec>, Vec<String>)> {
|
||||
let mut prefix = room_id.to_string().as_bytes().to_vec();
|
||||
prefix.push(0xff);
|
||||
|
||||
let words = search_string
|
||||
.split_terminator(|c: char| !c.is_alphanumeric())
|
||||
.map(str::to_lowercase)
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let mut iterators = words.iter().map(|word| {
|
||||
let mut prefix2 = prefix.clone();
|
||||
prefix2.extend_from_slice(word.as_bytes());
|
||||
prefix2.push(0xff);
|
||||
self.tokenids
|
||||
.scan_prefix(&prefix2)
|
||||
.keys()
|
||||
.filter_map(|r| r.ok())
|
||||
.map(|key| {
|
||||
let pduid_index = key
|
||||
.iter()
|
||||
.enumerate()
|
||||
.filter(|(_, &b)| b == 0xff)
|
||||
.nth(1)
|
||||
.ok_or_else(|| Error::bad_database("Invalid tokenid in db."))?
|
||||
.0 + 1; // +1 because the pdu id starts AFTER the separator
|
||||
|
||||
let pdu_id =
|
||||
key.subslice(pduid_index, key.len() - pduid_index);
|
||||
|
||||
Ok::<_, Error>(pdu_id)
|
||||
})
|
||||
.filter_map(|r| r.ok())
|
||||
.peekable()
|
||||
});
|
||||
|
||||
let first_iterator = match iterators.next() {
|
||||
Some(i) => i,
|
||||
None => {
|
||||
return Err(Error::BadRequest(
|
||||
ErrorKind::InvalidParam,
|
||||
"search_term needs to contain at least one word.",
|
||||
))
|
||||
}
|
||||
};
|
||||
|
||||
let mut other_iterators = iterators.collect::<Vec<_>>();
|
||||
|
||||
Ok((
|
||||
first_iterator.filter(move |target| {
|
||||
other_iterators
|
||||
.iter_mut()
|
||||
.map(|it| {
|
||||
while let Some(element) = it.peek() {
|
||||
if dbg!(element) > dbg!(target) {
|
||||
return false;
|
||||
} else if element == target {
|
||||
return true;
|
||||
} else {
|
||||
it.next();
|
||||
}
|
||||
}
|
||||
|
||||
false
|
||||
})
|
||||
.all(|b| b)
|
||||
}),
|
||||
words,
|
||||
))
|
||||
}
|
||||
|
||||
/// Returns an iterator over all joined members of a room.
|
||||
pub fn room_members(&self, room_id: &RoomId) -> impl Iterator<Item = Result<UserId>> {
|
||||
self.roomuserid_joined
|
||||
|
|
|
@ -90,6 +90,7 @@ fn setup_rocket() -> rocket::Rocket {
|
|||
client_server::sync_events_route,
|
||||
client_server::get_context_route,
|
||||
client_server::get_message_events_route,
|
||||
client_server::search_events_route,
|
||||
client_server::turn_server_route,
|
||||
client_server::send_event_to_device_route,
|
||||
client_server::get_media_config_route,
|
||||
|
|
Loading…
Reference in a new issue