session.rs 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. use libc::{c_int, c_char};
  2. use std::ffi::CStr;
  3. use std::slice::from_raw_parts;
  4. use std::sync::mpsc;
  5. use std::boxed::FnBox;
  6. use std::sync::Mutex;
  7. use librespot::session::{Session, Config, Bitrate};
  8. use eventual::{Async, AsyncResult, Future};
  9. use cstring_cache::CStringCache;
  10. use types::sp_error;
  11. use types::sp_error::*;
  12. use types::sp_session_config;
  13. use types::sp_session_callbacks;
  14. static mut global_session: Option<(*const sp_session, *const Mutex<mpsc::Sender<SpSessionEvent>>)> = None;
  15. pub type SpSessionEvent = Box<FnBox(&mut SpSession) -> ()>;
  16. pub struct SpSession {
  17. pub session: Session,
  18. cache: CStringCache,
  19. rx: mpsc::Receiver<SpSessionEvent>,
  20. pub callbacks: &'static sp_session_callbacks,
  21. }
  22. impl SpSession {
  23. pub unsafe fn global() -> &'static SpSession {
  24. &*global_session.unwrap().0
  25. }
  26. pub fn run<F: FnOnce(&mut SpSession) -> () + 'static>(event: F) {
  27. let tx = unsafe {
  28. &*global_session.unwrap().1
  29. };
  30. tx.lock().unwrap().send(Box::new(event)).unwrap();
  31. }
  32. pub fn receive<T, E, F>(future: Future<T, E>, handler: F)
  33. where T : Send, E: Send,
  34. F : FnOnce(&mut SpSession, AsyncResult<T, E>) -> () + Send + 'static {
  35. future.receive(move |result| {
  36. SpSession::run(move |session| {
  37. handler(session, result);
  38. })
  39. })
  40. }
  41. }
  42. #[allow(non_camel_case_types)]
  43. pub type sp_session = SpSession;
  44. #[no_mangle]
  45. pub unsafe extern "C" fn sp_session_create(c_config: *const sp_session_config,
  46. c_session: *mut *mut sp_session) -> sp_error {
  47. assert!(global_session.is_none());
  48. let c_config = &*c_config;
  49. let application_key = from_raw_parts::<u8>(c_config.application_key as *const u8,
  50. c_config.application_key_size);
  51. let user_agent = CStr::from_ptr(c_config.user_agent).to_string_lossy().into_owned();
  52. let device_name = CStr::from_ptr(c_config.device_id).to_string_lossy().into_owned();
  53. let cache_location = CStr::from_ptr(c_config.cache_location).to_string_lossy().into_owned();
  54. let config = Config {
  55. application_key: application_key.to_owned(),
  56. user_agent: user_agent,
  57. device_name: device_name,
  58. cache_location: cache_location.into(),
  59. bitrate: Bitrate::Bitrate160,
  60. };
  61. let (tx, rx) = mpsc::channel();
  62. let session = SpSession {
  63. session: Session::new(config),
  64. cache: CStringCache::new(),
  65. rx: rx,
  66. callbacks: &*c_config.callbacks,
  67. };
  68. let session = Box::into_raw(Box::new(session));
  69. let tx = Box::into_raw(Box::new(Mutex::new(tx)));
  70. global_session = Some((session, tx));
  71. *c_session = session;
  72. SP_ERROR_OK
  73. }
  74. #[no_mangle]
  75. pub unsafe extern "C" fn sp_session_release(c_session: *mut sp_session) -> sp_error {
  76. global_session = None;
  77. drop(Box::from_raw(c_session));
  78. SP_ERROR_OK
  79. }
  80. #[no_mangle]
  81. pub unsafe extern "C" fn sp_session_login(c_session: *mut sp_session,
  82. c_username: *const c_char,
  83. c_password: *const c_char,
  84. _remember_me: bool,
  85. _blob: *const c_char) -> sp_error {
  86. let session = &*c_session;
  87. let username = CStr::from_ptr(c_username).to_string_lossy().into_owned();
  88. let password = CStr::from_ptr(c_password).to_string_lossy().into_owned();
  89. {
  90. let session = session.session.clone();
  91. SpSession::receive(Future::spawn(move || {
  92. session.login_password(username, password)
  93. }), |session, result| {
  94. result.unwrap();
  95. {
  96. let session = session.session.clone();
  97. ::std::thread::spawn(move || {
  98. loop {
  99. session.poll();
  100. }
  101. });
  102. }
  103. });
  104. }
  105. SP_ERROR_OK
  106. }
  107. #[no_mangle]
  108. pub unsafe extern "C" fn sp_session_user_name(c_session: *mut sp_session) -> *const c_char {
  109. let session = &mut *c_session;
  110. let username = session.session.username();
  111. session.cache.intern(&username).as_ptr()
  112. }
  113. #[no_mangle]
  114. pub unsafe extern "C" fn sp_session_user_country(c_session: *mut sp_session) -> c_int {
  115. let session = &*c_session;
  116. let country = session.session.country();
  117. country.chars().fold(0, |acc, x| {
  118. acc << 8 | (x as u32)
  119. }) as c_int
  120. }
  121. #[no_mangle]
  122. pub unsafe extern "C" fn sp_session_process_events(c_session: *mut sp_session, next_timeout: *mut c_int) -> sp_error {
  123. let session = &mut *c_session;
  124. if !next_timeout.is_null() {
  125. *next_timeout = 10;
  126. }
  127. let event = session.rx.recv().unwrap();
  128. event.call_box((session,));
  129. SP_ERROR_OK
  130. }