Remove Client lifetime from Futures by using Rc and clones
This commit is contained in:
		
							parent
							
								
									ceca663d69
								
							
						
					
					
						commit
						3dae62ec25
					
				| @ -12,30 +12,51 @@ extern crate url; | |||||||
| use std::convert::TryFrom; | use std::convert::TryFrom; | ||||||
| 
 | 
 | ||||||
| use futures::Future; | use futures::Future; | ||||||
| use hyper::client::Connect; |  | ||||||
| use ruma_client::Client; | use ruma_client::Client; | ||||||
| use ruma_client::api::r0; | use ruma_client::api::r0; | ||||||
| use ruma_events::EventType; | use ruma_events::EventType; | ||||||
| use ruma_events::room::message::{MessageEventContent, MessageType, TextMessageEventContent}; | use ruma_events::room::message::{MessageEventContent, MessageType, TextMessageEventContent}; | ||||||
| use ruma_identifiers::RoomAliasId; | use ruma_identifiers::RoomAliasId; | ||||||
| use tokio_core::reactor::Core; | use tokio_core::reactor::{Core as TokioCore, Handle as TokioHandle}; | ||||||
| use url::Url; | use url::Url; | ||||||
| 
 | 
 | ||||||
| fn hello_world<'a, C: Connect>(client: &'a Client<C>) | // from https://stackoverflow.com/a/43992218/1592377
 | ||||||
| -> impl Future<Item = (), Error = ruma_client::Error> + 'a | #[macro_export] | ||||||
| { | macro_rules! clone { | ||||||
|     client.register_guest().and_then(move |_| { |     (@param _) => ( _ ); | ||||||
|         r0::alias::get_alias::call(client, r0::alias::get_alias::Request { |     (@param $x:ident) => ( $x ); | ||||||
|  |     ($($n:ident),+ => move || $body:expr) => ( | ||||||
|  |         { | ||||||
|  |             $( let $n = $n.clone(); )+ | ||||||
|  |             move || $body | ||||||
|  |         } | ||||||
|  |     ); | ||||||
|  |     ($($n:ident),+ => move |$($p:tt),+| $body:expr) => ( | ||||||
|  |         { | ||||||
|  |             $( let $n = $n.clone(); )+ | ||||||
|  |             move |$(clone!(@param $p),)+| $body | ||||||
|  |         } | ||||||
|  |     ); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn hello_world( | ||||||
|  |     tokio_handle: TokioHandle, | ||||||
|  |     homeserver_url: Url, | ||||||
|  | ) -> impl Future<Item = (), Error = ruma_client::Error> + 'static { | ||||||
|  |     let client = Client::https(&tokio_handle, homeserver_url, None).unwrap(); | ||||||
|  | 
 | ||||||
|  |     client.register_guest().and_then(clone!(client => move |_| { | ||||||
|  |         r0::alias::get_alias::call(client.clone(), r0::alias::get_alias::Request { | ||||||
|             room_alias: RoomAliasId::try_from("#ruma-client-test:matrix.org").unwrap(), |             room_alias: RoomAliasId::try_from("#ruma-client-test:matrix.org").unwrap(), | ||||||
|         }) |         }) | ||||||
|     }).and_then(move |response| { |     })).and_then(clone!(client => move |response| { | ||||||
|         let room_id = response.room_id; |         let room_id = response.room_id; | ||||||
| 
 | 
 | ||||||
|         r0::membership::join_room_by_id::call(client, r0::membership::join_room_by_id::Request { |         r0::membership::join_room_by_id::call(client.clone(), r0::membership::join_room_by_id::Request { | ||||||
|             room_id: room_id.clone(), |             room_id: room_id.clone(), | ||||||
|             third_party_signed: None, |             third_party_signed: None, | ||||||
|         }).and_then(move |_| { |         }).and_then(clone!(client => move |_| { | ||||||
|             r0::send::send_message_event::call(client, r0::send::send_message_event::Request { |             r0::send::send_message_event::call(client.clone(), r0::send::send_message_event::Request { | ||||||
|                 room_id: room_id, |                 room_id: room_id, | ||||||
|                 event_type: EventType::RoomMessage, |                 event_type: EventType::RoomMessage, | ||||||
|                 txn_id: "1".to_owned(), |                 txn_id: "1".to_owned(), | ||||||
| @ -44,15 +65,14 @@ fn hello_world<'a, C: Connect>(client: &'a Client<C>) | |||||||
|                     msgtype: MessageType::Text, |                     msgtype: MessageType::Text, | ||||||
|                 }), |                 }), | ||||||
|             }) |             }) | ||||||
|         }) |         })) | ||||||
|     }).map(|_| ()) |     })).map(|_| ()) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| fn main() { | fn main() { | ||||||
|     let mut core = Core::new().unwrap(); |     let mut core = TokioCore::new().unwrap(); | ||||||
|     let handle = core.handle(); |     let handle = core.handle(); | ||||||
|     let server = Url::parse("https://matrix.org/").unwrap(); |     let server = Url::parse("https://matrix.org/").unwrap(); | ||||||
| 
 | 
 | ||||||
|     let client = Client::https(&handle, server, None).unwrap(); |     core.run(hello_world(handle, server)).unwrap(); | ||||||
|     core.run(hello_world(&client)).unwrap(); |  | ||||||
| } | } | ||||||
|  | |||||||
| @ -32,10 +32,10 @@ macro_rules! endpoint { | |||||||
|             use {Client, Error}; |             use {Client, Error}; | ||||||
| 
 | 
 | ||||||
|             /// Make a request to this API endpoint.
 |             /// Make a request to this API endpoint.
 | ||||||
|             pub fn call<'a, C>( |             pub fn call<C>( | ||||||
|                 client: &'a Client<C>, |                 client: Client<C>, | ||||||
|                 request: Request, |                 request: Request, | ||||||
|             ) -> impl Future<Item = Response, Error = Error> + 'a |             ) -> impl Future<Item = Response, Error = Error> | ||||||
|             where |             where | ||||||
|                 C: Connect, |                 C: Connect, | ||||||
|             { |             { | ||||||
|  | |||||||
							
								
								
									
										78
									
								
								src/lib.rs
									
									
									
									
									
								
							
							
						
						
									
										78
									
								
								src/lib.rs
									
									
									
									
									
								
							| @ -45,23 +45,23 @@ mod error; | |||||||
| mod session; | mod session; | ||||||
| 
 | 
 | ||||||
| /// A client for the Matrix client-server API.
 | /// A client for the Matrix client-server API.
 | ||||||
| #[derive(Clone, Debug)] | #[derive(Debug)] | ||||||
| pub struct Client<C> | pub struct Client<C> | ||||||
| where | where | ||||||
|     C: Connect, |     C: Connect, | ||||||
| { | { | ||||||
|     homeserver_url: Url, |     homeserver_url: Rc<Url>, | ||||||
|     hyper: Rc<HyperClient<C>>, |     hyper: Rc<HyperClient<C>>, | ||||||
|     session: RefCell<Option<Session>>, |     session: Rc<RefCell<Option<Session>>>, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl Client<HttpConnector> { | impl Client<HttpConnector> { | ||||||
|     /// Creates a new client for making HTTP requests to the given homeserver.
 |     /// Creates a new client for making HTTP requests to the given homeserver.
 | ||||||
|     pub fn new(handle: &Handle, homeserver_url: Url, session: Option<Session>) -> Self { |     pub fn new(handle: &Handle, homeserver_url: Url, session: Option<Session>) -> Self { | ||||||
|         Client { |         Client { | ||||||
|             homeserver_url, |             homeserver_url: Rc::new(homeserver_url), | ||||||
|             hyper: Rc::new(HyperClient::configure().keep_alive(true).build(handle)), |             hyper: Rc::new(HyperClient::configure().keep_alive(true).build(handle)), | ||||||
|             session: RefCell::new(session), |             session: Rc::new(RefCell::new(session)), | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @ -73,14 +73,14 @@ impl Client<HttpsConnector<HttpConnector>> { | |||||||
|         let connector = HttpsConnector::new(4, handle)?; |         let connector = HttpsConnector::new(4, handle)?; | ||||||
| 
 | 
 | ||||||
|         Ok(Client { |         Ok(Client { | ||||||
|             homeserver_url, |             homeserver_url: Rc::new(homeserver_url), | ||||||
|             hyper: Rc::new( |             hyper: Rc::new( | ||||||
|                 HyperClient::configure() |                 HyperClient::configure() | ||||||
|                     .connector(connector) |                     .connector(connector) | ||||||
|                     .keep_alive(true) |                     .keep_alive(true) | ||||||
|                     .build(handle), |                     .build(handle), | ||||||
|             ), |             ), | ||||||
|             session: RefCell::new(session), |             session: Rc::new(RefCell::new(session)), | ||||||
|         }) |         }) | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @ -94,9 +94,9 @@ where | |||||||
|     /// This allows the user to configure the details of HTTP as desired.
 |     /// This allows the user to configure the details of HTTP as desired.
 | ||||||
|     pub fn custom(hyper_client: HyperClient<C>, homeserver_url: Url, session: Option<Session>) -> Self { |     pub fn custom(hyper_client: HyperClient<C>, homeserver_url: Url, session: Option<Session>) -> Self { | ||||||
|         Client { |         Client { | ||||||
|             homeserver_url, |             homeserver_url: Rc::new(homeserver_url), | ||||||
|             hyper: Rc::new(hyper_client), |             hyper: Rc::new(hyper_client), | ||||||
|             session: RefCell::new(session), |             session: Rc::new(RefCell::new(session)), | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -105,8 +105,8 @@ where | |||||||
|     /// In contrast to api::r0::session::login::call(), this method stores the
 |     /// In contrast to api::r0::session::login::call(), this method stores the
 | ||||||
|     /// session data returned by the endpoint in this client, instead of
 |     /// session data returned by the endpoint in this client, instead of
 | ||||||
|     /// returning it.
 |     /// returning it.
 | ||||||
|     pub fn log_in<'a>(&'a self, user: String, password: String) |     pub fn log_in(&self, user: String, password: String) | ||||||
|     -> impl Future<Item = (), Error = Error> + 'a { |     -> impl Future<Item = (), Error = Error> { | ||||||
|         let request = login::Request { |         let request = login::Request { | ||||||
|             address: None, |             address: None, | ||||||
|             login_type: login::LoginType::Password, |             login_type: login::LoginType::Password, | ||||||
| @ -115,8 +115,10 @@ where | |||||||
|             user, |             user, | ||||||
|         }; |         }; | ||||||
| 
 | 
 | ||||||
|         login::call(self, request).and_then(move |response| { |         let session = self.session.clone(); | ||||||
|             *self.session.borrow_mut() = Some(Session::new(response.access_token, response.user_id)); | 
 | ||||||
|  |         login::call(self.clone(), request).and_then(move |response| { | ||||||
|  |             *session.borrow_mut() = Some(Session::new(response.access_token, response.user_id)); | ||||||
| 
 | 
 | ||||||
|             Ok(()) |             Ok(()) | ||||||
|         }) |         }) | ||||||
| @ -125,10 +127,12 @@ where | |||||||
|     /// Register as a guest. In contrast to api::r0::account::register::call(),
 |     /// Register as a guest. In contrast to api::r0::account::register::call(),
 | ||||||
|     /// this method stores the session data returned by the endpoint in this
 |     /// this method stores the session data returned by the endpoint in this
 | ||||||
|     /// client, instead of returning it.
 |     /// client, instead of returning it.
 | ||||||
|     pub fn register_guest<'a>(&'a self) -> impl Future<Item = (), Error = Error> + 'a { |     pub fn register_guest(&self) -> impl Future<Item = (), Error = Error> { | ||||||
|         use api::r0::account::register; |         use api::r0::account::register; | ||||||
| 
 | 
 | ||||||
|         register::call(self, register::Request { |         let session = self.session.clone(); | ||||||
|  | 
 | ||||||
|  |         register::call(self.clone(), register::Request { | ||||||
|             auth: None, |             auth: None, | ||||||
|             bind_email: None, |             bind_email: None, | ||||||
|             device_id: None, |             device_id: None, | ||||||
| @ -137,8 +141,7 @@ where | |||||||
|             password: None, |             password: None, | ||||||
|             username: None, |             username: None, | ||||||
|         }).map(move |response| { |         }).map(move |response| { | ||||||
|             *self.session.borrow_mut() = |             *session.borrow_mut() = Some(Session::new(response.access_token, response.user_id)); | ||||||
|                 Some(Session::new(response.access_token, response.user_id)); |  | ||||||
|         }) |         }) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -150,14 +153,16 @@ where | |||||||
|     ///
 |     ///
 | ||||||
|     /// The username is the local part of the returned user_id. If it is
 |     /// The username is the local part of the returned user_id. If it is
 | ||||||
|     /// omitted from this request, the server will generate one.
 |     /// omitted from this request, the server will generate one.
 | ||||||
|     pub fn register_user<'a>( |     pub fn register_user( | ||||||
|         &'a self, |         &self, | ||||||
|         username: Option<String>, |         username: Option<String>, | ||||||
|         password: String, |         password: String, | ||||||
|     ) -> impl Future<Item = (), Error = Error> + 'a { |     ) -> impl Future<Item = (), Error = Error> { | ||||||
|         use api::r0::account::register; |         use api::r0::account::register; | ||||||
| 
 | 
 | ||||||
|         register::call(self, register::Request { |         let session = self.session.clone(); | ||||||
|  | 
 | ||||||
|  |         register::call(self.clone(), register::Request { | ||||||
|             auth: None, |             auth: None, | ||||||
|             bind_email: None, |             bind_email: None, | ||||||
|             device_id: None, |             device_id: None, | ||||||
| @ -166,21 +171,21 @@ where | |||||||
|             password: Some(password), |             password: Some(password), | ||||||
|             username: username, |             username: username, | ||||||
|         }).map(move |response| { |         }).map(move |response| { | ||||||
|             *self.session.borrow_mut() = |             *session.borrow_mut() = Some(Session::new(response.access_token, response.user_id)); | ||||||
|                 Some(Session::new(response.access_token, response.user_id)); |  | ||||||
|         }) |         }) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /// Makes a request to a Matrix API endpoint.
 |     /// Makes a request to a Matrix API endpoint.
 | ||||||
|     pub(crate) fn request<'a, E>( |     pub(crate) fn request<E>( | ||||||
|         &'a self, |         self, | ||||||
|         request: <E as Endpoint>::Request, |         request: <E as Endpoint>::Request, | ||||||
|     ) -> impl Future<Item = E::Response, Error = Error> + 'a |     ) -> impl Future<Item = E::Response, Error = Error> | ||||||
|     where |     where | ||||||
|         E: Endpoint, |         E: Endpoint, | ||||||
|         <E as Endpoint>::Response: 'a, |  | ||||||
|     { |     { | ||||||
|         let mut url = self.homeserver_url.clone(); |         let mut url = (*self.homeserver_url).clone(); | ||||||
|  |         let hyper = self.hyper; | ||||||
|  |         let session = self.session; | ||||||
| 
 | 
 | ||||||
|         request |         request | ||||||
|             .try_into() |             .try_into() | ||||||
| @ -194,7 +199,7 @@ where | |||||||
|                     url.set_query(uri.query()); |                     url.set_query(uri.query()); | ||||||
| 
 | 
 | ||||||
|                     if E::METADATA.requires_authentication { |                     if E::METADATA.requires_authentication { | ||||||
|                         if let Some(ref session) = *self.session.borrow() { |                         if let Some(ref session) = *session.borrow() { | ||||||
|                             url.query_pairs_mut().append_pair("access_token", session.access_token()); |                             url.query_pairs_mut().append_pair("access_token", session.access_token()); | ||||||
|                         } else { |                         } else { | ||||||
|                             return Err(Error::AuthenticationRequired); |                             return Err(Error::AuthenticationRequired); | ||||||
| @ -202,15 +207,14 @@ where | |||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 Uri::from_str(url.as_ref()) |                 Uri::from_str(url.as_ref().as_ref()) | ||||||
|                     .map(move |uri| (uri, hyper_request)) |                     .map(move |uri| (uri, hyper_request)) | ||||||
|                     .map_err(Error::from) |                     .map_err(Error::from) | ||||||
|             }) |             }) | ||||||
|             .and_then(move |(uri, mut hyper_request)| { |             .and_then(move |(uri, mut hyper_request)| { | ||||||
|                 hyper_request.set_uri(uri); |                 hyper_request.set_uri(uri); | ||||||
| 
 | 
 | ||||||
|                 self.hyper |                 hyper | ||||||
|                     .clone() |  | ||||||
|                     .request(hyper_request) |                     .request(hyper_request) | ||||||
|                     .map_err(Error::from) |                     .map_err(Error::from) | ||||||
|             }) |             }) | ||||||
| @ -219,3 +223,13 @@ where | |||||||
|             }) |             }) | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | impl<C: Connect> Clone for Client<C> { | ||||||
|  |     fn clone(&self) -> Client<C> { | ||||||
|  |         Client { | ||||||
|  |             homeserver_url: self.homeserver_url.clone(), | ||||||
|  |             hyper: self.hyper.clone(), | ||||||
|  |             session: self.session.clone(), | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user