vtx_sdk/host/
stream.rs

1//! Host-side stream I/O helpers (Buffer).
2
3use crate::bindings::vtx::api::stream_io;
4use crate::bindings::vtx::api::stream_io::Buffer;
5use crate::error::{VtxError, VtxResult};
6use serde::de::DeserializeOwned;
7
8pub type StreamBuffer = Buffer;
9
10/// 通过宿主的 UUID 打开文件并返回 `Buffer` 资源句柄。
11pub fn open_file(uuid: &str) -> VtxResult<Buffer> {
12    stream_io::open_file(uuid).map_err(VtxError::from_host_message)
13}
14
15/// 创建一个内存 Buffer(通常用于构造 `HttpResponse.body`)。
16pub fn memory_buffer(data: impl AsRef<[u8]>) -> Buffer {
17    stream_io::create_memory_buffer(data.as_ref())
18}
19
20/// `Buffer` 资源的便捷扩展方法。
21pub trait BufferExt {
22    /// 读取整个 Buffer。
23    ///
24    /// - 对于 file/memory:使用 `size()` 做分块读取。
25    /// - 对于 pipe:会持续读取直到 EOF(返回空数组)或到达 `max_total_bytes`。
26    fn read_all(&self) -> Vec<u8>;
27
28    /// 按 UTF-8 读取整个 Buffer。
29    fn read_to_string(&self) -> VtxResult<String>;
30
31    /// 将 Buffer 中的 JSON 反序列化为目标类型。
32    fn read_json<T: DeserializeOwned>(&self) -> VtxResult<T>;
33
34    /// 向 Buffer 追加写入(对文件:append;对 pipe:写入 stdin;对 memory:append)。
35    fn write_all(&self, data: impl AsRef<[u8]>) -> u64;
36}
37
38impl BufferExt for Buffer {
39    fn read_all(&self) -> Vec<u8> {
40        const CHUNK: u64 = 64 * 1024;
41        const MAX_TOTAL: usize = 64 * 1024 * 1024;
42
43        let mut out = Vec::new();
44
45        let total = self.size();
46        if total > 0 {
47            let mut offset = 0u64;
48            while offset < total && out.len() < MAX_TOTAL {
49                let to_read = std::cmp::min(CHUNK, total - offset);
50                let chunk = self.read(offset, to_read);
51                if chunk.is_empty() {
52                    break;
53                }
54                out.extend_from_slice(&chunk);
55                offset += chunk.len() as u64;
56            }
57            return out;
58        }
59
60        // Pipe 模式:不知道 size,读到空为止(EOF)。
61        while out.len() < MAX_TOTAL {
62            let chunk = self.read(0, CHUNK);
63            if chunk.is_empty() {
64                break;
65            }
66            out.extend_from_slice(&chunk);
67        }
68
69        out
70    }
71
72    fn read_to_string(&self) -> VtxResult<String> {
73        let bytes = self.read_all();
74        String::from_utf8(bytes).map_err(|e| VtxError::SerializationError(e.to_string()))
75    }
76
77    fn read_json<T: DeserializeOwned>(&self) -> VtxResult<T> {
78        let s = self.read_to_string()?;
79        serde_json::from_str(&s).map_err(|e| VtxError::SerializationError(e.to_string()))
80    }
81
82    fn write_all(&self, data: impl AsRef<[u8]>) -> u64 {
83        self.write(data.as_ref())
84    }
85}