1use super::{BodyCapture, Engine, Headers, READ_PRESERVED_PATH, Response, auth::Verified};
3use crate::{BoxStream, Code, NamespaceStore, ServerError};
4use base64::{Engine as _, engine::general_purpose::STANDARD};
5use bytes::Bytes;
6use futures::stream;
7use serde_json::{Value, json};
8use std::sync::Arc;
9
10pub struct PreservedPiece {
12 pub data: Bytes,
14 pub offset: u64,
16 pub last: bool,
18}
19impl std::fmt::Debug for PreservedPiece {
20 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
21 f.debug_struct("PreservedPiece")
22 .field("length", &self.data.len())
23 .field("offset", &self.offset)
24 .field("last", &self.last)
25 .finish()
26 }
27}
28pub enum Reply {
30 Unary(Response),
32 Stream(BoxStream<'static, Result<Bytes, ServerError>>),
34}
35impl std::fmt::Debug for Reply {
36 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
37 match self {
38 Self::Unary(response) => response.fmt(f),
39 Self::Stream(_) => f.write_str("AdminStream"),
40 }
41 }
42}
43fn frame(flags: u8, value: &Value) -> Result<Bytes, ServerError> {
44 let encoded = serde_json::to_vec(value)
45 .map_err(|_| ServerError::new(Code::Internal, "admin stream encoding failed"))?;
46 let length = u32::try_from(encoded.len())
47 .map_err(|_| ServerError::new(Code::Internal, "admin stream overflow"))?;
48 let mut out = Vec::with_capacity(encoded.len() + 5);
49 out.push(flags);
50 out.extend_from_slice(&length.to_be_bytes());
51 out.extend(encoded);
52 Ok(Bytes::from(out))
53}
54impl<S: NamespaceStore + 'static> Engine<S> {
55 pub async fn handle_streamed(
58 self: Arc<Self>,
59 path: &str,
60 headers: &Headers,
61 wire: &BodyCapture,
62 decoded: Option<Result<Vec<u8>, ServerError>>,
63 now_ms: i64,
64 ) -> Reply {
65 let verified = match self.config.verify(path, headers, wire, now_ms) {
66 Ok(verified) => verified,
67 Err(error) => return Reply::Unary(Response::error(&error)),
68 };
69 let result = match self
70 .dispatch(path, headers, wire, decoded, now_ms, true)
71 .await
72 {
73 Ok(response) => response,
74 Err(error) => return Reply::Unary(Response::error(&error)),
75 };
76 if path != READ_PRESERVED_PATH || result.status != 200 {
77 return Reply::Unary(result);
78 }
79 let Ok(descriptor) = serde_json::from_slice::<Value>(&result.body) else {
80 let error = ServerError::new(Code::DataLoss, "invalid read descriptor");
81 let result = self
82 .record_result(&verified, now_ms, Response::error(&error))
83 .await
84 .unwrap_or_else(|error| Response::error(&error));
85 return Reply::Unary(result);
86 };
87 Reply::Stream(Box::pin(stream::unfold(
89 (self, verified, descriptor, 0u8),
90 |(engine, verified, mut descriptor, stage)| async move {
91 if stage == 2 {
92 return None;
93 }
94 if stage == 1 {
95 return Some((
96 frame(2, &json!({"metadata":{}})),
97 (engine, verified, descriptor, 2),
98 ));
99 }
100 let result = engine.next_piece(&descriptor).await;
101 let (message, next_stage) = match result {
102 Ok(piece) => match piece.offset.checked_add(piece.data.len() as u64) {
103 Some(next) => {
104 descriptor["offset"] = json!(next.to_string());
105 (
106 frame(
107 0,
108 &json!({"data":STANDARD.encode(&piece.data), "offset":piece.offset.to_string(), "last":piece.last}),
109 ),
110 u8::from(piece.last),
111 )
112 }
113 None => (
114 engine
115 .stream_error(
116 &verified,
117 &ServerError::new(Code::DataLoss, "invalid preserved offset"),
118 )
119 .await,
120 2,
121 ),
122 },
123 Err(error) => (engine.stream_error(&verified, &error).await, 2),
124 };
125 Some((message, (engine, verified, descriptor, next_stage)))
126 },
127 )))
128 }
129 async fn next_piece(&self, descriptor: &Value) -> Result<PreservedPiece, ServerError> {
130 let service = self
131 .operations
132 .as_ref()
133 .ok_or_else(|| ServerError::unavailable("preservation service unavailable"))?;
134 service.preserved_piece(descriptor).await
135 }
136 async fn stream_error(
137 &self,
138 verified: &Verified,
139 error: &ServerError,
140 ) -> Result<Bytes, ServerError> {
141 self.record_result(
142 verified,
143 self.operations
144 .as_ref()
145 .ok_or_else(|| ServerError::unavailable("preservation service unavailable"))?
146 .preserved_now_ms()?,
147 Response::error(error),
148 )
149 .await?;
150 frame(
151 2,
152 &json!({"metadata":{}, "error":{"code":error.code().as_str(),"message":error.public_message()}}),
153 )
154 }
155}