ソースを参照

Improve history management, implement error handling, remove history file

timvisee 7 年 前
コミット
8167470784
3 ファイル変更118 行追加46 行削除
  1. 0 15
      cli/history.toml
  2. 4 9
      cli/src/action/upload.rs
  3. 114 22
      cli/src/history.rs

+ 0 - 15
cli/history.toml

@@ -1,15 +0,0 @@
-[[files]]
-id = "462aad1de5"
-time = "2018-04-18T22:45:01.121174527Z"
-host = "http://localhost:8081/"
-url = "http://localhost:8081/download/462aad1de5/"
-secret = [244, 53, 118, 229, 172, 83, 160, 232, 231, 244, 119, 59, 193, 11, 114, 78]
-owner_token = "07734e9bfc8fc7d59873"
-
-[[files]]
-id = "d0ef8edb0a"
-time = "2018-04-18T22:45:06.934834655Z"
-host = "http://localhost:8081/"
-url = "http://localhost:8081/download/d0ef8edb0a/"
-secret = [7, 190, 112, 142, 31, 59, 95, 158, 167, 57, 12, 120, 224, 150, 88, 94]
-owner_token = "3e17d911164114ff3973"

+ 4 - 9
cli/src/action/upload.rs

@@ -125,16 +125,11 @@ impl<'a> Upload<'a> {
         println!("Download URL: {}", url);
         println!("Owner token: {}", file.owner_token().unwrap());
 
-        // Update the history manager, load it first
-        // TODO: complete this implementation
+        // Add the file to the history manager
+        // TODO: specify the proper path here
         let history_path = PathBuf::from("./history.toml");
-        match History::load_or_new(history_path) {
-            Ok(mut history) => {
-                // Add the file, and save
-                history.add(file.clone());
-                history.save();
-            },
-            Err(err) => println!("TODO: PRINT LOAD ERROR HERE"),
+        if let Err(err) = History::load_add_save(history_path, file.clone()) {
+            print_error(err.context("Failed to add file to history, ignoring"));
         }
 
         // Open the URL in the browser

+ 114 - 22
cli/src/history.rs

@@ -1,10 +1,14 @@
 extern crate toml;
 
 use std::fs;
-use std::io::Read;
+use std::io::Error as IoError;
 use std::path::PathBuf;
 
 use ffsend_api::file::remote_file::RemoteFile;
+use self::toml::de::Error as DeError;
+use self::toml::ser::Error as SerError;
+
+use util::print_error;
 
 #[derive(Serialize, Deserialize)]
 pub struct History {
@@ -29,11 +33,23 @@ impl History {
         history
     }
 
+    /// Load the history from the given file.
+    pub fn load(path: PathBuf) -> Result<Self, LoadError> {
+        // Read the file to a string
+        let data = fs::read_to_string(path.clone())?;
+
+        // Parse the data, set the autosave path
+        let mut history: Self = toml::from_str(&data)?;
+        history.autosave = Some(path);
+
+        Ok(history)
+    }
+
     /// Load the history from the given file.
     /// If the file doesn't exist, create a new empty history instance.
     ///
     /// Autosaving will be enabled, and will save to the given file path.
-    pub fn load_or_new(file: PathBuf) -> Result<Self, ()> {
+    pub fn load_or_new(file: PathBuf) -> Result<Self, LoadError> {
         if file.is_file() {
             Self::load(file)
         } else {
@@ -41,28 +57,18 @@ impl History {
         }
     }
 
-    /// Load the history from the given file.
-    pub fn load(path: PathBuf) -> Result<Self, ()> {
-        // Read the file to a string
-        // TODO: handle error
-        let data = fs::read_to_string(path.clone()).unwrap();
-
-        // Parse the data, set the autosave path
-        let mut history: Self = toml::from_str(&data).unwrap();
-        history.autosave = Some(path);
-
-        Ok(history)
-    }
-
     /// Save the history to the internal autosave file.
-    pub fn save(&mut self) -> Result<(), ()> {
+    pub fn save(&mut self) -> Result<(), SaveError> {
+        // TODO: create the parent directories if needed
+
         // Build the data
-        // TODO: handle error
-        let data = toml::to_string(self).unwrap();
+        let data = toml::to_string(self)?;
 
-        // Write to a file
-        // TODO: handle error
-        fs::write(self.autosave.as_ref().unwrap(), data).unwrap();
+        // Get the path, write to a file
+        let path = self.autosave
+            .as_ref()
+            .ok_or(SaveError::NoPath)?;
+        fs::write(path, data)?;
 
         // There are no new changes, set the flag
         self.changed = false;
@@ -76,6 +82,16 @@ impl History {
         self.changed = true;
     }
 
+    /// Load the history from the given path, add the given file, and save it
+    /// again.
+    /// If there is not history file at the given path, a new empty one will
+    /// be created.
+    pub fn load_add_save(path: PathBuf, file: RemoteFile) -> Result<(), Error> {
+        let mut history = Self::load_or_new(path)?;
+        history.add(file);
+        history.save().map_err(|err| err.into())
+    }
+
     /// Get all files.
     pub fn files(&self) -> &Vec<RemoteFile> {
         &self.files
@@ -86,7 +102,10 @@ impl Drop for History {
     fn drop(&mut self) {
         // Automatically save if enabled and something was changed
         if self.autosave.is_some() && self.changed {
-            self.save();
+            // Save and report errors
+            if let Err(err) = self.save() {
+                print_error(err);
+            }
         }
     }
 }
@@ -100,3 +119,76 @@ impl Default for History {
         }
     }
 }
+
+#[derive(Debug, Fail)]
+pub enum Error {
+    /// An error occurred while loading the history from a file.
+    #[fail(display = "Failed to load history from file")]
+    Load(#[cause] LoadError),
+
+    /// An error occurred while saving the history to a file.
+    #[fail(display = "Failed to save history to file")]
+    Save(#[cause] SaveError),
+}
+
+impl From<LoadError> for Error {
+    fn from(err: LoadError) -> Self {
+        Error::Load(err)
+    }
+}
+
+impl From<SaveError> for Error {
+    fn from(err: SaveError) -> Self {
+        Error::Save(err)
+    }
+}
+
+#[derive(Debug, Fail)]
+pub enum LoadError {
+    /// Failed to read the file contents from the given file.
+    #[fail(display = "Failed to read from the history file")]
+    Read(#[cause] IoError),
+
+    /// Failed to parse the loaded file.
+    #[fail(display = "Failed to parse the file contents")]
+    Parse(#[cause] DeError),
+}
+
+impl From<IoError> for LoadError {
+    fn from(err: IoError) -> Self {
+        LoadError::Read(err)
+    }
+}
+
+impl From<DeError> for LoadError {
+    fn from(err: DeError) -> Self {
+        LoadError::Parse(err)
+    }
+}
+
+#[derive(Debug, Fail)]
+pub enum SaveError {
+    /// No autosave file path was present, failed to save.
+    #[fail(display = "No autosave file path specified")]
+    NoPath,
+
+    /// Failed to serialize the history for saving.
+    #[fail(display = "Failed to serialize the history for saving")]
+    Serialize(#[cause] SerError),
+
+    /// Failed to write to the history file.
+    #[fail(display = "Failed to write to the history file")]
+    Write(#[cause] IoError),
+}
+
+impl From<SerError> for SaveError {
+    fn from(err: SerError) -> Self {
+        SaveError::Serialize(err)
+    }
+}
+
+impl From<IoError> for SaveError {
+    fn from(err: IoError) -> Self {
+        SaveError::Write(err)
+    }
+}