From 3d6b3c47862a2e83c8df3bbf571ef5fa96b89d0e Mon Sep 17 00:00:00 2001 From: Wolfgang Bumiller Date: Wed, 4 Sep 2024 11:20:11 +0200 Subject: [PATCH] router: split streaming reader impl into 'stream' feature so 'no-default-features' compiles again Signed-off-by: Wolfgang Bumiller --- proxmox-router/Cargo.toml | 3 +- proxmox-router/src/router.rs | 7 ++-- proxmox-router/src/stream/mod.rs | 36 +++++++++++++++++++ .../src/{stream.rs => stream/parsing.rs} | 33 ++--------------- 4 files changed, 43 insertions(+), 36 deletions(-) create mode 100644 proxmox-router/src/stream/mod.rs rename proxmox-router/src/{stream.rs => stream/parsing.rs} (89%) diff --git a/proxmox-router/Cargo.toml b/proxmox-router/Cargo.toml index e1c6a01f..4cd5b568 100644 --- a/proxmox-router/Cargo.toml +++ b/proxmox-router/Cargo.toml @@ -42,6 +42,7 @@ tokio-stream.workspace = true [features] default = [ "cli", "server" ] -cli = [ "dep:env_logger", "dep:libc", "dep:rustyline" ] +cli = [ "stream", "dep:env_logger", "dep:libc", "dep:rustyline" ] server = [ "dep:http", "dep:hyper" ] test-harness = [ "proxmox-schema/test-harness" ] +stream = [ "dep:hyper" ] diff --git a/proxmox-router/src/router.rs b/proxmox-router/src/router.rs index 4491e59b..33b598da 100644 --- a/proxmox-router/src/router.rs +++ b/proxmox-router/src/router.rs @@ -80,11 +80,6 @@ pub type SerializingApiHandlerFn = &'static (dyn Fn( /// A record for a streaming API call. This contains a `Result` and allows formatting /// as a `json-seq` formatted string. -/// -/// This is currently just a json string, but we don't want to fixate strings or byte vectors as -/// output for the streaming API handler, but also not commit to creating lots of allocated -/// `Box` elements, so this can be turned into either without breaking the -/// API. pub struct Record { // direct access is only for the CLI code pub(crate) data: crate::stream::Record, @@ -204,6 +199,7 @@ impl SyncStream { self.inner } + #[cfg(feature = "stream")] pub fn try_collect(self) -> Result { let mut acc = Vec::new(); for i in self.inner { @@ -347,6 +343,7 @@ impl Stream { self.inner } + #[cfg(feature = "stream")] pub async fn try_collect(mut self) -> Result { use futures::StreamExt; diff --git a/proxmox-router/src/stream/mod.rs b/proxmox-router/src/stream/mod.rs new file mode 100644 index 00000000..976b8695 --- /dev/null +++ b/proxmox-router/src/stream/mod.rs @@ -0,0 +1,36 @@ +use anyhow::Error; +use serde::{Deserialize, Serialize}; + +#[cfg(feature = "stream")] +mod parsing; +#[cfg(feature = "stream")] +pub use parsing::{BodyBufReader, JsonRecords, Records}; + +/// Streamed JSON records can contain either "data" or an error. +/// +/// Errors can be a simple string or structured data. +#[derive(Deserialize, Serialize)] +#[serde(rename_all = "kebab-case")] +pub enum Record { + /// A successful record. + Data(T), + /// An error entry. + Error(serde_json::Value), +} + +impl Record { + /// Convenience method to turn the record into a `Result`. + /// + /// The error is converted to either a message or, for structured errors, a json + /// representation. + pub fn into_result(self) -> Result { + match self { + Self::Data(data) => Ok(data), + Self::Error(serde_json::Value::String(s)) => Err(Error::msg(s)), + Self::Error(other) => match serde_json::to_string(&other) { + Ok(s) => Err(Error::msg(s)), + Err(err) => Err(Error::from(err)), + }, + } + } +} diff --git a/proxmox-router/src/stream.rs b/proxmox-router/src/stream/parsing.rs similarity index 89% rename from proxmox-router/src/stream.rs rename to proxmox-router/src/stream/parsing.rs index 49b1fba4..4e13d687 100644 --- a/proxmox-router/src/stream.rs +++ b/proxmox-router/src/stream/parsing.rs @@ -6,7 +6,9 @@ use std::task::{ready, Poll}; use anyhow::{format_err, Context as _, Error}; use futures::io::{AsyncBufRead, AsyncBufReadExt, AsyncRead, BufReader}; use hyper::body::{Body, Bytes}; -use serde::{Deserialize, Serialize}; +use serde::Deserialize; + +use super::Record; pub struct Records where @@ -308,32 +310,3 @@ impl AsyncBufRead for BodyBufReader { } } } - -/// Streamed JSON records can contain either "data" or an error. -/// -/// Errors can be a simple string or structured data. -/// -/// For convenience, an [`into_result()`](Record::into_result) method is provided to turn the -/// record into a regular `Result`, where the error is converted to either a message or, for -/// structured errors, a json representation. -#[derive(Deserialize, Serialize)] -#[serde(rename_all = "kebab-case")] -pub enum Record { - /// A successful record. - Data(T), - /// An error entry. - Error(serde_json::Value), -} - -impl Record { - pub fn into_result(self) -> Result { - match self { - Self::Data(data) => Ok(data), - Self::Error(serde_json::Value::String(s)) => Err(Error::msg(s)), - Self::Error(other) => match serde_json::to_string(&other) { - Ok(s) => Err(Error::msg(s)), - Err(err) => Err(Error::from(err)), - }, - } - } -}