use crate::error::Result;
use crate::presigned::PresignedRequest;
use alien_core::{BuildConfig, BuildExecution};
use async_trait::async_trait;
use object_store::path::Path;
use object_store::ObjectStore;
use serde::{Deserialize, Serialize};
use std::collections::BTreeMap;
use std::sync::Arc;
use std::time::Duration;
use url::Url;
#[cfg(feature = "openapi")]
use utoipa::ToSchema;
pub trait Binding: Send + Sync + std::fmt::Debug {}
#[async_trait]
pub trait Storage: Binding + ObjectStore {
fn get_base_dir(&self) -> Path;
fn get_url(&self) -> Url;
async fn presigned_put(&self, path: &Path, expires_in: Duration) -> Result<PresignedRequest>;
async fn presigned_get(&self, path: &Path, expires_in: Duration) -> Result<PresignedRequest>;
async fn presigned_delete(&self, path: &Path, expires_in: Duration)
-> Result<PresignedRequest>;
}
#[async_trait]
pub trait Build: Binding {
async fn start_build(&self, config: BuildConfig) -> Result<BuildExecution>;
async fn get_build_status(&self, build_id: &str) -> Result<BuildExecution>;
async fn stop_build(&self, build_id: &str) -> Result<()>;
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
#[cfg_attr(feature = "openapi", derive(ToSchema))]
pub struct AwsServiceAccountInfo {
pub role_name: String,
pub role_arn: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
#[cfg_attr(feature = "openapi", derive(ToSchema))]
pub struct GcpServiceAccountInfo {
pub email: String,
pub unique_id: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
#[cfg_attr(feature = "openapi", derive(ToSchema))]
pub struct AzureServiceAccountInfo {
pub client_id: String,
pub resource_id: String,
pub principal_id: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "platform", rename_all = "camelCase")]
#[cfg_attr(feature = "openapi", derive(ToSchema))]
pub enum ServiceAccountInfo {
Aws(AwsServiceAccountInfo),
Gcp(GcpServiceAccountInfo),
Azure(AzureServiceAccountInfo),
}
#[derive(Debug, Clone)]
pub struct ImpersonationRequest {
pub session_name: Option<String>,
pub duration_seconds: Option<i32>,
pub scopes: Option<Vec<String>>,
}
impl Default for ImpersonationRequest {
fn default() -> Self {
Self {
session_name: None,
duration_seconds: Some(3600), scopes: None,
}
}
}
#[async_trait]
pub trait ServiceAccount: Binding {
async fn get_info(&self) -> Result<ServiceAccountInfo>;
async fn impersonate(&self, request: ImpersonationRequest) -> Result<alien_core::ClientConfig>;
fn as_any(&self) -> &dyn std::any::Any;
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
#[cfg_attr(feature = "openapi", derive(ToSchema))]
pub struct RepositoryResponse {
pub name: String,
pub uri: Option<String>,
pub created_at: Option<String>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "kebab-case")]
#[cfg_attr(feature = "openapi", derive(ToSchema))]
pub enum ArtifactRegistryPermissions {
Pull,
PushPull,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "lowercase")]
#[cfg_attr(feature = "openapi", derive(ToSchema))]
pub enum RegistryAuthMethod {
Basic,
Bearer,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
#[cfg_attr(feature = "openapi", derive(ToSchema))]
pub struct ArtifactRegistryCredentials {
pub auth_method: RegistryAuthMethod,
pub username: String,
pub password: String,
pub expires_at: Option<String>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "kebab-case")]
#[cfg_attr(feature = "openapi", derive(ToSchema))]
pub enum ComputeServiceType {
Worker,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
#[cfg_attr(feature = "openapi", derive(ToSchema))]
pub struct AwsCrossAccountAccess {
pub account_ids: Vec<String>,
pub regions: Vec<String>,
pub allowed_service_types: Vec<ComputeServiceType>,
pub role_arns: Vec<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
#[cfg_attr(feature = "openapi", derive(ToSchema))]
pub struct GcpCrossAccountAccess {
pub project_numbers: Vec<String>,
pub allowed_service_types: Vec<ComputeServiceType>,
pub service_account_emails: Vec<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "platform", rename_all = "lowercase")]
#[cfg_attr(feature = "openapi", derive(ToSchema))]
pub enum CrossAccountAccess {
Aws(AwsCrossAccountAccess),
Gcp(GcpCrossAccountAccess),
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
#[cfg_attr(feature = "openapi", derive(ToSchema))]
pub struct CrossAccountPermissions {
pub access: CrossAccountAccess,
pub last_updated: Option<String>,
}
#[async_trait]
pub trait ArtifactRegistry: Binding {
fn registry_endpoint(&self) -> String {
String::new()
}
fn upstream_repository_prefix(&self) -> String {
String::new()
}
async fn create_repository(&self, repo_name: &str) -> Result<RepositoryResponse>;
async fn get_repository(&self, repo_id: &str) -> Result<RepositoryResponse>;
async fn add_cross_account_access(
&self,
repo_id: &str,
access: CrossAccountAccess,
) -> Result<()>;
async fn remove_cross_account_access(
&self,
repo_id: &str,
access: CrossAccountAccess,
) -> Result<()>;
async fn get_cross_account_access(&self, repo_id: &str) -> Result<CrossAccountPermissions>;
async fn generate_credentials(
&self,
repo_id: &str,
permissions: ArtifactRegistryPermissions,
ttl_seconds: Option<u32>,
) -> Result<ArtifactRegistryCredentials>;
async fn delete_repository(&self, repo_id: &str) -> Result<()>;
}
#[async_trait]
pub trait Vault: Binding {
async fn get_secret(&self, secret_name: &str) -> Result<String>;
async fn set_secret(&self, secret_name: &str, value: &str) -> Result<()>;
async fn delete_secret(&self, secret_name: &str) -> Result<()>;
}
#[derive(Debug, Clone, Default)]
pub struct PutOptions {
pub ttl: Option<Duration>,
pub if_not_exists: bool,
}
#[derive(Debug)]
pub struct ScanResult {
pub items: Vec<(String, Vec<u8>)>,
pub next_cursor: Option<String>,
}
#[async_trait]
pub trait Kv: Binding {
async fn get(&self, key: &str) -> Result<Option<Vec<u8>>>;
async fn put(&self, key: &str, value: Vec<u8>, options: Option<PutOptions>) -> Result<bool>;
async fn delete(&self, key: &str) -> Result<()>;
async fn exists(&self, key: &str) -> Result<bool>;
async fn scan_prefix(
&self,
prefix: &str,
limit: Option<usize>,
cursor: Option<String>,
) -> Result<ScanResult>;
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "type", rename_all = "lowercase")]
#[cfg_attr(feature = "openapi", derive(ToSchema))]
pub enum MessagePayload {
Json(serde_json::Value),
Text(String),
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
#[cfg_attr(feature = "openapi", derive(ToSchema))]
pub struct QueueMessage {
pub payload: MessagePayload,
pub receipt_handle: String,
}
pub const MAX_MESSAGE_BYTES: usize = 65_536;
pub const MAX_BATCH_SIZE: usize = 10;
pub const LEASE_SECONDS: u64 = 30;
#[async_trait]
pub trait Queue: Binding {
async fn send(&self, queue: &str, message: MessagePayload) -> Result<()>;
async fn receive(&self, queue: &str, max_messages: usize) -> Result<Vec<QueueMessage>>;
async fn ack(&self, queue: &str, receipt_handle: &str) -> Result<()>;
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
#[cfg_attr(feature = "openapi", derive(ToSchema))]
pub struct WorkerInvokeRequest {
pub target_worker: String,
pub method: String,
pub path: String,
pub headers: BTreeMap<String, String>,
pub body: Vec<u8>,
pub timeout: Option<Duration>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
#[cfg_attr(feature = "openapi", derive(ToSchema))]
pub struct WorkerInvokeResponse {
pub status: u16,
pub headers: BTreeMap<String, String>,
pub body: Vec<u8>,
}
#[async_trait]
pub trait Worker: Binding {
async fn invoke(&self, request: WorkerInvokeRequest) -> Result<WorkerInvokeResponse>;
async fn get_worker_url(&self) -> Result<Option<String>>;
fn as_any(&self) -> &dyn std::any::Any;
}
#[async_trait]
pub trait Container: Binding {
fn get_internal_url(&self) -> &str;
fn get_public_url(&self) -> Option<&str>;
fn get_container_name(&self) -> &str;
fn as_any(&self) -> &dyn std::any::Any;
}
#[async_trait]
pub trait BindingsProviderApi: Send + Sync + std::fmt::Debug {
async fn load_storage(&self, binding_name: &str) -> Result<Arc<dyn Storage>>;
async fn load_build(&self, binding_name: &str) -> Result<Arc<dyn Build>>;
async fn load_artifact_registry(&self, binding_name: &str)
-> Result<Arc<dyn ArtifactRegistry>>;
async fn load_vault(&self, binding_name: &str) -> Result<Arc<dyn Vault>>;
async fn load_kv(&self, binding_name: &str) -> Result<Arc<dyn Kv>>;
async fn load_queue(&self, binding_name: &str) -> Result<Arc<dyn Queue>>;
async fn load_worker(&self, binding_name: &str) -> Result<Arc<dyn Worker>>;
async fn load_container(&self, binding_name: &str) -> Result<Arc<dyn Container>>;
async fn load_service_account(&self, binding_name: &str) -> Result<Arc<dyn ServiceAccount>>;
}