session.rs 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270
  1. use bytes::Bytes;
  2. use futures::{Async, Future, IntoFuture, Poll, Stream};
  3. use futures::sync::mpsc;
  4. use std::io;
  5. use std::sync::{Arc, RwLock, Weak};
  6. use std::sync::atomic::{AtomicUsize, Ordering, ATOMIC_USIZE_INIT};
  7. use tokio_core::reactor::{Handle, Remote};
  8. use apresolve::apresolve_or_fallback;
  9. use authentication::Credentials;
  10. use cache::Cache;
  11. use component::Lazy;
  12. use config::SessionConfig;
  13. use connection;
  14. use audio_key::AudioKeyManager;
  15. use channel::ChannelManager;
  16. use mercury::MercuryManager;
  17. struct SessionData {
  18. country: String,
  19. canonical_username: String,
  20. }
  21. struct SessionInternal {
  22. config: SessionConfig,
  23. data: RwLock<SessionData>,
  24. tx_connection: mpsc::UnboundedSender<(u8, Vec<u8>)>,
  25. audio_key: Lazy<AudioKeyManager>,
  26. channel: Lazy<ChannelManager>,
  27. mercury: Lazy<MercuryManager>,
  28. cache: Option<Arc<Cache>>,
  29. handle: Remote,
  30. session_id: usize,
  31. }
  32. static SESSION_COUNTER: AtomicUsize = ATOMIC_USIZE_INIT;
  33. #[derive(Clone)]
  34. pub struct Session(Arc<SessionInternal>);
  35. impl Session {
  36. pub fn connect(
  37. config: SessionConfig,
  38. credentials: Credentials,
  39. cache: Option<Cache>,
  40. handle: Handle,
  41. ) -> Box<Future<Item = Session, Error = io::Error>> {
  42. let access_point = apresolve_or_fallback::<io::Error>(&handle);
  43. let handle_ = handle.clone();
  44. let connection = access_point.and_then(move |addr| {
  45. info!("Connecting to AP \"{}\"", addr);
  46. connection::connect::<&str>(&addr, &handle_)
  47. });
  48. let device_id = config.device_id.clone();
  49. let authentication = connection
  50. .and_then(move |connection| connection::authenticate(connection, credentials, device_id));
  51. let result = authentication.map(move |(transport, reusable_credentials)| {
  52. info!("Authenticated as \"{}\" !", reusable_credentials.username);
  53. if let Some(ref cache) = cache {
  54. cache.save_credentials(&reusable_credentials);
  55. }
  56. let (session, task) = Session::create(
  57. &handle,
  58. transport,
  59. config,
  60. cache,
  61. reusable_credentials.username.clone(),
  62. );
  63. handle.spawn(task.map_err(|e| panic!(e)));
  64. session
  65. });
  66. Box::new(result)
  67. }
  68. fn create(
  69. handle: &Handle,
  70. transport: connection::Transport,
  71. config: SessionConfig,
  72. cache: Option<Cache>,
  73. username: String,
  74. ) -> (Session, Box<Future<Item = (), Error = io::Error>>) {
  75. let (sink, stream) = transport.split();
  76. let (sender_tx, sender_rx) = mpsc::unbounded();
  77. let session_id = SESSION_COUNTER.fetch_add(1, Ordering::Relaxed);
  78. debug!("new Session[{}]", session_id);
  79. let session = Session(Arc::new(SessionInternal {
  80. config: config,
  81. data: RwLock::new(SessionData {
  82. country: String::new(),
  83. canonical_username: username,
  84. }),
  85. tx_connection: sender_tx,
  86. cache: cache.map(Arc::new),
  87. audio_key: Lazy::new(),
  88. channel: Lazy::new(),
  89. mercury: Lazy::new(),
  90. handle: handle.remote().clone(),
  91. session_id: session_id,
  92. }));
  93. let sender_task = sender_rx
  94. .map_err(|e| -> io::Error { panic!(e) })
  95. .forward(sink)
  96. .map(|_| ());
  97. let receiver_task = DispatchTask(stream, session.weak());
  98. let task = Box::new(
  99. (receiver_task, sender_task)
  100. .into_future()
  101. .map(|((), ())| ()),
  102. );
  103. (session, task)
  104. }
  105. pub fn audio_key(&self) -> &AudioKeyManager {
  106. self.0.audio_key.get(|| AudioKeyManager::new(self.weak()))
  107. }
  108. pub fn channel(&self) -> &ChannelManager {
  109. self.0.channel.get(|| ChannelManager::new(self.weak()))
  110. }
  111. pub fn mercury(&self) -> &MercuryManager {
  112. self.0.mercury.get(|| MercuryManager::new(self.weak()))
  113. }
  114. pub fn spawn<F, R>(&self, f: F)
  115. where
  116. F: FnOnce(&Handle) -> R + Send + 'static,
  117. R: IntoFuture<Item = (), Error = ()>,
  118. R::Future: 'static,
  119. {
  120. self.0.handle.spawn(f)
  121. }
  122. fn debug_info(&self) {
  123. debug!(
  124. "Session[{}] strong={} weak={}",
  125. self.0.session_id,
  126. Arc::strong_count(&self.0),
  127. Arc::weak_count(&self.0)
  128. );
  129. }
  130. #[cfg_attr(feature = "cargo-clippy", allow(match_same_arms))]
  131. fn dispatch(&self, cmd: u8, data: Bytes) {
  132. match cmd {
  133. 0x4 => {
  134. self.debug_info();
  135. self.send_packet(0x49, data.as_ref().to_owned());
  136. }
  137. 0x4a => (),
  138. 0x1b => {
  139. let country = String::from_utf8(data.as_ref().to_owned()).unwrap();
  140. info!("Country: {:?}", country);
  141. self.0.data.write().unwrap().country = country;
  142. }
  143. 0x9 | 0xa => self.channel().dispatch(cmd, data),
  144. 0xd | 0xe => self.audio_key().dispatch(cmd, data),
  145. 0xb2...0xb6 => self.mercury().dispatch(cmd, data),
  146. _ => (),
  147. }
  148. }
  149. pub fn send_packet(&self, cmd: u8, data: Vec<u8>) {
  150. self.0.tx_connection.unbounded_send((cmd, data)).unwrap();
  151. }
  152. pub fn cache(&self) -> Option<&Arc<Cache>> {
  153. self.0.cache.as_ref()
  154. }
  155. fn config(&self) -> &SessionConfig {
  156. &self.0.config
  157. }
  158. pub fn username(&self) -> String {
  159. self.0.data.read().unwrap().canonical_username.clone()
  160. }
  161. pub fn country(&self) -> String {
  162. self.0.data.read().unwrap().country.clone()
  163. }
  164. pub fn device_id(&self) -> &str {
  165. &self.config().device_id
  166. }
  167. fn weak(&self) -> SessionWeak {
  168. SessionWeak(Arc::downgrade(&self.0))
  169. }
  170. pub fn session_id(&self) -> usize {
  171. self.0.session_id
  172. }
  173. }
  174. #[derive(Clone)]
  175. pub struct SessionWeak(Weak<SessionInternal>);
  176. impl SessionWeak {
  177. fn try_upgrade(&self) -> Option<Session> {
  178. self.0.upgrade().map(Session)
  179. }
  180. pub(crate) fn upgrade(&self) -> Session {
  181. self.try_upgrade().expect("Session died")
  182. }
  183. }
  184. impl Drop for SessionInternal {
  185. fn drop(&mut self) {
  186. debug!("drop Session[{}]", self.session_id);
  187. }
  188. }
  189. struct DispatchTask<S>(S, SessionWeak)
  190. where
  191. S: Stream<Item = (u8, Bytes)>;
  192. impl<S> Future for DispatchTask<S>
  193. where
  194. S: Stream<Item = (u8, Bytes)>,
  195. {
  196. type Item = ();
  197. type Error = S::Error;
  198. fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
  199. let session = match self.1.try_upgrade() {
  200. Some(session) => session,
  201. None => return Ok(Async::Ready(())),
  202. };
  203. loop {
  204. let (cmd, data) = try_ready!(self.0.poll()).expect("connection closed");
  205. session.dispatch(cmd, data);
  206. }
  207. }
  208. }
  209. impl<S> Drop for DispatchTask<S>
  210. where
  211. S: Stream<Item = (u8, Bytes)>,
  212. {
  213. fn drop(&mut self) {
  214. debug!("drop Dispatch");
  215. }
  216. }