diff options
| author | Linus Färnstrand <linus@mullvad.net> | 2017-10-26 21:34:45 +0200 |
|---|---|---|
| committer | Linus Färnstrand <linus@mullvad.net> | 2017-10-27 08:55:32 +0200 |
| commit | 71cc79e4365cd16d287262b12fb4f4d7804c943d (patch) | |
| tree | 1bdda4d38925dd961544f8b5a47fcfcd693e9af9 | |
| parent | b31de5df85dedcb52e4b1bfc52a0ce85b61b9160 (diff) | |
| download | mullvadvpn-71cc79e4365cd16d287262b12fb4f4d7804c943d.tar.xz mullvadvpn-71cc79e4365cd16d287262b12fb4f4d7804c943d.zip | |
Implement problem report send
| -rw-r--r-- | mullvad-daemon/src/bin/problem-report.rs | 77 |
1 files changed, 42 insertions, 35 deletions
diff --git a/mullvad-daemon/src/bin/problem-report.rs b/mullvad-daemon/src/bin/problem-report.rs index ef9534b7cb..0c1a7718d6 100644 --- a/mullvad-daemon/src/bin/problem-report.rs +++ b/mullvad-daemon/src/bin/problem-report.rs @@ -11,6 +11,8 @@ extern crate clap; #[macro_use] extern crate error_chain; +extern crate mullvad_rpc; + use error_chain::ChainedError; use std::cmp::min; use std::fmt; @@ -20,6 +22,9 @@ use std::path::{Path, PathBuf}; /// Maximum number of bytes to read from each log file const LOG_MAX_READ_BYTES: usize = 5 * 1024 * 1024; +/// Maximum number of bytes allowed in a report. +const REPORT_MAX_SIZE: usize = 4 * LOG_MAX_READ_BYTES; + /// Field delimeter in generated problem report const LOG_DELIMITER: &'static str = "===================="; @@ -34,6 +39,9 @@ error_chain!{ description("Error reading the contents of log file") display("Error reading the contents of log file: {}", path.to_string_lossy()) } + RpcError { + description("Error during RPC call") + } } } @@ -104,11 +112,10 @@ fn run() -> Result<()> { let output_path = value_t_or_exit!(collect_matches.value_of("output"), String); collect_report(log_paths, PathBuf::from(output_path)) } else if let Some(send_matches) = matches.subcommand_matches("send") { - let report_path = value_t_or_exit!(send_matches.value_of("report"), String); - let user_email = value_t!(send_matches.value_of("email"), String).unwrap_or(String::new()); - let user_message = - value_t!(send_matches.value_of("message"), String).unwrap_or(String::new()); - send_problem_report(user_email, user_message, PathBuf::from(report_path)) + let report_path = Path::new(send_matches.value_of_os("report").unwrap()); + let user_email = send_matches.value_of("email").unwrap_or(""); + let user_message = send_matches.value_of("message").unwrap_or(""); + send_problem_report(user_email, user_message, report_path) } else { unreachable!("No sub command given"); } @@ -123,13 +130,15 @@ fn collect_report(log_paths: Vec<PathBuf>, save_path: PathBuf) -> Result<()> { .chain_err(|| ErrorKind::WriteReportError(save_path.clone())) } -fn send_problem_report( - _user_email: String, - _user_message: String, - _report_path: PathBuf, -) -> Result<()> { - // TODO: Implement submission to master - Ok(()) +fn send_problem_report(user_email: &str, user_message: &str, report_path: &Path) -> Result<()> { + let report_content = read_file_lossy(report_path, REPORT_MAX_SIZE) + .chain_err(|| ErrorKind::ReadLogError(report_path.to_path_buf()))?; + let mut rpc_client = + mullvad_rpc::ProblemReportProxy::connect().chain_err(|| ErrorKind::RpcError)?; + rpc_client + .problem_report(user_email, user_message, &report_content) + .call() + .chain_err(|| ErrorKind::RpcError) } fn write_problem_report(path: &Path, problem_report: ProblemReport) -> io::Result<()> { @@ -147,32 +156,14 @@ struct ProblemReport { } impl ProblemReport { - /// Attach file log to this report. This method uses the error chain instead of log contents if - /// error occurred when reading log file. + /// Attach file log to this report. This method uses the error chain instead of log + /// contents if error occurred when reading log file. fn add_log(&mut self, path: &Path) { - let content = Self::read_file_lossy(path, LOG_MAX_READ_BYTES) + let content = read_file_lossy(path, LOG_MAX_READ_BYTES) .chain_err(|| ErrorKind::ReadLogError(path.to_path_buf())) .unwrap_or_else(|e| e.display_chain().to_string()); - self.logs.push(( - path.to_string_lossy().into_owned(), - content, - )); - } - - /// Private helper to safely read the given number of bytes off the tail of UTF-8 log file - /// and return it as a string - fn read_file_lossy(path: &Path, max_bytes: usize) -> io::Result<String> { - let mut file = File::open(path)?; - let file_size = file.metadata()?.len(); - - if file_size > max_bytes as u64 { - file.seek(SeekFrom::Start(file_size - max_bytes as u64))?; - } - - let capacity = min(file_size, max_bytes as u64) as usize; - let mut buffer = Vec::with_capacity(capacity); - file.take(max_bytes as u64).read_to_end(&mut buffer)?; - Ok(String::from_utf8_lossy(&buffer).into_owned()) + self.logs + .push((path.to_string_lossy().into_owned(), content)); } } @@ -188,3 +179,19 @@ impl fmt::Display for ProblemReport { Ok(()) } } + +/// Helper to lossily read a file to a `String`. If the file size exceeds the given `max_bytes`, +/// only the last `max_bytes` of the file is read. +fn read_file_lossy(path: &Path, max_bytes: usize) -> io::Result<String> { + let mut file = File::open(path)?; + let file_size = file.metadata()?.len(); + + if file_size > max_bytes as u64 { + file.seek(SeekFrom::Start(file_size - max_bytes as u64))?; + } + + let capacity = min(file_size, max_bytes as u64) as usize; + let mut buffer = Vec::with_capacity(capacity); + file.take(max_bytes as u64).read_to_end(&mut buffer)?; + Ok(String::from_utf8_lossy(&buffer).into_owned()) +} |
