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