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 UpdateRtc,
37}
38
39pub struct Server {
41 adjust_sender: RefCell<mpsc::Sender<Command>>,
43}
44
45impl Server {
46 pub fn new(adjust_sender: mpsc::Sender<Command>) -> Self {
51 Self { adjust_sender: RefCell::new(adjust_sender) }
53 }
54
55 pub async fn serve(&self, mut stream: ffte::AdjustRequestStream) -> Result<()> {
57 debug!("time_adjust::serve: entering serving loop");
58 defer! {
59 debug!("time_adjust::serve: exited serving loop");
60 };
61 while let Some(request) = stream.next().await {
62 trace::duration!("timekeeper", "adjust:request");
63 debug!("time_adjust::Server::serve: request: {:?}", request);
64 match request {
65 Ok(ffte::AdjustRequest::ReportBootToUtcMapping {
66 boot_reference,
67 utc_reference,
68 responder,
69 }) => {
70 trace::instant!("alarms", "adjust:request:params", trace::Scope::Process,
71 "boot_reference" => boot_reference.into_nanos(), "utc_reference" => utc_reference);
72 let utc_reference = fxr::UtcInstant::from_nanos(utc_reference);
73 let (tx, mut rx) = mpsc::channel(1);
74 let command =
75 Command::Reference { boot_reference, utc_reference, responder: tx };
76 self.adjust_sender
77 .borrow_mut()
78 .send(command)
79 .await
80 .context("while trying to send to adjust_sender")?;
81 let result = rx.next().await.context("could not get a response")?;
82 responder.send(
83 result
84 .context("while sending response to Adjust")
85 .map_err(|e| {
86 error!("could not send response: {:?}", e);
87 e
88 })
89 .map_err(|_| ffte::Error::Internal),
90 )?;
91 }
92 Err(e) => {
93 error!("FIDL error: {:?}", e);
94 }
95 };
96 }
97 Ok(())
98 }
99}
100
101#[cfg(test)]
102mod tests {
103 use super::*;
104 use fuchsia_async as fasync;
105
106 #[fuchsia::test]
107 async fn basic_test() -> Result<()> {
108 let (tx, mut rx) = mpsc::channel(1);
109 let (proxy, stream) = fidl::endpoints::create_proxy_and_stream::<ffte::AdjustMarker>();
110 let server = Server::new(tx);
111 let _task = fasync::Task::local(async move { server.serve(stream).await });
112
113 let _success = fasync::Task::local(async move {
114 proxy
117 .report_boot_to_utc_mapping(zx::BootInstant::from_nanos(42), 4200i64)
118 .await
119 .expect("infallible")
120 });
121 let recv = rx.next().await.expect("infallible");
122 match recv {
123 Command::Reference { boot_reference, utc_reference, mut responder } => {
124 responder.send(Ok(())).await.unwrap();
125 assert_eq!(boot_reference, zx::BootInstant::from_nanos(42));
126 assert_eq!(utc_reference, fxr::UtcInstant::from_nanos(4200));
127 }
128 e => {
129 error!("Unexpected response: {:?}", e)
130 }
131 }
132
133 Ok(())
134 }
135}