summaryrefslogtreecommitdiffhomepage
path: root/mullvad-cli/src/cmds
diff options
context:
space:
mode:
authorDavid Lönnhager <david.l@mullvad.net>2024-01-10 10:42:27 +0100
committerDavid Lönnhager <david.l@mullvad.net>2024-01-10 10:42:50 +0100
commit01bcf9ed16a903aa80ff8bc48cc6f2aaf3d6e80d (patch)
treedee82ab3f307f8d1a72a0cf01fceb8fa51612ac1 /mullvad-cli/src/cmds
parent10ef7c04decb5c57a52a2565d4f6e573658d6c6d (diff)
downloadmullvadvpn-01bcf9ed16a903aa80ff8bc48cc6f2aaf3d6e80d.tar.xz
mullvadvpn-01bcf9ed16a903aa80ff8bc48cc6f2aaf3d6e80d.zip
Simplify JSON import and export in the CLI
Diffstat (limited to 'mullvad-cli/src/cmds')
-rw-r--r--mullvad-cli/src/cmds/patch.rs126
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)
}