feat: search pdus

next
timokoesters 2020-08-18 12:15:27 +02:00 committed by Timo
parent 27d35f5ab4
commit e457e19088
No known key found for this signature in database
GPG Key ID: 24DA7517711A2BA4
7 changed files with 193 additions and 17 deletions

13
Cargo.lock generated
View File

@ -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",

View File

@ -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

View File

@ -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::*;

View 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())
}

View File

@ -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")?,

View File

@ -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

View File

@ -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,