feat: search pdus
parent
27d35f5ab4
commit
e457e19088
|
@ -1560,7 +1560,6 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ruma"
|
name = "ruma"
|
||||||
version = "0.0.1"
|
version = "0.0.1"
|
||||||
source = "git+https://github.com/timokoesters/ruma?branch=timo-fixes#7f8c78e8ba4be7fda450285e62493f6b33cb085a"
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ruma-api",
|
"ruma-api",
|
||||||
"ruma-client-api",
|
"ruma-client-api",
|
||||||
|
@ -1574,7 +1573,6 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ruma-api"
|
name = "ruma-api"
|
||||||
version = "0.17.0-alpha.1"
|
version = "0.17.0-alpha.1"
|
||||||
source = "git+https://github.com/timokoesters/ruma?branch=timo-fixes#7f8c78e8ba4be7fda450285e62493f6b33cb085a"
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"http",
|
"http",
|
||||||
"percent-encoding",
|
"percent-encoding",
|
||||||
|
@ -1589,7 +1587,6 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ruma-api-macros"
|
name = "ruma-api-macros"
|
||||||
version = "0.17.0-alpha.1"
|
version = "0.17.0-alpha.1"
|
||||||
source = "git+https://github.com/timokoesters/ruma?branch=timo-fixes#7f8c78e8ba4be7fda450285e62493f6b33cb085a"
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro-crate",
|
"proc-macro-crate",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
|
@ -1600,7 +1597,6 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ruma-client-api"
|
name = "ruma-client-api"
|
||||||
version = "0.10.0-alpha.1"
|
version = "0.10.0-alpha.1"
|
||||||
source = "git+https://github.com/timokoesters/ruma?branch=timo-fixes#7f8c78e8ba4be7fda450285e62493f6b33cb085a"
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"assign",
|
"assign",
|
||||||
"http",
|
"http",
|
||||||
|
@ -1618,7 +1614,6 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ruma-common"
|
name = "ruma-common"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
source = "git+https://github.com/timokoesters/ruma?branch=timo-fixes#7f8c78e8ba4be7fda450285e62493f6b33cb085a"
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"js_int",
|
"js_int",
|
||||||
"ruma-identifiers",
|
"ruma-identifiers",
|
||||||
|
@ -1631,7 +1626,6 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ruma-events"
|
name = "ruma-events"
|
||||||
version = "0.22.0-alpha.1"
|
version = "0.22.0-alpha.1"
|
||||||
source = "git+https://github.com/timokoesters/ruma?branch=timo-fixes#7f8c78e8ba4be7fda450285e62493f6b33cb085a"
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"js_int",
|
"js_int",
|
||||||
"ruma-common",
|
"ruma-common",
|
||||||
|
@ -1646,7 +1640,6 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ruma-events-macros"
|
name = "ruma-events-macros"
|
||||||
version = "0.22.0-alpha.1"
|
version = "0.22.0-alpha.1"
|
||||||
source = "git+https://github.com/timokoesters/ruma?branch=timo-fixes#7f8c78e8ba4be7fda450285e62493f6b33cb085a"
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro-crate",
|
"proc-macro-crate",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
|
@ -1657,7 +1650,6 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ruma-federation-api"
|
name = "ruma-federation-api"
|
||||||
version = "0.0.3"
|
version = "0.0.3"
|
||||||
source = "git+https://github.com/timokoesters/ruma?branch=timo-fixes#7f8c78e8ba4be7fda450285e62493f6b33cb085a"
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"js_int",
|
"js_int",
|
||||||
"ruma-api",
|
"ruma-api",
|
||||||
|
@ -1672,7 +1664,6 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ruma-identifiers"
|
name = "ruma-identifiers"
|
||||||
version = "0.17.4"
|
version = "0.17.4"
|
||||||
source = "git+https://github.com/timokoesters/ruma?branch=timo-fixes#7f8c78e8ba4be7fda450285e62493f6b33cb085a"
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"rand",
|
"rand",
|
||||||
"ruma-identifiers-macros",
|
"ruma-identifiers-macros",
|
||||||
|
@ -1684,7 +1675,6 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ruma-identifiers-macros"
|
name = "ruma-identifiers-macros"
|
||||||
version = "0.17.4"
|
version = "0.17.4"
|
||||||
source = "git+https://github.com/timokoesters/ruma?branch=timo-fixes#7f8c78e8ba4be7fda450285e62493f6b33cb085a"
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
|
@ -1695,7 +1685,6 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ruma-identifiers-validation"
|
name = "ruma-identifiers-validation"
|
||||||
version = "0.1.1"
|
version = "0.1.1"
|
||||||
source = "git+https://github.com/timokoesters/ruma?branch=timo-fixes#7f8c78e8ba4be7fda450285e62493f6b33cb085a"
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ruma-serde",
|
"ruma-serde",
|
||||||
"serde",
|
"serde",
|
||||||
|
@ -1706,7 +1695,6 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ruma-serde"
|
name = "ruma-serde"
|
||||||
version = "0.2.3"
|
version = "0.2.3"
|
||||||
source = "git+https://github.com/timokoesters/ruma?branch=timo-fixes#7f8c78e8ba4be7fda450285e62493f6b33cb085a"
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"form_urlencoded",
|
"form_urlencoded",
|
||||||
"itoa",
|
"itoa",
|
||||||
|
@ -1718,7 +1706,6 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ruma-signatures"
|
name = "ruma-signatures"
|
||||||
version = "0.6.0-dev.1"
|
version = "0.6.0-dev.1"
|
||||||
source = "git+https://github.com/timokoesters/ruma?branch=timo-fixes#7f8c78e8ba4be7fda450285e62493f6b33cb085a"
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"base64 0.12.3",
|
"base64 0.12.3",
|
||||||
"ring",
|
"ring",
|
||||||
|
|
|
@ -17,8 +17,8 @@ edition = "2018"
|
||||||
rocket = { git = "https://github.com/timokoesters/Rocket.git", branch = "empty_parameters", features = ["tls"] }
|
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/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 = { 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 = { path = "../ruma/ruma", features = ["rand", "client-api", "federation-api", "unstable-pre-spec", "unstable-synapse-quirks"] }
|
||||||
tokio = "0.2.22" # Used for long polling
|
tokio = "0.2.22" # Used for long polling
|
||||||
sled = "0.32.0" # Used for storing data permanently
|
sled = "0.32.0" # Used for storing data permanently
|
||||||
log = "0.4.8" # Used for emitting log entries
|
log = "0.4.8" # Used for emitting log entries
|
||||||
|
|
|
@ -17,6 +17,7 @@ mod push;
|
||||||
mod read_marker;
|
mod read_marker;
|
||||||
mod redact;
|
mod redact;
|
||||||
mod room;
|
mod room;
|
||||||
|
mod search;
|
||||||
mod session;
|
mod session;
|
||||||
mod state;
|
mod state;
|
||||||
mod sync;
|
mod sync;
|
||||||
|
@ -47,6 +48,7 @@ pub use push::*;
|
||||||
pub use read_marker::*;
|
pub use read_marker::*;
|
||||||
pub use redact::*;
|
pub use redact::*;
|
||||||
pub use room::*;
|
pub use room::*;
|
||||||
|
pub use search::*;
|
||||||
pub use session::*;
|
pub use session::*;
|
||||||
pub use state::*;
|
pub use state::*;
|
||||||
pub use sync::*;
|
pub use sync::*;
|
||||||
|
|
|
@ -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")?,
|
aliasid_alias: db.open_tree("alias_roomid")?,
|
||||||
publicroomids: db.open_tree("publicroomids")?,
|
publicroomids: db.open_tree("publicroomids")?,
|
||||||
|
|
||||||
|
tokenids: db.open_tree("tokenids")?,
|
||||||
|
|
||||||
userroomid_joined: db.open_tree("userroomid_joined")?,
|
userroomid_joined: db.open_tree("userroomid_joined")?,
|
||||||
roomuserid_joined: db.open_tree("roomuserid_joined")?,
|
roomuserid_joined: db.open_tree("roomuserid_joined")?,
|
||||||
userroomid_invited: db.open_tree("userroomid_invited")?,
|
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) aliasid_alias: sled::Tree, // AliasId = RoomId + Count
|
||||||
pub(super) publicroomids: sled::Tree,
|
pub(super) publicroomids: sled::Tree,
|
||||||
|
|
||||||
|
pub(super) tokenids: sled::Tree, // TokenId = RoomId + Token + PduId
|
||||||
|
|
||||||
pub(super) userroomid_joined: sled::Tree,
|
pub(super) userroomid_joined: sled::Tree,
|
||||||
pub(super) roomuserid_joined: sled::Tree,
|
pub(super) roomuserid_joined: sled::Tree,
|
||||||
pub(super) userroomid_invited: 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.pduid_pdu.insert(&pdu_id, &*pdu_json.to_string())?;
|
||||||
|
|
||||||
self.eventid_pduid
|
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 {
|
if let Some(state_key) = pdu.state_key {
|
||||||
let mut key = room_id.to_string().as_bytes().to_vec();
|
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())?;
|
self.roomstateid_pdu.insert(key, &*pdu_json.to_string())?;
|
||||||
}
|
}
|
||||||
|
|
||||||
match event_type {
|
match dbg!(event_type) {
|
||||||
EventType::RoomRedaction => {
|
EventType::RoomRedaction => {
|
||||||
if let Some(redact_id) = &redacts {
|
if let Some(redact_id) = &redacts {
|
||||||
// TODO: Reason
|
// 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)?;
|
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.
|
/// Returns an iterator over all joined members of a room.
|
||||||
pub fn room_members(&self, room_id: &RoomId) -> impl Iterator<Item = Result<UserId>> {
|
pub fn room_members(&self, room_id: &RoomId) -> impl Iterator<Item = Result<UserId>> {
|
||||||
self.roomuserid_joined
|
self.roomuserid_joined
|
||||||
|
|
|
@ -90,6 +90,7 @@ fn setup_rocket() -> rocket::Rocket {
|
||||||
client_server::sync_events_route,
|
client_server::sync_events_route,
|
||||||
client_server::get_context_route,
|
client_server::get_context_route,
|
||||||
client_server::get_message_events_route,
|
client_server::get_message_events_route,
|
||||||
|
client_server::search_events_route,
|
||||||
client_server::turn_server_route,
|
client_server::turn_server_route,
|
||||||
client_server::send_event_to_device_route,
|
client_server::send_event_to_device_route,
|
||||||
client_server::get_media_config_route,
|
client_server::get_media_config_route,
|
||||||
|
|
Loading…
Reference in New Issue