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 futures::Future; | ||||
| use hyper::client::Connect; | ||||
| use ruma_client::Client; | ||||
| use ruma_client::api::r0; | ||||
| use ruma_events::EventType; | ||||
| use ruma_events::room::message::{MessageEventContent, MessageType, TextMessageEventContent}; | ||||
| use ruma_identifiers::RoomAliasId; | ||||
| use tokio_core::reactor::Core; | ||||
| use tokio_core::reactor::{Core as TokioCore, Handle as TokioHandle}; | ||||
| use url::Url; | ||||
| 
 | ||||
| fn hello_world<'a, C: Connect>(client: &'a Client<C>) | ||||
| -> impl Future<Item = (), Error = ruma_client::Error> + 'a | ||||
| // from https://stackoverflow.com/a/43992218/1592377
 | ||||
| #[macro_export] | ||||
| macro_rules! clone { | ||||
|     (@param _) => ( _ ); | ||||
|     (@param $x:ident) => ( $x ); | ||||
|     ($($n:ident),+ => move || $body:expr) => ( | ||||
|         { | ||||
|     client.register_guest().and_then(move |_| { | ||||
|         r0::alias::get_alias::call(client, r0::alias::get_alias::Request { | ||||
|             $( 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(), | ||||
|         }) | ||||
|     }).and_then(move |response| { | ||||
|     })).and_then(clone!(client => move |response| { | ||||
|         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(), | ||||
|             third_party_signed: None, | ||||
|         }).and_then(move |_| { | ||||
|             r0::send::send_message_event::call(client, r0::send::send_message_event::Request { | ||||
|         }).and_then(clone!(client => move |_| { | ||||
|             r0::send::send_message_event::call(client.clone(), r0::send::send_message_event::Request { | ||||
|                 room_id: room_id, | ||||
|                 event_type: EventType::RoomMessage, | ||||
|                 txn_id: "1".to_owned(), | ||||
| @ -44,15 +65,14 @@ fn hello_world<'a, C: Connect>(client: &'a Client<C>) | ||||
|                     msgtype: MessageType::Text, | ||||
|                 }), | ||||
|             }) | ||||
|         }) | ||||
|     }).map(|_| ()) | ||||
|         })) | ||||
|     })).map(|_| ()) | ||||
| } | ||||
| 
 | ||||
| fn main() { | ||||
|     let mut core = Core::new().unwrap(); | ||||
|     let mut core = TokioCore::new().unwrap(); | ||||
|     let handle = core.handle(); | ||||
|     let server = Url::parse("https://matrix.org/").unwrap(); | ||||
| 
 | ||||
|     let client = Client::https(&handle, server, None).unwrap(); | ||||
|     core.run(hello_world(&client)).unwrap(); | ||||
|     core.run(hello_world(handle, server)).unwrap(); | ||||
| } | ||||
|  | ||||
| @ -32,10 +32,10 @@ macro_rules! endpoint { | ||||
|             use {Client, Error}; | ||||
| 
 | ||||
|             /// Make a request to this API endpoint.
 | ||||
|             pub fn call<'a, C>( | ||||
|                 client: &'a Client<C>, | ||||
|             pub fn call<C>( | ||||
|                 client: Client<C>, | ||||
|                 request: Request, | ||||
|             ) -> impl Future<Item = Response, Error = Error> + 'a | ||||
|             ) -> impl Future<Item = Response, Error = Error> | ||||
|             where | ||||
|                 C: Connect, | ||||
|             { | ||||
|  | ||||
							
								
								
									
										78
									
								
								src/lib.rs
									
									
									
									
									
								
							
							
						
						
									
										78
									
								
								src/lib.rs
									
									
									
									
									
								
							| @ -45,23 +45,23 @@ mod error; | ||||
| mod session; | ||||
| 
 | ||||
| /// A client for the Matrix client-server API.
 | ||||
| #[derive(Clone, Debug)] | ||||
| #[derive(Debug)] | ||||
| pub struct Client<C> | ||||
| where | ||||
|     C: Connect, | ||||
| { | ||||
|     homeserver_url: Url, | ||||
|     homeserver_url: Rc<Url>, | ||||
|     hyper: Rc<HyperClient<C>>, | ||||
|     session: RefCell<Option<Session>>, | ||||
|     session: Rc<RefCell<Option<Session>>>, | ||||
| } | ||||
| 
 | ||||
| impl Client<HttpConnector> { | ||||
|     /// Creates a new client for making HTTP requests to the given homeserver.
 | ||||
|     pub fn new(handle: &Handle, homeserver_url: Url, session: Option<Session>) -> Self { | ||||
|         Client { | ||||
|             homeserver_url, | ||||
|             homeserver_url: Rc::new(homeserver_url), | ||||
|             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)?; | ||||
| 
 | ||||
|         Ok(Client { | ||||
|             homeserver_url, | ||||
|             homeserver_url: Rc::new(homeserver_url), | ||||
|             hyper: Rc::new( | ||||
|                 HyperClient::configure() | ||||
|                     .connector(connector) | ||||
|                     .keep_alive(true) | ||||
|                     .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.
 | ||||
|     pub fn custom(hyper_client: HyperClient<C>, homeserver_url: Url, session: Option<Session>) -> Self { | ||||
|         Client { | ||||
|             homeserver_url, | ||||
|             homeserver_url: Rc::new(homeserver_url), | ||||
|             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
 | ||||
|     /// session data returned by the endpoint in this client, instead of
 | ||||
|     /// returning it.
 | ||||
|     pub fn log_in<'a>(&'a self, user: String, password: String) | ||||
|     -> impl Future<Item = (), Error = Error> + 'a { | ||||
|     pub fn log_in(&self, user: String, password: String) | ||||
|     -> impl Future<Item = (), Error = Error> { | ||||
|         let request = login::Request { | ||||
|             address: None, | ||||
|             login_type: login::LoginType::Password, | ||||
| @ -115,8 +115,10 @@ where | ||||
|             user, | ||||
|         }; | ||||
| 
 | ||||
|         login::call(self, request).and_then(move |response| { | ||||
|             *self.session.borrow_mut() = Some(Session::new(response.access_token, response.user_id)); | ||||
|         let session = self.session.clone(); | ||||
| 
 | ||||
|         login::call(self.clone(), request).and_then(move |response| { | ||||
|             *session.borrow_mut() = Some(Session::new(response.access_token, response.user_id)); | ||||
| 
 | ||||
|             Ok(()) | ||||
|         }) | ||||
| @ -125,10 +127,12 @@ where | ||||
|     /// Register as a guest. In contrast to api::r0::account::register::call(),
 | ||||
|     /// this method stores the session data returned by the endpoint in this
 | ||||
|     /// 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; | ||||
| 
 | ||||
|         register::call(self, register::Request { | ||||
|         let session = self.session.clone(); | ||||
| 
 | ||||
|         register::call(self.clone(), register::Request { | ||||
|             auth: None, | ||||
|             bind_email: None, | ||||
|             device_id: None, | ||||
| @ -137,8 +141,7 @@ where | ||||
|             password: None, | ||||
|             username: None, | ||||
|         }).map(move |response| { | ||||
|             *self.session.borrow_mut() = | ||||
|                 Some(Session::new(response.access_token, response.user_id)); | ||||
|             *session.borrow_mut() = 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
 | ||||
|     /// omitted from this request, the server will generate one.
 | ||||
|     pub fn register_user<'a>( | ||||
|         &'a self, | ||||
|     pub fn register_user( | ||||
|         &self, | ||||
|         username: Option<String>, | ||||
|         password: String, | ||||
|     ) -> impl Future<Item = (), Error = Error> + 'a { | ||||
|     ) -> impl Future<Item = (), Error = Error> { | ||||
|         use api::r0::account::register; | ||||
| 
 | ||||
|         register::call(self, register::Request { | ||||
|         let session = self.session.clone(); | ||||
| 
 | ||||
|         register::call(self.clone(), register::Request { | ||||
|             auth: None, | ||||
|             bind_email: None, | ||||
|             device_id: None, | ||||
| @ -166,21 +171,21 @@ where | ||||
|             password: Some(password), | ||||
|             username: username, | ||||
|         }).map(move |response| { | ||||
|             *self.session.borrow_mut() = | ||||
|                 Some(Session::new(response.access_token, response.user_id)); | ||||
|             *session.borrow_mut() = Some(Session::new(response.access_token, response.user_id)); | ||||
|         }) | ||||
|     } | ||||
| 
 | ||||
|     /// Makes a request to a Matrix API endpoint.
 | ||||
|     pub(crate) fn request<'a, E>( | ||||
|         &'a self, | ||||
|     pub(crate) fn request<E>( | ||||
|         self, | ||||
|         request: <E as Endpoint>::Request, | ||||
|     ) -> impl Future<Item = E::Response, Error = Error> + 'a | ||||
|     ) -> impl Future<Item = E::Response, Error = Error> | ||||
|     where | ||||
|         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 | ||||
|             .try_into() | ||||
| @ -194,7 +199,7 @@ where | ||||
|                     url.set_query(uri.query()); | ||||
| 
 | ||||
|                     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()); | ||||
|                         } else { | ||||
|                             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_err(Error::from) | ||||
|             }) | ||||
|             .and_then(move |(uri, mut hyper_request)| { | ||||
|                 hyper_request.set_uri(uri); | ||||
| 
 | ||||
|                 self.hyper | ||||
|                     .clone() | ||||
|                 hyper | ||||
|                     .request(hyper_request) | ||||
|                     .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