use serde_json;
use serde_json::json;
use std::any::Any;
use std::collections::HashMap;
use std::marker::{Send, Sync};
use std::sync::{Arc, RwLock};
use std::vec::Drain;
use valico::json_schema;
use super::action::Action;
use super::event::Event;
use super::property::Property;
pub trait Thing: Send + Sync {
fn as_thing_description(&self) -> serde_json::Map<String, serde_json::Value>;
fn as_any(&self) -> &dyn Any;
fn as_mut_any(&mut self) -> &mut dyn Any;
fn get_href(&self) -> String;
fn get_href_prefix(&self) -> String;
fn get_ui_href(&self) -> Option<String>;
fn set_href_prefix(&mut self, prefix: String);
fn set_ui_href(&mut self, href: String);
fn get_id(&self) -> String;
fn get_title(&self) -> String;
fn get_context(&self) -> String;
fn get_type(&self) -> Vec<String>;
fn get_description(&self) -> String;
fn get_property_descriptions(&self) -> serde_json::Map<String, serde_json::Value>;
fn get_action_descriptions(&self, action_name: Option<String>) -> serde_json::Value;
fn get_event_descriptions(&self, event_name: Option<String>) -> serde_json::Value;
fn add_property(&mut self, property: Box<dyn Property>);
fn remove_property(&mut self, property_name: String);
fn find_property(&mut self, property_name: &String) -> Option<&mut Box<dyn Property>>;
fn get_property(&self, property_name: &String) -> Option<serde_json::Value>;
fn get_properties(&self) -> serde_json::Map<String, serde_json::Value>;
fn has_property(&self, property_name: &String) -> bool;
fn set_property(
&mut self,
property_name: String,
value: serde_json::Value,
) -> Result<(), &'static str> {
let property = self
.find_property(&property_name)
.ok_or_else(|| "Property not found")?;
property.set_value(value.clone())?;
self.property_notify(property_name, value);
Ok(())
}
fn get_action(
&self,
action_name: String,
action_id: String,
) -> Option<Arc<RwLock<Box<dyn Action>>>>;
fn add_event(&mut self, event: Box<dyn Event>);
fn add_available_event(
&mut self,
name: String,
metadata: serde_json::Map<String, serde_json::Value>,
);
fn add_action(
&mut self,
action: Arc<RwLock<Box<dyn Action>>>,
input: Option<&serde_json::Value>,
) -> Result<(), &str>;
fn remove_action(&mut self, action_name: String, action_id: String) -> bool;
fn add_available_action(
&mut self,
name: String,
metadata: serde_json::Map<String, serde_json::Value>,
);
fn add_subscriber(&mut self, ws_id: String);
fn remove_subscriber(&mut self, ws_id: String);
fn add_event_subscriber(&mut self, name: String, ws_id: String);
fn remove_event_subscriber(&mut self, name: String, ws_id: String);
fn property_notify(&mut self, name: String, value: serde_json::Value);
fn action_notify(&mut self, action: serde_json::Map<String, serde_json::Value>);
fn event_notify(&mut self, name: String, event: serde_json::Map<String, serde_json::Value>);
fn start_action(&mut self, name: String, id: String);
fn cancel_action(&mut self, name: String, id: String);
fn finish_action(&mut self, name: String, id: String);
fn drain_queue(&mut self, ws_id: String) -> Vec<Drain<String>>;
}
#[derive(Default)]
pub struct BaseThing {
id: String,
context: String,
type_: Vec<String>,
title: String,
description: String,
properties: HashMap<String, Box<dyn Property>>,
available_actions: HashMap<String, AvailableAction>,
available_events: HashMap<String, AvailableEvent>,
actions: HashMap<String, Vec<Arc<RwLock<Box<dyn Action>>>>>,
events: Vec<Box<dyn Event>>,
subscribers: HashMap<String, Vec<String>>,
href_prefix: String,
ui_href: Option<String>,
}
impl BaseThing {
pub fn new(
id: String,
title: String,
type_: Option<Vec<String>>,
description: Option<String>,
) -> Self {
Self {
id,
context: "https://iot.mozilla.org/schemas".to_owned(),
type_: type_.unwrap_or_else(|| vec![]),
title,
description: description.unwrap_or_else(|| "".to_string()),
..Default::default()
}
}
}
impl Thing for BaseThing {
fn as_thing_description(&self) -> serde_json::Map<String, serde_json::Value> {
let mut description = serde_json::Map::new();
description.insert("id".to_owned(), json!(self.get_id()));
description.insert("title".to_owned(), json!(self.get_title()));
description.insert("@context".to_owned(), json!(self.get_context()));
description.insert("@type".to_owned(), json!(self.get_type()));
description.insert(
"properties".to_owned(),
json!(self.get_property_descriptions()),
);
let mut links: Vec<serde_json::Map<String, serde_json::Value>> = Vec::new();
let mut properties_link = serde_json::Map::new();
properties_link.insert("rel".to_owned(), json!("properties"));
properties_link.insert(
"href".to_owned(),
json!(format!("{}/properties", self.get_href_prefix())),
);
links.push(properties_link);
let mut actions_link = serde_json::Map::new();
actions_link.insert("rel".to_owned(), json!("actions"));
actions_link.insert(
"href".to_owned(),
json!(format!("{}/actions", self.get_href_prefix())),
);
links.push(actions_link);
let mut events_link = serde_json::Map::new();
events_link.insert("rel".to_owned(), json!("events"));
events_link.insert(
"href".to_owned(),
json!(format!("{}/events", self.get_href_prefix())),
);
links.push(events_link);
let ui_href = self.get_ui_href();
if ui_href.is_some() {
let mut ui_link = serde_json::Map::new();
ui_link.insert("rel".to_owned(), json!("alternate"));
ui_link.insert("mediaType".to_owned(), json!("text/html"));
ui_link.insert("href".to_owned(), json!(ui_href.unwrap()));
links.push(ui_link);
}
description.insert("links".to_owned(), json!(links));
let mut actions = serde_json::Map::new();
for (name, action) in self.available_actions.iter() {
let mut metadata = action.get_metadata().clone();
metadata.insert(
"links".to_string(),
json!([
{
"rel": "action",
"href": format!("{}/actions/{}", self.get_href_prefix(), name),
},
]),
);
actions.insert(name.to_string(), json!(metadata));
}
description.insert("actions".to_owned(), json!(actions));
let mut events = serde_json::Map::new();
for (name, event) in self.available_events.iter() {
let mut metadata = event.get_metadata().clone();
metadata.insert(
"links".to_string(),
json!([
{
"rel": "event",
"href": format!("{}/events/{}", self.get_href_prefix(), name),
},
]),
);
events.insert(name.to_string(), json!(metadata));
}
description.insert("events".to_owned(), json!(events));
if self.description.len() > 0 {
description.insert("description".to_owned(), json!(self.description));
}
description
}
fn as_any(&self) -> &dyn Any {
self
}
fn as_mut_any(&mut self) -> &mut dyn Any {
self
}
fn get_href(&self) -> String {
if self.href_prefix == "" {
"/".to_owned()
} else {
self.href_prefix.clone()
}
}
fn get_href_prefix(&self) -> String {
self.href_prefix.clone()
}
fn get_ui_href(&self) -> Option<String> {
self.ui_href.clone()
}
fn set_href_prefix(&mut self, prefix: String) {
self.href_prefix = prefix.clone();
for property in self.properties.values_mut() {
property.set_href_prefix(prefix.clone());
}
for actions in self.actions.values_mut() {
for action in actions {
action.write().unwrap().set_href_prefix(prefix.clone());
}
}
}
fn set_ui_href(&mut self, href: String) {
self.ui_href = Some(href);
}
fn get_id(&self) -> String {
self.id.clone()
}
fn get_title(&self) -> String {
self.title.clone()
}
fn get_context(&self) -> String {
self.context.clone()
}
fn get_type(&self) -> Vec<String> {
self.type_.clone()
}
fn get_description(&self) -> String {
self.description.clone()
}
fn get_property_descriptions(&self) -> serde_json::Map<String, serde_json::Value> {
let mut descriptions = serde_json::Map::new();
for (name, property) in self.properties.iter() {
descriptions.insert(name.to_string(), json!(property.as_property_description()));
}
descriptions
}
fn get_action_descriptions(&self, action_name: Option<String>) -> serde_json::Value {
let mut descriptions = Vec::new();
match action_name {
Some(action_name) => {
let actions = self.actions.get(&action_name);
if actions.is_some() {
let actions = actions.unwrap();
for action in actions {
descriptions.push(action.read().unwrap().as_action_description());
}
}
}
None => {
for action in self.actions.values().flatten() {
descriptions.push(action.read().unwrap().as_action_description());
}
}
}
json!(descriptions)
}
fn get_event_descriptions(&self, event_name: Option<String>) -> serde_json::Value {
let mut descriptions = Vec::new();
match event_name {
Some(event_name) => {
for event in &self.events {
if event.get_name() == event_name {
descriptions.push(event.as_event_description());
}
}
}
None => {
for event in &self.events {
descriptions.push(event.as_event_description());
}
}
}
json!(descriptions)
}
fn add_property(&mut self, mut property: Box<dyn Property>) {
property.set_href_prefix(self.get_href_prefix());
self.properties.insert(property.get_name(), property);
}
fn remove_property(&mut self, property_name: String) {
self.properties.remove(&property_name);
}
fn find_property(&mut self, property_name: &String) -> Option<&mut Box<dyn Property>> {
self.properties.get_mut(property_name)
}
fn get_property(&self, property_name: &String) -> Option<serde_json::Value> {
if self.has_property(property_name) {
Some(self.properties.get(property_name).unwrap().get_value())
} else {
None
}
}
fn get_properties(&self) -> serde_json::Map<String, serde_json::Value> {
let mut properties = serde_json::Map::new();
for (name, property) in self.properties.iter() {
properties.insert(name.to_string(), json!(property.get_value()));
}
properties
}
fn has_property(&self, property_name: &String) -> bool {
self.properties.contains_key(property_name)
}
fn get_action(
&self,
action_name: String,
action_id: String,
) -> Option<Arc<RwLock<Box<dyn Action>>>> {
match self.actions.get(&action_name) {
Some(entry) => {
for action in entry {
if action.read().unwrap().get_id() == action_id {
return Some(action.clone());
}
}
None
}
None => None,
}
}
fn add_event(&mut self, event: Box<dyn Event>) {
self.event_notify(event.get_name(), event.as_event_description());
self.events.push(event);
}
fn add_available_event(
&mut self,
name: String,
metadata: serde_json::Map<String, serde_json::Value>,
) {
let event = AvailableEvent::new(metadata);
self.available_events.insert(name, event);
}
fn add_action(
&mut self,
action: Arc<RwLock<Box<dyn Action>>>,
input: Option<&serde_json::Value>,
) -> Result<(), &str> {
let action_name = action.read().unwrap().get_name();
if !self.available_actions.contains_key(&action_name) {
return Err("Action type not found");
}
let action_type = self.available_actions.get(&action_name).unwrap();
if !action_type.validate_action_input(input) {
return Err("Action input invalid");
}
action
.write()
.unwrap()
.set_href_prefix(self.get_href_prefix());
self.action_notify(action.read().unwrap().as_action_description());
self.actions.get_mut(&action_name).unwrap().push(action);
Ok(())
}
fn remove_action(&mut self, action_name: String, action_id: String) -> bool {
let action = self.get_action(action_name.clone(), action_id.clone());
match action {
Some(action) => {
action.write().unwrap().cancel();
let actions = self.actions.get_mut(&action_name).unwrap();
actions.retain(|ref a| a.read().unwrap().get_id() != action_id);
true
}
None => false,
}
}
fn add_available_action(
&mut self,
name: String,
metadata: serde_json::Map<String, serde_json::Value>,
) {
let action = AvailableAction::new(metadata);
self.available_actions.insert(name.clone(), action);
self.actions.insert(name, Vec::new());
}
fn add_subscriber(&mut self, ws_id: String) {
self.subscribers.insert(ws_id, Vec::new());
}
fn remove_subscriber(&mut self, ws_id: String) {
self.subscribers.remove(&ws_id);
for event in self.available_events.values_mut() {
event.remove_subscriber(ws_id.clone());
}
}
fn add_event_subscriber(&mut self, name: String, ws_id: String) {
if self.available_events.contains_key(&name) {
self.available_events
.get_mut(&name)
.unwrap()
.add_subscriber(ws_id);
}
}
fn remove_event_subscriber(&mut self, name: String, ws_id: String) {
if self.available_events.contains_key(&name) {
self.available_events
.get_mut(&name)
.unwrap()
.remove_subscriber(ws_id);
}
}
fn property_notify(&mut self, name: String, value: serde_json::Value) {
let message = json!({
"messageType": "propertyStatus",
"data": {
name: value
}
})
.to_string();
self.subscribers
.values_mut()
.for_each(|queue| queue.push(message.clone()));
}
fn action_notify(&mut self, action: serde_json::Map<String, serde_json::Value>) {
let message = json!({
"messageType": "actionStatus",
"data": action
})
.to_string();
self.subscribers
.values_mut()
.for_each(|queue| queue.push(message.clone()));
}
fn event_notify(&mut self, name: String, event: serde_json::Map<String, serde_json::Value>) {
if !self.available_events.contains_key(&name) {
return;
}
let message = json!({
"messageType": "event",
"data": event,
})
.to_string();
self.available_events
.get_mut(&name)
.unwrap()
.get_subscribers()
.values_mut()
.for_each(|queue| queue.push(message.clone()));
}
fn start_action(&mut self, name: String, id: String) {
match self.get_action(name, id) {
Some(action) => {
let mut a = action.write().unwrap();
a.start();
self.action_notify(a.as_action_description());
a.perform_action();
}
None => (),
}
}
fn cancel_action(&mut self, name: String, id: String) {
match self.get_action(name, id) {
Some(action) => {
let mut a = action.write().unwrap();
a.cancel();
}
None => (),
}
}
fn finish_action(&mut self, name: String, id: String) {
match self.get_action(name, id) {
Some(action) => {
let mut a = action.write().unwrap();
a.finish();
self.action_notify(a.as_action_description());
}
None => (),
}
}
fn drain_queue(&mut self, ws_id: String) -> Vec<Drain<String>> {
let mut drains: Vec<Drain<String>> = Vec::new();
match self.subscribers.get_mut(&ws_id) {
Some(v) => {
drains.push(v.drain(..));
}
None => (),
}
self.available_events.values_mut().for_each(|evt| {
match evt.get_subscribers().get_mut(&ws_id) {
Some(v) => {
drains.push(v.drain(..));
}
None => (),
}
});
drains
}
}
struct AvailableAction {
metadata: serde_json::Map<String, serde_json::Value>,
}
impl AvailableAction {
fn new(metadata: serde_json::Map<String, serde_json::Value>) -> AvailableAction {
AvailableAction { metadata: metadata }
}
fn get_metadata(&self) -> &serde_json::Map<String, serde_json::Value> {
&self.metadata
}
fn validate_action_input(&self, input: Option<&serde_json::Value>) -> bool {
let mut scope = json_schema::Scope::new();
let validator = if self.metadata.contains_key("input") {
let mut schema = self
.metadata
.get("input")
.unwrap()
.as_object()
.unwrap()
.clone();
if schema.contains_key("properties") {
let properties = schema
.get_mut("properties")
.unwrap()
.as_object_mut()
.unwrap();
for value in properties.values_mut() {
let value = value.as_object_mut().unwrap();
value.remove("@type");
value.remove("unit");
value.remove("title");
}
}
match scope.compile_and_return(json!(schema), true) {
Ok(s) => Some(s),
Err(_) => None,
}
} else {
None
};
match validator {
Some(ref v) => match input {
Some(i) => v.validate(&i).is_valid(),
None => v.validate(&serde_json::Value::Null).is_valid(),
},
None => true,
}
}
}
struct AvailableEvent {
metadata: serde_json::Map<String, serde_json::Value>,
subscribers: HashMap<String, Vec<String>>,
}
impl AvailableEvent {
fn new(metadata: serde_json::Map<String, serde_json::Value>) -> AvailableEvent {
AvailableEvent {
metadata: metadata,
subscribers: HashMap::new(),
}
}
fn get_metadata(&self) -> &serde_json::Map<String, serde_json::Value> {
&self.metadata
}
fn add_subscriber(&mut self, ws_id: String) {
self.subscribers.insert(ws_id, Vec::new());
}
fn remove_subscriber(&mut self, ws_id: String) {
self.subscribers.remove(&ws_id);
}
fn get_subscribers(&mut self) -> &mut HashMap<String, Vec<String>> {
&mut self.subscribers
}
}