瀏覽代碼

Add version subcommand to determine remote server API version

timvisee 6 年之前
父節點
當前提交
f53f11a9f1
共有 9 個文件被更改,包括 143 次插入4 次删除
  1. 1 0
      src/action/mod.rs
  2. 62 0
      src/action/version.rs
  3. 9 2
      src/cmd/handler.rs
  4. 3 1
      src/cmd/matcher/mod.rs
  5. 30 0
      src/cmd/matcher/version.rs
  6. 3 1
      src/cmd/subcmd/mod.rs
  7. 16 0
      src/cmd/subcmd/version.rs
  8. 11 0
      src/error.rs
  9. 8 0
      src/main.rs

+ 1 - 0
src/action/mod.rs

@@ -8,3 +8,4 @@ pub mod info;
 pub mod params;
 pub mod password;
 pub mod upload;
+pub mod version;

+ 62 - 0
src/action/version.rs

@@ -0,0 +1,62 @@
+use clap::ArgMatches;
+use ffsend_api::action::version::{Error as VersionError, Version as ApiVersion};
+use ffsend_api::file::remote_file::{FileParseError, RemoteFile};
+
+use crate::client::create_client;
+use crate::cmd::matcher::main::MainMatcher;
+use crate::cmd::matcher::{version::VersionMatcher, Matcher};
+use crate::error::ActionError;
+#[cfg(feature = "history")]
+use crate::history_tool;
+
+/// A file version action.
+pub struct Version<'a> {
+    cmd_matches: &'a ArgMatches<'a>,
+}
+
+impl<'a> Version<'a> {
+    /// Construct a new version action.
+    pub fn new(cmd_matches: &'a ArgMatches<'a>) -> Self {
+        Self { cmd_matches }
+    }
+
+    /// Invoke the version action.
+    // TODO: create a trait for this method
+    pub fn invoke(&self) -> Result<(), ActionError> {
+        // Create the command matchers
+        let matcher_version = VersionMatcher::with(self.cmd_matches).unwrap();
+        let matcher_main = MainMatcher::with(self.cmd_matches).unwrap();
+
+        // Get the host
+        let host = matcher_version.host();
+
+        // Create a reqwest client
+        let client = create_client(&matcher_main);
+
+        // Make sure the file version
+        let response = ApiVersion::new(host).invoke(&client);
+
+        // Print the result
+        match response {
+            Ok(v) => println!("API version: {}", v),
+            Err(VersionError::Unknown) => println!("Version: unknown"),
+            Err(VersionError::Unsupported(v)) => println!("Version: {} (unsupported)", v),
+            Err(e) => return Err(e.into()),
+        }
+
+        Ok(())
+    }
+}
+
+#[derive(Debug, Fail)]
+pub enum Error {
+    /// An error occurred while attempting to determine the Send server version.
+    #[fail(display = "failed to check the server version")]
+    Version(#[cause] VersionError),
+}
+
+impl From<VersionError> for Error {
+    fn from(err: VersionError) -> Error {
+        Error::Version(err)
+    }
+}

+ 9 - 2
src/cmd/handler.rs

@@ -6,12 +6,13 @@ use clap::{App, AppSettings, Arg, ArgMatches};
 use super::matcher::HistoryMatcher;
 use super::matcher::{
     DebugMatcher, DeleteMatcher, DownloadMatcher, ExistsMatcher, InfoMatcher, Matcher,
-    ParamsMatcher, PasswordMatcher, UploadMatcher,
+    ParamsMatcher, PasswordMatcher, UploadMatcher, VersionMatcher,
 };
 #[cfg(feature = "history")]
 use super::subcmd::CmdHistory;
 use super::subcmd::{
     CmdDebug, CmdDelete, CmdDownload, CmdExists, CmdInfo, CmdParams, CmdPassword, CmdUpload,
+    CmdVersion,
 };
 use crate::config::{CLIENT_TIMEOUT, CLIENT_TRANSFER_TIMEOUT};
 #[cfg(feature = "history")]
@@ -145,7 +146,8 @@ impl<'a: 'b, 'b> Handler<'a> {
             .subcommand(CmdInfo::build())
             .subcommand(CmdParams::build())
             .subcommand(CmdPassword::build())
-            .subcommand(CmdUpload::build().display_order(1));
+            .subcommand(CmdUpload::build().display_order(1))
+            .subcommand(CmdVersion::build());
 
         // With history support, a flag for the history file and incognito mode
         #[cfg(feature = "history")]
@@ -239,4 +241,9 @@ impl<'a: 'b, 'b> Handler<'a> {
     pub fn upload(&'a self) -> Option<UploadMatcher> {
         UploadMatcher::with(&self.matches)
     }
+
+    /// Get the version sub command, if matched.
+    pub fn version(&'a self) -> Option<VersionMatcher> {
+        VersionMatcher::with(&self.matches)
+    }
 }

+ 3 - 1
src/cmd/matcher/mod.rs

@@ -9,8 +9,9 @@ pub mod main;
 pub mod params;
 pub mod password;
 pub mod upload;
+pub mod version;
 
-// Reexport to matcher module
+// Re-export to matcher module
 pub use self::debug::DebugMatcher;
 pub use self::delete::DeleteMatcher;
 pub use self::download::DownloadMatcher;
@@ -22,6 +23,7 @@ pub use self::main::MainMatcher;
 pub use self::params::ParamsMatcher;
 pub use self::password::PasswordMatcher;
 pub use self::upload::UploadMatcher;
+pub use self::version::VersionMatcher;
 
 use clap::ArgMatches;
 

+ 30 - 0
src/cmd/matcher/version.rs

@@ -0,0 +1,30 @@
+use ffsend_api::url::Url;
+
+use clap::ArgMatches;
+
+use super::Matcher;
+use crate::cmd::arg::{ArgHost, CmdArgOption};
+
+/// The version command matcher.
+pub struct VersionMatcher<'a> {
+    matches: &'a ArgMatches<'a>,
+}
+
+impl<'a: 'b, 'b> VersionMatcher<'a> {
+    /// Get the host to probe.
+    ///
+    /// This method parses the host into an `Url`.
+    /// If the given host is invalid,
+    /// the program will quit with an error message.
+    pub fn host(&'a self) -> Url {
+        ArgHost::value(self.matches)
+    }
+}
+
+impl<'a> Matcher<'a> for VersionMatcher<'a> {
+    fn with(matches: &'a ArgMatches) -> Option<Self> {
+        matches
+            .subcommand_matches("version")
+            .map(|matches| VersionMatcher { matches })
+    }
+}

+ 3 - 1
src/cmd/subcmd/mod.rs

@@ -8,8 +8,9 @@ pub mod info;
 pub mod params;
 pub mod password;
 pub mod upload;
+pub mod version;
 
-// Reexport to cmd module
+// Re-export to cmd module
 pub use self::debug::CmdDebug;
 pub use self::delete::CmdDelete;
 pub use self::download::CmdDownload;
@@ -20,3 +21,4 @@ pub use self::info::CmdInfo;
 pub use self::params::CmdParams;
 pub use self::password::CmdPassword;
 pub use self::upload::CmdUpload;
+pub use self::version::CmdVersion;

+ 16 - 0
src/cmd/subcmd/version.rs

@@ -0,0 +1,16 @@
+use clap::{App, SubCommand};
+
+use crate::cmd::arg::{ArgHost, CmdArg};
+
+/// The version command definition.
+pub struct CmdVersion;
+
+impl CmdVersion {
+    pub fn build<'a, 'b>() -> App<'a, 'b> {
+        SubCommand::with_name("version")
+            .about("Determine the Send server version")
+            .alias("ver")
+            .visible_alias("v")
+            .arg(ArgHost::build())
+    }
+}

+ 11 - 0
src/error.rs

@@ -2,6 +2,7 @@ use ffsend_api::action::delete::Error as DeleteError;
 use ffsend_api::action::exists::Error as ExistsError;
 use ffsend_api::action::params::Error as ParamsError;
 use ffsend_api::action::password::Error as PasswordError;
+use ffsend_api::action::version::Error as VersionError;
 use ffsend_api::file::remote_file::FileParseError;
 
 use crate::action::download::Error as CliDownloadError;
@@ -72,6 +73,10 @@ pub enum ActionError {
     #[fail(display = "failed to change the password")]
     Password(#[cause] PasswordError),
 
+    /// An error occurred while invoking the version action.
+    #[fail(display = "failed to determine server version")]
+    Version(#[cause] VersionError),
+
     /// An error occurred while invoking the upload action.
     #[fail(display = "failed to upload the specified file")]
     Upload(#[cause] CliUploadError),
@@ -113,6 +118,12 @@ impl From<PasswordError> for ActionError {
     }
 }
 
+impl From<VersionError> for ActionError {
+    fn from(err: VersionError) -> ActionError {
+        ActionError::Version(err)
+    }
+}
+
 impl From<FileParseError> for ActionError {
     fn from(err: FileParseError) -> ActionError {
         ActionError::InvalidUrl(err)

+ 8 - 0
src/main.rs

@@ -43,6 +43,7 @@ use crate::action::info::Info;
 use crate::action::params::Params;
 use crate::action::password::Password;
 use crate::action::upload::Upload;
+use crate::action::version::Version;
 use crate::cmd::{
     matcher::{MainMatcher, Matcher},
     Handler,
@@ -135,6 +136,13 @@ fn invoke_action(handler: &Handler) -> Result<(), Error> {
             .map_err(|err| err.into());
     }
 
+    // Match the version command
+    if handler.version().is_some() {
+        return Version::new(handler.matches())
+            .invoke()
+            .map_err(|err| err.into());
+    }
+
     // Get the main matcher
     let matcher_main = MainMatcher::with(handler.matches()).unwrap();