Skip to main content

n5i_plugin_proto/
lib.rs

1// SPDX-FileCopyrightText: 2024-2026 The n5i Project
2//
3// SPDX-License-Identifier: AGPL-3.0-or-later
4
5//! Protobuf definitions for n5i plugins
6//!
7//! This crate contains only the protobuf type definitions with minimal dependencies.
8//! For higher-level plugin runtime functionality, use the `n5i-plugin-common` crate.
9
10pub mod api {
11    tonic::include_proto!("n5i_plugin");
12}
13
14#[cfg(feature = "conversions")]
15pub mod conversions {
16    use n5i::settings::{EnumOption, EnumOptionRepresentation};
17    use n5i::utils::MultiLanguageItem;
18
19    use crate::api::{self, DnsSettingType, ProviderSetting, SettingType, setting::Options};
20
21    impl From<api::MultiLanguageItem> for MultiLanguageItem {
22        fn from(value: api::MultiLanguageItem) -> Self {
23            Self(value.text.into_iter().collect())
24        }
25    }
26
27    impl From<api::SettingOption> for n5i::settings::EnumOption {
28        fn from(value: api::SettingOption) -> Self {
29            Self {
30                value: value.value,
31                display_name: MultiLanguageItem(
32                    value
33                        .display_name
34                        .unwrap_or_default()
35                        .text
36                        .into_iter()
37                        .collect(),
38                ),
39            }
40        }
41    }
42
43    impl From<api::SettingOption> for n5i::settings::EnumOptionRepresentation {
44        fn from(value: api::SettingOption) -> Self {
45            Self::Detailed(value.into())
46        }
47    }
48
49    impl TryFrom<api::Setting> for n5i::settings::Setting {
50        type Error = prost::UnknownEnumValue;
51
52        fn try_from(value: api::Setting) -> Result<Self, Self::Error> {
53            let setting_type = SettingType::try_from(value.r#type)?;
54            Ok(match setting_type {
55                SettingType::SettingString
56                | SettingType::SettingUrl
57                | SettingType::SettingEmail
58                | SettingType::SettingPassword => {
59                    let additional_options = value.options.and_then(|opts| {
60                        let Options::StringLikeOptions(string_opts) = opts else {
61                            return None;
62                        };
63                        Some(string_opts)
64                    });
65                    Self::String(n5i::settings::StringSetting {
66                        default: additional_options
67                            .as_ref()
68                            .and_then(|opts| opts.default_value.clone()),
69                        name: value.name.unwrap_or_default().into(),
70                        description: value.description.unwrap_or_default().into(),
71                        max_len: additional_options
72                            .as_ref()
73                            .and_then(|opts| opts.max_length.map(|v| v as usize)),
74                        string_type: match setting_type {
75                            SettingType::SettingString => None,
76                            SettingType::SettingUrl => Some(n5i::settings::StringType::Url),
77                            SettingType::SettingEmail => Some(n5i::settings::StringType::Email),
78                            SettingType::SettingPassword => {
79                                Some(n5i::settings::StringType::Password)
80                            }
81                            _ => unreachable!(),
82                        },
83                        required: value.required,
84                        placeholder: additional_options.as_ref().and_then(|opts| {
85                            opts.placeholder.clone().map(std::convert::Into::into)
86                        }),
87                        immutable: value.immutable,
88                    })
89                }
90                SettingType::SettingBoolean => {
91                    let additional_options = value.options.and_then(|opts| {
92                        let Options::BooleanOptions(bool_opts) = opts else {
93                            return None;
94                        };
95                        Some(bool_opts)
96                    });
97                    Self::Bool(n5i::settings::BoolSetting {
98                        default: additional_options
99                            .as_ref()
100                            .and_then(|opts| opts.default_value)
101                            .unwrap_or(false),
102                        name: value.name.unwrap_or_default().into(),
103                        description: value.description.unwrap_or_default().into(),
104                        immutable: value.immutable,
105                        required: value.required,
106                    })
107                }
108                SettingType::SettingFloat => {
109                    let additional_options = value.options.and_then(|opts| {
110                        let Options::FloatOptions(float_opts) = opts else {
111                            return None;
112                        };
113                        Some(float_opts)
114                    });
115                    Self::Float(n5i::settings::FloatSetting {
116                        default: additional_options
117                            .as_ref()
118                            .and_then(|opts| opts.default_value),
119                        name: value.name.unwrap_or_default().into(),
120                        description: value.description.unwrap_or_default().into(),
121                        min: additional_options.as_ref().and_then(|opts| opts.min),
122                        max: additional_options.as_ref().and_then(|opts| opts.max),
123                        step_size: additional_options.as_ref().and_then(|opts| opts.step_size),
124                        placeholder: additional_options.as_ref().and_then(|opts| {
125                            opts.placeholder.clone().map(std::convert::Into::into)
126                        }),
127                        immutable: value.immutable,
128                        required: value.required,
129                    })
130                }
131                SettingType::SettingSelect => {
132                    let additional_options = value.options.and_then(|opts| {
133                        let Options::EnumOptions(select_opts) = opts else {
134                            return None;
135                        };
136                        Some(select_opts)
137                    });
138                    Self::Enum(n5i::settings::EnumSetting {
139                        default: additional_options
140                            .as_ref()
141                            .and_then(|opts| opts.default_value.clone()),
142                        name: value.name.unwrap_or_default().into(),
143                        description: value.description.unwrap_or_default().into(),
144                        values: additional_options
145                            .as_ref()
146                            .map(|opts| opts.options.iter().map(|o| o.clone().into()).collect())
147                            .unwrap_or_default(),
148                        immutable: value.immutable,
149                        required: value.required,
150                    })
151                }
152                SettingType::SettingInteger => {
153                    let additional_options = value.options.and_then(|opts| {
154                        let Options::IntegerOptions(int_opts) = opts else {
155                            return None;
156                        };
157                        Some(int_opts)
158                    });
159                    Self::Int(n5i::settings::IntSetting {
160                        default: additional_options
161                            .as_ref()
162                            .and_then(|opts| opts.default_value),
163                        name: value.name.unwrap_or_default().into(),
164                        description: value.description.unwrap_or_default().into(),
165                        min: additional_options.as_ref().and_then(|opts| opts.min),
166                        max: additional_options.as_ref().and_then(|opts| opts.max),
167                        step_size: additional_options.as_ref().and_then(|opts| opts.step_size),
168                        placeholder: additional_options.as_ref().and_then(|opts| {
169                            opts.placeholder.clone().map(std::convert::Into::into)
170                        }),
171                        immutable: value.immutable,
172                        required: value.required,
173                    })
174                }
175            })
176        }
177    }
178
179    impl From<api::AppScope> for n5i_apps::metadata::AppScope {
180        fn from(value: api::AppScope) -> Self {
181            match value {
182                api::AppScope::User => Self::User,
183                api::AppScope::System => Self::System,
184            }
185        }
186    }
187
188    impl From<api::ProviderSetting> for n5i::settings::Setting {
189        fn from(value: ProviderSetting) -> Self {
190            let setting_type = value.r#type();
191            match setting_type {
192                DnsSettingType::String
193                | DnsSettingType::Email
194                | DnsSettingType::Url
195                | DnsSettingType::Password => Self::String(n5i::settings::StringSetting {
196                    default: value.default_value.clone(),
197                    name: value.name.unwrap_or_default().into(),
198                    description: value.description.unwrap_or_default().into(),
199                    max_len: None,
200                    string_type: match setting_type {
201                        DnsSettingType::String => None,
202                        DnsSettingType::Email => Some(n5i::settings::StringType::Email),
203                        DnsSettingType::Url => Some(n5i::settings::StringType::Url),
204                        DnsSettingType::Password => Some(n5i::settings::StringType::Password),
205                        _ => unreachable!(),
206                    },
207                    required: value.required,
208                    placeholder: None,
209                    immutable: false,
210                }),
211                DnsSettingType::Boolean => Self::Bool(n5i::settings::BoolSetting {
212                    default: value.default_value.as_deref() == Some("true"),
213                    name: value.name.unwrap_or_default().into(),
214                    description: value.description.unwrap_or_default().into(),
215                    immutable: false,
216                    required: value.required,
217                }),
218                DnsSettingType::Number => Self::Float(n5i::settings::FloatSetting {
219                    default: value
220                        .default_value
221                        .as_ref()
222                        .and_then(|v| v.parse::<f64>().ok()),
223                    name: value.name.unwrap_or_default().into(),
224                    description: value.description.unwrap_or_default().into(),
225                    min: None,
226                    max: None,
227                    step_size: None,
228                    placeholder: None,
229                    immutable: false,
230                    required: value.required,
231                }),
232                DnsSettingType::Select => Self::Enum(n5i::settings::EnumSetting {
233                    default: value.default_value.clone(),
234                    name: value.name.unwrap_or_default().into(),
235                    description: value.description.unwrap_or_default().into(),
236                    values: value
237                        .options
238                        .into_iter()
239                        .map(|v| {
240                            EnumOptionRepresentation::Detailed(EnumOption {
241                                value: v.value,
242                                display_name: v
243                                    .display_name
244                                    .map(std::convert::Into::into)
245                                    .unwrap_or_default(),
246                            })
247                        })
248                        .collect(),
249                    immutable: false,
250                    required: value.required,
251                }),
252            }
253        }
254    }
255}