photonic_interface_grpc/
lib.rs

1#![feature(impl_trait_in_assoc_type)]
2
3use std::pin::Pin;
4use std::sync::Arc;
5
6use anyhow::Result;
7use futures::StreamExt;
8use tonic::codegen::tokio_stream::Stream;
9use tonic::transport::Server;
10use tonic::{async_trait, Request, Response, Status};
11
12use photonic::attr::Range;
13use photonic::input::{InputSink, InputValueType, Trigger};
14use photonic::interface::{Interface, Introspection};
15use photonic_interface_grpc_proto::input_value::{ColorRange, DecimalRange, IntegerRange, Rgb};
16use photonic_interface_grpc_proto::interface_server::InterfaceServer;
17use photonic_interface_grpc_proto::{
18    input_value, interface_server, AttrInfoRequest, AttrInfoResponse, InputInfoRequest, InputInfoResponse,
19    InputSendRequest, InputSubscribeRequest, InputValue, InputsResponse, NodeInfoRequest, NodeInfoResponse,
20    NodesResponse,
21};
22
23pub struct GRPC {}
24
25impl GRPC {
26    pub fn new() -> Result<Self> {
27        return Ok(Self {});
28    }
29}
30
31impl Interface for GRPC {
32    async fn listen(self, introspection: Arc<Introspection>) -> Result<()> {
33        let addr = "[::1]:51889".parse().expect("Invalid interface");
34
35        Server::builder()
36            .add_service(InterfaceServer::new(InterfaceImpl {
37                introspection,
38            }))
39            .serve(addr)
40            .await?;
41
42        return Ok(());
43    }
44}
45
46struct InterfaceImpl {
47    introspection: Arc<Introspection>,
48}
49
50#[async_trait]
51impl interface_server::Interface for InterfaceImpl {
52    type InputSubscribeStream = Pin<Box<dyn Stream<Item = Result<InputValue, Status>> + Send + 'static>>;
53
54    async fn nodes(&self, _request: Request<()>) -> Result<Response<NodesResponse>, Status> {
55        let nodes = self.introspection.nodes.keys().cloned().collect();
56
57        return Ok(Response::new(NodesResponse {
58            nodes,
59        }));
60    }
61
62    async fn inputs(&self, _request: Request<()>) -> Result<Response<InputsResponse>, Status> {
63        let inputs = self.introspection.inputs.keys().cloned().collect();
64
65        return Ok(Response::new(InputsResponse {
66            inputs,
67        }));
68    }
69    async fn root(&self, _request: Request<()>) -> Result<Response<NodeInfoResponse>, Status> {
70        let root = &*self.introspection.root;
71
72        return Ok(Response::new(NodeInfoResponse {
73            kind: root.kind().to_string(),
74            name: root.name().to_string(),
75            nodes: root.nodes().iter().map(|(name, info)| (name.clone(), info.name().to_owned())).collect(),
76            attrs: root.attrs().keys().cloned().collect(),
77        }));
78    }
79
80    async fn node(&self, request: Request<NodeInfoRequest>) -> Result<Response<NodeInfoResponse>, Status> {
81        let request = request.get_ref();
82
83        let node = &**self
84            .introspection
85            .nodes
86            .get(&request.name)
87            .ok_or_else(|| Status::not_found(format!("No such node: {}", request.name)))?;
88
89        return Ok(Response::new(NodeInfoResponse {
90            kind: node.kind().to_string(),
91            name: node.name().to_string(),
92            nodes: node.nodes().iter().map(|(name, info)| (name.clone(), info.name().to_owned())).collect(),
93            attrs: node.attrs().keys().cloned().collect(),
94        }));
95    }
96
97    async fn attr(&self, request: Request<AttrInfoRequest>) -> Result<Response<AttrInfoResponse>, Status> {
98        let request = request.get_ref();
99
100        let attr_ref = request.name.as_ref().ok_or_else(|| Status::invalid_argument("Value missing: attr"))?;
101
102        let node = &**self
103            .introspection
104            .nodes
105            .get(&attr_ref.node)
106            .ok_or_else(|| Status::not_found(format!("No such node: {}", attr_ref.node)))?;
107
108        let attr = node.find_attr(attr_ref.path.iter()).ok_or_else(|| {
109            Status::not_found(format!("No such attribute: {}/{}", attr_ref.node, attr_ref.path.join("/")))
110        })?;
111
112        return Ok(Response::new(AttrInfoResponse {
113            attr: Some(attr_ref.clone()),
114            kind: attr.kind().to_string(),
115            value_type: attr.value_type().to_string(),
116            attrs: attr.attrs().keys().cloned().collect(),
117            inputs: attr.inputs().iter().map(|(name, info)| (name.clone(), info.name().to_owned())).collect(),
118        }));
119    }
120
121    async fn input(&self, request: Request<InputInfoRequest>) -> Result<Response<InputInfoResponse>, Status> {
122        let request = request.get_ref();
123
124        let input = &**self
125            .introspection
126            .inputs
127            .get(&request.name)
128            .ok_or_else(|| Status::not_found(format!("No such input: {}", request.name)))?;
129
130        return Ok(Response::new(InputInfoResponse {
131            name: input.name().to_string(),
132            value_type: match input.value_type() {
133                InputValueType::Trigger => photonic_interface_grpc_proto::InputValueType::Trigger,
134                InputValueType::Boolean => photonic_interface_grpc_proto::InputValueType::Bool,
135                InputValueType::Integer => photonic_interface_grpc_proto::InputValueType::Integer,
136                InputValueType::Decimal => photonic_interface_grpc_proto::InputValueType::Decimal,
137                InputValueType::Color => photonic_interface_grpc_proto::InputValueType::Color,
138                InputValueType::IntegerRange => photonic_interface_grpc_proto::InputValueType::IntegerRange,
139                InputValueType::DecimalRange => photonic_interface_grpc_proto::InputValueType::DecimalRange,
140                InputValueType::ColorRange => photonic_interface_grpc_proto::InputValueType::ColorRange,
141            }
142            .into(),
143        }));
144    }
145
146    async fn input_send(&self, request: Request<InputSendRequest>) -> Result<Response<()>, Status> {
147        let request = request.get_ref();
148
149        let input = &**self
150            .introspection
151            .inputs
152            .get(&request.name)
153            .ok_or_else(|| Status::not_found(format!("No such input: {}", request.name)))?;
154
155        macro_rules! match_value {
156            ($pattern:ident) => {
157                match request
158                    .value
159                    .as_ref()
160                    .ok_or(Status::invalid_argument("Value missing"))?
161                    .value
162                    .as_ref()
163                    .ok_or(Status::invalid_argument("Value missing"))?
164                {
165                    input_value::Value::$pattern(ref value) => value,
166                    _ => return Err(Status::invalid_argument("Value of wrong type")),
167                }
168            };
169        }
170
171        match &input.sink() {
172            InputSink::Trigger(sink) => {
173                match_value!(Trigger);
174                sink.send(Trigger::next()).await
175            }
176
177            InputSink::Boolean(sink) => {
178                let value = match_value!(Bool);
179                sink.send(*value).await
180            }
181
182            InputSink::Integer(sink) => {
183                let value = match_value!(Integer);
184                sink.send(*value).await
185            }
186
187            InputSink::Decimal(sink) => {
188                let value = match_value!(Decimal);
189                sink.send(*value).await
190            }
191
192            InputSink::Color(sink) => {
193                let value = match_value!(Color);
194                let value = palette::Srgb::new(value.r, value.g, value.b);
195                sink.send(value).await
196            }
197
198            InputSink::IntegerRange(sink) => {
199                let value = match_value!(IntegerRange);
200                let value = Range::new(value.a, value.b);
201                sink.send(value).await
202            }
203
204            InputSink::DecimalRange(sink) => {
205                let value = match_value!(DecimalRange);
206                let value = Range::new(value.a, value.b);
207                sink.send(value).await
208            }
209
210            InputSink::ColorRange(sink) => {
211                let value = match_value!(ColorRange);
212                let value_a = value.a.as_ref().ok_or(Status::invalid_argument("Value missing"))?;
213                let value_b = value.b.as_ref().ok_or(Status::invalid_argument("Value missing"))?;
214                let value = Range::new(
215                    palette::Srgb::new(value_a.r, value_a.g, value_a.b),
216                    palette::Srgb::new(value_b.r, value_b.g, value_b.b),
217                );
218                sink.send(value).await
219            }
220        }
221        .map_err(|err| Status::invalid_argument(format!("Invalid value: {err}")))?;
222
223        return Ok(Response::new(()));
224    }
225
226    async fn input_subscribe(
227        &self,
228        request: Request<InputSubscribeRequest>,
229    ) -> Result<Response<Self::InputSubscribeStream>, Status> {
230        let request = request.get_ref();
231
232        let input = &**self
233            .introspection
234            .inputs
235            .get(&request.name)
236            .ok_or_else(|| Status::not_found(format!("No such input: {}", request.name)))?;
237
238        let stream: Pin<Box<dyn Stream<Item = Result<_, _>> + Send + 'static>> = match &input.sink() {
239            InputSink::Trigger(sink) => Box::pin(sink.subscribe().map(|_| {
240                Ok(InputValue {
241                    value: Some(input_value::Value::Trigger(())),
242                })
243            })),
244
245            InputSink::Boolean(sink) => Box::pin(sink.subscribe().map(|value| {
246                Ok(InputValue {
247                    value: Some(input_value::Value::Bool(value)),
248                })
249            })),
250
251            InputSink::Integer(sink) => Box::pin(sink.subscribe().map(|value| {
252                Ok(InputValue {
253                    value: Some(input_value::Value::Integer(value)),
254                })
255            })),
256
257            InputSink::Decimal(sink) => Box::pin(sink.subscribe().map(|value| {
258                Ok(InputValue {
259                    value: Some(input_value::Value::Decimal(value)),
260                })
261            })),
262
263            InputSink::Color(sink) => Box::pin(sink.subscribe().map(|value| {
264                Ok(InputValue {
265                    value: Some(input_value::Value::Color(Rgb {
266                        r: value.red,
267                        g: value.green,
268                        b: value.blue,
269                    })),
270                })
271            })),
272
273            InputSink::IntegerRange(sink) => Box::pin(sink.subscribe().map(|value| {
274                Ok(InputValue {
275                    value: Some(input_value::Value::IntegerRange(IntegerRange {
276                        a: value.0,
277                        b: value.1,
278                    })),
279                })
280            })),
281
282            InputSink::DecimalRange(sink) => Box::pin(sink.subscribe().map(|value| {
283                Ok(InputValue {
284                    value: Some(input_value::Value::DecimalRange(DecimalRange {
285                        a: value.0,
286                        b: value.1,
287                    })),
288                })
289            })),
290
291            InputSink::ColorRange(sink) => Box::pin(sink.subscribe().map(|value| {
292                Ok(InputValue {
293                    value: Some(input_value::Value::ColorRange(ColorRange {
294                        a: Some(Rgb {
295                            r: value.0.red,
296                            g: value.0.green,
297                            b: value.0.blue,
298                        }),
299                        b: Some(Rgb {
300                            r: value.1.red,
301                            g: value.1.green,
302                            b: value.1.blue,
303                        }),
304                    })),
305                })
306            })),
307        };
308
309        return Ok(Response::new(stream));
310    }
311}