From fa5c9f7d11367e6d298b11e4d4aaad26d5f21472 Mon Sep 17 00:00:00 2001 From: johannesd3 Date: Mon, 25 Jan 2021 02:22:25 +0100 Subject: [PATCH] Made locations in cache optional The locations of credentials, volume and audio are now stored in three separate Optionals. Removed the clearing of the cache if an error occurs. This might be added again later. --- audio/src/fetch.rs | 4 +- core/src/cache.rs | 179 ++++++++++++++++++++------------------------- src/main.rs | 42 +++++++---- 3 files changed, 108 insertions(+), 117 deletions(-) diff --git a/audio/src/fetch.rs b/audio/src/fetch.rs index c65482bd..bae69419 100644 --- a/audio/src/fetch.rs +++ b/audio/src/fetch.rs @@ -430,9 +430,7 @@ impl AudioFile { .map(move |mut file| { if let Some(cache) = session_.cache() { debug!("File {} complete, saving to cache", file_id); - if let Err(err) = cache.save_file(file_id, &mut file) { - warn!("Cannot save file to cache: {}", err); - } + cache.save_file(file_id, &mut file); } else { debug!("File {} complete", file_id); } diff --git a/core/src/cache.rs b/core/src/cache.rs index 4dcce968..76d49fa9 100644 --- a/core/src/cache.rs +++ b/core/src/cache.rs @@ -7,59 +7,58 @@ use crate::authentication::Credentials; use crate::spotify_id::FileId; use crate::volume::Volume; +/// A cache for volume, credentials and audio files. #[derive(Clone)] pub struct Cache { - audio_root: PathBuf, - system_root: PathBuf, - use_audio_cache: bool, -} - -fn mkdir_existing(path: &Path) -> io::Result<()> { - fs::create_dir(path).or_else(|err| { - if err.kind() == io::ErrorKind::AlreadyExists { - Ok(()) - } else { - Err(err) - } - }) + credentials_location: Option, + volume_location: Option, + audio_location: Option, } impl Cache { - pub fn new( - audio_location: PathBuf, - system_location: PathBuf, - use_audio_cache: bool, - ) -> io::Result { - if use_audio_cache { - mkdir_existing(&audio_location)?; - mkdir_existing(&audio_location.join("files"))?; + pub fn new>( + system_location: Option

, + audio_location: Option

, + ) -> io::Result { + if let Some(location) = &system_location { + fs::create_dir_all(location)?; } - mkdir_existing(&system_location)?; - Ok(Cache { - audio_root: audio_location, - system_root: system_location, - use_audio_cache, - }) - } -} + if let Some(location) = &audio_location { + fs::create_dir_all(location)?; + } -impl Cache { - fn open_credentials_file(&self) -> io::Result { - File::open(self.system_root.join("credentials.json")) - } + let audio_location = audio_location.map(|p| p.as_ref().to_owned()); + let volume_location = system_location.as_ref().map(|p| p.as_ref().join("volume")); + let credentials_location = system_location + .as_ref() + .map(|p| p.as_ref().join("credentials.json")); - fn read_credentials(&self) -> io::Result { - let mut file = self.open_credentials_file()?; - let mut contents = String::new(); - file.read_to_string(&mut contents)?; - serde_json::from_str(&contents).map_err(|e| Error::new(ErrorKind::InvalidData, e)) + let cache = Cache { + credentials_location, + volume_location, + audio_location, + }; + + Ok(cache) } pub fn credentials(&self) -> Option { - match self.read_credentials() { + let location = self.credentials_location.as_ref()?; + + // This closure is just convencience to enable the question mark operator + let read = || { + let mut file = File::open(location)?; + let mut contents = String::new(); + file.read_to_string(&mut contents)?; + serde_json::from_str(&contents).map_err(|e| Error::new(ErrorKind::InvalidData, e)) + }; + + match read() { Ok(c) => Some(c), Err(e) => { + // If the file did not exist, the file was probably not written + // before. Otherwise, log the error. if e.kind() != ErrorKind::NotFound { warn!("Error reading credentials from cache: {}", e); } @@ -69,32 +68,31 @@ impl Cache { } pub fn save_credentials(&self, cred: &Credentials) { - let result = self - .open_credentials_file() - .and_then(|mut file| write!(file, "{}", serde_json::to_string(cred)?)); - if let Err(e) = result { - warn!("Cannot save credentials to cache: {}", e); + if let Some(location) = &self.credentials_location { + let result = File::create(location).and_then(|mut file| { + let data = serde_json::to_string(cred)?; + write!(file, "{}", data) + }); + + if let Err(e) = result { + warn!("Cannot save credentials to cache: {}", e) + } } } -} - -// cache volume to system_root/volume -impl Cache { - fn open_volume_file(&self) -> io::Result { - File::open(self.system_root.join("volume")) - } - - fn read_volume(&self) -> io::Result { - let mut file = self.open_volume_file()?; - let mut contents = String::new(); - file.read_to_string(&mut contents)?; - contents - .parse() - .map_err(|e| Error::new(ErrorKind::InvalidData, e)) - } pub fn volume(&self) -> Option { - match self.read_volume() { + let location = self.volume_location.as_ref()?; + + let read = || { + let mut file = File::open(location)?; + let mut contents = String::new(); + file.read_to_string(&mut contents)?; + contents + .parse() + .map_err(|e| Error::new(ErrorKind::InvalidData, e)) + }; + + match read() { Ok(v) => Some(v), Err(e) => { if e.kind() != ErrorKind::NotFound { @@ -106,26 +104,25 @@ impl Cache { } pub fn save_volume(&self, volume: Volume) { - let result = self - .open_volume_file() - .and_then(|mut file| write!(file, "{}", volume)); - if let Err(e) = result { - warn!("Cannot save volume to cache: {}", e); + if let Some(ref location) = self.volume_location { + let result = File::create(location).and_then(|mut file| write!(file, "{}", volume)); + if let Err(e) = result { + warn!("Cannot save volume to cache: {}", e); + } } } -} -impl Cache { - fn file_path(&self, file: FileId) -> PathBuf { - let name = file.to_base16(); - self.audio_root - .join("files") - .join(&name[0..2]) - .join(&name[2..]) + fn file_path(&self, file: FileId) -> Option { + self.audio_location.as_ref().map(|location| { + let name = file.to_base16(); + let mut path = location.join(&name[0..2]); + path.push(&name[2..]); + path + }) } pub fn file(&self, file: FileId) -> Option { - File::open(self.file_path(file)) + File::open(self.file_path(file)?) .map_err(|e| { if e.kind() != ErrorKind::NotFound { warn!("Error reading file from cache: {}", e) @@ -134,30 +131,16 @@ impl Cache { .ok() } - pub fn save_file(&self, file: FileId, contents: &mut F) -> io::Result<()> { - if self.use_audio_cache { - let path = self.file_path(file); - mkdir_existing(path.parent().unwrap())?; + pub fn save_file(&self, file: FileId, contents: &mut F) { + if let Some(path) = self.file_path(file) { + let parent = path.parent().unwrap(); + let result = fs::create_dir_all(parent) + .and_then(|_| File::create(path)) + .and_then(|mut file| io::copy(contents, &mut file)); - let mut cache_file = File::create(path).or_else(|_| { - fs::remove_dir_all(&self.audio_root.join("files"))?; - mkdir_existing(&self.audio_root.join("files"))?; - - let path = self.file_path(file); - mkdir_existing(path.parent().unwrap())?; - File::create(path) - })?; - - io::copy(contents, &mut cache_file).or_else(|_| { - fs::remove_dir_all(&self.audio_root.join("files"))?; - mkdir_existing(&self.audio_root.join("files"))?; - - let path = self.file_path(file); - mkdir_existing(path.parent().unwrap())?; - let mut file = File::create(path)?; - io::copy(contents, &mut file) - })?; + if let Err(e) = result { + warn!("Cannot save file to cache: {}", e) + } } - Ok(()) } } diff --git a/src/main.rs b/src/main.rs index 8c029f5a..b22d7d5f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -5,7 +5,7 @@ use sha1::{Digest, Sha1}; use std::env; use std::io::{self, stderr, Write}; use std::mem; -use std::path::PathBuf; +use std::path::Path; use std::process::exit; use std::str::FromStr; use std::time::Instant; @@ -254,22 +254,32 @@ fn setup(args: &[String]) -> Setup { mapped_volume: !matches.opt_present("mixer-linear-volume"), }; - let use_audio_cache = !matches.opt_present("disable-audio-cache"); + let cache = { + let audio_dir; + let system_dir; + if matches.opt_present("disable-audio-cache") { + audio_dir = None; + system_dir = matches + .opt_str("system-cache") + .or_else(|| matches.opt_str("c")) + .map(|p| p.into()); + } else { + let cache_dir = matches.opt_str("c"); + audio_dir = cache_dir + .as_ref() + .map(|p| AsRef::::as_ref(p).join("files")); + system_dir = matches + .opt_str("system-cache") + .or_else(|| cache_dir) + .map(|p| p.into()); + } - let cache_directory = matches.opt_str("c").unwrap_or(String::from("")); - let system_cache_directory = matches - .opt_str("system-cache") - .unwrap_or(String::from(cache_directory.clone())); - - let cache = match Cache::new( - PathBuf::from(cache_directory), - PathBuf::from(system_cache_directory), - use_audio_cache, - ) { - Ok(cache) => Some(cache), - Err(e) => { - warn!("Cannot create cache: {}", e); - None + match Cache::new(system_dir, audio_dir) { + Ok(cache) => Some(cache), + Err(e) => { + warn!("Cannot create cache: {}", e); + None + } } };