default_cache.rs 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  1. use std::path::PathBuf;
  2. use std::io::Read;
  3. use std::fs::File;
  4. use util::{SpotifyId, FileId, ReadSeek, mkdir_existing};
  5. use authentication::Credentials;
  6. use audio_key::AudioKey;
  7. use super::Cache;
  8. pub struct DefaultCache {
  9. environment: lmdb::Environment,
  10. root: PathBuf,
  11. }
  12. impl DefaultCache {
  13. pub fn new(location: PathBuf) -> Result<DefaultCache, ()> {
  14. let env = lmdb::EnvBuilder::new().max_dbs(5).open(&location.join("db"), 0o755).unwrap();
  15. mkdir_existing(&location).unwrap();
  16. mkdir_existing(&location.join("files")).unwrap();
  17. Ok(DefaultCache {
  18. environment: env,
  19. root: location
  20. })
  21. }
  22. fn audio_keys(&self) -> MdbResult<lmdb::DbHandle> {
  23. self.environment.create_db("audio-keys", lmdb::DbFlags::empty())
  24. }
  25. fn file_path(&self, file: FileId) -> PathBuf {
  26. let name = file.to_base16();
  27. self.root.join("files").join(&name[0..2]).join(&name[2..])
  28. }
  29. fn credentials_path(&self) -> PathBuf {
  30. self.root.join("credentials.json")
  31. }
  32. }
  33. impl Cache for DefaultCache {
  34. fn get_audio_key(&self, track: SpotifyId, file: FileId) -> Option<AudioKey> {
  35. let reader = self.environment.get_reader().unwrap();
  36. let handle = self.audio_keys().unwrap();
  37. let db = reader.bind(&handle);
  38. let mut key = Vec::new();
  39. key.extend_from_slice(&track.to_raw());
  40. key.extend_from_slice(&file.0);
  41. let value : Option<Vec<_>> = db.get(&key).ok();
  42. value.and_then(|value| if value.len() == 16 {
  43. let mut result = [0u8; 16];
  44. result.clone_from_slice(&value);
  45. Some(AudioKey(result))
  46. } else {
  47. None
  48. })
  49. }
  50. fn put_audio_key(&self, track: SpotifyId, file: FileId, audio_key: AudioKey) {
  51. let xact = self.environment.new_transaction().unwrap();
  52. let handle = self.audio_keys().unwrap();
  53. {
  54. let db = xact.bind(&handle);
  55. let mut key = Vec::new();
  56. key.extend_from_slice(&track.to_raw());
  57. key.extend_from_slice(&file.0);
  58. db.set(&key, &audio_key.0.as_ref()).unwrap();
  59. }
  60. xact.commit().unwrap();
  61. }
  62. fn get_credentials(&self) -> Option<Credentials> {
  63. let path = self.credentials_path();
  64. Credentials::from_file(path)
  65. }
  66. fn put_credentials(&self, cred: &Credentials) {
  67. let path = self.credentials_path();
  68. cred.save_to_file(&path);
  69. }
  70. fn get_file(&self, file: FileId) -> Option<Box<ReadSeek>> {
  71. File::open(self.file_path(file)).ok().map(|f| Box::new(f) as Box<ReadSeek>)
  72. }
  73. fn put_file(&self, file: FileId, contents: &mut Read) {
  74. let path = self.file_path(file);
  75. mkdir_existing(path.parent().unwrap()).unwrap();
  76. let mut cache_file = File::create(path).unwrap();
  77. ::std::io::copy(contents, &mut cache_file).unwrap();
  78. }
  79. }