mirror of
https://github.com/timvisee/ffsend.git
synced 2025-10-05 10:19:23 +02:00
Apply clippy suggestions
This commit is contained in:
parent
f0ca016f4a
commit
b62f3fd343
34 changed files with 126 additions and 119 deletions
|
@ -24,7 +24,7 @@ impl<'a> Delete<'a> {
|
||||||
pub fn new(file: &'a RemoteFile, nonce: Option<Vec<u8>>) -> Self {
|
pub fn new(file: &'a RemoteFile, nonce: Option<Vec<u8>>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
file,
|
file,
|
||||||
nonce: nonce.unwrap_or(Vec::new()),
|
nonce: nonce.unwrap_or_default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -42,7 +42,7 @@ impl<'a> Delete<'a> {
|
||||||
))?;
|
))?;
|
||||||
|
|
||||||
// Send the delete request
|
// Send the delete request
|
||||||
self.request_delete(client, data).map_err(|err| err.into())
|
self.request_delete(client, &data)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Fetch the authentication nonce for the file from the remote server.
|
/// Fetch the authentication nonce for the file from the remote server.
|
||||||
|
@ -59,7 +59,7 @@ impl<'a> Delete<'a> {
|
||||||
fn request_delete(
|
fn request_delete(
|
||||||
&self,
|
&self,
|
||||||
client: &Client,
|
client: &Client,
|
||||||
data: OwnedData<DeleteData>,
|
data: &OwnedData<DeleteData>,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
// Get the delete URL, and send the request
|
// Get the delete URL, and send the request
|
||||||
let url = UrlBuilder::api_delete(self.file);
|
let url = UrlBuilder::api_delete(self.file);
|
||||||
|
@ -77,13 +77,13 @@ impl<'a> Delete<'a> {
|
||||||
/// The delete data object.
|
/// The delete data object.
|
||||||
/// This object is currently empty, as no additional data is sent to the
|
/// This object is currently empty, as no additional data is sent to the
|
||||||
/// server.
|
/// server.
|
||||||
#[derive(Debug, Serialize)]
|
#[derive(Debug, Serialize, Default)]
|
||||||
pub struct DeleteData { }
|
pub struct DeleteData { }
|
||||||
|
|
||||||
impl DeleteData {
|
impl DeleteData {
|
||||||
/// Constructor.
|
/// Constructor.
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
DeleteData { }
|
DeleteData::default()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -66,7 +66,7 @@ impl<'a> Download<'a> {
|
||||||
pub fn invoke(
|
pub fn invoke(
|
||||||
mut self,
|
mut self,
|
||||||
client: &Client,
|
client: &Client,
|
||||||
reporter: Arc<Mutex<ProgressReporter>>,
|
reporter: &Arc<Mutex<ProgressReporter>>,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
// Create a key set for the file
|
// Create a key set for the file
|
||||||
let mut key = KeySet::from(self.file, self.password.as_ref());
|
let mut key = KeySet::from(self.file, self.password.as_ref());
|
||||||
|
@ -101,7 +101,7 @@ impl<'a> Download<'a> {
|
||||||
// Create the file reader for downloading
|
// Create the file reader for downloading
|
||||||
let (reader, len) = self.create_file_reader(
|
let (reader, len) = self.create_file_reader(
|
||||||
&key,
|
&key,
|
||||||
metadata.nonce().to_vec(),
|
metadata.nonce(),
|
||||||
&client,
|
&client,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
|
@ -110,11 +110,11 @@ impl<'a> Download<'a> {
|
||||||
out,
|
out,
|
||||||
len,
|
len,
|
||||||
&key,
|
&key,
|
||||||
reporter.clone(),
|
&reporter,
|
||||||
).map_err(|err| Error::File(path_str.clone(), err))?;
|
).map_err(|err| Error::File(path_str.clone(), err))?;
|
||||||
|
|
||||||
// Download the file
|
// Download the file
|
||||||
self.download(reader, writer, len, reporter)?;
|
self.download(reader, writer, len, &reporter)?;
|
||||||
|
|
||||||
// TODO: return the file path
|
// TODO: return the file path
|
||||||
// TODO: return the new remote state (does it still exist remote)
|
// TODO: return the new remote state (does it still exist remote)
|
||||||
|
@ -160,7 +160,7 @@ impl<'a> Download<'a> {
|
||||||
fn create_file_reader(
|
fn create_file_reader(
|
||||||
&self,
|
&self,
|
||||||
key: &KeySet,
|
key: &KeySet,
|
||||||
meta_nonce: Vec<u8>,
|
meta_nonce: &[u8],
|
||||||
client: &Client,
|
client: &Client,
|
||||||
) -> Result<(Response, u64), DownloadError> {
|
) -> Result<(Response, u64), DownloadError> {
|
||||||
// Compute the cryptographic signature
|
// Compute the cryptographic signature
|
||||||
|
@ -177,7 +177,7 @@ impl<'a> Download<'a> {
|
||||||
|
|
||||||
// Ensure the response is succesful
|
// Ensure the response is succesful
|
||||||
ensure_success(&response)
|
ensure_success(&response)
|
||||||
.map_err(|err| DownloadError::Response(err))?;
|
.map_err(DownloadError::Response)?;
|
||||||
|
|
||||||
// Get the content length
|
// Get the content length
|
||||||
// TODO: make sure there is enough disk space
|
// TODO: make sure there is enough disk space
|
||||||
|
@ -196,7 +196,7 @@ impl<'a> Download<'a> {
|
||||||
file: File,
|
file: File,
|
||||||
len: u64,
|
len: u64,
|
||||||
key: &KeySet,
|
key: &KeySet,
|
||||||
reporter: Arc<Mutex<ProgressReporter>>,
|
reporter: &Arc<Mutex<ProgressReporter>>,
|
||||||
) -> Result<ProgressWriter<EncryptedFileWriter>, FileError> {
|
) -> Result<ProgressWriter<EncryptedFileWriter>, FileError> {
|
||||||
// Build an encrypted writer
|
// Build an encrypted writer
|
||||||
let mut writer = ProgressWriter::new(
|
let mut writer = ProgressWriter::new(
|
||||||
|
@ -223,7 +223,7 @@ impl<'a> Download<'a> {
|
||||||
mut reader: R,
|
mut reader: R,
|
||||||
mut writer: ProgressWriter<EncryptedFileWriter>,
|
mut writer: ProgressWriter<EncryptedFileWriter>,
|
||||||
len: u64,
|
len: u64,
|
||||||
reporter: Arc<Mutex<ProgressReporter>>,
|
reporter: &Arc<Mutex<ProgressReporter>>,
|
||||||
) -> Result<(), DownloadError> {
|
) -> Result<(), DownloadError> {
|
||||||
// Start the writer
|
// Start the writer
|
||||||
reporter.lock()
|
reporter.lock()
|
||||||
|
|
|
@ -29,7 +29,7 @@ impl<'a> Info<'a> {
|
||||||
pub fn new(file: &'a RemoteFile, nonce: Option<Vec<u8>>) -> Self {
|
pub fn new(file: &'a RemoteFile, nonce: Option<Vec<u8>>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
file,
|
file,
|
||||||
nonce: nonce.unwrap_or(Vec::new()),
|
nonce: nonce.unwrap_or_default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -45,7 +45,7 @@ impl<'a> Info<'a> {
|
||||||
.map_err(|err| -> PrepareError { err.into() })?;
|
.map_err(|err| -> PrepareError { err.into() })?;
|
||||||
|
|
||||||
// Send the info request
|
// Send the info request
|
||||||
self.fetch_info(client, data).map_err(|err| err.into())
|
self.fetch_info(client, &data)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Fetch the authentication nonce for the file from the remote server.
|
/// Fetch the authentication nonce for the file from the remote server.
|
||||||
|
@ -62,7 +62,7 @@ impl<'a> Info<'a> {
|
||||||
fn fetch_info(
|
fn fetch_info(
|
||||||
&self,
|
&self,
|
||||||
client: &Client,
|
client: &Client,
|
||||||
data: OwnedData<InfoData>,
|
data: &OwnedData<InfoData>,
|
||||||
) -> Result<InfoResponse, Error> {
|
) -> Result<InfoResponse, Error> {
|
||||||
// Get the info URL, and send the request
|
// Get the info URL, and send the request
|
||||||
let url = UrlBuilder::api_info(self.file);
|
let url = UrlBuilder::api_info(self.file);
|
||||||
|
@ -87,13 +87,13 @@ impl<'a> Info<'a> {
|
||||||
/// The info data object.
|
/// The info data object.
|
||||||
/// This object is currently empty, as no additional data is sent to the
|
/// This object is currently empty, as no additional data is sent to the
|
||||||
/// server.
|
/// server.
|
||||||
#[derive(Debug, Serialize)]
|
#[derive(Debug, Serialize, Default)]
|
||||||
pub struct InfoData { }
|
pub struct InfoData { }
|
||||||
|
|
||||||
impl InfoData {
|
impl InfoData {
|
||||||
/// Constructor.
|
/// Constructor.
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
InfoData { }
|
InfoData::default()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -56,19 +56,19 @@ impl<'a> Metadata<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure a password is given when it is required
|
// Make sure a password is given when it is required
|
||||||
if !self.password.is_some() && exist_response.has_password() {
|
if self.password.is_none() && exist_response.has_password() {
|
||||||
return Err(Error::PasswordRequired);
|
return Err(Error::PasswordRequired);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a key set for the file
|
// Create a key set for the file
|
||||||
let mut key = KeySet::from(self.file, self.password.as_ref());
|
let key = KeySet::from(self.file, self.password.as_ref());
|
||||||
|
|
||||||
// Fetch the authentication nonce
|
// Fetch the authentication nonce
|
||||||
let auth_nonce = self.fetch_auth_nonce(client)?;
|
let auth_nonce = self.fetch_auth_nonce(client)?;
|
||||||
|
|
||||||
// Fetch the metadata and the metadata nonce, return the result
|
// Fetch the metadata and the metadata nonce, return the result
|
||||||
self.fetch_metadata(&client, &mut key, auth_nonce)
|
self.fetch_metadata(&client, &key, &auth_nonce)
|
||||||
.map_err(|err| err.into())
|
.map_err(|err| err.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -92,7 +92,7 @@ impl<'a> Metadata<'a> {
|
||||||
&self,
|
&self,
|
||||||
client: &Client,
|
client: &Client,
|
||||||
key: &KeySet,
|
key: &KeySet,
|
||||||
auth_nonce: Vec<u8>,
|
auth_nonce: &[u8],
|
||||||
) -> Result<MetadataResponse, MetaError> {
|
) -> Result<MetadataResponse, MetaError> {
|
||||||
// Compute the cryptographic signature for authentication
|
// Compute the cryptographic signature for authentication
|
||||||
let sig = signature_encoded(key.auth_key().unwrap(), &auth_nonce)
|
let sig = signature_encoded(key.auth_key().unwrap(), &auth_nonce)
|
||||||
|
@ -108,11 +108,11 @@ impl<'a> Metadata<'a> {
|
||||||
|
|
||||||
// Ensure the status code is successful
|
// Ensure the status code is successful
|
||||||
ensure_success(&response)
|
ensure_success(&response)
|
||||||
.map_err(|err| MetaError::NonceResponse(err))?;
|
.map_err(MetaError::NonceResponse)?;
|
||||||
|
|
||||||
// Get the metadata nonce
|
// Get the metadata nonce
|
||||||
let nonce = header_nonce(&response)
|
let nonce = header_nonce(&response)
|
||||||
.map_err(|err| MetaError::Nonce(err))?;
|
.map_err(MetaError::Nonce)?;
|
||||||
|
|
||||||
// Parse the metadata response
|
// Parse the metadata response
|
||||||
MetadataResponse::from(
|
MetadataResponse::from(
|
||||||
|
|
|
@ -11,7 +11,7 @@ use file::remote_file::RemoteFile;
|
||||||
|
|
||||||
/// The default download count.
|
/// The default download count.
|
||||||
pub const PARAMS_DEFAULT_DOWNLOAD: u8 = 1;
|
pub const PARAMS_DEFAULT_DOWNLOAD: u8 = 1;
|
||||||
pub const PARAMS_DEFAULT_DOWNLOAD_STR: &'static str = "1";
|
pub const PARAMS_DEFAULT_DOWNLOAD_STR: &str = "1";
|
||||||
|
|
||||||
/// The minimum allowed number of downloads, enforced by the server.
|
/// The minimum allowed number of downloads, enforced by the server.
|
||||||
pub const PARAMS_DOWNLOAD_MIN: u8 = 1;
|
pub const PARAMS_DOWNLOAD_MIN: u8 = 1;
|
||||||
|
@ -43,7 +43,7 @@ impl<'a> Params<'a> {
|
||||||
Self {
|
Self {
|
||||||
file,
|
file,
|
||||||
params,
|
params,
|
||||||
nonce: nonce.unwrap_or(Vec::new()),
|
nonce: nonce.unwrap_or_default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -61,8 +61,7 @@ impl<'a> Params<'a> {
|
||||||
.map_err(|err| -> PrepareError { err.into() })?;
|
.map_err(|err| -> PrepareError { err.into() })?;
|
||||||
|
|
||||||
// Send the request to change the parameters
|
// Send the request to change the parameters
|
||||||
self.change_params(client, data)
|
self.change_params(client, &data)
|
||||||
.map_err(|err| err.into())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Fetch the authentication nonce for the file from the remote server.
|
/// Fetch the authentication nonce for the file from the remote server.
|
||||||
|
@ -79,7 +78,7 @@ impl<'a> Params<'a> {
|
||||||
fn change_params(
|
fn change_params(
|
||||||
&self,
|
&self,
|
||||||
client: &Client,
|
client: &Client,
|
||||||
data: OwnedData<ParamsData>,
|
data: &OwnedData<ParamsData>,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
// Get the params URL, and send the change
|
// Get the params URL, and send the change
|
||||||
let url = UrlBuilder::api_params(self.file);
|
let url = UrlBuilder::api_params(self.file);
|
||||||
|
|
|
@ -33,7 +33,7 @@ impl<'a> Password<'a> {
|
||||||
Self {
|
Self {
|
||||||
file,
|
file,
|
||||||
password,
|
password,
|
||||||
nonce: nonce.unwrap_or(Vec::new()),
|
nonce: nonce.unwrap_or_default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -55,8 +55,7 @@ impl<'a> Password<'a> {
|
||||||
.map_err(|err| -> PrepareError { err.into() })?;
|
.map_err(|err| -> PrepareError { err.into() })?;
|
||||||
|
|
||||||
// Send the request to change the password
|
// Send the request to change the password
|
||||||
self.change_password(client, data)
|
self.change_password(client, &data)
|
||||||
.map_err(|err| err.into())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Fetch the authentication nonce for the file from the Send server.
|
/// Fetch the authentication nonce for the file from the Send server.
|
||||||
|
@ -73,7 +72,7 @@ impl<'a> Password<'a> {
|
||||||
fn change_password(
|
fn change_password(
|
||||||
&self,
|
&self,
|
||||||
client: &Client,
|
client: &Client,
|
||||||
data: OwnedData<PasswordData>,
|
data: &OwnedData<PasswordData>,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
// Get the password URL, and send the change
|
// Get the password URL, and send the change
|
||||||
let url = UrlBuilder::api_password(self.file);
|
let url = UrlBuilder::api_password(self.file);
|
||||||
|
|
|
@ -86,7 +86,7 @@ impl Upload {
|
||||||
pub fn invoke(
|
pub fn invoke(
|
||||||
self,
|
self,
|
||||||
client: &Client,
|
client: &Client,
|
||||||
reporter: Arc<Mutex<ProgressReporter>>,
|
reporter: &Arc<Mutex<ProgressReporter>>,
|
||||||
) -> Result<RemoteFile, Error> {
|
) -> Result<RemoteFile, Error> {
|
||||||
// Create file data, generate a key
|
// Create file data, generate a key
|
||||||
let file = FileData::from(&self.path)?;
|
let file = FileData::from(&self.path)?;
|
||||||
|
@ -101,7 +101,7 @@ impl Upload {
|
||||||
let req = self.create_request(
|
let req = self.create_request(
|
||||||
client,
|
client,
|
||||||
&key,
|
&key,
|
||||||
metadata,
|
&metadata,
|
||||||
reader,
|
reader,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -137,13 +137,13 @@ impl Upload {
|
||||||
{
|
{
|
||||||
// Determine what filename to use
|
// Determine what filename to use
|
||||||
let name = self.name.clone()
|
let name = self.name.clone()
|
||||||
.unwrap_or(file.name().to_owned());
|
.unwrap_or_else(|| file.name().to_owned());
|
||||||
|
|
||||||
// Construct the metadata
|
// Construct the metadata
|
||||||
let metadata = Metadata::from(
|
let metadata = Metadata::from(
|
||||||
key.iv(),
|
key.iv(),
|
||||||
name,
|
name,
|
||||||
file.mime().clone(),
|
&file.mime(),
|
||||||
).to_json().into_bytes();
|
).to_json().into_bytes();
|
||||||
|
|
||||||
// Encrypt the metadata
|
// Encrypt the metadata
|
||||||
|
@ -207,7 +207,7 @@ impl Upload {
|
||||||
&self,
|
&self,
|
||||||
client: &Client,
|
client: &Client,
|
||||||
key: &KeySet,
|
key: &KeySet,
|
||||||
metadata: Vec<u8>,
|
metadata: &[u8],
|
||||||
reader: EncryptedReader,
|
reader: EncryptedReader,
|
||||||
) -> Request {
|
) -> Request {
|
||||||
// Get the reader length
|
// Get the reader length
|
||||||
|
@ -250,7 +250,7 @@ impl Upload {
|
||||||
|
|
||||||
// Ensure the response is successful
|
// Ensure the response is successful
|
||||||
ensure_success(&response)
|
ensure_success(&response)
|
||||||
.map_err(|err| UploadError::Response(err))?;
|
.map_err(UploadError::Response)?;
|
||||||
|
|
||||||
// Try to get the nonce, don't error on failure
|
// Try to get the nonce, don't error on failure
|
||||||
let nonce = header_nonce(&response).ok();
|
let nonce = header_nonce(&response).ok();
|
||||||
|
|
|
@ -5,7 +5,7 @@ use api::request::{ensure_success, ResponseError};
|
||||||
use crypto::b64;
|
use crypto::b64;
|
||||||
|
|
||||||
/// The name of the header the nonce is delivered in.
|
/// The name of the header the nonce is delivered in.
|
||||||
const HEADER_NONCE: &'static str = "WWW-Authenticate";
|
const HEADER_NONCE: &str = "WWW-Authenticate";
|
||||||
|
|
||||||
/// Do a new request, and extract the nonce from a header in the given
|
/// Do a new request, and extract the nonce from a header in the given
|
||||||
/// response.
|
/// response.
|
||||||
|
@ -38,11 +38,10 @@ pub fn header_nonce(response: &Response)
|
||||||
.and_then(|line| String::from_utf8(line.to_vec())
|
.and_then(|line| String::from_utf8(line.to_vec())
|
||||||
.map_err(|_| NonceError::MalformedNonce)
|
.map_err(|_| NonceError::MalformedNonce)
|
||||||
)?
|
)?
|
||||||
.split_terminator(" ")
|
.split_terminator(' ')
|
||||||
.skip(1)
|
.nth(2)
|
||||||
.next()
|
|
||||||
.ok_or(NonceError::MalformedNonce)?
|
.ok_or(NonceError::MalformedNonce)?
|
||||||
).map_err(|_| NonceError::MalformedNonce.into())
|
).map_err(|_| NonceError::MalformedNonce)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Fail, Debug)]
|
#[derive(Fail, Debug)]
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use reqwest::StatusCode;
|
use reqwest::StatusCode;
|
||||||
|
|
||||||
/// The Send host to use by default.
|
/// The Send host to use by default.
|
||||||
pub const SEND_DEFAULT_HOST: &'static str = "https://send.firefox.com/";
|
pub const SEND_DEFAULT_HOST: &str = "https://send.firefox.com/";
|
||||||
|
|
||||||
/// The default time after which uploaded files expire after, in seconds.
|
/// The default time after which uploaded files expire after, in seconds.
|
||||||
pub const SEND_DEFAULT_EXPIRE_TIME: i64 = 24 * 60 * 60;
|
pub const SEND_DEFAULT_EXPIRE_TIME: i64 = 24 * 60 * 60;
|
||||||
|
@ -13,7 +13,7 @@ pub const HTTP_STATUS_EXPIRED: StatusCode = StatusCode::NotFound;
|
||||||
pub const HTTP_STATUS_UNAUTHORIZED: StatusCode = StatusCode::Unauthorized;
|
pub const HTTP_STATUS_UNAUTHORIZED: StatusCode = StatusCode::Unauthorized;
|
||||||
|
|
||||||
/// The recommended maximum upload size in bytes.
|
/// The recommended maximum upload size in bytes.
|
||||||
pub const UPLOAD_SIZE_MAX_RECOMMENDED: u64 = 1024 * 1024 * 1024 * 1;
|
pub const UPLOAD_SIZE_MAX_RECOMMENDED: u64 = 1024 * 1024 * 1024;
|
||||||
|
|
||||||
/// The maximum upload size in bytes.
|
/// The maximum upload size in bytes.
|
||||||
pub const UPLOAD_SIZE_MAX: u64 = 1024 * 1024 * 1024 * 2;
|
pub const UPLOAD_SIZE_MAX: u64 = 1024 * 1024 * 1024 * 2;
|
||||||
|
|
|
@ -26,7 +26,7 @@ const KEY_AUTH_ITERATIONS: usize = 100;
|
||||||
/// # Returns
|
/// # Returns
|
||||||
/// The output keying material, with the length as as specified in the `length`
|
/// The output keying material, with the length as as specified in the `length`
|
||||||
/// argument.
|
/// argument.
|
||||||
fn hkdf<'a>(
|
fn hkdf(
|
||||||
length: usize,
|
length: usize,
|
||||||
ikm: &[u8],
|
ikm: &[u8],
|
||||||
info: Option<&[u8]>,
|
info: Option<&[u8]>,
|
||||||
|
|
|
@ -10,6 +10,6 @@ impl StatusCodeExt for StatusCode {
|
||||||
fn err_text(&self) -> String {
|
fn err_text(&self) -> String {
|
||||||
self.canonical_reason()
|
self.canonical_reason()
|
||||||
.map(|text| format!("{} {}", self.as_u16(), text))
|
.map(|text| format!("{} {}", self.as_u16(), text))
|
||||||
.unwrap_or(format!("{}", self.as_u16()))
|
.unwrap_or_else(|| format!("{}", self.as_u16()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,7 +34,7 @@ impl Metadata {
|
||||||
/// * iv: initialisation vector
|
/// * iv: initialisation vector
|
||||||
/// * name: file name
|
/// * name: file name
|
||||||
/// * mime: file mimetype
|
/// * mime: file mimetype
|
||||||
pub fn from(iv: &[u8], name: String, mime: Mime) -> Self {
|
pub fn from(iv: &[u8], name: String, mime: &Mime) -> Self {
|
||||||
Metadata {
|
Metadata {
|
||||||
iv: b64::encode(iv),
|
iv: b64::encode(iv),
|
||||||
name,
|
name,
|
||||||
|
|
|
@ -17,11 +17,11 @@ use crypto::b64;
|
||||||
// TODO: match any sub-path?
|
// TODO: match any sub-path?
|
||||||
// TODO: match URL-safe base64 chars for the file ID?
|
// TODO: match URL-safe base64 chars for the file ID?
|
||||||
// TODO: constrain the ID length?
|
// TODO: constrain the ID length?
|
||||||
const SHARE_PATH_PATTERN: &'static str = r"^/?download/([[:alnum:]]{8,}={0,3})/?$";
|
const SHARE_PATH_PATTERN: &str = r"^/?download/([[:alnum:]]{8,}={0,3})/?$";
|
||||||
|
|
||||||
/// A pattern for share URL fragments, capturing the file secret.
|
/// A pattern for share URL fragments, capturing the file secret.
|
||||||
// TODO: constrain the secret length?
|
// TODO: constrain the secret length?
|
||||||
const SHARE_FRAGMENT_PATTERN: &'static str = r"^([a-zA-Z0-9-_+/]+)?\s*$";
|
const SHARE_FRAGMENT_PATTERN: &str = r"^([a-zA-Z0-9-_+/]+)?\s*$";
|
||||||
|
|
||||||
/// A struct representing an uploaded file on a Send host.
|
/// A struct representing an uploaded file on a Send host.
|
||||||
///
|
///
|
||||||
|
@ -289,19 +289,20 @@ impl RemoteFile {
|
||||||
/// This is ofcourse only done for properties that may be empty.
|
/// This is ofcourse only done for properties that may be empty.
|
||||||
///
|
///
|
||||||
/// The file IDs are not asserted for equality.
|
/// The file IDs are not asserted for equality.
|
||||||
|
#[allow(useless_let_if_seq)]
|
||||||
pub fn merge(&mut self, other: &RemoteFile, overwrite: bool) -> bool {
|
pub fn merge(&mut self, other: &RemoteFile, overwrite: bool) -> bool {
|
||||||
// Remember whether anything was changed
|
// Remember whether anything has changed
|
||||||
let mut changed = false;
|
let mut changed = false;
|
||||||
|
|
||||||
// Set the upload time
|
// Set the upload time
|
||||||
if other.upload_at.is_some() && (self.upload_at.is_none() || overwrite) {
|
if other.upload_at.is_some() && (self.upload_at.is_none() || overwrite) {
|
||||||
self.upload_at = other.upload_at.clone();
|
self.upload_at = other.upload_at;
|
||||||
changed = true;
|
changed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set the expire time
|
// Set the expire time
|
||||||
if !other.expire_uncertain() && (self.expire_uncertain() || overwrite) {
|
if !other.expire_uncertain() && (self.expire_uncertain() || overwrite) {
|
||||||
self.expire_at = other.expire_at.clone();
|
self.expire_at = other.expire_at;
|
||||||
self.expire_uncertain = other.expire_uncertain();
|
self.expire_uncertain = other.expire_uncertain();
|
||||||
changed = true;
|
changed = true;
|
||||||
}
|
}
|
||||||
|
@ -318,7 +319,7 @@ impl RemoteFile {
|
||||||
changed = true;
|
changed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return changed;
|
changed
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -94,7 +94,7 @@ impl EncryptedFileReader {
|
||||||
/// returned.
|
/// returned.
|
||||||
fn read_internal(&mut self, buf: &mut [u8]) -> usize {
|
fn read_internal(&mut self, buf: &mut [u8]) -> usize {
|
||||||
// Return if there is no data to read
|
// Return if there is no data to read
|
||||||
if self.internal_buf.is_empty() || buf.len() == 0 {
|
if self.internal_buf.is_empty() || buf.is_empty() {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -335,6 +335,11 @@ pub trait ProgressReporter: Send {
|
||||||
pub trait ExactLengthReader {
|
pub trait ExactLengthReader {
|
||||||
/// Get the exact length of the reader in bytes.
|
/// Get the exact length of the reader in bytes.
|
||||||
fn len(&self) -> Result<u64, io::Error>;
|
fn len(&self) -> Result<u64, io::Error>;
|
||||||
|
|
||||||
|
/// Check whehter this extact length reader is emtpy.
|
||||||
|
fn is_empty(&self) -> Result<bool, io::Error> {
|
||||||
|
self.len().map(|l| l == 0)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<R: ExactLengthReader + Read> ExactLengthReader for BufReader<R> {
|
impl<R: ExactLengthReader + Read> ExactLengthReader for BufReader<R> {
|
||||||
|
|
|
@ -18,6 +18,7 @@ use ffsend_api::action::metadata::{
|
||||||
Metadata as ApiMetadata,
|
Metadata as ApiMetadata,
|
||||||
};
|
};
|
||||||
use ffsend_api::file::remote_file::{FileParseError, RemoteFile};
|
use ffsend_api::file::remote_file::{FileParseError, RemoteFile};
|
||||||
|
use ffsend_api::reader::ProgressReporter;
|
||||||
use ffsend_api::reqwest::Client;
|
use ffsend_api::reqwest::Client;
|
||||||
|
|
||||||
use cmd::matcher::{
|
use cmd::matcher::{
|
||||||
|
@ -93,7 +94,7 @@ impl<'a> Download<'a> {
|
||||||
|
|
||||||
// Prepare the output path to use
|
// Prepare the output path to use
|
||||||
let target = Self::prepare_path(
|
let target = Self::prepare_path(
|
||||||
target,
|
&target,
|
||||||
metadata.metadata().name(),
|
metadata.metadata().name(),
|
||||||
&matcher_main,
|
&matcher_main,
|
||||||
);
|
);
|
||||||
|
@ -104,7 +105,8 @@ impl<'a> Download<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a progress bar reporter
|
// Create a progress bar reporter
|
||||||
let bar = Arc::new(Mutex::new(ProgressBar::new_download()));
|
let progress_bar = Arc::new(Mutex::new(ProgressBar::new_download()));
|
||||||
|
let progress_reader: Arc<Mutex<ProgressReporter>> = progress_bar;
|
||||||
|
|
||||||
// Execute an download action
|
// Execute an download action
|
||||||
ApiDownload::new(
|
ApiDownload::new(
|
||||||
|
@ -113,7 +115,7 @@ impl<'a> Download<'a> {
|
||||||
password,
|
password,
|
||||||
false,
|
false,
|
||||||
Some(metadata),
|
Some(metadata),
|
||||||
).invoke(&client, bar)?;
|
).invoke(&client, &progress_reader)?;
|
||||||
|
|
||||||
// Add the file to the history
|
// Add the file to the history
|
||||||
#[cfg(feature = "history")]
|
#[cfg(feature = "history")]
|
||||||
|
@ -138,12 +140,12 @@ impl<'a> Download<'a> {
|
||||||
///
|
///
|
||||||
/// The program will quit with an error message if a problem occurs.
|
/// The program will quit with an error message if a problem occurs.
|
||||||
fn prepare_path(
|
fn prepare_path(
|
||||||
target: PathBuf,
|
target: &PathBuf,
|
||||||
name_hint: &str,
|
name_hint: &str,
|
||||||
main_matcher: &MainMatcher,
|
main_matcher: &MainMatcher,
|
||||||
) -> PathBuf {
|
) -> PathBuf {
|
||||||
// Select the path to use
|
// Select the path to use
|
||||||
let target = Self::select_path(target, name_hint);
|
let target = Self::select_path(&target, name_hint);
|
||||||
|
|
||||||
// Ask to overwrite
|
// Ask to overwrite
|
||||||
if target.exists() && !main_matcher.force() {
|
if target.exists() && !main_matcher.force() {
|
||||||
|
@ -185,7 +187,7 @@ impl<'a> Download<'a> {
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
|
|
||||||
return target;
|
target
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This methods prepares a full file path to use for the file to
|
/// This methods prepares a full file path to use for the file to
|
||||||
|
@ -195,7 +197,7 @@ impl<'a> Download<'a> {
|
||||||
/// If no file name was given, the original file name is used.
|
/// If no file name was given, the original file name is used.
|
||||||
///
|
///
|
||||||
/// The full path including the file name will be returned.
|
/// The full path including the file name will be returned.
|
||||||
fn select_path(target: PathBuf, name_hint: &str) -> PathBuf {
|
fn select_path(target: &PathBuf, name_hint: &str) -> PathBuf {
|
||||||
// If we're already working with a file, canonicalize and return
|
// If we're already working with a file, canonicalize and return
|
||||||
if target.is_file() {
|
if target.is_file() {
|
||||||
match target.canonicalize() {
|
match target.canonicalize() {
|
||||||
|
@ -255,7 +257,7 @@ impl<'a> Download<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return target;
|
target
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,7 @@ use ffsend_api::action::upload::{
|
||||||
Upload as ApiUpload,
|
Upload as ApiUpload,
|
||||||
};
|
};
|
||||||
use ffsend_api::config::{UPLOAD_SIZE_MAX, UPLOAD_SIZE_MAX_RECOMMENDED};
|
use ffsend_api::config::{UPLOAD_SIZE_MAX, UPLOAD_SIZE_MAX_RECOMMENDED};
|
||||||
|
use ffsend_api::reader::ProgressReporter;
|
||||||
use ffsend_api::reqwest::Client;
|
use ffsend_api::reqwest::Client;
|
||||||
use self::tempfile::{
|
use self::tempfile::{
|
||||||
Builder as TempBuilder,
|
Builder as TempBuilder,
|
||||||
|
@ -106,7 +107,7 @@ impl<'a> Upload<'a> {
|
||||||
let client = Client::new();
|
let client = Client::new();
|
||||||
|
|
||||||
// Create a progress bar reporter
|
// Create a progress bar reporter
|
||||||
let bar = Arc::new(Mutex::new(ProgressBar::new_upload()));
|
let progress_bar = Arc::new(Mutex::new(ProgressBar::new_upload()));
|
||||||
|
|
||||||
// Build a parameters object to set for the file
|
// Build a parameters object to set for the file
|
||||||
let params = {
|
let params = {
|
||||||
|
@ -142,14 +143,14 @@ impl<'a> Upload<'a> {
|
||||||
.prefix(&format!(".{}-archive-", crate_name!()))
|
.prefix(&format!(".{}-archive-", crate_name!()))
|
||||||
.suffix(archive_extention)
|
.suffix(archive_extention)
|
||||||
.tempfile()
|
.tempfile()
|
||||||
.map_err(|err| ArchiveError::TempFile(err))?
|
.map_err(ArchiveError::TempFile)?
|
||||||
);
|
);
|
||||||
if let Some(tmp_archive) = &tmp_archive {
|
if let Some(tmp_archive) = &tmp_archive {
|
||||||
// Get the path, and the actual file
|
// Get the path, and the actual file
|
||||||
let archive_path = tmp_archive.path().clone().to_path_buf();
|
let archive_path = tmp_archive.path().to_path_buf();
|
||||||
let archive_file = tmp_archive.as_file()
|
let archive_file = tmp_archive.as_file()
|
||||||
.try_clone()
|
.try_clone()
|
||||||
.map_err(|err| ArchiveError::CloneHandle(err))?;
|
.map_err(ArchiveError::CloneHandle)?;
|
||||||
|
|
||||||
// Select the file name to use if not set
|
// Select the file name to use if not set
|
||||||
if file_name.is_none() {
|
if file_name.is_none() {
|
||||||
|
@ -166,10 +167,10 @@ impl<'a> Upload<'a> {
|
||||||
// Build an archiver and append the file
|
// Build an archiver and append the file
|
||||||
let mut archiver = Archiver::new(archive_file);
|
let mut archiver = Archiver::new(archive_file);
|
||||||
archiver.append_path(file_name.as_ref().unwrap(), &path)
|
archiver.append_path(file_name.as_ref().unwrap(), &path)
|
||||||
.map_err(|err| ArchiveError::AddFile(err))?;
|
.map_err(ArchiveError::AddFile)?;
|
||||||
|
|
||||||
// Finish the archival process, writes the archive file
|
// Finish the archival process, writes the archive file
|
||||||
archiver.finish().map_err(|err| ArchiveError::Write(err))?;
|
archiver.finish().map_err(ArchiveError::Write)?;
|
||||||
|
|
||||||
// Append archive extention to name, set to upload archived file
|
// Append archive extention to name, set to upload archived file
|
||||||
if let Some(ref mut file_name) = file_name {
|
if let Some(ref mut file_name) = file_name {
|
||||||
|
@ -179,6 +180,9 @@ impl<'a> Upload<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Build the progress reporter
|
||||||
|
let progress_reporter: Arc<Mutex<ProgressReporter>> = progress_bar;
|
||||||
|
|
||||||
// Execute an upload action
|
// Execute an upload action
|
||||||
let file = ApiUpload::new(
|
let file = ApiUpload::new(
|
||||||
host,
|
host,
|
||||||
|
@ -186,7 +190,7 @@ impl<'a> Upload<'a> {
|
||||||
file_name,
|
file_name,
|
||||||
matcher_upload.password(),
|
matcher_upload.password(),
|
||||||
params,
|
params,
|
||||||
).invoke(&client, bar)?;
|
).invoke(&client, &progress_reporter)?;
|
||||||
|
|
||||||
// Get the download URL, and report it in the console
|
// Get the download URL, and report it in the console
|
||||||
let url = file.download_url(true);
|
let url = file.download_url(true);
|
||||||
|
@ -199,7 +203,7 @@ impl<'a> Upload<'a> {
|
||||||
|
|
||||||
// Open the URL in the browser
|
// Open the URL in the browser
|
||||||
if matcher_upload.open() {
|
if matcher_upload.open() {
|
||||||
if let Err(err) = open_url(url.clone()) {
|
if let Err(err) = open_url(&url) {
|
||||||
print_error(
|
print_error(
|
||||||
err.context("failed to open the URL in the browser")
|
err.context("failed to open the URL in the browser")
|
||||||
);
|
);
|
||||||
|
@ -209,12 +213,10 @@ impl<'a> Upload<'a> {
|
||||||
// Copy the URL in the user's clipboard
|
// Copy the URL in the user's clipboard
|
||||||
#[cfg(feature = "clipboard")]
|
#[cfg(feature = "clipboard")]
|
||||||
{
|
{
|
||||||
if matcher_upload.copy() {
|
if matcher_upload.copy() && set_clipboard(url.as_str().to_owned()).is_err() {
|
||||||
if set_clipboard(url.as_str().to_owned()).is_err() {
|
|
||||||
print_error_msg("failed to copy the URL to the clipboard");
|
print_error_msg("failed to copy the URL to the clipboard");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Close the temporary zip file, to ensure it's removed
|
// Close the temporary zip file, to ensure it's removed
|
||||||
if let Some(tmp_archive) = tmp_archive.take() {
|
if let Some(tmp_archive) = tmp_archive.take() {
|
||||||
|
|
|
@ -14,7 +14,7 @@ use super::matcher::{
|
||||||
};
|
};
|
||||||
#[cfg(feature = "history")]
|
#[cfg(feature = "history")]
|
||||||
use super::matcher::HistoryMatcher;
|
use super::matcher::HistoryMatcher;
|
||||||
use super::cmd::{
|
use super::subcmd::{
|
||||||
CmdDelete,
|
CmdDelete,
|
||||||
CmdDownload,
|
CmdDownload,
|
||||||
CmdExists,
|
CmdExists,
|
||||||
|
@ -24,7 +24,7 @@ use super::cmd::{
|
||||||
CmdUpload,
|
CmdUpload,
|
||||||
};
|
};
|
||||||
#[cfg(feature = "history")]
|
#[cfg(feature = "history")]
|
||||||
use super::cmd::CmdHistory;
|
use super::subcmd::CmdHistory;
|
||||||
#[cfg(feature = "history")]
|
#[cfg(feature = "history")]
|
||||||
use util::app_history_file_path_string;
|
use util::app_history_file_path_string;
|
||||||
|
|
||||||
|
|
|
@ -32,8 +32,8 @@ impl<'a: 'b, 'b> DownloadMatcher<'a> {
|
||||||
/// will be used.
|
/// will be used.
|
||||||
pub fn output(&'a self) -> PathBuf {
|
pub fn output(&'a self) -> PathBuf {
|
||||||
self.matches.value_of("output")
|
self.matches.value_of("output")
|
||||||
.map(|path| PathBuf::from(path))
|
.map(PathBuf::from)
|
||||||
.unwrap_or(PathBuf::from("./"))
|
.unwrap_or_else(|| PathBuf::from("./"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -33,7 +33,7 @@ impl<'a: 'b, 'b> MainMatcher<'a> {
|
||||||
pub fn history(&self) -> PathBuf {
|
pub fn history(&self) -> PathBuf {
|
||||||
// Get the path
|
// Get the path
|
||||||
let path = self.matches.value_of("history")
|
let path = self.matches.value_of("history")
|
||||||
.map(|path| PathBuf::from(path));
|
.map(PathBuf::from);
|
||||||
|
|
||||||
// Ensure the path is correct
|
// Ensure the path is correct
|
||||||
match path {
|
match path {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
pub mod arg;
|
pub mod arg;
|
||||||
pub mod cmd;
|
pub mod subcmd;
|
||||||
pub mod handler;
|
pub mod handler;
|
||||||
pub mod matcher;
|
pub mod matcher;
|
||||||
|
|
||||||
|
|
|
@ -17,10 +17,10 @@ use self::version_compare::{
|
||||||
use util::{print_error, print_warning};
|
use util::{print_error, print_warning};
|
||||||
|
|
||||||
/// The minimum supported history file version.
|
/// The minimum supported history file version.
|
||||||
const VERSION_MIN: &'static str = "0.0.1";
|
const VERSION_MIN: &str = "0.0.1";
|
||||||
|
|
||||||
/// The maximum supported history file version.
|
/// The maximum supported history file version.
|
||||||
const VERSION_MAX: &'static str = crate_version!();
|
const VERSION_MAX: &str = crate_version!();
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
pub struct History {
|
pub struct History {
|
||||||
|
@ -105,7 +105,7 @@ impl History {
|
||||||
if self.files.is_empty() {
|
if self.files.is_empty() {
|
||||||
if path.is_file() {
|
if path.is_file() {
|
||||||
fs::remove_file(&path)
|
fs::remove_file(&path)
|
||||||
.map_err(|err| SaveError::Delete(err))?;
|
.map_err(SaveError::Delete)?;
|
||||||
}
|
}
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
@ -189,9 +189,7 @@ impl History {
|
||||||
/// If multiple files exist within the history that are equal, only one is returned.
|
/// If multiple files exist within the history that are equal, only one is returned.
|
||||||
/// If no matching file was found, `None` is returned.
|
/// If no matching file was found, `None` is returned.
|
||||||
pub fn get_file(&self, file: &RemoteFile) -> Option<&RemoteFile> {
|
pub fn get_file(&self, file: &RemoteFile) -> Option<&RemoteFile> {
|
||||||
self.files.iter()
|
self.files.iter().find(|f| f.id() == file.id() && f.host() == file.host())
|
||||||
.filter(|f| f.id() == file.id() && f.host() == file.host())
|
|
||||||
.next()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Garbage collect (remove) all files that have been expired,
|
/// Garbage collect (remove) all files that have been expired,
|
||||||
|
|
|
@ -125,8 +125,8 @@ pub fn derive_file_properties(matcher_main: &MainMatcher, file: &mut RemoteFile)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return whether any property was derived
|
// Return whether any property was derived
|
||||||
return f.has_secret() || f.has_owner_token();
|
f.has_secret() || f.has_owner_token()
|
||||||
},
|
},
|
||||||
None => return false,
|
None => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -121,13 +121,13 @@ pub fn print_main_info() {
|
||||||
// Print the main info
|
// Print the main info
|
||||||
println!("{} {}", crate_name!(), crate_version!());
|
println!("{} {}", crate_name!(), crate_version!());
|
||||||
println!("Usage: {} [FLAGS] <SUBCOMMAND> ...", exe);
|
println!("Usage: {} [FLAGS] <SUBCOMMAND> ...", exe);
|
||||||
println!("");
|
println!();
|
||||||
println!("{}", crate_description!());
|
println!(crate_description!());
|
||||||
println!("");
|
println!();
|
||||||
println!("Missing subcommand. Here are the most used:");
|
println!("Missing subcommand. Here are the most used:");
|
||||||
println!(" {}", highlight(&format!("{} upload <FILE> ...", exe)));
|
println!(" {}", highlight(&format!("{} upload <FILE> ...", exe)));
|
||||||
println!(" {}", highlight(&format!("{} download <URL> ...", exe)));
|
println!(" {}", highlight(&format!("{} download <URL> ...", exe)));
|
||||||
println!("");
|
println!();
|
||||||
println!("To show all subcommands, features and other help:");
|
println!("To show all subcommands, features and other help:");
|
||||||
println!(" {}", highlight(&format!("{} help [SUBCOMMAND]", exe)));
|
println!(" {}", highlight(&format!("{} help [SUBCOMMAND]", exe)));
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,7 @@ const PROGRESS_BAR_FPS_MILLIS: u64 = 200;
|
||||||
|
|
||||||
/// A progress bar reporter.
|
/// A progress bar reporter.
|
||||||
pub struct ProgressBar<'a> {
|
pub struct ProgressBar<'a> {
|
||||||
bar: Option<Pbr<Stdout>>,
|
progress_bar: Option<Pbr<Stdout>>,
|
||||||
msg_progress: &'a str,
|
msg_progress: &'a str,
|
||||||
msg_finish: &'a str,
|
msg_finish: &'a str,
|
||||||
}
|
}
|
||||||
|
@ -23,7 +23,7 @@ impl<'a> ProgressBar<'a> {
|
||||||
/// Construct a new progress bar, with the given messages.
|
/// Construct a new progress bar, with the given messages.
|
||||||
pub fn new(msg_progress: &'a str, msg_finish: &'a str) -> ProgressBar<'a> {
|
pub fn new(msg_progress: &'a str, msg_finish: &'a str) -> ProgressBar<'a> {
|
||||||
Self {
|
Self {
|
||||||
bar: None,
|
progress_bar: None,
|
||||||
msg_progress,
|
msg_progress,
|
||||||
msg_finish,
|
msg_finish,
|
||||||
}
|
}
|
||||||
|
@ -44,26 +44,26 @@ impl<'a> ProgressReporter for ProgressBar<'a> {
|
||||||
/// Start the progress with the given total.
|
/// Start the progress with the given total.
|
||||||
fn start(&mut self, total: u64) {
|
fn start(&mut self, total: u64) {
|
||||||
// Initialize the progress bar
|
// Initialize the progress bar
|
||||||
let mut bar = Pbr::new(total);
|
let mut progress_bar = Pbr::new(total);
|
||||||
bar.set_max_refresh_rate(
|
progress_bar.set_max_refresh_rate(
|
||||||
Some(Duration::from_millis(PROGRESS_BAR_FPS_MILLIS))
|
Some(Duration::from_millis(PROGRESS_BAR_FPS_MILLIS))
|
||||||
);
|
);
|
||||||
bar.set_units(Units::Bytes);
|
progress_bar.set_units(Units::Bytes);
|
||||||
bar.message(self.msg_progress);
|
progress_bar.message(self.msg_progress);
|
||||||
|
|
||||||
self.bar = Some(bar);
|
self.progress_bar = Some(progress_bar);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A progress update.
|
/// A progress update.
|
||||||
fn progress(&mut self, progress: u64) {
|
fn progress(&mut self, progress: u64) {
|
||||||
self.bar.as_mut()
|
self.progress_bar.as_mut()
|
||||||
.expect("progress bar not yet instantiated, cannot set progress")
|
.expect("progress bar not yet instantiated, cannot set progress")
|
||||||
.set(progress);
|
.set(progress);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Finish the progress.
|
/// Finish the progress.
|
||||||
fn finish(&mut self) {
|
fn finish(&mut self) {
|
||||||
self.bar.as_mut()
|
self.progress_bar.as_mut()
|
||||||
.expect("progress bar not yet instantiated")
|
.expect("progress bar not yet instantiated")
|
||||||
.finish_print(self.msg_finish);
|
.finish_print(self.msg_finish);
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@ extern crate directories;
|
||||||
extern crate fs2;
|
extern crate fs2;
|
||||||
extern crate open;
|
extern crate open;
|
||||||
|
|
||||||
|
use std::borrow::Borrow;
|
||||||
use std::env::current_exe;
|
use std::env::current_exe;
|
||||||
#[cfg(feature = "clipboard")]
|
#[cfg(feature = "clipboard")]
|
||||||
use std::error::Error as StdError;
|
use std::error::Error as StdError;
|
||||||
|
@ -40,9 +41,11 @@ pub fn print_success(msg: &str) {
|
||||||
|
|
||||||
/// Print the given error in a proper format for the user,
|
/// Print the given error in a proper format for the user,
|
||||||
/// with it's causes.
|
/// with it's causes.
|
||||||
pub fn print_error<E: Fail>(err: E) {
|
pub fn print_error<E: Fail>(err: impl Borrow<E>) {
|
||||||
// Report each printable error, count them
|
// Report each printable error, count them
|
||||||
let count = err.causes() .map(|err| format!("{}", err))
|
let count = err.borrow()
|
||||||
|
.causes()
|
||||||
|
.map(|err| format!("{}", err))
|
||||||
.filter(|err| !err.is_empty())
|
.filter(|err| !err.is_empty())
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.map(|(i, err)| if i == 0 {
|
.map(|(i, err)| if i == 0 {
|
||||||
|
@ -57,7 +60,6 @@ pub fn print_error<E: Fail>(err: E) {
|
||||||
eprintln!("{} {}", highlight_error("error:"), "an undefined error occurred");
|
eprintln!("{} {}", highlight_error("error:"), "an undefined error occurred");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Print the given error message in a proper format for the user,
|
/// Print the given error message in a proper format for the user,
|
||||||
/// with it's causes.
|
/// with it's causes.
|
||||||
pub fn print_error_msg<S>(err: S)
|
pub fn print_error_msg<S>(err: S)
|
||||||
|
@ -83,12 +85,12 @@ pub fn quit() -> ! {
|
||||||
|
|
||||||
/// Quit the application with an error code,
|
/// Quit the application with an error code,
|
||||||
/// and print the given error.
|
/// and print the given error.
|
||||||
pub fn quit_error<E: Fail>(err: E, hints: ErrorHints) -> ! {
|
pub fn quit_error<E: Fail>(err: E, hints: impl Borrow<ErrorHints>) -> ! {
|
||||||
// Print the error
|
// Print the error
|
||||||
print_error(err);
|
print_error(err);
|
||||||
|
|
||||||
// Print error hints
|
// Print error hints
|
||||||
hints.print();
|
hints.borrow().print();
|
||||||
|
|
||||||
// Quit
|
// Quit
|
||||||
exit(1);
|
exit(1);
|
||||||
|
@ -96,7 +98,7 @@ pub fn quit_error<E: Fail>(err: E, hints: ErrorHints) -> ! {
|
||||||
|
|
||||||
/// Quit the application with an error code,
|
/// Quit the application with an error code,
|
||||||
/// and print the given error message.
|
/// and print the given error message.
|
||||||
pub fn quit_error_msg<S>(err: S, hints: ErrorHints) -> !
|
pub fn quit_error_msg<S>(err: S, hints: impl Borrow<ErrorHints>) -> !
|
||||||
where
|
where
|
||||||
S: AsRef<str> + Display + Debug + Sync + Send + 'static
|
S: AsRef<str> + Display + Debug + Sync + Send + 'static
|
||||||
{
|
{
|
||||||
|
@ -247,8 +249,8 @@ pub fn highlight_info(msg: &str) -> ColoredString {
|
||||||
|
|
||||||
/// Open the given URL in the users default browser.
|
/// Open the given URL in the users default browser.
|
||||||
/// The browsers exit statis is returned.
|
/// The browsers exit statis is returned.
|
||||||
pub fn open_url(url: Url) -> Result<ExitStatus, IoError> {
|
pub fn open_url(url: impl Borrow<Url>) -> Result<ExitStatus, IoError> {
|
||||||
open_path(url.as_str())
|
open_path(url.borrow().as_str())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Open the given path or URL using the program configured on the system.
|
/// Open the given path or URL using the program configured on the system.
|
||||||
|
@ -538,15 +540,15 @@ pub fn format_duration(duration: &Duration) -> String {
|
||||||
// Build a list of time units, define a list for time components
|
// Build a list of time units, define a list for time components
|
||||||
let mut components = Vec::new();
|
let mut components = Vec::new();
|
||||||
let units = [
|
let units = [
|
||||||
(1 * 60 * 60 * 24 * 7, "w"),
|
(60 * 60 * 24 * 7, "w"),
|
||||||
(1 * 60 * 60 * 24, "d"),
|
(60 * 60 * 24, "d"),
|
||||||
(1 * 60 * 60, "h"),
|
(60 * 60, "h"),
|
||||||
(1 * 60, "m"),
|
(60, "m"),
|
||||||
(1, "s"),
|
(1, "s"),
|
||||||
];
|
];
|
||||||
|
|
||||||
// Fill the list of time components based on the units which fit
|
// Fill the list of time components based on the units which fit
|
||||||
for unit in units.iter() {
|
for unit in &units {
|
||||||
if secs >= unit.0 {
|
if secs >= unit.0 {
|
||||||
components.push(format!("{}{}", secs / unit.0, unit.1));
|
components.push(format!("{}{}", secs / unit.0, unit.1));
|
||||||
secs %= unit.0;
|
secs %= unit.0;
|
||||||
|
@ -564,7 +566,7 @@ pub fn exe_name() -> String {
|
||||||
.ok()
|
.ok()
|
||||||
.and_then(|p| p.file_name().map(|n| n.to_owned()))
|
.and_then(|p| p.file_name().map(|n| n.to_owned()))
|
||||||
.and_then(|n| n.into_string().ok())
|
.and_then(|n| n.into_string().ok())
|
||||||
.unwrap_or(crate_name!().into())
|
.unwrap_or_else(|| crate_name!().into())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Ensure that there is enough free disk space available at the given `path`,
|
/// Ensure that there is enough free disk space available at the given `path`,
|
||||||
|
@ -620,7 +622,7 @@ pub fn app_project_dirs() -> ProjectDirs {
|
||||||
|
|
||||||
/// Get the default path to use for the history file.
|
/// Get the default path to use for the history file.
|
||||||
#[cfg(feature = "history")]
|
#[cfg(feature = "history")]
|
||||||
pub fn app_history_file_path<'a>() -> PathBuf {
|
pub fn app_history_file_path() -> PathBuf {
|
||||||
app_project_dirs().cache_dir().join("history.toml")
|
app_project_dirs().cache_dir().join("history.toml")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue