n5i-plugin-proto 0.12.0-dev.2

Protobuf definitions for n5i plugins
Documentation
// SPDX-FileCopyrightText: 2024-2026 The n5i Project
//
// SPDX-License-Identifier: AGPL-3.0-or-later

//! Protobuf definitions for n5i plugins
//!
//! This crate contains only the protobuf type definitions with minimal dependencies.
//! For higher-level plugin runtime functionality, use the `n5i-plugin-common` crate.

pub mod api {
    tonic::include_proto!("n5i_plugin");
}

#[cfg(feature = "conversions")]
pub mod conversions {
    use n5i::settings::{EnumOption, EnumOptionRepresentation};
    use n5i::utils::MultiLanguageItem;

    use crate::api::{self, DnsSettingType, ProviderSetting, SettingType, setting::Options};

    impl From<api::MultiLanguageItem> for MultiLanguageItem {
        fn from(value: api::MultiLanguageItem) -> Self {
            Self(value.text.into_iter().collect())
        }
    }

    impl From<api::SettingOption> for n5i::settings::EnumOption {
        fn from(value: api::SettingOption) -> Self {
            Self {
                value: value.value,
                display_name: MultiLanguageItem(
                    value
                        .display_name
                        .unwrap_or_default()
                        .text
                        .into_iter()
                        .collect(),
                ),
            }
        }
    }

    impl From<api::SettingOption> for n5i::settings::EnumOptionRepresentation {
        fn from(value: api::SettingOption) -> Self {
            Self::Detailed(value.into())
        }
    }

    impl TryFrom<api::Setting> for n5i::settings::Setting {
        type Error = prost::UnknownEnumValue;

        fn try_from(value: api::Setting) -> Result<Self, Self::Error> {
            let setting_type = SettingType::try_from(value.r#type)?;
            Ok(match setting_type {
                SettingType::SettingString
                | SettingType::SettingUrl
                | SettingType::SettingEmail
                | SettingType::SettingPassword => {
                    let additional_options = value.options.and_then(|opts| {
                        let Options::StringLikeOptions(string_opts) = opts else {
                            return None;
                        };
                        Some(string_opts)
                    });
                    Self::String(n5i::settings::StringSetting {
                        default: additional_options
                            .as_ref()
                            .and_then(|opts| opts.default_value.clone()),
                        name: value.name.unwrap_or_default().into(),
                        description: value.description.unwrap_or_default().into(),
                        max_len: additional_options
                            .as_ref()
                            .and_then(|opts| opts.max_length.map(|v| v as usize)),
                        string_type: match setting_type {
                            SettingType::SettingString => None,
                            SettingType::SettingUrl => Some(n5i::settings::StringType::Url),
                            SettingType::SettingEmail => Some(n5i::settings::StringType::Email),
                            SettingType::SettingPassword => {
                                Some(n5i::settings::StringType::Password)
                            }
                            _ => unreachable!(),
                        },
                        required: value.required,
                        placeholder: additional_options.as_ref().and_then(|opts| {
                            opts.placeholder.clone().map(std::convert::Into::into)
                        }),
                        immutable: value.immutable,
                    })
                }
                SettingType::SettingBoolean => {
                    let additional_options = value.options.and_then(|opts| {
                        let Options::BooleanOptions(bool_opts) = opts else {
                            return None;
                        };
                        Some(bool_opts)
                    });
                    Self::Bool(n5i::settings::BoolSetting {
                        default: additional_options
                            .as_ref()
                            .and_then(|opts| opts.default_value)
                            .unwrap_or(false),
                        name: value.name.unwrap_or_default().into(),
                        description: value.description.unwrap_or_default().into(),
                        immutable: value.immutable,
                        required: value.required,
                    })
                }
                SettingType::SettingFloat => {
                    let additional_options = value.options.and_then(|opts| {
                        let Options::FloatOptions(float_opts) = opts else {
                            return None;
                        };
                        Some(float_opts)
                    });
                    Self::Float(n5i::settings::FloatSetting {
                        default: additional_options
                            .as_ref()
                            .and_then(|opts| opts.default_value),
                        name: value.name.unwrap_or_default().into(),
                        description: value.description.unwrap_or_default().into(),
                        min: additional_options.as_ref().and_then(|opts| opts.min),
                        max: additional_options.as_ref().and_then(|opts| opts.max),
                        step_size: additional_options.as_ref().and_then(|opts| opts.step_size),
                        placeholder: additional_options.as_ref().and_then(|opts| {
                            opts.placeholder.clone().map(std::convert::Into::into)
                        }),
                        immutable: value.immutable,
                        required: value.required,
                    })
                }
                SettingType::SettingSelect => {
                    let additional_options = value.options.and_then(|opts| {
                        let Options::EnumOptions(select_opts) = opts else {
                            return None;
                        };
                        Some(select_opts)
                    });
                    Self::Enum(n5i::settings::EnumSetting {
                        default: additional_options
                            .as_ref()
                            .and_then(|opts| opts.default_value.clone()),
                        name: value.name.unwrap_or_default().into(),
                        description: value.description.unwrap_or_default().into(),
                        values: additional_options
                            .as_ref()
                            .map(|opts| opts.options.iter().map(|o| o.clone().into()).collect())
                            .unwrap_or_default(),
                        immutable: value.immutable,
                        required: value.required,
                    })
                }
                SettingType::SettingInteger => {
                    let additional_options = value.options.and_then(|opts| {
                        let Options::IntegerOptions(int_opts) = opts else {
                            return None;
                        };
                        Some(int_opts)
                    });
                    Self::Int(n5i::settings::IntSetting {
                        default: additional_options
                            .as_ref()
                            .and_then(|opts| opts.default_value),
                        name: value.name.unwrap_or_default().into(),
                        description: value.description.unwrap_or_default().into(),
                        min: additional_options.as_ref().and_then(|opts| opts.min),
                        max: additional_options.as_ref().and_then(|opts| opts.max),
                        step_size: additional_options.as_ref().and_then(|opts| opts.step_size),
                        placeholder: additional_options.as_ref().and_then(|opts| {
                            opts.placeholder.clone().map(std::convert::Into::into)
                        }),
                        immutable: value.immutable,
                        required: value.required,
                    })
                }
            })
        }
    }

    impl From<api::AppScope> for n5i_apps::metadata::AppScope {
        fn from(value: api::AppScope) -> Self {
            match value {
                api::AppScope::User => Self::User,
                api::AppScope::System => Self::System,
            }
        }
    }

    impl From<api::ProviderSetting> for n5i::settings::Setting {
        fn from(value: ProviderSetting) -> Self {
            let setting_type = value.r#type();
            match setting_type {
                DnsSettingType::String
                | DnsSettingType::Email
                | DnsSettingType::Url
                | DnsSettingType::Password => Self::String(n5i::settings::StringSetting {
                    default: value.default_value.clone(),
                    name: value.name.unwrap_or_default().into(),
                    description: value.description.unwrap_or_default().into(),
                    max_len: None,
                    string_type: match setting_type {
                        DnsSettingType::String => None,
                        DnsSettingType::Email => Some(n5i::settings::StringType::Email),
                        DnsSettingType::Url => Some(n5i::settings::StringType::Url),
                        DnsSettingType::Password => Some(n5i::settings::StringType::Password),
                        _ => unreachable!(),
                    },
                    required: value.required,
                    placeholder: None,
                    immutable: false,
                }),
                DnsSettingType::Boolean => Self::Bool(n5i::settings::BoolSetting {
                    default: value.default_value.as_deref() == Some("true"),
                    name: value.name.unwrap_or_default().into(),
                    description: value.description.unwrap_or_default().into(),
                    immutable: false,
                    required: value.required,
                }),
                DnsSettingType::Number => Self::Float(n5i::settings::FloatSetting {
                    default: value
                        .default_value
                        .as_ref()
                        .and_then(|v| v.parse::<f64>().ok()),
                    name: value.name.unwrap_or_default().into(),
                    description: value.description.unwrap_or_default().into(),
                    min: None,
                    max: None,
                    step_size: None,
                    placeholder: None,
                    immutable: false,
                    required: value.required,
                }),
                DnsSettingType::Select => Self::Enum(n5i::settings::EnumSetting {
                    default: value.default_value.clone(),
                    name: value.name.unwrap_or_default().into(),
                    description: value.description.unwrap_or_default().into(),
                    values: value
                        .options
                        .into_iter()
                        .map(|v| {
                            EnumOptionRepresentation::Detailed(EnumOption {
                                value: v.value,
                                display_name: v
                                    .display_name
                                    .map(std::convert::Into::into)
                                    .unwrap_or_default(),
                            })
                        })
                        .collect(),
                    immutable: false,
                    required: value.required,
                }),
            }
        }
    }
}