use derive_builder::Builder;
use partial_derive2::{Diff, MaybeNone, Partial, PartialDiff};
use serde::{Deserialize, Serialize};
use strum::{AsRefStr, Display, EnumDiscriminants, EnumString};
use typeshare::typeshare;
use crate::deserializers::{
option_string_list_deserializer, string_list_deserializer,
};
use super::{
MergePartial,
config::{DockerRegistry, GitProvider},
resource::{AddFilters, Resource, ResourceListItem, ResourceQuery},
};
#[cfg(feature = "utoipa")]
#[derive(utoipa::ToSchema)]
#[schema(as = Builder)]
pub struct BuilderSchema(
#[schema(inline)]
pub Resource<BuilderConfig, crate::entities::NoData>,
);
#[typeshare]
pub type Builder = Resource<BuilderConfig, ()>;
#[typeshare]
pub type BuilderListItem = ResourceListItem<BuilderListItemInfo>;
#[typeshare(serialized_as = "Partial<BuilderConfig>")]
pub type _PartialBuilderConfig = PartialBuilderConfig;
#[typeshare]
#[derive(Serialize, Deserialize, Debug, Clone)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
pub struct BuilderListItemInfo {
pub builder_type: String,
pub instance_type: Option<String>,
}
#[typeshare]
#[derive(Serialize, Deserialize, Debug, Clone, EnumDiscriminants)]
#[strum_discriminants(name(BuilderConfigVariant))]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[cfg_attr(
not(feature = "utoipa"),
strum_discriminants(derive(
PartialOrd,
Ord,
Hash,
Serialize,
Deserialize,
Display,
EnumString,
AsRefStr
))
)]
#[cfg_attr(
feature = "utoipa",
strum_discriminants(derive(
PartialOrd,
Ord,
Hash,
Serialize,
Deserialize,
Display,
EnumString,
AsRefStr,
utoipa::ToSchema
))
)]
#[serde(tag = "type", content = "params")]
#[allow(clippy::large_enum_variant)]
pub enum BuilderConfig {
Url(UrlBuilderConfig),
Server(ServerBuilderConfig),
Aws(AwsBuilderConfig),
}
impl Default for BuilderConfig {
fn default() -> Self {
Self::Aws(Default::default())
}
}
#[typeshare]
#[derive(Serialize, Deserialize, Debug, Clone, EnumDiscriminants)]
#[strum_discriminants(name(PartialBuilderConfigVariant))]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[cfg_attr(
not(feature = "utoipa"),
strum_discriminants(derive(
PartialOrd,
Ord,
Hash,
Serialize,
Deserialize,
Display,
EnumString,
AsRefStr
))
)]
#[cfg_attr(
feature = "utoipa",
strum_discriminants(derive(
PartialOrd,
Ord,
Hash,
Serialize,
Deserialize,
Display,
EnumString,
AsRefStr,
utoipa::ToSchema
))
)]
#[serde(tag = "type", content = "params")]
#[allow(clippy::large_enum_variant)]
pub enum PartialBuilderConfig {
Url(#[serde(default)] _PartialUrlBuilderConfig),
Server(#[serde(default)] _PartialServerBuilderConfig),
Aws(#[serde(default)] _PartialAwsBuilderConfig),
}
impl Default for PartialBuilderConfig {
fn default() -> Self {
Self::Url(Default::default())
}
}
impl MaybeNone for PartialBuilderConfig {
fn is_none(&self) -> bool {
match self {
PartialBuilderConfig::Url(config) => config.is_none(),
PartialBuilderConfig::Server(config) => config.is_none(),
PartialBuilderConfig::Aws(config) => config.is_none(),
}
}
}
#[allow(clippy::large_enum_variant)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum BuilderConfigDiff {
Url(UrlBuilderConfigDiff),
Server(ServerBuilderConfigDiff),
Aws(AwsBuilderConfigDiff),
}
impl From<BuilderConfigDiff> for PartialBuilderConfig {
fn from(value: BuilderConfigDiff) -> Self {
match value {
BuilderConfigDiff::Url(diff) => {
PartialBuilderConfig::Url(diff.into())
}
BuilderConfigDiff::Server(diff) => {
PartialBuilderConfig::Server(diff.into())
}
BuilderConfigDiff::Aws(diff) => {
PartialBuilderConfig::Aws(diff.into())
}
}
}
}
impl Diff for BuilderConfigDiff {
fn iter_field_diffs(
&self,
) -> impl Iterator<Item = partial_derive2::FieldDiff> {
match self {
BuilderConfigDiff::Url(diff) => {
diff.iter_field_diffs().collect::<Vec<_>>().into_iter()
}
BuilderConfigDiff::Server(diff) => {
diff.iter_field_diffs().collect::<Vec<_>>().into_iter()
}
BuilderConfigDiff::Aws(diff) => {
diff.iter_field_diffs().collect::<Vec<_>>().into_iter()
}
}
}
}
impl PartialDiff<PartialBuilderConfig, BuilderConfigDiff>
for BuilderConfig
{
fn partial_diff(
&self,
partial: PartialBuilderConfig,
) -> BuilderConfigDiff {
match self {
BuilderConfig::Url(original) => match partial {
PartialBuilderConfig::Url(partial) => {
BuilderConfigDiff::Url(original.partial_diff(partial))
}
PartialBuilderConfig::Server(partial) => {
let default = ServerBuilderConfig::default();
BuilderConfigDiff::Server(default.partial_diff(partial))
}
PartialBuilderConfig::Aws(partial) => {
let default = AwsBuilderConfig::default();
BuilderConfigDiff::Aws(default.partial_diff(partial))
}
},
BuilderConfig::Server(original) => match partial {
PartialBuilderConfig::Server(partial) => {
BuilderConfigDiff::Server(original.partial_diff(partial))
}
PartialBuilderConfig::Url(partial) => {
let default = UrlBuilderConfig::default();
BuilderConfigDiff::Url(default.partial_diff(partial))
}
PartialBuilderConfig::Aws(partial) => {
let default = AwsBuilderConfig::default();
BuilderConfigDiff::Aws(default.partial_diff(partial))
}
},
BuilderConfig::Aws(original) => match partial {
PartialBuilderConfig::Aws(partial) => {
BuilderConfigDiff::Aws(original.partial_diff(partial))
}
PartialBuilderConfig::Url(partial) => {
let default = UrlBuilderConfig::default();
BuilderConfigDiff::Url(default.partial_diff(partial))
}
PartialBuilderConfig::Server(partial) => {
let default = ServerBuilderConfig::default();
BuilderConfigDiff::Server(default.partial_diff(partial))
}
},
}
}
}
impl MaybeNone for BuilderConfigDiff {
fn is_none(&self) -> bool {
match self {
BuilderConfigDiff::Url(config) => config.is_none(),
BuilderConfigDiff::Server(config) => config.is_none(),
BuilderConfigDiff::Aws(config) => config.is_none(),
}
}
}
impl From<PartialBuilderConfig> for BuilderConfig {
fn from(value: PartialBuilderConfig) -> BuilderConfig {
match value {
PartialBuilderConfig::Url(server) => {
BuilderConfig::Url(server.into())
}
PartialBuilderConfig::Server(server) => {
BuilderConfig::Server(server.into())
}
PartialBuilderConfig::Aws(builder) => {
BuilderConfig::Aws(builder.into())
}
}
}
}
impl From<BuilderConfig> for PartialBuilderConfig {
fn from(value: BuilderConfig) -> Self {
match value {
BuilderConfig::Url(config) => {
PartialBuilderConfig::Url(config.into())
}
BuilderConfig::Server(config) => {
PartialBuilderConfig::Server(config.into())
}
BuilderConfig::Aws(config) => {
PartialBuilderConfig::Aws(config.into())
}
}
}
}
impl MergePartial for BuilderConfig {
type Partial = PartialBuilderConfig;
fn merge_partial(
self,
partial: PartialBuilderConfig,
) -> BuilderConfig {
match partial {
PartialBuilderConfig::Url(partial) => match self {
BuilderConfig::Url(config) => {
let config = UrlBuilderConfig {
address: partial.address.unwrap_or(config.address),
periphery_public_key: partial
.periphery_public_key
.unwrap_or(config.periphery_public_key),
insecure_tls: partial
.insecure_tls
.unwrap_or(config.insecure_tls),
passkey: partial.passkey.unwrap_or(config.passkey),
};
BuilderConfig::Url(config)
}
_ => BuilderConfig::Url(partial.into()),
},
PartialBuilderConfig::Server(partial) => match self {
BuilderConfig::Server(config) => {
let config = ServerBuilderConfig {
server_id: partial.server_id.unwrap_or(config.server_id),
};
BuilderConfig::Server(config)
}
_ => BuilderConfig::Server(partial.into()),
},
PartialBuilderConfig::Aws(partial) => match self {
BuilderConfig::Aws(config) => {
let config = AwsBuilderConfig {
region: partial.region.unwrap_or(config.region),
instance_type: partial
.instance_type
.unwrap_or(config.instance_type),
volume_gb: partial.volume_gb.unwrap_or(config.volume_gb),
ami_id: partial.ami_id.unwrap_or(config.ami_id),
subnet_id: partial.subnet_id.unwrap_or(config.subnet_id),
security_group_ids: partial
.security_group_ids
.unwrap_or(config.security_group_ids),
key_pair_name: partial
.key_pair_name
.unwrap_or(config.key_pair_name),
assign_public_ip: partial
.assign_public_ip
.unwrap_or(config.assign_public_ip),
use_public_ip: partial
.use_public_ip
.unwrap_or(config.use_public_ip),
port: partial.port.unwrap_or(config.port),
use_https: partial.use_https.unwrap_or(config.use_https),
periphery_public_key: partial
.periphery_public_key
.unwrap_or(config.periphery_public_key),
insecure_tls: partial
.insecure_tls
.unwrap_or(config.insecure_tls),
user_data: partial.user_data.unwrap_or(config.user_data),
git_providers: partial
.git_providers
.unwrap_or(config.git_providers),
docker_registries: partial
.docker_registries
.unwrap_or(config.docker_registries),
secrets: partial.secrets.unwrap_or(config.secrets),
};
BuilderConfig::Aws(config)
}
_ => BuilderConfig::Aws(partial.into()),
},
}
}
}
#[typeshare(serialized_as = "Partial<UrlBuilderConfig>")]
pub type _PartialUrlBuilderConfig = PartialUrlBuilderConfig;
#[typeshare]
#[derive(Serialize, Deserialize, Debug, Clone, Builder, Partial)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[cfg_attr(
not(feature = "utoipa"),
partial_derive(Serialize, Deserialize, Debug, Clone, Default)
)]
#[cfg_attr(
feature = "utoipa",
partial_derive(Serialize, Deserialize, Debug, Clone, Default,)
)]
#[diff_derive(Serialize, Deserialize, Debug, Clone, Default)]
#[partial(skip_serializing_none, from, diff)]
pub struct UrlBuilderConfig {
#[serde(default = "default_address")]
#[builder(default = default_address())]
#[partial_default(default_address())]
pub address: String,
#[serde(default)]
#[builder(default)]
pub periphery_public_key: String,
#[serde(default = "default_insecure_tls")]
#[builder(default = default_insecure_tls())]
#[partial_default(default_insecure_tls())]
pub insecure_tls: bool,
#[serde(default)]
#[builder(default)]
pub passkey: String,
}
fn default_address() -> String {
String::from("https://periphery:8120")
}
fn default_insecure_tls() -> bool {
true
}
impl Default for UrlBuilderConfig {
fn default() -> Self {
Self {
address: default_address(),
periphery_public_key: Default::default(),
insecure_tls: default_insecure_tls(),
passkey: Default::default(),
}
}
}
impl UrlBuilderConfig {
pub fn builder() -> UrlBuilderConfigBuilder {
UrlBuilderConfigBuilder::default()
}
}
#[cfg(feature = "utoipa")]
impl utoipa::PartialSchema for PartialUrlBuilderConfig {
fn schema()
-> utoipa::openapi::RefOr<utoipa::openapi::schema::Schema> {
utoipa::schema!(#[inline] std::collections::HashMap<String, serde_json::Value>).into()
}
}
#[cfg(feature = "utoipa")]
impl utoipa::ToSchema for PartialUrlBuilderConfig {}
#[typeshare(serialized_as = "Partial<ServerBuilderConfig>")]
pub type _PartialServerBuilderConfig = PartialServerBuilderConfig;
#[typeshare]
#[derive(
Serialize, Deserialize, Debug, Clone, Default, Builder, Partial,
)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[partial_derive(Serialize, Deserialize, Debug, Clone, Default)]
#[diff_derive(Serialize, Deserialize, Debug, Clone, Default)]
#[partial(skip_serializing_none, from, diff)]
pub struct ServerBuilderConfig {
#[serde(default, alias = "server")]
#[partial_attr(serde(alias = "server"))]
pub server_id: String,
}
impl ServerBuilderConfig {
pub fn builder() -> ServerBuilderConfigBuilder {
ServerBuilderConfigBuilder::default()
}
}
#[cfg(feature = "utoipa")]
impl utoipa::PartialSchema for PartialServerBuilderConfig {
fn schema()
-> utoipa::openapi::RefOr<utoipa::openapi::schema::Schema> {
utoipa::schema!(#[inline] std::collections::HashMap<String, serde_json::Value>).into()
}
}
#[cfg(feature = "utoipa")]
impl utoipa::ToSchema for PartialServerBuilderConfig {}
#[typeshare(serialized_as = "Partial<AwsBuilderConfig>")]
pub type _PartialAwsBuilderConfig = PartialAwsBuilderConfig;
#[typeshare]
#[derive(Debug, Clone, Serialize, Deserialize, Builder, Partial)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[partial_derive(Serialize, Deserialize, Debug, Clone, Default)]
#[diff_derive(Serialize, Deserialize, Debug, Clone, Default)]
#[partial(skip_serializing_none, from, diff)]
pub struct AwsBuilderConfig {
#[serde(default = "aws_default_region")]
#[builder(default = "aws_default_region()")]
#[partial_default(aws_default_region())]
pub region: String,
#[serde(default = "aws_default_instance_type")]
#[builder(default = "aws_default_instance_type()")]
#[partial_default(aws_default_instance_type())]
pub instance_type: String,
#[serde(default = "aws_default_volume_gb")]
#[builder(default = "aws_default_volume_gb()")]
#[partial_default(aws_default_volume_gb())]
pub volume_gb: i32,
#[serde(default)]
#[builder(default)]
pub ami_id: String,
#[serde(default)]
#[builder(default)]
pub subnet_id: String,
#[serde(default)]
#[builder(default)]
pub key_pair_name: String,
#[serde(default)]
#[builder(default)]
pub assign_public_ip: bool,
#[serde(default)]
#[builder(default)]
pub use_public_ip: bool,
#[serde(default, deserialize_with = "string_list_deserializer")]
#[partial_attr(serde(
default,
deserialize_with = "option_string_list_deserializer"
))]
#[builder(default)]
pub security_group_ids: Vec<String>,
#[serde(default)]
#[builder(default)]
pub user_data: String,
#[serde(default = "default_port")]
#[builder(default = "default_port()")]
#[partial_default(default_port())]
pub port: i32,
#[serde(default = "default_use_https")]
#[builder(default = "default_use_https()")]
#[partial_default(default_use_https())]
pub use_https: bool,
#[serde(default)]
pub periphery_public_key: String,
#[serde(default = "default_insecure_tls")]
#[builder(default = default_insecure_tls())]
#[partial_default(default_insecure_tls())]
pub insecure_tls: bool,
#[serde(default)]
#[builder(default)]
pub git_providers: Vec<GitProvider>,
#[serde(default)]
#[builder(default)]
pub docker_registries: Vec<DockerRegistry>,
#[serde(default, deserialize_with = "string_list_deserializer")]
#[partial_attr(serde(
default,
deserialize_with = "option_string_list_deserializer"
))]
#[builder(default)]
pub secrets: Vec<String>,
}
impl Default for AwsBuilderConfig {
fn default() -> Self {
Self {
region: aws_default_region(),
instance_type: aws_default_instance_type(),
volume_gb: aws_default_volume_gb(),
port: default_port(),
use_https: default_use_https(),
ami_id: Default::default(),
subnet_id: Default::default(),
security_group_ids: Default::default(),
key_pair_name: Default::default(),
assign_public_ip: Default::default(),
use_public_ip: Default::default(),
user_data: Default::default(),
periphery_public_key: Default::default(),
insecure_tls: default_insecure_tls(),
git_providers: Default::default(),
docker_registries: Default::default(),
secrets: Default::default(),
}
}
}
impl AwsBuilderConfig {
pub fn builder() -> AwsBuilderConfigBuilder {
AwsBuilderConfigBuilder::default()
}
}
fn aws_default_region() -> String {
String::from("us-east-1")
}
fn aws_default_instance_type() -> String {
String::from("c5.2xlarge")
}
fn aws_default_volume_gb() -> i32 {
20
}
fn default_port() -> i32 {
8120
}
fn default_use_https() -> bool {
true
}
#[cfg(feature = "utoipa")]
impl utoipa::PartialSchema for PartialAwsBuilderConfig {
fn schema()
-> utoipa::openapi::RefOr<utoipa::openapi::schema::Schema> {
utoipa::schema!(#[inline] std::collections::HashMap<String, serde_json::Value>).into()
}
}
#[cfg(feature = "utoipa")]
impl utoipa::ToSchema for PartialAwsBuilderConfig {}
#[typeshare]
pub type BuilderQuery = ResourceQuery<BuilderQuerySpecifics>;
#[typeshare]
#[derive(Serialize, Deserialize, Debug, Clone, Default)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
pub struct BuilderQuerySpecifics {}
impl AddFilters for BuilderQuerySpecifics {}