blob: 464c42eecae8221e877e6d7a4493a2ff09332dd5 [file] [log] [blame]
// Copyright 2020 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use {
fidl_fuchsia_examples_inspect::{ReverserRequest, ReverserRequestStream},
fuchsia_async as fasync,
fuchsia_inspect::{self as inspect, NumericProperty},
futures::TryStreamExt,
std::sync::Arc,
};
pub struct ReverserServerFactory {
node: inspect::Node,
request_count: Arc<inspect::UintProperty>,
connection_count: inspect::UintProperty,
}
impl ReverserServerFactory {
pub fn new(node: inspect::Node) -> Self {
let request_count = Arc::new(node.create_uint("total_requests", 0));
let connection_count = node.create_uint("connection_count", 0);
Self { node, request_count, connection_count }
}
pub fn spawn_new(&self, stream: ReverserRequestStream) {
self.spawn_new_internal(stream, || {})
}
fn spawn_new_internal<F>(&self, stream: ReverserRequestStream, callback: F)
where
F: FnOnce() -> () + 'static,
{
let node = self.node.create_child(inspect::unique_name("connection"));
let metrics = ReverserServerMetrics::new(node, self.request_count.clone());
ReverserServer::new(metrics).spawn(stream, callback);
self.connection_count.add(1);
}
}
// The default implementation of ReverserServerMetrics is a no-op on the inspect properties.
#[derive(Default)]
struct ReverserServerMetrics {
global_request_count: Arc<inspect::UintProperty>,
request_count: inspect::UintProperty,
response_count: inspect::UintProperty,
_node: inspect::Node,
}
impl ReverserServerMetrics {
fn new(node: inspect::Node, global_request_count: Arc<inspect::UintProperty>) -> Self {
let request_count = node.create_uint("request_count", 0);
let response_count = node.create_uint("response_count", 0);
let metrics = Self {
global_request_count,
// Hold to the node until we are done with this connection.
_node: node,
request_count,
response_count,
};
metrics
}
}
struct ReverserServer {
metrics: ReverserServerMetrics,
}
impl ReverserServer {
fn new(metrics: ReverserServerMetrics) -> Self {
Self { metrics }
}
pub fn spawn<F>(self, mut stream: ReverserRequestStream, test_on_done: F)
where
F: FnOnce() -> () + 'static,
{
fasync::Task::local(async move {
while let Some(request) = stream.try_next().await.expect("serve reverser") {
self.metrics.request_count.add(1);
self.metrics.global_request_count.add(1);
let ReverserRequest::Reverse { input, responder } = request;
let result = input.chars().rev().collect::<String>();
responder.send(&result).expect("send reverse request response");
self.metrics.response_count.add(1);
}
test_on_done();
})
.detach();
}
}
#[cfg(test)]
mod tests {
use {
super::*,
anyhow::Error,
fidl_fuchsia_examples_inspect::{ReverserMarker, ReverserProxy},
// [START include_testing]
fuchsia_inspect::{self, assert_inspect_tree},
// [END include_testing]
futures::channel::oneshot,
};
#[fasync::run_singlethreaded(test)]
async fn test_reverser() -> Result<(), Error> {
// [START test_inspector]
let inspector = inspect::Inspector::new();
// [END test_inspector]
let node = inspector.root().create_child("reverser_service");
let factory = ReverserServerFactory::new(node);
let (channel_closed_snd_1, channel_closed_rcv_1) = oneshot::channel::<()>();
let reverser1 = open_reverser(&factory, || {
channel_closed_snd_1.send(()).expect("send close event");
})?;
let (channel_closed_snd_2, channel_closed_rcv_2) = oneshot::channel::<()>();
let reverser2 = open_reverser(&factory, || {
channel_closed_snd_2.send(()).expect("send close event");
})?;
let result = reverser1.reverse("hello").await?;
assert_eq!(result, "olleh");
let result = reverser1.reverse("world").await?;
assert_eq!(result, "dlrow");
let result = reverser2.reverse("another").await?;
assert_eq!(result, "rehtona");
// [START assert_tree]
assert_inspect_tree!(inspector, root: {
reverser_service: {
total_requests: 3u64,
connection_count: 2u64,
"connection0": {
request_count: 2u64,
response_count: 2u64,
},
"connection1": {
request_count: 1u64,
response_count: 1u64,
},
}
});
// [END assert_tree]
drop(reverser1);
channel_closed_rcv_1.await?;
assert_inspect_tree!(inspector, root: {
reverser_service: {
total_requests: 3u64,
connection_count: 2u64,
"connection1": {
request_count: 1u64,
response_count: 1u64,
},
}
});
drop(reverser2);
channel_closed_rcv_2.await?;
Ok(())
}
fn open_reverser<F>(
factory: &ReverserServerFactory,
callback: F,
) -> Result<ReverserProxy, Error>
where
F: FnOnce() -> () + 'static,
{
let (proxy, stream) = fidl::endpoints::create_proxy_and_stream::<ReverserMarker>()?;
factory.spawn_new_internal(stream, callback);
Ok(proxy)
}
}