fake_archive_accessor/fake_archive_accessor/
archivist_server.rs

1// Copyright 2020 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5// This code is adapted and simplified from
6// fuchsia-mirror/src/diagnostics/archivist/src/server.rs
7
8use fidl::prelude::*;
9use fidl_fuchsia_diagnostics::{
10    BatchIteratorControlHandle, BatchIteratorRequest, BatchIteratorRequestStream, FormattedContent,
11};
12
13use futures::prelude::*;
14use log::warn;
15use thiserror::Error;
16use zx_status::Status as ZxStatus;
17
18pub struct AccessorServer {
19    requests: BatchIteratorRequestStream,
20}
21
22impl AccessorServer {
23    pub fn new(requests: BatchIteratorRequestStream) -> Self {
24        Self { requests }
25    }
26
27    // This fails tests that try to send more data than a single VMO should hold.
28    fn build_vmo(&self, data: &str) -> Result<Vec<FormattedContent>, ServerError> {
29        let size = data.len() as u64;
30        if size > 1024 * 1024 {
31            return Err(ServerError::DataTooBig);
32        }
33        let vmo = zx::Vmo::create(size).map_err(ServerError::VmoCreate)?;
34        vmo.write(data.as_bytes(), 0).map_err(ServerError::VmoWrite)?;
35        Ok(vec![FormattedContent::Json(fidl_fuchsia_mem::Buffer { vmo, size })])
36    }
37
38    pub async fn send(mut self, data: &str) -> Result<(), ServerError> {
39        if let Some(res) = self.requests.next().await {
40            match res? {
41                BatchIteratorRequest::GetNext { responder } => {
42                    let response = self.build_vmo(data)?;
43                    responder.send(Ok(response))?;
44                }
45                BatchIteratorRequest::WaitForReady { responder } => responder.send()?,
46                BatchIteratorRequest::_UnknownMethod { .. } => {
47                    unreachable!("Unexpected method call");
48                }
49            };
50            if let Some(res) = self.requests.next().await {
51                match res? {
52                    BatchIteratorRequest::GetNext { responder } => responder.send(Ok(vec![]))?,
53                    BatchIteratorRequest::WaitForReady { responder } => responder.send()?,
54                    BatchIteratorRequest::_UnknownMethod { .. } => {
55                        unreachable!("Unexpected method call");
56                    }
57                };
58            } else {
59                return Err(ServerError::TooFewBatchRequests);
60            }
61        } else {
62            return Err(ServerError::TooFewBatchRequests);
63        }
64        Ok(())
65    }
66}
67
68#[derive(Debug, Error)]
69pub enum ServerError {
70    #[error("Inspect data for test must be <1 MB")]
71    DataTooBig,
72
73    #[error("The client closed the batch connection early")]
74    TooFewBatchRequests,
75
76    #[error("data_type must be set")]
77    MissingDataType,
78
79    #[error("client_selector_configuration must be set")]
80    MissingSelectors,
81
82    #[error("no selectors were provided")]
83    EmptySelectors,
84
85    #[error("requested selectors are unsupported: {}", .0)]
86    InvalidSelectors(&'static str),
87
88    #[error("couldn't parse/validate the provided selectors")]
89    ParseSelectors(#[from] selectors::Error),
90
91    #[error("format must be set")]
92    MissingFormat,
93
94    #[error("Only Inspect supported right now")]
95    UnsupportedType,
96
97    #[error("only JSON supported right now")]
98    UnsupportedFormat,
99
100    #[error("stream_mode must be set")]
101    MissingMode,
102
103    #[error("only snapshot supported right now")]
104    UnsupportedMode,
105
106    #[error("IPC failure")]
107    Ipc {
108        #[from]
109        source: fidl::Error,
110    },
111
112    #[error("Unable to create a VMO -- extremely unusual!")]
113    VmoCreate(#[source] ZxStatus),
114
115    #[error("Unable to write to VMO -- we may be OOMing")]
116    VmoWrite(#[source] ZxStatus),
117}
118
119impl ServerError {
120    pub fn close(self, control: BatchIteratorControlHandle) {
121        warn!("Closing BatchIterator: {}", &self);
122        let epitaph = match self {
123            ServerError::MissingDataType | ServerError::DataTooBig => ZxStatus::INVALID_ARGS,
124            ServerError::EmptySelectors
125            | ServerError::MissingSelectors
126            | ServerError::InvalidSelectors(_)
127            | ServerError::ParseSelectors(_) => ZxStatus::INVALID_ARGS,
128            ServerError::VmoCreate(status) | ServerError::VmoWrite(status) => status,
129            ServerError::MissingFormat | ServerError::MissingMode => ZxStatus::INVALID_ARGS,
130            ServerError::UnsupportedFormat
131            | ServerError::UnsupportedMode
132            | ServerError::UnsupportedType => ZxStatus::WRONG_TYPE,
133            ServerError::Ipc { .. } | ServerError::TooFewBatchRequests => ZxStatus::IO,
134        };
135        control.shutdown_with_epitaph(epitaph);
136    }
137}