1use anyhow::{Context, Result};
8use futures::channel::mpsc;
9use futures::{SinkExt, StreamExt};
10use log::{debug, error};
11use scopeguard::defer;
12use std::cell::RefCell;
13use {fidl_fuchsia_time_external as ffte, fuchsia_runtime as fxr, fuchsia_trace as trace};
14
15#[derive(Debug)]
16pub enum Command {
17 PowerManagement,
19 Reference {
22 boot_reference: zx::BootInstant,
24 utc_reference: fxr::UtcInstant,
26 responder: mpsc::Sender<Result<()>>,
29 },
30 Connectivity {
32 http_available: bool,
34 },
35}
36
37pub struct Server {
39 adjust_sender: RefCell<mpsc::Sender<Command>>,
41}
42
43impl Server {
44 pub fn new(adjust_sender: mpsc::Sender<Command>) -> Self {
49 Self { adjust_sender: RefCell::new(adjust_sender) }
51 }
52
53 pub async fn serve(&self, mut stream: ffte::AdjustRequestStream) -> Result<()> {
55 debug!("time_adjust::serve: entering serving loop");
56 defer! {
57 debug!("time_adjust::serve: exited serving loop");
58 };
59 while let Some(request) = stream.next().await {
60 trace::duration!(c"timekeeper", c"adjust:request");
61 debug!("time_adjust::Server::serve: request: {:?}", request);
62 match request {
63 Ok(ffte::AdjustRequest::ReportBootToUtcMapping {
64 boot_reference,
65 utc_reference,
66 responder,
67 }) => {
68 trace::instant!(c"alarms", c"adjust:request:params", trace::Scope::Process,
69 "boot_reference" => boot_reference.into_nanos(), "utc_reference" => utc_reference);
70 let utc_reference = fxr::UtcInstant::from_nanos(utc_reference);
71 let (tx, mut rx) = mpsc::channel(1);
72 let command =
73 Command::Reference { boot_reference, utc_reference, responder: tx };
74 self.adjust_sender
75 .borrow_mut()
76 .send(command)
77 .await
78 .context("while trying to send to adjust_sender")?;
79 let result = rx.next().await.context("could not get a response")?;
80 responder.send(
81 result
82 .context("while sending response to Adjust")
83 .map_err(|e| {
84 error!("could not send response: {:?}", e);
85 e
86 })
87 .map_err(|_| ffte::Error::Internal),
88 )?;
89 }
90 Err(e) => {
91 error!("FIDL error: {:?}", e);
92 }
93 };
94 }
95 Ok(())
96 }
97}
98
99#[cfg(test)]
100mod tests {
101 use super::*;
102 use fuchsia_async as fasync;
103
104 #[fuchsia::test]
105 async fn basic_test() -> Result<()> {
106 let (tx, mut rx) = mpsc::channel(1);
107 let (proxy, stream) = fidl::endpoints::create_proxy_and_stream::<ffte::AdjustMarker>();
108 let server = Server::new(tx);
109 let _task = fasync::Task::local(async move { server.serve(stream).await });
110
111 let _success = fasync::Task::local(async move {
112 proxy
115 .report_boot_to_utc_mapping(zx::BootInstant::from_nanos(42), 4200i64)
116 .await
117 .expect("infallible")
118 });
119 let recv = rx.next().await.expect("infallible");
120 match recv {
121 Command::Reference { boot_reference, utc_reference, mut responder } => {
122 responder.send(Ok(())).await.unwrap();
123 assert_eq!(boot_reference, zx::BootInstant::from_nanos(42));
124 assert_eq!(utc_reference, fxr::UtcInstant::from_nanos(4200));
125 }
126 e => {
127 error!("Unexpected response: {:?}", e)
128 }
129 }
130
131 Ok(())
132 }
133}