diff options
| author | David Lönnhager <david.l@mullvad.net> | 2024-01-10 10:42:27 +0100 |
|---|---|---|
| committer | David Lönnhager <david.l@mullvad.net> | 2024-01-10 10:42:50 +0100 |
| commit | 01bcf9ed16a903aa80ff8bc48cc6f2aaf3d6e80d (patch) | |
| tree | dee82ab3f307f8d1a72a0cf01fceb8fa51612ac1 /mullvad-cli/src | |
| parent | 10ef7c04decb5c57a52a2565d4f6e573658d6c6d (diff) | |
| download | mullvadvpn-01bcf9ed16a903aa80ff8bc48cc6f2aaf3d6e80d.tar.xz mullvadvpn-01bcf9ed16a903aa80ff8bc48cc6f2aaf3d6e80d.zip | |
Simplify JSON import and export in the CLI
Diffstat (limited to 'mullvad-cli/src')
| -rw-r--r-- | mullvad-cli/src/cmds/patch.rs | 126 |
1 files changed, 20 insertions, 106 deletions
diff --git a/mullvad-cli/src/cmds/patch.rs b/mullvad-cli/src/cmds/patch.rs index c935c08aac..bec686e56d 100644 --- a/mullvad-cli/src/cmds/patch.rs +++ b/mullvad-cli/src/cmds/patch.rs @@ -1,14 +1,10 @@ -use anyhow::{anyhow, Context, Result}; +use anyhow::{Context, Result}; use mullvad_management_interface::MullvadProxyClient; use std::{ fs::File, - io::{stdin, stdout, BufRead, BufReader, BufWriter, Write}, - path::Path, + io::{stdin, BufReader, Read}, }; -/// Maximum size of a settings patch. Bigger files/streams cause the read to fail. -const MAX_PATCH_BYTES: usize = 10 * 1024; - /// If source is specified, read from the provided file and send it as a settings patch to the /// daemon. Otherwise, read the patch from standard input. pub async fn import(source: String) -> Result<()> { @@ -30,117 +26,35 @@ pub async fn import(source: String) -> Result<()> { /// output. pub async fn export(dest: String) -> Result<()> { let mut rpc = MullvadProxyClient::new().await?; - let json_blob = rpc + let blob = rpc .export_json_settings() .await .context("Error exporting patch")?; - tokio::task::spawn_blocking(|| put_blob(dest, json_blob)) - .await - .unwrap()?; - - Ok(()) + match dest.as_str() { + "-" => { + println!("{blob}"); + Ok(()) + } + _ => tokio::fs::write(&dest, blob) + .await + .context(format!("Failed to write to path {dest}")), + } } fn get_blob(source: String) -> Result<String> { match source.as_str() { - "-" => read_settings_from_stdin().context("Failed to read from stdin"), - _ => { - read_settings_from_file(&source).context(format!("Failed to read from path: {source}")) + "-" => { + read_settings_from_reader(BufReader::new(stdin())).context("Failed to read from stdin") } + _ => read_settings_from_reader(File::open(&source)?) + .context(format!("Failed to read from path: {source}")), } } -/// Read settings from standard input -fn read_settings_from_stdin() -> Result<String> { - read_settings_from_reader(BufReader::new(stdin())) -} - -/// Read settings from a path -fn read_settings_from_file(path: impl AsRef<Path>) -> Result<String> { - read_settings_from_reader(BufReader::new(File::open(path)?)) -} - /// Read until EOF or until newline when the last pair of braces has been closed -fn read_settings_from_reader(mut reader: impl BufRead) -> Result<String> { - let mut buf = [0u8; MAX_PATCH_BYTES]; - - let mut was_open = false; - let mut close_after_newline = false; - let mut brace_count: usize = 0; - let mut cursor_pos = 0; - - loop { - let Some(cursor) = buf.get_mut(cursor_pos..) else { - return Err(anyhow!( - "Patch too long: maximum length is {MAX_PATCH_BYTES} bytes" - )); - }; - - let prev_cursor_pos = cursor_pos; - let read_n = reader.read(cursor)?; - if read_n == 0 { - // EOF - break; - } - cursor_pos += read_n; - - let additional_bytes = &buf[prev_cursor_pos..cursor_pos]; - - if !close_after_newline { - for next in additional_bytes { - match next { - b'{' => brace_count += 1, - b'}' => { - brace_count = brace_count.checked_sub(1).with_context(|| { - // exit: too many closing braces - "syntax error: unexpected '}'" - })? - } - _ => (), - } - was_open |= brace_count > 0; - } - if brace_count == 0 && was_open { - // complete settings - close_after_newline = true; - } - } - - if close_after_newline && additional_bytes.contains(&b'\n') { - // done - break; - } - } - - Ok(std::str::from_utf8(&buf[0..cursor_pos]) - .context("settings must be utf8 encoded")? - .to_owned()) -} - -fn put_blob(dest: String, blob: String) -> Result<()> { - match dest.as_str() { - "-" => write_settings_to_stdout(blob).context("Failed to write to stdout"), - _ => write_settings_to_file(&dest, blob).context(format!("Failed to write to path {dest}")), - } -} - -/// Write patch to standard output -fn write_settings_to_stdout(blob: String) -> Result<()> { - write_settings_using_writer(BufWriter::new(stdout()), blob) -} - -/// Write patch to path -fn write_settings_to_file(path: impl AsRef<Path>, blob: String) -> Result<()> { - write_settings_using_writer( - BufWriter::new(File::options().create(true).write(true).open(path)?), - blob, - ) -} - -fn write_settings_using_writer(mut writer: impl Write, blob: String) -> Result<()> { - writer - .write_all(blob.as_bytes()) - .context("Failed to write blob to destination")?; - writer.write_all(b"\n").context("Failed to write newline") +fn read_settings_from_reader(mut reader: impl Read) -> Result<String> { + let mut s = String::new(); + reader.read_to_string(&mut s)?; + Ok(s) } |
