state_store: add associated store and error type, custom deserialization for ruma event types

master
Devin R 2020-04-18 18:06:30 -04:00
parent d000996205
commit 9fb4bd9d19
14 changed files with 142 additions and 50 deletions

View File

@ -12,11 +12,14 @@ use url::Url;
struct CommandBot { 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`.
client: AsyncClient, ///
/// The two type parameters are for the `StateStore` trait and specify the `Store`
/// type and `IoError` type to use, here we don't care.
client: AsyncClient<(), ()>,
} }
impl CommandBot { impl CommandBot {
pub fn new(client: AsyncClient) -> Self { pub fn new(client: AsyncClient<(), ()>) -> Self {
Self { client } Self { client }
} }
} }

View File

@ -45,7 +45,8 @@ async fn login(
.proxy("http://localhost:8080")? .proxy("http://localhost:8080")?
.disable_ssl_verification(); .disable_ssl_verification();
let homeserver_url = Url::parse(&homeserver_url)?; let homeserver_url = Url::parse(&homeserver_url)?;
let mut client = AsyncClient::new_with_config(homeserver_url, None, client_config).unwrap(); let mut client =
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;

View File

@ -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 { pub struct AsyncClient<State, E> {
/// 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>>, pub(crate) base_client: Arc<RwLock<BaseClient<State, E>>>,
} }
impl std::fmt::Debug for AsyncClient { impl<State, E> std::fmt::Debug for AsyncClient<State, E> {
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 AsyncClient { impl<State, E> AsyncClient<State, E> {
/// 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
@ -485,7 +485,7 @@ impl AsyncClient {
/// .name("name") /// .name("name")
/// .room_version("v1.0"); /// .room_version("v1.0");
/// ///
/// let mut cli = AsyncClient::new(homeserver, None).unwrap(); /// let mut cli = AsyncClient::<(), ()>::new(homeserver, None).unwrap();
/// # use futures::executor::block_on; /// # use futures::executor::block_on;
/// # block_on(async { /// # block_on(async {
/// assert!(cli.create_room(builder).await.is_ok()); /// assert!(cli.create_room(builder).await.is_ok());
@ -529,7 +529,7 @@ impl AsyncClient {
/// .direction(Direction::Backward) /// .direction(Direction::Backward)
/// .limit(UInt::new(10).unwrap()); /// .limit(UInt::new(10).unwrap());
/// ///
/// let mut cli = AsyncClient::new(homeserver, None).unwrap(); /// let mut cli = AsyncClient::<(), ()>::new(homeserver, None).unwrap();
/// # use futures::executor::block_on; /// # use futures::executor::block_on;
/// # block_on(async { /// # block_on(async {
/// assert!(cli.room_messages(builder).await.is_ok()); /// assert!(cli.room_messages(builder).await.is_ok());
@ -673,7 +673,7 @@ impl AsyncClient {
/// # use futures::executor::block_on; /// # use futures::executor::block_on;
/// # block_on(async { /// # block_on(async {
/// # let homeserver = Url::parse("http://localhost:8080").unwrap(); /// # let homeserver = Url::parse("http://localhost:8080").unwrap();
/// # let mut client = AsyncClient::new(homeserver, None).unwrap(); /// # let mut client = AsyncClient::<(), ()>::new(homeserver, None).unwrap();
/// ///
/// use async_std::sync::channel; /// use async_std::sync::channel;
/// ///
@ -863,7 +863,7 @@ impl AsyncClient {
/// use matrix_sdk::events::room::message::{MessageEventContent, TextMessageEventContent}; /// use matrix_sdk::events::room::message::{MessageEventContent, TextMessageEventContent};
/// # block_on(async { /// # block_on(async {
/// # let homeserver = Url::parse("http://localhost:8080").unwrap(); /// # let homeserver = Url::parse("http://localhost:8080").unwrap();
/// # let mut client = AsyncClient::new(homeserver, None).unwrap(); /// # let mut client = AsyncClient::<(), ()>::new(homeserver, None).unwrap();
/// # let room_id = RoomId::try_from("!test:localhost").unwrap(); /// # let room_id = RoomId::try_from("!test:localhost").unwrap();
/// use uuid::Uuid; /// use uuid::Uuid;
/// ///
@ -1120,7 +1120,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();
@ -1152,7 +1152,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)
@ -1182,7 +1182,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(

View File

@ -34,6 +34,7 @@ use crate::events::EventResult;
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::state::StateStore;
use crate::EventEmitter; use crate::EventEmitter;
#[cfg(feature = "encryption")] #[cfg(feature = "encryption")]
@ -60,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 { pub struct Client<S, E> {
/// 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>,
@ -75,12 +76,14 @@ pub struct Client {
/// Any implementor of EventEmitter will act as the callbacks for various /// Any implementor of EventEmitter will act as the callbacks for various
/// 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>>>,
#[cfg(feature = "encryption")] #[cfg(feature = "encryption")]
olm: Arc<Mutex<Option<OlmMachine>>>, olm: Arc<Mutex<Option<OlmMachine>>>,
} }
impl fmt::Debug for Client { impl<S, E> fmt::Debug for Client<S, E> {
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)
@ -93,7 +96,7 @@ impl fmt::Debug for Client {
} }
} }
impl Client { impl<S, E> Client<S, E> {
/// Create a new client. /// Create a new client.
/// ///
/// # Arguments /// # Arguments
@ -114,6 +117,7 @@ impl Client {
ignored_users: Vec::new(), ignored_users: Vec::new(),
push_ruleset: None, push_ruleset: None,
event_emitter: None, event_emitter: None,
state_store: None,
#[cfg(feature = "encryption")] #[cfg(feature = "encryption")]
olm: Arc::new(Mutex::new(olm)), olm: Arc::new(Mutex::new(olm)),
}) })
@ -811,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));

View File

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

56
src/models/event_deser.rs Normal file
View File

@ -0,0 +1,56 @@
//! De-/serialization functions to and from json strings, allows the type to be used as a query string.
use serde::de::{Deserialize, Deserializer, Error as _};
use crate::events::collections::all::Event;
use crate::events::presence::PresenceEvent;
use crate::events::EventResult;
pub fn deserialize_events<'de, D>(deserializer: D) -> Result<Vec<Event>, D::Error>
where
D: Deserializer<'de>,
{
let mut events = vec![];
let ev = Vec::<EventResult<Event>>::deserialize(deserializer)?;
for event in ev {
events.push(event.into_result().map_err(D::Error::custom)?);
}
Ok(events)
}
pub fn deserialize_presence<'de, D>(deserializer: D) -> Result<Vec<PresenceEvent>, D::Error>
where
D: Deserializer<'de>,
{
let mut events = vec![];
let ev = Vec::<EventResult<PresenceEvent>>::deserialize(deserializer)?;
for event in ev {
events.push(event.into_result().map_err(D::Error::custom)?);
}
Ok(events)
}
#[cfg(test)]
mod test {
use std::fs;
use crate::events::room::member::MemberEvent;
use crate::events::EventResult;
use crate::models::RoomMember;
#[test]
fn events_and_presence_deserialization() {
let ev_json = fs::read_to_string("./tests/data/events/member.json").unwrap();
let ev = serde_json::from_str::<EventResult<MemberEvent>>(&ev_json)
.unwrap()
.into_result()
.unwrap();
let member = RoomMember::new(&ev);
let member_json = serde_json::to_string(&member).unwrap();
let mem = serde_json::from_str::<RoomMember>(&member_json).unwrap();
assert_eq!(member, mem);
}
}

View File

@ -1,3 +1,4 @@
mod event_deser;
mod room; mod room;
mod room_member; mod room_member;

View File

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

View File

@ -58,16 +58,16 @@ pub struct RoomMember {
/// The human readable name of this room member. /// The human readable name of this room member.
pub name: String, pub name: String,
/// The events that created the state of this room member. /// The events that created the state of this room member.
#[serde(skip)] #[serde(deserialize_with = "super::event_deser::deserialize_events")]
pub events: Vec<Event>, pub events: Vec<Event>,
/// The `PresenceEvent`s connected to this user. /// The `PresenceEvent`s connected to this user.
#[serde(skip)] #[serde(deserialize_with = "super::event_deser::deserialize_presence")]
pub presence_events: Vec<PresenceEvent>, pub presence_events: Vec<PresenceEvent>,
} }
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 dont 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

View File

@ -29,7 +29,7 @@ use js_int::UInt;
/// .visibility(Visibility::Public) /// .visibility(Visibility::Public)
/// .name("name") /// .name("name")
/// .room_version("v1.0"); /// .room_version("v1.0");
/// let mut cli = AsyncClient::new(homeserver, None).unwrap(); /// let mut cli = AsyncClient::<(), ()>::new(homeserver, None).unwrap();
/// cli.create_room(builder).await; /// cli.create_room(builder).await;
/// # }) /// # })
/// ``` /// ```
@ -186,7 +186,7 @@ impl Into<create_room::Request> for RoomBuilder {
/// # rt.block_on(async { /// # rt.block_on(async {
/// # let room_id = RoomId::new(homeserver.as_str()).unwrap(); /// # let room_id = RoomId::new(homeserver.as_str()).unwrap();
/// # let last_sync_token = "".to_string();; /// # let last_sync_token = "".to_string();;
/// let mut cli = AsyncClient::new(homeserver, None).unwrap(); /// let mut cli = AsyncClient::<(), ()>::new(homeserver, None).unwrap();
/// ///
/// let mut builder = MessagesRequestBuilder::new(); /// let mut builder = MessagesRequestBuilder::new();
/// builder.room_id(room_id) /// builder.room_id(room_id)
@ -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());
} }
} }

View File

@ -13,16 +13,18 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
use std::path::Path;
pub mod state_store; pub mod state_store;
pub use state_store::JsonStore; pub use state_store::JsonStore;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::base_client::Token;
use crate::events::push_rules::Ruleset; 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::{base_client::Token, Result};
#[derive(Debug, Default, PartialEq, Serialize, Deserialize)] #[derive(Debug, Default, PartialEq, Serialize, Deserialize)]
pub struct ClientState { pub struct ClientState {
@ -38,15 +40,24 @@ pub struct ClientState {
} }
/// Abstraction around the data store to avoid unnecessary request on client initialization. /// Abstraction around the data store to avoid unnecessary request on client initialization.
pub trait StateStore { pub trait StateStore: Send + Sync {
/// The type of store to create. The default `JsonStore` uses `ClientState` as the store
/// to serialize and deserialize state to JSON files.
type Store;
/// The error type to return.
type IoError;
/// Set up connections or open files to load/save state.
fn open(&self, path: &Path) -> Result<(), Self::IoError>;
/// ///
fn load_client_state(&self) -> Result<ClientState>; fn load_client_state(&self) -> Result<Self::Store, Self::IoError>;
/// ///
fn load_room_state(&self, room_id: &RoomId) -> Result<Room>; fn load_room_state(&self, room_id: &RoomId) -> Result<Room, Self::IoError>;
/// ///
fn store_client_state(&self, _: ClientState) -> Result<()>; fn store_client_state(&self, _: Self::Store) -> Result<(), Self::IoError>;
/// ///
fn store_room_state(&self, _: &Room) -> Result<()>; fn store_room_state(&self, _: &Room) -> Result<(), Self::IoError>;
} }
#[cfg(test)] #[cfg(test)]
@ -85,7 +96,10 @@ mod test {
"room_name": { "room_name": {
"name": null, "name": null,
"canonical_alias": null, "canonical_alias": null,
"aliases": [] "aliases": [],
"heroes": [],
"joined_member_count": null,
"invited_member_count": null
}, },
"own_user_id": "@example:example.com", "own_user_id": "@example:example.com",
"creator": null, "creator": null,

View File

@ -10,6 +10,15 @@ 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;
fn open(&self, path: &Path) -> Result<()> {
if !path.exists() {
std::fs::create_dir_all(path)?;
}
Ok(())
}
fn load_client_state(&self) -> Result<ClientState> { fn load_client_state(&self) -> Result<ClientState> {
if let Some(mut path) = dirs::home_dir() { if let Some(mut path) = dirs::home_dir() {
path.push(".matrix_store/client.json"); path.push(".matrix_store/client.json");

View File

@ -49,9 +49,9 @@ pub struct RoomTestRunner {
state_events: Vec<StateEvent>, state_events: Vec<StateEvent>,
} }
pub struct ClientTestRunner { pub struct ClientTestRunner<S, E> {
/// Used when testing the whole client /// Used when testing the whole client
client: Option<AsyncClient>, client: Option<AsyncClient<S, E>>,
/// 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 {
} }
#[allow(dead_code)] #[allow(dead_code)]
pub struct MockTestRunner { pub struct MockTestRunner<S, E> {
/// Used when testing the whole client /// Used when testing the whole client
client: Option<AsyncClient>, client: Option<AsyncClient<S, E>>,
/// 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<P: Into<mockito::Matcher>>( pub fn build_mock_runner<S, E, P: Into<mockito::Matcher>>(
mut self, mut self,
method: &str, method: &str,
path: P, path: P,
) -> MockTestRunner { ) -> MockTestRunner<S, E> {
let body = serde_json::json! { let body = serde_json::json! {
{ {
"device_one_time_keys_count": {}, "device_one_time_keys_count": {},
@ -238,7 +238,11 @@ 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(self, room_id: RoomId, user_id: UserId) -> ClientTestRunner { pub fn build_client_runner<S, E>(
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),
@ -313,8 +317,8 @@ impl RoomTestRunner {
} }
} }
impl ClientTestRunner { impl<S, E> ClientTestRunner<S, E> {
pub fn set_client(&mut self, client: AsyncClient) -> &mut Self { pub fn set_client(&mut self, client: AsyncClient<S, E>) -> &mut Self {
self.client = Some(client); self.client = Some(client);
self self
} }
@ -355,14 +359,14 @@ impl ClientTestRunner {
} }
} }
pub async fn to_client(&mut self) -> &mut AsyncClient { pub async fn to_client(&mut self) -> &mut AsyncClient<S, E> {
self.stream_client_events().await; self.stream_client_events().await;
self.client.as_mut().unwrap() self.client.as_mut().unwrap()
} }
} }
impl MockTestRunner { impl<S, E> MockTestRunner<S, E> {
pub fn set_client(&mut self, client: AsyncClient) -> &mut Self { pub fn set_client(&mut self, client: AsyncClient<S, E>) -> &mut Self {
self.client = Some(client); self.client = Some(client);
self self
} }
@ -372,7 +376,7 @@ impl MockTestRunner {
self self
} }
pub async fn to_client(&mut self) -> Result<&mut AsyncClient, crate::Error> { pub async fn to_client(&mut self) -> Result<&mut AsyncClient<S, E>, crate::Error> {
self.client self.client
.as_mut() .as_mut()
.unwrap() .unwrap()

View File

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