[discovermgr] setup for serde and actions json parsing

Change-Id: I279508e963803804ebb839ef142650a87eef6d9f
diff --git a/peridot/bin/discovermgr/BUILD.gn b/peridot/bin/discovermgr/BUILD.gn
index ebbadda..41805fb 100644
--- a/peridot/bin/discovermgr/BUILD.gn
+++ b/peridot/bin/discovermgr/BUILD.gn
@@ -20,8 +20,12 @@
     "//sdk/fidl/fuchsia.app.discover:fuchsia.app.discover-rustc",
     "//third_party/rust_crates:failure",
     "//third_party/rust_crates:futures-preview",
+    "//third_party/rust_crates:glob",
     "//third_party/rust_crates:maplit",
     "//third_party/rust_crates:parking_lot",
+    "//third_party/rust_crates:serde",
+    "//third_party/rust_crates:serde_derive",
+    "//third_party/rust_crates:serde_json",
   ]
 }
 
@@ -47,6 +51,13 @@
     ":bin",
   ]
 
+  resources = [
+    {
+      path = rebase_path("test_data/test_actions.json")
+      dest = "test_actions.json"
+    },
+  ]
+
   tests = [
     {
       name = "discovermgr_bin_test"
diff --git a/peridot/bin/discovermgr/src/main.rs b/peridot/bin/discovermgr/src/main.rs
index 0e02cd2..1ff7e68 100644
--- a/peridot/bin/discovermgr/src/main.rs
+++ b/peridot/bin/discovermgr/src/main.rs
@@ -17,6 +17,7 @@
     std::sync::Arc,
 };
 
+mod models;
 mod module_output;
 mod story_context_store;
 mod utils;
@@ -26,7 +27,7 @@
 
 enum IncomingServices {
     DiscoverRegistry(DiscoverRegistryRequestStream),
-    // TODO(miguelfrde): add additional services
+    // TODO: add additional services
 }
 
 /// Handle DiscoveryRegistry requests.
diff --git a/peridot/bin/discovermgr/src/models.rs b/peridot/bin/discovermgr/src/models.rs
new file mode 100644
index 0000000..58dbf3d
--- /dev/null
+++ b/peridot/bin/discovermgr/src/models.rs
@@ -0,0 +1,89 @@
+// 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.
+
+/// Deserialization of Actions.
+
+#[cfg(test)]
+use std::io::BufReader;
+
+use serde_derive::Deserialize;
+
+#[derive(Deserialize, Debug)]
+pub struct Action {
+    name: String,
+    parameters: Option<Vec<Parameter>>,
+    display_info: Option<DisplayInfo>,
+    web_fulfillment: Option<WebFulfillment>,
+}
+
+#[derive(Deserialize, Debug)]
+pub struct ParameterMapping {
+    name: String,
+    parameter_property: String,
+}
+
+#[derive(Deserialize, Debug)]
+pub struct Parameter {
+    #[serde(rename = "type")]
+    parameter_type: String,
+    name: String,
+}
+
+#[derive(Deserialize, Debug)]
+pub struct DisplayInfo {
+    icon: Option<String>,
+    parameter_mapping: Option<Vec<ParameterMapping>>,
+    title: Option<String>,
+    name: Option<String>,
+}
+
+#[derive(Deserialize, Debug)]
+pub struct WebFulfillment {
+    url_template: Option<String>,
+    parameter_mapping: Option<Vec<ParameterMapping>>,
+}
+
+#[derive(Debug)]
+pub enum ModelError {
+    Io(std::io::Error),
+    Serde(serde_json::error::Error),
+}
+
+impl std::convert::From<serde_json::error::Error> for ModelError {
+    fn from(err: serde_json::error::Error) -> ModelError {
+        ModelError::Serde(err)
+    }
+}
+
+impl std::convert::From<std::io::Error> for ModelError {
+    fn from(err: std::io::Error) -> ModelError {
+        ModelError::Io(err)
+    }
+}
+
+#[cfg(test)]
+type Result<T> = std::result::Result<T, ModelError>;
+
+#[cfg(test)]
+/// Returns an vector of actions from a file containing json.
+///
+pub fn actions_from_assets(file_name: &str) -> Result<Vec<Action>> {
+    let reader = BufReader::new(std::fs::File::open(file_name)?);
+    let actions: Vec<Action> = serde_json::from_reader(reader)?;
+    Ok(actions)
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    #[test]
+    fn test_from_assets() {
+        let data =
+            actions_from_assets("/pkgfs/packages/discovermgr_tests/0/data/test_actions.json")
+                .unwrap();
+        assert_eq!(data.len(), 2);
+        assert_eq!(data[0].name, "PLAY_MUSIC");
+        assert_eq!(data[1].name, "SHOW_WEATHER");
+    }
+}
diff --git a/peridot/bin/discovermgr/test_data/test_actions.json b/peridot/bin/discovermgr/test_data/test_actions.json
new file mode 100644
index 0000000..62f144e
--- /dev/null
+++ b/peridot/bin/discovermgr/test_data/test_actions.json
@@ -0,0 +1,58 @@
+[
+   {
+      "display_info" : {
+         "title" : "Listen to $artist",
+         "icon" : "https://www.shareicon.net/download/128x128//2016/08/01/639870_internet_512x512.png",
+         "parameter_mapping" : [
+            {
+               "parameter_property" : "artist.name",
+               "name" : "artist"
+            }
+         ]
+      },
+      "web_fulfillment" : {
+         "url_template" : "https://example.com/music",
+         "parameter_mapping" : [
+            {
+               "name" : "artistName",
+               "parameter_property" : "artist.name"
+            }
+         ]
+      },
+      "name" : "PLAY_MUSIC",
+      "parameters" : [
+         {
+            "type" : "https://schema.org/MusicGroup",
+            "name" : "artist"
+         }
+      ]
+   },
+   {
+      "web_fulfillment" : {
+         "url_template" : "https://example.com/locations",
+         "parameter_mapping" : [
+            {
+               "name" : "placeName",
+               "parameter_property" : "Location.name"
+            }
+         ]
+      },
+      "display_info" : {
+         "title" : "Weather in $place",
+         "parameter_mapping" : [
+            {
+               "parameter_property" : "Location.name",
+               "name" : "place"
+            }
+         ],
+         "icon" : "https://www.google.com/s2/favicons?domain=https://openweathermap.org/&sz=128"
+      },
+      "name" : "SHOW_WEATHER",
+      "parameters" : [
+         {
+            "type" : "https://schema.org/Place",
+            "name" : "Location"
+         }
+      ]
+   }
+]