From e6bedd99a543b44f4a12033424cbb829d754b5a1 Mon Sep 17 00:00:00 2001
From: Bryce Lee <brycelee@google.com>
Date: Fri, 26 Apr 2019 22:41:44 +0000
Subject: [PATCH] [SetUI] Refactor SetUIService into a Struct.

This changelist encapsulates the SetUIService into a struct/impl.
This structure will facilitate future changes where state and logical
units will need to exist across channels.

Test: fx run-test setui_service_tests -- --test
Bug: SU-167
Change-Id: I850d75321a7d9f830bc611ba4ffc3bfcb6680534
---
 garnet/bin/setui/src/main.rs          | 32 ++++++++-----
 garnet/bin/setui/src/setui_handler.rs | 68 +++++++++++++++++++++++++++
 garnet/bin/setui/src/setui_service.rs | 52 --------------------
 3 files changed, 87 insertions(+), 65 deletions(-)
 create mode 100644 garnet/bin/setui/src/setui_handler.rs
 delete mode 100644 garnet/bin/setui/src/setui_service.rs

diff --git a/garnet/bin/setui/src/main.rs b/garnet/bin/setui/src/main.rs
index 31d042f38af..fbed5784a12 100644
--- a/garnet/bin/setui/src/main.rs
+++ b/garnet/bin/setui/src/main.rs
@@ -5,14 +5,17 @@
 
 use {
     failure::Error,
-    fidl_fuchsia_setui::SetUiServiceRequestStream,
+    fidl_fuchsia_setui::*,
     fuchsia_async as fasync,
     fuchsia_component::server::ServiceFs,
     fuchsia_syslog::{self as syslog, fx_log_info},
-    futures::{StreamExt, TryFutureExt},
+    futures::StreamExt,
+    log::error,
+    setui_handler::SetUIHandler,
+    std::sync::Arc,
 };
 
-mod setui_service;
+mod setui_handler;
 
 fn main() -> Result<(), Error> {
     syslog::init_with_tags(&["setui-service"]).expect("Can't init logger");
@@ -21,17 +24,20 @@ fn main() -> Result<(), Error> {
     let mut executor = fasync::Executor::new()?;
 
     let mut fs = ServiceFs::new();
-    fs.dir("public").add_fidl_service(spawn_setui_service);
-    fs.take_and_serve_directory_handle()?;
+    let handler = Arc::new(SetUIHandler::new());
+
+    fs.dir("public").add_fidl_service(move |stream: SetUiServiceRequestStream| {
+        let handler_clone = handler.clone();
+        fx_log_info!("Connecting to setui_service");
+        fasync::spawn(
+            async move {
+                await!(handler_clone.handle_stream(stream))
+                    .unwrap_or_else(|e| error!("Failed to spawn {:?}", e))
+            },
+        );
+    });
 
+    fs.take_and_serve_directory_handle()?;
     let () = executor.run_singlethreaded(fs.collect());
     Ok(())
 }
-
-fn spawn_setui_service(stream: SetUiServiceRequestStream) {
-    fx_log_info!("Connecting to setui_service");
-    fasync::spawn(
-        setui_service::start_setui_service(stream)
-            .unwrap_or_else(|e| eprintln!("Failed to spawn {:?}", e)),
-    )
-}
diff --git a/garnet/bin/setui/src/setui_handler.rs b/garnet/bin/setui/src/setui_handler.rs
new file mode 100644
index 00000000000..179b556747d
--- /dev/null
+++ b/garnet/bin/setui/src/setui_handler.rs
@@ -0,0 +1,68 @@
+// Copyright 2019 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 failure::Error;
+use fidl_fuchsia_setui::*;
+use futures::prelude::*;
+
+pub struct SetUIHandler {}
+
+/// SetUIHandler handles all API calls for the service. It is intended to be
+/// used as a single instance to service multiple streams.
+impl SetUIHandler {
+    /// In the future, will populate with supporting classes, such as adapters.
+    pub fn new() -> SetUIHandler {
+        Self {}
+    }
+
+    /// Asynchronous handling of the given stream. Note that we must consider the
+    /// possibility of simultaneous active streams.
+    pub async fn handle_stream(&self, mut stream: SetUiServiceRequestStream) -> Result<(), Error> {
+        while let Some(req) = await!(stream.try_next())? {
+            await!(self.handle_request(req))?;
+        }
+
+        Ok(())
+    }
+
+    /// Routes a given request to the proper handling function.
+    pub async fn handle_request(&self, req: SetUiServiceRequest) -> Result<(), fidl::Error> {
+        match req {
+            SetUiServiceRequest::Mutate { setting_type, mutation, responder } => {
+                let mut response = self.mutate(setting_type, mutation);
+                responder.send(&mut response)?;
+            }
+            _ => {}
+        }
+        Ok(())
+    }
+
+    /// Applies a mutation
+    fn mutate(&self, _setting_type: SettingType, _mutation: Mutation) -> MutationResponse {
+        MutationResponse { return_code: ReturnCode::Ok }
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    /// A basic test to exercise that basic functionality works. In this case, we
+    /// mutate the unknown type, reserved for testing. We should always immediately
+    /// receive back an Ok response.
+    #[test]
+    fn test_ok() {
+        let handler = SetUIHandler::new();
+        let string_mutation =
+            StringMutation { operation: StringOperation::Update, value: "Hi".to_string() };
+
+        let result = handler.mutate(
+            SettingType::Unknown,
+            fidl_fuchsia_setui::Mutation::StringMutationValue(string_mutation),
+        );
+
+        assert_eq!(result, MutationResponse { return_code: ReturnCode::Ok });
+    }
+
+}
diff --git a/garnet/bin/setui/src/setui_service.rs b/garnet/bin/setui/src/setui_service.rs
deleted file mode 100644
index 5fd2e90ebff..00000000000
--- a/garnet/bin/setui/src/setui_service.rs
+++ /dev/null
@@ -1,52 +0,0 @@
-// Copyright 2019 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 {
-    failure::Error,
-    failure::ResultExt,
-    fidl_fuchsia_setui::*,
-    futures::prelude::*,
-};
-
-pub async fn start_setui_service(mut stream: SetUiServiceRequestStream) -> Result<(), Error> {
-    while let Some(event) = await!(stream.try_next()).context("error reading value from stream")? {
-        await!(handler(event))?;
-    }
-    // event_listener will now be dropped, closing the listener
-    Ok(())
-}
-
-async fn handler(event: SetUiServiceRequest) -> fidl::Result<()> {
-    match event {
-        SetUiServiceRequest::Mutate { setting_type, mutation, responder } => {
-            responder.send(&mut mutate(setting_type, mutation))?;
-        }
-        _ => {}
-    }
-
-    Ok(())
-}
-
-fn mutate(_setting_type: SettingType, _mutation: Mutation) -> MutationResponse {
-    MutationResponse { return_code: ReturnCode::Ok }
-}
-
-#[cfg(test)]
-mod tests {
-    use super::*;
-
-    #[test]
-    fn test_ok() {
-        let string_mutation =
-            StringMutation { operation: StringOperation::Update, value: "Hi".to_string() };
-
-        let result = mutate(
-            SettingType::Unknown,
-            fidl_fuchsia_setui::Mutation::StringMutationValue(string_mutation),
-        );
-
-        assert_eq!(result, MutationResponse { return_code: ReturnCode::Ok });
-    }
-
-}
-- 
GitLab