From c69bbec8df6758b54747de276273abd16ed7c478 Mon Sep 17 00:00:00 2001 From: Emi Simpson Date: Wed, 17 Aug 2022 22:55:31 -0400 Subject: [PATCH] Error messages for downloads --- src/errors.rs | 132 ++++++++++++++++++++++++++++++++++++++++++++++++-- src/main.rs | 7 ++- 2 files changed, 133 insertions(+), 6 deletions(-) diff --git a/src/errors.rs b/src/errors.rs index 31e70d2..ed53d48 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -281,10 +281,12 @@ pub enum AviaryDownloadError { /// An important reason this might occur is if the gallery expired and the server re-assigned /// the ID to another file, and both used the .bin extension. /// - /// Handling: If this occurs for an image where the URL and key are both provided by the - /// index, it should always be interpreted as an expiration. If it occurs for an index, ask - /// the user to verify that they key and file ID were copied correctly, and if they are - /// correct, then the gallery expired. + /// Note: If there is a key mismatch for an image in a gallery, rather than on the index, this + /// should be interpretted as an expiration instead, and should use the [`ExpiredImage`][] + /// variant. + /// + /// Handling: Ask the user to verify that they key and file ID were copied correctly, and if + /// they are correct, then the gallery expired. KeyMismatch, /// Indicates that the index did not conform to the protobuf spec @@ -376,3 +378,125 @@ impl AviaryDownloadError { } }} } + +impl fmt::Display for AviaryDownloadError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + if let AviaryDownloadError::Cancelled = self { + writeln!(f, "\x1b[31mCancelled\x1b[0m")?; + } else { + writeln!(f, "\x1b[31mError!\x1b[0m\n")?; + } + match self { + AviaryDownloadError::MalformedKey(invalid) => + write!(f, concat!( + "It looks like that key {} Double check to make sure that you ", + "copied it correctly. If you did, ask the person who sent you the ", + "link to make sure that /they/ copied it correctly." + ), if *invalid { + "isn't valid base64, and won't work here." + } else { + "is the wrong length!" + }), + AviaryDownloadError::ServerError(err_code, msg) => + write!(f, concat!( + "The server storing this gallery seems to be behaving in a way we ", + "didn't expect. Double check to make sure that you've set the ", + "correct instance with \x1b[35m-s\x1b[0m/\x1b[35m--server\x1b[0m, ", + "and if the problem persists, reach out the server administrator to ", + "let them know that something went wrong.\n\n", + "This information might help to diagnose the issue:\n\x1b[31m{}", + ), if let Some(err_code) = err_code { + format!("Error code {:03}:\n{}", err_code, &msg[..usize::min(50, msg.len())]) + } else { + format!("Server misbehaviour: {}", msg) + }), + AviaryDownloadError::PermissionDenied(path) => + write!(f, concat!( + "It looks like you don't have permission for the directory you're ", + "trying to download this album into. Specifically, permission was ", + "denied for \x1b[36m{}\x1b[0m\n\n", + "Try acquiring permission, or picking a different directory with ", + "\x1b[35m-ox1b[0m/x1b[35m--outputx1b[0m." + ), path.display()), + AviaryDownloadError::FilesystemError(err, path) => + write!(f, concat!( + "Some uncommon filesystem error happened while we were trying to ", + "write to/create \x1b[36m{}\x1b[0m. This shouldn't happen very ", + "often, but here's a few guesses as to what might have happened:\n", + "\x1b[37m- \x1b[0mA disk was ejected while we were saving a file\n", + "\x1b[37m- \x1b[0mYou're using a special filesystem that ", + "encountered an error\n", + "\x1b[37m- \x1b[0mThe disk you were writing to is read only\n\n", + "If you're getting this error and you don't know why, we'd really ", + "appreciate it if you could open an issue on our bug tracker. Even ", + "just the filesystem you were using and the error you got could be ", + "enough to help.\n\n", + "The full error that we got is:\n\x1b[31m{:?}", + ), path.display(), err), + AviaryDownloadError::BadServerParameter => + write!(f, concat!( + "Oops! The server you entered looks like it might not be correct. ", + "Double check that your \x1b[35m-s\x1b[0m/\x1b[35m--server\x1b[0m ", + "parameter is correct" + )), + AviaryDownloadError::ConnectionError(msg) => + write!(f, concat!( + "There was an issue connecting to the server! Check that your ", + "internet is online, and you can access websites normally. ", + "This information might help diagnose the issue:\n\n", + "\x1b[31m{}\x1b[0m" + ), msg), + AviaryDownloadError::MissingIndex => + write!(f, concat!( + "No album found at this URL! Double check that the file ID you ", + "entered is correct and that you've specified the right instance ", + "using \x1b[35m-s\x1b[0m/\x1b[35m--server\x1b[0m. If you have, this ", + "album may have expired." + )), + AviaryDownloadError::ExpiredImage => + write!(f, concat!( + "One or more images in this album have expired. Currently, the ", + "command line tool has no support for downloading partially expired ", + "albums, although this may change in the future. Please contact the ", + "original uploader to get a new album link." + )), + AviaryDownloadError::KeyMismatch => + write!(f, concat!( + "Wrong key! Either the base64 key that you entered isn't right, or ", + "it doesn't go to this album. Double check that you've copied both ", + "the album ID and the key correctly. If you're not using the main ", + "instance, you should also double check that you've set the ", + "\x1b[35m-s\x1b[0m/\x1b[35m--server\x1b[0m. If all of this is ", + "correct, then the album may be expired." + )), + AviaryDownloadError::CorruptIndex(msg) => + write!(f, concat!( + "Something very strange has occurred. \x1b[31;1mIf you are a ", + "non-technical user, feel free to stop here and open an issue, and ", + "we can help figure out why this happened and how we can stop it ", + "from happening in the future.\x1b[0m If you are a technical user, ", + "read on to learn what happened.\n\n", + "The index which stores a listing of the files in this album (along ", + "with metadata like the title and description) was corrupt. ", + "However, the decryption was succeeded, including the MAC ", + "checking. This could stem from a couple possibilities:\n", + "\x1b[37m- \x1b[0mThe key/file id pair provided was valid, but ", + "points to an image rather than a gallery\n", + "\x1b[37m- \x1b[0mA very poorly behaved client generated this ", + "album, and produced a corrupt index\n", + "\x1b[37m- \x1b[0mThis is a key/file pair which is meant to be ", + "used with a different project with a very similar encryption scheme\n\n", + "The specific error is as follows:\n\x1b[31m{}" + ), msg), + AviaryDownloadError::NotOverwriting(path) => + write!(f, concat!( + "The file \x1b[36m{}\x1b[0m already exists! To keep your data ", + "safe, we won't overwrite it unless you pass the ", + "\x1b[35m-f\x1b[0m/\x1b[35m--force\x1b[0m flag. Consider removing ", + "the file yourself or choosing a new directory with the ", + "\x1b[35m-o\x1b[0m/\x1b[35m--output\x1b[0m flag.", + ), path.display()), + AviaryDownloadError::Cancelled => Ok(()), + } + } +} diff --git a/src/main.rs b/src/main.rs index 25439ff..95d2ac2 100644 --- a/src/main.rs +++ b/src/main.rs @@ -46,7 +46,10 @@ fn main() { }; match args.command { Command::Create(create_args) => create(&*full_server, create_args), - Command::Download(download_args) => download(&*full_server, download_args).unwrap(), + Command::Download(download_args) => + if let Err(e) = download(&*full_server, download_args) { + println!("{e}") + }, } } @@ -243,7 +246,7 @@ fn download(server: &str, args: DownloadArgs) -> Result<(), AviaryDownloadError> _ => println!(""), } } - print!("\x1b[37m├─\x1b[0m Reserving file... "); + print!("\x1b[37m├─\x1b[0m Reserving file... "); stdout().flush().unwrap(); let path = dest_dir.join(format!("{indx:03}.{extension}")); let mut dest_file = OpenOptions::new()