session.rs 7.1 KB

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