use super::State; use crate::{pdu::PduBuilder, ConduitResult, Database, Error, Ruma}; use ruma::{ api::client::{ error::ErrorKind, r0::message::{get_message_events, send_message_event}, }, events::EventContent, }; use std::convert::TryInto; #[cfg(feature = "conduit_bin")] use rocket::{get, put}; #[cfg_attr( feature = "conduit_bin", put("/_matrix/client/r0/rooms/<_>/send/<_>/<_>", data = "") )] pub fn send_message_event_route( db: State<'_, Database>, body: Ruma, ) -> ConduitResult { let sender_id = body.sender_id.as_ref().expect("user is authenticated"); let mut unsigned = serde_json::Map::new(); unsigned.insert("transaction_id".to_owned(), body.txn_id.clone().into()); let event_id = db.rooms.build_and_append_pdu( PduBuilder { room_id: body.room_id.clone(), sender: sender_id.clone(), event_type: body.content.event_type().into(), content: serde_json::from_str( body.json_body .ok_or(Error::BadRequest(ErrorKind::BadJson, "Invalid JSON body."))? .get(), ) .map_err(|_| Error::BadRequest(ErrorKind::BadJson, "Invalid JSON body."))?, unsigned: Some(unsigned), state_key: None, redacts: None, }, &db.globals, &db.account_data, )?; Ok(send_message_event::Response::new(event_id).into()) } #[cfg_attr( feature = "conduit_bin", get("/_matrix/client/r0/rooms/<_>/messages", data = "") )] pub fn get_message_events_route( db: State<'_, Database>, body: Ruma, ) -> ConduitResult { let sender_id = body.sender_id.as_ref().expect("user is authenticated"); if !db.rooms.is_joined(sender_id, &body.room_id)? { return Err(Error::BadRequest( ErrorKind::Forbidden, "You don't have permission to view this room.", )); } let from = body .from .clone() .parse() .map_err(|_| Error::BadRequest(ErrorKind::InvalidParam, "Invalid `from` value."))?; let to = body.to.as_ref().map(|t| t.parse()); // Use limit or else 10 let limit = body .limit .try_into() .map_or(Ok::<_, Error>(10_usize), |l: u32| Ok(l as usize))?; match body.dir { get_message_events::Direction::Forward => { let events_after = db .rooms .pdus_after(&sender_id, &body.room_id, from) .take(limit) .filter_map(|r| r.ok()) // Filter out buggy events .take_while(|&(k, _)| Some(Ok(k)) != to) // Stop at `to` .collect::>(); let end_token = events_after.last().map(|(count, _)| count.to_string()); let events_after = events_after .into_iter() .map(|(_, pdu)| pdu.to_room_event()) .collect::>(); let mut resp = get_message_events::Response::new(); resp.start = Some(body.from.clone()); resp.end = end_token; resp.chunk = events_after; resp.state = Vec::new(); Ok(resp.into()) } get_message_events::Direction::Backward => { let events_before = db .rooms .pdus_until(&sender_id, &body.room_id, from) .take(limit) .filter_map(|r| r.ok()) // Filter out buggy events .take_while(|&(k, _)| Some(Ok(k)) != to) // Stop at `to` .collect::>(); let start_token = events_before.last().map(|(count, _)| count.to_string()); let events_before = events_before .into_iter() .map(|(_, pdu)| pdu.to_room_event()) .collect::>(); let mut resp = get_message_events::Response::new(); resp.start = Some(body.from.clone()); resp.end = start_token; resp.chunk = events_before; resp.state = Vec::new(); Ok(resp.into()) } } }