forked from eclipse-chariott/chariott
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathchariott_provider.rs
133 lines (118 loc) · 4.69 KB
/
chariott_provider.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
// SPDX-License-Identifier: MIT
use std::collections::HashMap;
use std::sync::Arc;
use std::vec;
use async_trait::async_trait;
use chariott_proto::{
common::{
discover_fulfillment::Service, DiscoverFulfillment, FulfillmentEnum, FulfillmentMessage,
IntentEnum, InvokeFulfillment, ValueMessage,
},
provider::{provider_service_server::ProviderService, FulfillRequest, FulfillResponse},
};
use examples_common::chariott;
use examples_common::chariott::inspection::{fulfill, Entry};
use examples_common::chariott::streaming::ProtoExt as _;
use examples_common::chariott::value::Value;
use tonic::{Request, Response, Status};
use url::Url;
use crate::simulation::VehicleSimulation;
pub const CABIN_TEMPERATURE_PROPERTY: &str = "Vehicle.Cabin.HVAC.AmbientAirTemperature";
pub const BATTERY_LEVEL_PROPERTY: &str = "Vehicle.OBD.HybridBatteryRemaining";
pub const AIR_CONDITIONING_STATE_PROPERTY: &str = "Vehicle.Cabin.HVAC.IsAirConditioningActive";
pub const ACTIVATE_AIR_CONDITIONING_COMMAND: &str = "Vehicle.Cabin.HVAC.IsAirConditioningActive";
pub const SEND_NOTIFICATION_COMMAND: &str = "send_notification";
pub const SET_UI_MESSAGE_COMMAND: &str = "set_ui_message";
const SCHEMA_VERSION_STREAMING: &str = "chariott.streaming.v1";
const SCHEMA_REFERENCE: &str = "grpc+proto";
pub type StreamingStore = chariott::streaming::StreamingStore<Value>;
pub struct ChariottProvider {
url: Url,
vehicle_simulation: VehicleSimulation,
streaming_store: Arc<StreamingStore>,
}
impl ChariottProvider {
pub fn new(
url: Url,
simulation: VehicleSimulation,
streaming_store: Arc<StreamingStore>,
) -> Self {
Self { url, vehicle_simulation: simulation, streaming_store }
}
}
lazy_static::lazy_static! {
static ref VDT_SCHEMA: Vec<Entry> = vec![
property(CABIN_TEMPERATURE_PROPERTY, "int32"),
property(BATTERY_LEVEL_PROPERTY, "int32"),
property(AIR_CONDITIONING_STATE_PROPERTY, "bool"),
command(ACTIVATE_AIR_CONDITIONING_COMMAND, "IAcmeAirconControl"),
command(SEND_NOTIFICATION_COMMAND, "ISendNotification"),
command(SET_UI_MESSAGE_COMMAND, "ISetUiMessage"),
];
}
fn property(path: &str, r#type: &str) -> Entry {
Entry::new(
path,
[
("member_type", "property".into()),
("type", r#type.into()),
("read", Value::TRUE),
("write", Value::FALSE),
("watch", Value::TRUE),
],
)
}
fn command(path: &str, r#type: &str) -> Entry {
Entry::new(path, [("member_type", "command"), ("type", r#type)])
}
#[async_trait]
impl ProviderService for ChariottProvider {
async fn fulfill(
&self,
request: Request<FulfillRequest>,
) -> Result<Response<FulfillResponse>, Status> {
let response = match request
.into_inner()
.intent
.and_then(|i| i.intent)
.ok_or_else(|| Status::invalid_argument("Intent must be specified"))?
{
IntentEnum::Discover(_) => FulfillmentEnum::Discover(DiscoverFulfillment {
services: vec![Service {
url: self.url.to_string(),
schema_kind: SCHEMA_REFERENCE.to_owned(),
schema_reference: SCHEMA_VERSION_STREAMING.to_owned(),
metadata: HashMap::new(),
}],
}),
IntentEnum::Invoke(intent) => {
let args = intent
.args
.into_iter()
.map(|arg| arg.try_into())
.collect::<Result<Vec<Value>, ()>>()
.map_err(|_| Status::invalid_argument("Invalid argument."))?;
let result = self
.vehicle_simulation
.invoke(&intent.command, args)
.await
.map_err(|e| {
Status::unknown(format!("Error when invoking hardware function: '{}'", e))
})?
.into();
FulfillmentEnum::Invoke(InvokeFulfillment {
r#return: Some(ValueMessage { value: Some(result) }),
})
}
IntentEnum::Inspect(inspect) => fulfill(inspect.query, &*VDT_SCHEMA),
IntentEnum::Subscribe(subscribe) => self.streaming_store.subscribe(subscribe)?,
IntentEnum::Read(read) => self.streaming_store.read(read),
_ => return Err(Status::unknown("Unknown or unsupported intent!")),
};
Ok(Response::new(FulfillResponse {
fulfillment: Some(FulfillmentMessage { fulfillment: Some(response) }),
}))
}
}