state_store: add Path to StateStore methods, remove associated Error type
parent
1f173b4919
commit
267453de4d
|
@ -13,13 +13,13 @@ struct CommandBot {
|
||||||
/// This clone of the `AsyncClient` will send requests to the server,
|
/// This clone of the `AsyncClient` will send requests to the server,
|
||||||
/// while the other keeps us in sync with the server using `sync_forever`.
|
/// while the other keeps us in sync with the server using `sync_forever`.
|
||||||
///
|
///
|
||||||
/// The two type parameters are for the `StateStore` trait and specify the `Store`
|
/// The type parameter is for the `StateStore` trait specifying the `Store`
|
||||||
/// type and `IoError` type to use, here we don't care.
|
/// type for state storage, here we don't care.
|
||||||
client: AsyncClient<(), ()>,
|
client: AsyncClient<()>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CommandBot {
|
impl CommandBot {
|
||||||
pub fn new(client: AsyncClient<(), ()>) -> Self {
|
pub fn new(client: AsyncClient<()>) -> Self {
|
||||||
Self { client }
|
Self { client }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,7 +46,7 @@ async fn login(
|
||||||
.disable_ssl_verification();
|
.disable_ssl_verification();
|
||||||
let homeserver_url = Url::parse(&homeserver_url)?;
|
let homeserver_url = Url::parse(&homeserver_url)?;
|
||||||
let mut client =
|
let mut client =
|
||||||
AsyncClient::<(), ()>::new_with_config(homeserver_url, None, client_config).unwrap();
|
AsyncClient::<()>::new_with_config(homeserver_url, None, client_config).unwrap();
|
||||||
|
|
||||||
client.add_event_emitter(Box::new(EventCallback)).await;
|
client.add_event_emitter(Box::new(EventCallback)).await;
|
||||||
|
|
||||||
|
|
|
@ -55,16 +55,16 @@ const DEFAULT_SYNC_TIMEOUT: Duration = Duration::from_secs(30);
|
||||||
/// An async/await enabled Matrix client.
|
/// An async/await enabled Matrix client.
|
||||||
///
|
///
|
||||||
/// All of the state is held in an `Arc` so the `AsyncClient` can be cloned freely.
|
/// All of the state is held in an `Arc` so the `AsyncClient` can be cloned freely.
|
||||||
pub struct AsyncClient<State, E> {
|
pub struct AsyncClient<State> {
|
||||||
/// The URL of the homeserver to connect to.
|
/// The URL of the homeserver to connect to.
|
||||||
homeserver: Url,
|
homeserver: Url,
|
||||||
/// The underlying HTTP client.
|
/// The underlying HTTP client.
|
||||||
http_client: reqwest::Client,
|
http_client: reqwest::Client,
|
||||||
/// User session data.
|
/// User session data.
|
||||||
pub(crate) base_client: Arc<RwLock<BaseClient<State, E>>>,
|
pub(crate) base_client: Arc<RwLock<BaseClient<State>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<State, E> std::fmt::Debug for AsyncClient<State, E> {
|
impl<State> std::fmt::Debug for AsyncClient<State> {
|
||||||
fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> StdResult<(), std::fmt::Error> {
|
fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> StdResult<(), std::fmt::Error> {
|
||||||
write!(fmt, "AsyncClient {{ homeserver: {} }}", self.homeserver)
|
write!(fmt, "AsyncClient {{ homeserver: {} }}", self.homeserver)
|
||||||
}
|
}
|
||||||
|
@ -197,7 +197,7 @@ use api::r0::room::create_room;
|
||||||
use api::r0::session::login;
|
use api::r0::session::login;
|
||||||
use api::r0::sync::sync_events;
|
use api::r0::sync::sync_events;
|
||||||
|
|
||||||
impl<State, E> AsyncClient<State, E> {
|
impl<State> AsyncClient<State> {
|
||||||
/// Creates a new client for making HTTP requests to the given homeserver.
|
/// Creates a new client for making HTTP requests to the given homeserver.
|
||||||
///
|
///
|
||||||
/// # Arguments
|
/// # Arguments
|
||||||
|
@ -1119,7 +1119,7 @@ mod test {
|
||||||
device_id: "DEVICEID".to_owned(),
|
device_id: "DEVICEID".to_owned(),
|
||||||
};
|
};
|
||||||
let homeserver = url::Url::parse(&mockito::server_url()).unwrap();
|
let homeserver = url::Url::parse(&mockito::server_url()).unwrap();
|
||||||
let client = AsyncClient::<(), ()>::new(homeserver, Some(session)).unwrap();
|
let client = AsyncClient::<()>::new(homeserver, Some(session)).unwrap();
|
||||||
|
|
||||||
let rid = RoomId::try_from("!roomid:room.com").unwrap();
|
let rid = RoomId::try_from("!roomid:room.com").unwrap();
|
||||||
let uid = UserId::try_from("@example:localhost").unwrap();
|
let uid = UserId::try_from("@example:localhost").unwrap();
|
||||||
|
@ -1151,7 +1151,7 @@ mod test {
|
||||||
};
|
};
|
||||||
|
|
||||||
let homeserver = url::Url::parse(&mockito::server_url()).unwrap();
|
let homeserver = url::Url::parse(&mockito::server_url()).unwrap();
|
||||||
let client = AsyncClient::<(), ()>::new(homeserver, Some(session)).unwrap();
|
let client = AsyncClient::<()>::new(homeserver, Some(session)).unwrap();
|
||||||
|
|
||||||
let mut bld = EventBuilder::default()
|
let mut bld = EventBuilder::default()
|
||||||
.add_room_event_from_file("./tests/data/events/member.json", RoomEvent::RoomMember)
|
.add_room_event_from_file("./tests/data/events/member.json", RoomEvent::RoomMember)
|
||||||
|
@ -1181,7 +1181,7 @@ mod test {
|
||||||
.with_body_from_file("tests/data/login_response_error.json")
|
.with_body_from_file("tests/data/login_response_error.json")
|
||||||
.create();
|
.create();
|
||||||
|
|
||||||
let client = AsyncClient::<(), ()>::new(homeserver, None).unwrap();
|
let client = AsyncClient::<()>::new(homeserver, None).unwrap();
|
||||||
|
|
||||||
if let Err(err) = client.login("example", "wordpass", None, None).await {
|
if let Err(err) = client.login("example", "wordpass", None, None).await {
|
||||||
if let crate::Error::RumaResponse(ruma_api::error::FromHttpResponseError::Http(
|
if let crate::Error::RumaResponse(ruma_api::error::FromHttpResponseError::Http(
|
||||||
|
|
|
@ -61,7 +61,7 @@ pub type Token = String;
|
||||||
///
|
///
|
||||||
/// This Client is a state machine that receives responses and events and
|
/// This Client is a state machine that receives responses and events and
|
||||||
/// accordingly updates it's state.
|
/// accordingly updates it's state.
|
||||||
pub struct Client<S, E> {
|
pub struct Client<S> {
|
||||||
/// The current client session containing our user id, device id and access
|
/// The current client session containing our user id, device id and access
|
||||||
/// token.
|
/// token.
|
||||||
pub session: Option<Session>,
|
pub session: Option<Session>,
|
||||||
|
@ -77,13 +77,13 @@ pub struct Client<S, E> {
|
||||||
/// events.
|
/// events.
|
||||||
pub event_emitter: Option<Box<dyn EventEmitter>>,
|
pub event_emitter: Option<Box<dyn EventEmitter>>,
|
||||||
///
|
///
|
||||||
pub state_store: Option<Box<dyn StateStore<Store = S, IoError = E>>>,
|
pub state_store: Option<Box<dyn StateStore<Store = S>>>,
|
||||||
|
|
||||||
#[cfg(feature = "encryption")]
|
#[cfg(feature = "encryption")]
|
||||||
olm: Arc<Mutex<Option<OlmMachine>>>,
|
olm: Arc<Mutex<Option<OlmMachine>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S, E> fmt::Debug for Client<S, E> {
|
impl<S> fmt::Debug for Client<S> {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
f.debug_struct("Client")
|
f.debug_struct("Client")
|
||||||
.field("session", &self.session)
|
.field("session", &self.session)
|
||||||
|
@ -96,7 +96,7 @@ impl<S, E> fmt::Debug for Client<S, E> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S, E> Client<S, E> {
|
impl<S> Client<S> {
|
||||||
/// Create a new client.
|
/// Create a new client.
|
||||||
///
|
///
|
||||||
/// # Arguments
|
/// # Arguments
|
||||||
|
@ -815,7 +815,7 @@ mod test {
|
||||||
.with_body_from_file("tests/data/sync.json")
|
.with_body_from_file("tests/data/sync.json")
|
||||||
.create();
|
.create();
|
||||||
|
|
||||||
let client = AsyncClient::<(), ()>::new(homeserver, Some(session)).unwrap();
|
let client = AsyncClient::<()>::new(homeserver, Some(session)).unwrap();
|
||||||
|
|
||||||
let sync_settings = SyncSettings::new().timeout(Duration::from_millis(3000));
|
let sync_settings = SyncSettings::new().timeout(Duration::from_millis(3000));
|
||||||
|
|
||||||
|
|
|
@ -238,7 +238,7 @@ mod test {
|
||||||
let vec = Arc::new(Mutex::new(Vec::new()));
|
let vec = Arc::new(Mutex::new(Vec::new()));
|
||||||
let test_vec = Arc::clone(&vec);
|
let test_vec = Arc::clone(&vec);
|
||||||
let emitter = Box::new(EvEmitterTest(vec)) as Box<(dyn EventEmitter)>;
|
let emitter = Box::new(EvEmitterTest(vec)) as Box<(dyn EventEmitter)>;
|
||||||
let mut client = AsyncClient::<(), ()>::new(homeserver, Some(session)).unwrap();
|
let mut client = AsyncClient::<()>::new(homeserver, Some(session)).unwrap();
|
||||||
client.add_event_emitter(emitter).await;
|
client.add_event_emitter(emitter).await;
|
||||||
|
|
||||||
let sync_settings = SyncSettings::new().timeout(Duration::from_millis(3000));
|
let sync_settings = SyncSettings::new().timeout(Duration::from_millis(3000));
|
||||||
|
|
|
@ -439,7 +439,7 @@ mod test {
|
||||||
.with_body_from_file("tests/data/sync.json")
|
.with_body_from_file("tests/data/sync.json")
|
||||||
.create();
|
.create();
|
||||||
|
|
||||||
let client = AsyncClient::<(), ()>::new(homeserver, Some(session)).unwrap();
|
let client = AsyncClient::<()>::new(homeserver, Some(session)).unwrap();
|
||||||
|
|
||||||
let sync_settings = SyncSettings::new().timeout(Duration::from_millis(3000));
|
let sync_settings = SyncSettings::new().timeout(Duration::from_millis(3000));
|
||||||
|
|
||||||
|
|
|
@ -67,7 +67,7 @@ pub struct RoomMember {
|
||||||
|
|
||||||
impl PartialEq for RoomMember {
|
impl PartialEq for RoomMember {
|
||||||
fn eq(&self, other: &RoomMember) -> bool {
|
fn eq(&self, other: &RoomMember) -> bool {
|
||||||
// TODO check everything but events and presence_events they don;t impl PartialEq
|
// TODO check everything but events and presence_events they don't impl PartialEq
|
||||||
self.room_id == other.room_id
|
self.room_id == other.room_id
|
||||||
&& self.user_id == other.user_id
|
&& self.user_id == other.user_id
|
||||||
&& self.name == other.name
|
&& self.name == other.name
|
||||||
|
|
|
@ -341,7 +341,7 @@ mod test {
|
||||||
.room_alias_name("room_alias")
|
.room_alias_name("room_alias")
|
||||||
.topic("room topic")
|
.topic("room topic")
|
||||||
.visibility(Visibility::Private);
|
.visibility(Visibility::Private);
|
||||||
let cli = AsyncClient::<(), ()>::new(homeserver, Some(session)).unwrap();
|
let cli = AsyncClient::<()>::new(homeserver, Some(session)).unwrap();
|
||||||
assert!(cli.create_room(builder).await.is_ok());
|
assert!(cli.create_room(builder).await.is_ok());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -373,7 +373,7 @@ mod test {
|
||||||
// TODO this makes ruma error `Err(IntoHttp(IntoHttpError(Query(Custom("unsupported value")))))`??
|
// TODO this makes ruma error `Err(IntoHttp(IntoHttpError(Query(Custom("unsupported value")))))`??
|
||||||
// .filter(RoomEventFilter::default());
|
// .filter(RoomEventFilter::default());
|
||||||
|
|
||||||
let cli = AsyncClient::<(), ()>::new(homeserver, Some(session)).unwrap();
|
let cli = AsyncClient::<()>::new(homeserver, Some(session)).unwrap();
|
||||||
assert!(cli.room_messages(builder).await.is_ok());
|
assert!(cli.room_messages(builder).await.is_ok());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,7 +26,7 @@ use crate::events::push_rules::Ruleset;
|
||||||
use crate::identifiers::{RoomId, UserId};
|
use crate::identifiers::{RoomId, UserId};
|
||||||
use crate::models::Room;
|
use crate::models::Room;
|
||||||
use crate::session::Session;
|
use crate::session::Session;
|
||||||
|
use crate::Result;
|
||||||
#[derive(Debug, Default, PartialEq, Serialize, Deserialize)]
|
#[derive(Debug, Default, PartialEq, Serialize, Deserialize)]
|
||||||
pub struct ClientState {
|
pub struct ClientState {
|
||||||
/// The current client session containing our user id, device id and access
|
/// The current client session containing our user id, device id and access
|
||||||
|
@ -46,23 +46,20 @@ pub trait StateStore: Send + Sync {
|
||||||
/// to serialize and deserialize state to JSON files.
|
/// to serialize and deserialize state to JSON files.
|
||||||
type Store;
|
type Store;
|
||||||
|
|
||||||
/// The error type to return.
|
|
||||||
type IoError;
|
|
||||||
|
|
||||||
/// Set up connections or open files to load/save state.
|
/// Set up connections or open files to load/save state.
|
||||||
fn open(&self, path: &Path) -> Result<(), Self::IoError>;
|
fn open(&self, path: &Path) -> Result<()>;
|
||||||
/// Loads the state of `BaseClient` through `StateStore::Store` type.
|
/// Loads the state of `BaseClient` through `StateStore::Store` type.
|
||||||
fn load_client_state(&self) -> Result<Self::Store, Self::IoError>;
|
fn load_client_state(&self, path: &Path) -> Result<Self::Store>;
|
||||||
/// Load the state of a single `Room` by `RoomId`.
|
/// Load the state of a single `Room` by `RoomId`.
|
||||||
fn load_room_state(&self, room_id: &RoomId) -> Result<Room, Self::IoError>;
|
fn load_room_state(&self, path: &Path, room_id: &RoomId) -> Result<Room>;
|
||||||
/// Load the state of all `Room`s.
|
/// Load the state of all `Room`s.
|
||||||
///
|
///
|
||||||
/// This will be mapped over in the client in order to store `Room`s in an async safe way.
|
/// This will be mapped over in the client in order to store `Room`s in an async safe way.
|
||||||
fn load_all_rooms(&self) -> Result<HashMap<RoomId, Room>, Self::IoError>;
|
fn load_all_rooms(&self, path: &Path) -> Result<HashMap<RoomId, Room>>;
|
||||||
/// Save the current state of the `BaseClient` using the `StateStore::Store` type.
|
/// Save the current state of the `BaseClient` using the `StateStore::Store` type.
|
||||||
fn store_client_state(&self, _: Self::Store) -> Result<(), Self::IoError>;
|
fn store_client_state(&self, path: &Path, _: Self::Store) -> Result<()>;
|
||||||
/// Save the state a single `Room`.
|
/// Save the state a single `Room`.
|
||||||
fn store_room_state(&self, _: &Room) -> Result<(), Self::IoError>;
|
fn store_room_state(&self, path: &Path, _: &Room) -> Result<()>;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::fs::{self, OpenOptions};
|
use std::fs::{self, OpenOptions};
|
||||||
use std::io::{BufReader, BufWriter, Write};
|
use std::io::{BufReader, BufWriter, Write};
|
||||||
use std::path::Path;
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
use super::{ClientState, StateStore};
|
use super::{ClientState, StateStore};
|
||||||
use crate::identifiers::RoomId;
|
use crate::identifiers::RoomId;
|
||||||
|
@ -11,7 +11,6 @@ use crate::{Error, Result, Room};
|
||||||
pub struct JsonStore;
|
pub struct JsonStore;
|
||||||
|
|
||||||
impl StateStore for JsonStore {
|
impl StateStore for JsonStore {
|
||||||
type IoError = Error;
|
|
||||||
type Store = ClientState;
|
type Store = ClientState;
|
||||||
|
|
||||||
fn open(&self, path: &Path) -> Result<()> {
|
fn open(&self, path: &Path) -> Result<()> {
|
||||||
|
@ -20,98 +19,84 @@ impl StateStore for JsonStore {
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
fn load_client_state(&self) -> Result<ClientState> {
|
fn load_client_state(&self, path: &Path) -> Result<ClientState> {
|
||||||
if let Some(mut path) = dirs::home_dir() {
|
let mut path = path.to_path_buf();
|
||||||
path.push(".matrix_store/client.json");
|
path.push("client.json");
|
||||||
let file = OpenOptions::new().read(true).open(path)?;
|
|
||||||
let reader = BufReader::new(file);
|
let file = OpenOptions::new().read(true).open(path)?;
|
||||||
serde_json::from_reader(reader).map_err(Error::from)
|
let reader = BufReader::new(file);
|
||||||
} else {
|
serde_json::from_reader(reader).map_err(Error::from)
|
||||||
todo!("Error maybe")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load_room_state(&self, room_id: &RoomId) -> Result<Room> {
|
fn load_room_state(&self, path: &Path, room_id: &RoomId) -> Result<Room> {
|
||||||
if let Some(mut path) = dirs::home_dir() {
|
let mut path = path.to_path_buf();
|
||||||
path.push(&format!(".matrix_store/rooms/{}.json", room_id));
|
path.push(&format!("rooms/{}.json", room_id));
|
||||||
|
|
||||||
let file = OpenOptions::new().read(true).open(path)?;
|
let file = OpenOptions::new().read(true).open(path)?;
|
||||||
let reader = BufReader::new(file);
|
let reader = BufReader::new(file);
|
||||||
serde_json::from_reader(reader).map_err(Error::from)
|
serde_json::from_reader(reader).map_err(Error::from)
|
||||||
} else {
|
|
||||||
todo!("Error maybe")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load_all_rooms(&self) -> Result<HashMap<RoomId, Room>> {
|
fn load_all_rooms(&self, path: &Path) -> Result<HashMap<RoomId, Room>> {
|
||||||
if let Some(mut path) = dirs::home_dir() {
|
let mut path = path.to_path_buf();
|
||||||
path.push(".matrix_store/rooms/");
|
path.push("rooms");
|
||||||
|
|
||||||
let mut rooms_map = HashMap::new();
|
let mut rooms_map = HashMap::new();
|
||||||
for file in fs::read_dir(&path)? {
|
for file in fs::read_dir(&path)? {
|
||||||
let file = file?.path();
|
let file = file?.path();
|
||||||
|
|
||||||
if file.is_dir() {
|
if file.is_dir() {
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
|
|
||||||
let f_hdl = OpenOptions::new().read(true).open(&file)?;
|
|
||||||
let reader = BufReader::new(f_hdl);
|
|
||||||
|
|
||||||
let room = serde_json::from_reader::<_, Room>(reader).map_err(Error::from)?;
|
|
||||||
let room_id = room.room_id.clone();
|
|
||||||
|
|
||||||
rooms_map.insert(room_id, room);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(rooms_map)
|
let f_hdl = OpenOptions::new().read(true).open(&file)?;
|
||||||
} else {
|
let reader = BufReader::new(f_hdl);
|
||||||
todo!("Error maybe")
|
|
||||||
|
let room = serde_json::from_reader::<_, Room>(reader).map_err(Error::from)?;
|
||||||
|
let room_id = room.room_id.clone();
|
||||||
|
|
||||||
|
rooms_map.insert(room_id, room);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Ok(rooms_map)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn store_client_state(&self, state: ClientState) -> Result<()> {
|
fn store_client_state(&self, path: &Path, state: ClientState) -> Result<()> {
|
||||||
if let Some(mut path) = dirs::home_dir() {
|
let mut path = path.to_path_buf();
|
||||||
path.push(".matrix_store/client.json");
|
path.push("client.json");
|
||||||
|
|
||||||
if !Path::new(&path).exists() {
|
if !Path::new(&path).exists() {
|
||||||
let mut dir = path.clone();
|
let mut dir = path.clone();
|
||||||
dir.pop();
|
dir.pop();
|
||||||
std::fs::create_dir_all(dir)?;
|
std::fs::create_dir_all(dir)?;
|
||||||
}
|
|
||||||
|
|
||||||
let json = serde_json::to_string(&state).map_err(Error::from)?;
|
|
||||||
|
|
||||||
let file = OpenOptions::new().write(true).create(true).open(path)?;
|
|
||||||
let mut writer = BufWriter::new(file);
|
|
||||||
writer.write_all(json.as_bytes())?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
} else {
|
|
||||||
todo!("Error maybe")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let json = serde_json::to_string(&state).map_err(Error::from)?;
|
||||||
|
|
||||||
|
let file = OpenOptions::new().write(true).create(true).open(path)?;
|
||||||
|
let mut writer = BufWriter::new(file);
|
||||||
|
writer.write_all(json.as_bytes())?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn store_room_state(&self, room: &Room) -> Result<()> {
|
fn store_room_state(&self, path: &Path, room: &Room) -> Result<()> {
|
||||||
if let Some(mut path) = dirs::home_dir() {
|
let mut path = path.to_path_buf();
|
||||||
path.push(&format!(".matrix_store/rooms/{}.json", room.room_id));
|
path.push(&format!("rooms/{}.json", room.room_id));
|
||||||
|
|
||||||
if !Path::new(&path).exists() {
|
if !Path::new(&path).exists() {
|
||||||
let mut dir = path.clone();
|
let mut dir = path.clone();
|
||||||
dir.pop();
|
dir.pop();
|
||||||
std::fs::create_dir_all(dir)?;
|
std::fs::create_dir_all(dir)?;
|
||||||
}
|
|
||||||
|
|
||||||
let json = serde_json::to_string(&room).map_err(Error::from)?;
|
|
||||||
|
|
||||||
let file = OpenOptions::new().write(true).create(true).open(path)?;
|
|
||||||
let mut writer = BufWriter::new(file);
|
|
||||||
writer.write_all(json.as_bytes())?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
} else {
|
|
||||||
todo!("Error maybe")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let json = serde_json::to_string(&room).map_err(Error::from)?;
|
||||||
|
|
||||||
|
let file = OpenOptions::new().write(true).create(true).open(path)?;
|
||||||
|
let mut writer = BufWriter::new(file);
|
||||||
|
writer.write_all(json.as_bytes())?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -132,15 +117,22 @@ mod test {
|
||||||
pub static ref MTX: Mutex<()> = Mutex::new(());
|
pub static ref MTX: Mutex<()> = Mutex::new(());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
lazy_static! {
|
||||||
|
/// Limit io tests to one thread at a time.
|
||||||
|
pub static ref PATH: PathBuf = {
|
||||||
|
let mut path = dirs::home_dir().unwrap();
|
||||||
|
path.push(".matrix_store");
|
||||||
|
path
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
fn run_and_cleanup(test: fn()) {
|
fn run_and_cleanup(test: fn()) {
|
||||||
let _lock = MTX.lock();
|
let _lock = MTX.lock();
|
||||||
|
|
||||||
test();
|
test();
|
||||||
|
|
||||||
let mut path = dirs::home_dir().unwrap();
|
if PATH.exists() {
|
||||||
path.push(".matrix_store");
|
let path: &Path = &PATH;
|
||||||
|
|
||||||
if path.exists() {
|
|
||||||
fs::remove_dir_all(path).unwrap();
|
fs::remove_dir_all(path).unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -148,8 +140,8 @@ mod test {
|
||||||
fn test_store_client_state() {
|
fn test_store_client_state() {
|
||||||
let store = JsonStore;
|
let store = JsonStore;
|
||||||
let state = ClientState::default();
|
let state = ClientState::default();
|
||||||
store.store_client_state(state).unwrap();
|
store.store_client_state(&PATH, state).unwrap();
|
||||||
let loaded = store.load_client_state().unwrap();
|
let loaded = store.load_client_state(&PATH).unwrap();
|
||||||
assert_eq!(loaded, ClientState::default());
|
assert_eq!(loaded, ClientState::default());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -165,8 +157,8 @@ mod test {
|
||||||
let user = UserId::try_from("@example:example.com").unwrap();
|
let user = UserId::try_from("@example:example.com").unwrap();
|
||||||
|
|
||||||
let room = Room::new(&id, &user);
|
let room = Room::new(&id, &user);
|
||||||
store.store_room_state(&room).unwrap();
|
store.store_room_state(&PATH, &room).unwrap();
|
||||||
let loaded = store.load_room_state(&id).unwrap();
|
let loaded = store.load_room_state(&PATH, &id).unwrap();
|
||||||
assert_eq!(loaded, Room::new(&id, &user));
|
assert_eq!(loaded, Room::new(&id, &user));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -182,8 +174,8 @@ mod test {
|
||||||
let user = UserId::try_from("@example:example.com").unwrap();
|
let user = UserId::try_from("@example:example.com").unwrap();
|
||||||
|
|
||||||
let room = Room::new(&id, &user);
|
let room = Room::new(&id, &user);
|
||||||
store.store_room_state(&room).unwrap();
|
store.store_room_state(&PATH, &room).unwrap();
|
||||||
let loaded = store.load_all_rooms().unwrap();
|
let loaded = store.load_all_rooms(&PATH).unwrap();
|
||||||
println!("{:?}", loaded);
|
println!("{:?}", loaded);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -49,9 +49,9 @@ pub struct RoomTestRunner {
|
||||||
state_events: Vec<StateEvent>,
|
state_events: Vec<StateEvent>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ClientTestRunner<S, E> {
|
pub struct ClientTestRunner<S> {
|
||||||
/// Used when testing the whole client
|
/// Used when testing the whole client
|
||||||
client: Option<AsyncClient<S, E>>,
|
client: Option<AsyncClient<S>>,
|
||||||
/// RoomId and UserId to use for the events.
|
/// RoomId and UserId to use for the events.
|
||||||
///
|
///
|
||||||
/// The RoomId must match the RoomId of the events to track.
|
/// The RoomId must match the RoomId of the events to track.
|
||||||
|
@ -69,9 +69,9 @@ pub struct ClientTestRunner<S, E> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub struct MockTestRunner<S, E> {
|
pub struct MockTestRunner<S> {
|
||||||
/// Used when testing the whole client
|
/// Used when testing the whole client
|
||||||
client: Option<AsyncClient<S, E>>,
|
client: Option<AsyncClient<S>>,
|
||||||
/// The ephemeral room events that determine the state of a `Room`.
|
/// The ephemeral room events that determine the state of a `Room`.
|
||||||
ephemeral: Vec<Event>,
|
ephemeral: Vec<Event>,
|
||||||
/// The account data events that determine the state of a `Room`.
|
/// The account data events that determine the state of a `Room`.
|
||||||
|
@ -169,11 +169,11 @@ impl EventBuilder {
|
||||||
///
|
///
|
||||||
/// The `TestRunner` streams the events to the client and holds methods to make assertions
|
/// The `TestRunner` streams the events to the client and holds methods to make assertions
|
||||||
/// about the state of the client.
|
/// about the state of the client.
|
||||||
pub fn build_mock_runner<S, E, P: Into<mockito::Matcher>>(
|
pub fn build_mock_runner<S, P: Into<mockito::Matcher>>(
|
||||||
mut self,
|
mut self,
|
||||||
method: &str,
|
method: &str,
|
||||||
path: P,
|
path: P,
|
||||||
) -> MockTestRunner<S, E> {
|
) -> MockTestRunner<S> {
|
||||||
let body = serde_json::json! {
|
let body = serde_json::json! {
|
||||||
{
|
{
|
||||||
"device_one_time_keys_count": {},
|
"device_one_time_keys_count": {},
|
||||||
|
@ -238,11 +238,7 @@ impl EventBuilder {
|
||||||
///
|
///
|
||||||
/// The `TestRunner` streams the events to the `AsyncClient` and holds methods to make assertions
|
/// The `TestRunner` streams the events to the `AsyncClient` and holds methods to make assertions
|
||||||
/// about the state of the `AsyncClient`.
|
/// about the state of the `AsyncClient`.
|
||||||
pub fn build_client_runner<S, E>(
|
pub fn build_client_runner<S>(self, room_id: RoomId, user_id: UserId) -> ClientTestRunner<S> {
|
||||||
self,
|
|
||||||
room_id: RoomId,
|
|
||||||
user_id: UserId,
|
|
||||||
) -> ClientTestRunner<S, E> {
|
|
||||||
ClientTestRunner {
|
ClientTestRunner {
|
||||||
client: None,
|
client: None,
|
||||||
room_user_id: (room_id, user_id),
|
room_user_id: (room_id, user_id),
|
||||||
|
@ -317,8 +313,8 @@ impl RoomTestRunner {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S, E> ClientTestRunner<S, E> {
|
impl<S> ClientTestRunner<S> {
|
||||||
pub fn set_client(&mut self, client: AsyncClient<S, E>) -> &mut Self {
|
pub fn set_client(&mut self, client: AsyncClient<S>) -> &mut Self {
|
||||||
self.client = Some(client);
|
self.client = Some(client);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
@ -359,14 +355,14 @@ impl<S, E> ClientTestRunner<S, E> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn to_client(&mut self) -> &mut AsyncClient<S, E> {
|
pub async fn to_client(&mut self) -> &mut AsyncClient<S> {
|
||||||
self.stream_client_events().await;
|
self.stream_client_events().await;
|
||||||
self.client.as_mut().unwrap()
|
self.client.as_mut().unwrap()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S, E> MockTestRunner<S, E> {
|
impl<S> MockTestRunner<S> {
|
||||||
pub fn set_client(&mut self, client: AsyncClient<S, E>) -> &mut Self {
|
pub fn set_client(&mut self, client: AsyncClient<S>) -> &mut Self {
|
||||||
self.client = Some(client);
|
self.client = Some(client);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
@ -376,7 +372,7 @@ impl<S, E> MockTestRunner<S, E> {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn to_client(&mut self) -> Result<&mut AsyncClient<S, E>, crate::Error> {
|
pub async fn to_client(&mut self) -> Result<&mut AsyncClient<S>, crate::Error> {
|
||||||
self.client
|
self.client
|
||||||
.as_mut()
|
.as_mut()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
|
|
|
@ -17,7 +17,7 @@ async fn login() {
|
||||||
.with_body_from_file("tests/data/login_response.json")
|
.with_body_from_file("tests/data/login_response.json")
|
||||||
.create();
|
.create();
|
||||||
|
|
||||||
let client = AsyncClient::<(), ()>::new(homeserver, None).unwrap();
|
let client = AsyncClient::<()>::new(homeserver, None).unwrap();
|
||||||
|
|
||||||
client
|
client
|
||||||
.login("example", "wordpass", None, None)
|
.login("example", "wordpass", None, None)
|
||||||
|
@ -46,7 +46,7 @@ async fn sync() {
|
||||||
.with_body_from_file("tests/data/sync.json")
|
.with_body_from_file("tests/data/sync.json")
|
||||||
.create();
|
.create();
|
||||||
|
|
||||||
let client = AsyncClient::<(), ()>::new(homeserver, Some(session)).unwrap();
|
let client = AsyncClient::<()>::new(homeserver, Some(session)).unwrap();
|
||||||
|
|
||||||
let sync_settings = SyncSettings::new().timeout(Duration::from_millis(3000));
|
let sync_settings = SyncSettings::new().timeout(Duration::from_millis(3000));
|
||||||
|
|
||||||
|
@ -75,7 +75,7 @@ async fn room_names() {
|
||||||
.with_body_from_file("tests/data/sync.json")
|
.with_body_from_file("tests/data/sync.json")
|
||||||
.create();
|
.create();
|
||||||
|
|
||||||
let client = AsyncClient::<(), ()>::new(homeserver, Some(session)).unwrap();
|
let client = AsyncClient::<()>::new(homeserver, Some(session)).unwrap();
|
||||||
|
|
||||||
let sync_settings = SyncSettings::new().timeout(Duration::from_millis(3000));
|
let sync_settings = SyncSettings::new().timeout(Duration::from_millis(3000));
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue