support_bundle_viewer/
bundle_accessor.rs1use crate::index::SupportBundleIndex;
8use anyhow::Result;
9use async_trait::async_trait;
10use camino::Utf8Path;
11use std::io;
12use std::pin::Pin;
13use std::task::Context;
14use std::task::Poll;
15use tokio::io::AsyncRead;
16use tokio::io::ReadBuf;
17
18pub trait FileAccessor: AsyncRead + Unpin + Send {}
22impl<T: AsyncRead + Unpin + Send + ?Sized> FileAccessor for T {}
23
24pub type BoxedFileAccessor<'a> = Box<dyn FileAccessor + 'a>;
25
26#[async_trait]
28pub trait SupportBundleAccessor: Send {
29 async fn get_index(&self) -> Result<SupportBundleIndex>;
31
32 async fn get_file<'a>(&mut self, path: &Utf8Path) -> Result<BoxedFileAccessor<'a>>
34 where
35 Self: 'a;
36}
37
38pub struct LocalFileAccess {
39 archive: zip::read::ZipArchive<std::fs::File>,
40}
41
42impl LocalFileAccess {
43 pub fn new(path: &Utf8Path) -> Result<Self> {
44 let file = std::fs::File::open(path)?;
45 Ok(Self {
46 archive: zip::read::ZipArchive::new(file)?,
47 })
48 }
49}
50
51#[async_trait]
53impl SupportBundleAccessor for LocalFileAccess {
54 async fn get_index(&self) -> Result<SupportBundleIndex> {
55 let names: Vec<&str> = self.archive.file_names().collect();
56 let all_names = names.join("\n");
57 Ok(SupportBundleIndex::new(&all_names))
58 }
59
60 async fn get_file<'a>(&mut self, path: &Utf8Path) -> Result<BoxedFileAccessor<'a>> {
61 let mut file = self.archive.by_name(path.as_str())?;
62 let mut buf = Vec::new();
63 std::io::copy(&mut file, &mut buf)?;
64
65 Ok(Box::new(AsyncZipFile { buf, copied: 0 }))
66 }
67}
68
69pub struct AsyncZipFile {
72 buf: Vec<u8>,
73 copied: usize,
74}
75
76impl AsyncRead for AsyncZipFile {
77 fn poll_read(
78 mut self: Pin<&mut Self>,
79 _cx: &mut Context<'_>,
80 buf: &mut ReadBuf<'_>,
81 ) -> Poll<io::Result<()>> {
82 let to_copy = std::cmp::min(self.buf.len() - self.copied, buf.remaining());
83 if to_copy == 0 {
84 return Poll::Ready(Ok(()));
85 }
86 let src = &self.buf[self.copied..];
87 buf.put_slice(&src[..to_copy]);
88 self.copied += to_copy;
89 Poll::Ready(Ok(()))
90 }
91}