Skip to main content

edgehog_device_runtime_containers/properties/
mod.rs

1// This file is part of Edgehog.
2//
3// Copyright 2023 - 2025 SECO Mind Srl
4//
5// Licensed under the Apache License, Version 2.0 (the "License");
6// you may not use this file except in compliance with the License.
7// You may obtain a copy of the License at
8//
9//    http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing, software
12// distributed under the License is distributed on an "AS IS" BASIS,
13// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14// See the License for the specific language governing permissions and
15// limitations under the License.
16//
17// SPDX-License-Identifier: Apache-2.0
18
19//! Container properties sent from the device to Astarte.
20
21use astarte_device_sdk::AstarteData;
22use async_trait::async_trait;
23use tracing::error;
24use uuid::Uuid;
25
26cfg_if::cfg_if! {
27    if #[cfg(test)] {
28        pub use astarte_device_sdk_mock::Client;
29    } else {
30        pub use astarte_device_sdk::Client;
31    }
32}
33
34pub(crate) mod container;
35pub(crate) mod deployment;
36pub(crate) mod device_mapping;
37pub(crate) mod image;
38pub(crate) mod network;
39pub(crate) mod volume;
40
41/// Error returned when failing to publish a property
42#[derive(Debug, thiserror::Error, displaydoc::Display)]
43pub enum PropertyError {
44    /// couldn't send property {interface}{endpoint}
45    Send {
46        /// Interface of the property
47        interface: String,
48        /// Endpoint of the property
49        endpoint: String,
50    },
51    /// couldn't unset property {interface}{endpoint}
52    Unset {
53        /// Interface of the property
54        interface: String,
55        /// Endpoint of the property
56        endpoint: String,
57    },
58}
59
60#[async_trait]
61pub(crate) trait AvailableProp {
62    type Data: Into<AstarteData> + Send + 'static;
63
64    fn interface() -> &'static str;
65
66    fn field() -> &'static str;
67
68    fn id(&self) -> &Uuid;
69
70    async fn send<D>(&self, device: &mut D, data: Self::Data) -> Result<(), PropertyError>
71    where
72        D: Client + Send + Sync + 'static,
73    {
74        self.send_field(device, Self::field(), data).await
75    }
76
77    async fn send_field<D, T>(
78        &self,
79        device: &mut D,
80        field: &str,
81        data: T,
82    ) -> Result<(), PropertyError>
83    where
84        D: Client + Send + Sync + 'static,
85        T: Into<AstarteData> + Send + 'static,
86    {
87        let interface = Self::interface();
88        let endpoint = format!("/{}/{}", self.id(), field);
89
90        device
91            .set_property(interface, &endpoint, data.into())
92            .await
93            .map_err(|err| {
94                error!(
95                    error = format!("{:#}", eyre::Report::new(err)),
96                    "couldn't send data for {interface}{endpoint}"
97                );
98
99                PropertyError::Send {
100                    interface: interface.to_string(),
101                    endpoint,
102                }
103            })
104    }
105
106    async fn unset<D>(&self, device: &mut D) -> Result<(), PropertyError>
107    where
108        D: Client + Send + Sync + 'static,
109    {
110        let interface = Self::interface();
111        let field = Self::field();
112        let endpoint = format!("/{}/{}", self.id(), field);
113
114        device
115            .unset_property(interface, &endpoint)
116            .await
117            .map_err(|err| {
118                error!(
119                    error = format!("{:#}", eyre::Report::new(err)),
120                    "couldn't unset data for {interface}{endpoint}"
121                );
122
123                PropertyError::Unset {
124                    interface: interface.to_string(),
125                    endpoint,
126                }
127            })
128    }
129}