#![cfg_attr(not(test), warn(missing_docs))]
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
pub mod core;
pub use core::{
DynFaasExecutor, FaasConfig, FaasDeployment, FaasError, FaasExecutor, FaasMetrics, FaasPayload,
FaasRegistry, FaasResponse,
};
#[cfg(feature = "aws")]
pub mod aws;
#[cfg(feature = "gcp")]
pub mod gcp;
#[cfg(feature = "azure")]
pub mod azure;
#[cfg(feature = "custom")]
pub mod custom;
#[cfg(feature = "digitalocean")]
pub mod digitalocean;
#[cfg(any(
feature = "aws",
feature = "gcp",
feature = "azure",
feature = "custom",
feature = "digitalocean"
))]
pub mod factory {
use super::*;
use std::sync::Arc;
#[derive(Debug, Clone)]
pub struct FaasProviderConfig {
pub provider: FaasProvider,
pub default_memory_mb: u32,
pub default_timeout_secs: u32,
}
#[derive(Debug, Clone)]
pub enum FaasProvider {
#[cfg(feature = "aws")]
AwsLambda {
region: String,
role_arn: String,
},
#[cfg(feature = "gcp")]
GcpFunctions {
project_id: String,
region: String,
},
#[cfg(feature = "azure")]
AzureFunctions {
subscription_id: String,
region: String,
},
#[cfg(feature = "custom")]
Custom {
endpoint: String,
},
#[cfg(feature = "digitalocean")]
DigitalOcean {
api_token: String,
region: String,
},
}
pub async fn create_executor(
provider_config: FaasProviderConfig,
) -> Result<DynFaasExecutor, FaasError> {
match provider_config.provider {
#[cfg(feature = "aws")]
FaasProvider::AwsLambda { region, role_arn } => {
let executor = crate::aws::LambdaExecutor::new(®ion, role_arn).await?;
Ok(Arc::new(executor) as DynFaasExecutor)
}
#[cfg(feature = "gcp")]
FaasProvider::GcpFunctions { project_id, region } => {
let executor = crate::gcp::CloudFunctionExecutor::new(project_id, region).await?;
Ok(Arc::new(executor) as DynFaasExecutor)
}
#[cfg(feature = "azure")]
FaasProvider::AzureFunctions {
subscription_id,
region,
} => {
let executor =
crate::azure::AzureFunctionExecutor::new(subscription_id, region).await?;
Ok(Arc::new(executor) as DynFaasExecutor)
}
#[cfg(feature = "custom")]
FaasProvider::Custom { endpoint } => {
let executor = crate::custom::HttpFaasExecutor::new(endpoint);
Ok(Arc::new(executor) as DynFaasExecutor)
}
#[cfg(feature = "digitalocean")]
FaasProvider::DigitalOcean { api_token, region } => {
let executor =
crate::digitalocean::DigitalOceanExecutor::new(api_token, region).await?;
Ok(Arc::new(executor) as DynFaasExecutor)
}
}
}
pub async fn deploy_job(
provider_config: FaasProviderConfig,
job_id: u32,
binary: &[u8],
) -> Result<FaasDeployment, FaasError> {
let executor = create_executor(provider_config.clone()).await?;
let faas_config = FaasConfig {
memory_mb: provider_config.default_memory_mb,
timeout_secs: provider_config.default_timeout_secs,
..Default::default()
};
executor.deploy_job(job_id, binary, &faas_config).await
}
}
mod utils {
#[cfg(any(
feature = "aws",
feature = "gcp",
feature = "azure",
feature = "digitalocean"
))]
use super::FaasError;
#[cfg(any(
feature = "aws",
feature = "gcp",
feature = "azure",
feature = "digitalocean"
))]
pub(crate) fn create_lambda_package(binary: &[u8]) -> Result<Vec<u8>, FaasError> {
use std::io::Cursor;
use std::io::Write;
let mut zip = zip::ZipWriter::new(Cursor::new(Vec::new()));
let options: zip::write::FileOptions<()> = zip::write::FileOptions::default()
.compression_method(zip::CompressionMethod::Deflated)
.unix_permissions(0o755);
zip.start_file("bootstrap", options)
.map_err(|e| FaasError::InfrastructureError(format!("Failed to create zip: {}", e)))?;
zip.write_all(binary).map_err(|e| {
FaasError::InfrastructureError(format!("Failed to write binary: {}", e))
})?;
let cursor = zip.finish().map_err(|e| {
FaasError::InfrastructureError(format!("Failed to finalize zip: {}", e))
})?;
Ok(cursor.into_inner())
}
#[allow(dead_code)]
pub(crate) fn extract_job_id(function_name: &str, prefix: &str) -> Option<u32> {
function_name
.strip_prefix(&format!("{prefix}-job-"))
.and_then(|s| s.parse().ok())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_extract_job_id() {
assert_eq!(
utils::extract_job_id("blueprint-job-0", "blueprint"),
Some(0)
);
assert_eq!(
utils::extract_job_id("blueprint-job-42", "blueprint"),
Some(42)
);
assert_eq!(utils::extract_job_id("wrong-format", "blueprint"), None);
}
}