use std::collections::HashMap;
use std::net::SocketAddr;
use std::path::PathBuf;
use std::sync::Arc;
use anyhow::Result;
use async_channel::{Receiver, Sender};
use async_trait::async_trait;
use hydroflow_cli_integration::ServerBindConfig;
use tokio::sync::RwLock;
pub mod deployment;
pub use deployment::Deployment;
pub mod progress;
pub mod localhost;
pub use localhost::LocalhostHost;
pub mod ssh;
pub mod gcp;
pub use gcp::GCPComputeEngineHost;
pub mod hydroflow_crate;
pub use hydroflow_crate::HydroflowCrate;
pub mod custom_service;
pub use custom_service::CustomService;
pub mod terraform;
pub mod util;
#[derive(Default)]
pub struct ResourcePool {
pub terraform: terraform::TerraformPool,
}
pub struct ResourceBatch {
pub terraform: terraform::TerraformBatch,
}
impl ResourceBatch {
fn new() -> ResourceBatch {
ResourceBatch {
terraform: terraform::TerraformBatch::default(),
}
}
async fn provision(
self,
pool: &mut ResourcePool,
last_result: Option<Arc<ResourceResult>>,
) -> Result<ResourceResult> {
Ok(ResourceResult {
terraform: self.terraform.provision(&mut pool.terraform).await?,
_last_result: last_result,
})
}
}
#[derive(Debug)]
pub struct ResourceResult {
pub terraform: terraform::TerraformResult,
_last_result: Option<Arc<ResourceResult>>,
}
#[async_trait]
pub trait LaunchedBinary: Send + Sync {
async fn stdin(&self) -> Sender<String>;
async fn stdout(&self) -> Receiver<String>;
async fn stderr(&self) -> Receiver<String>;
async fn exit_code(&self) -> Option<i32>;
async fn wait(&mut self) -> Option<i32>;
}
#[async_trait]
pub trait LaunchedHost: Send + Sync {
fn server_config(&self, strategy: &ServerStrategy) -> ServerBindConfig;
async fn launch_binary(
&self,
id: String,
binary: Arc<(String, Vec<u8>, PathBuf)>,
args: &[String],
) -> Result<Arc<RwLock<dyn LaunchedBinary>>>;
async fn forward_port(&self, addr: &SocketAddr) -> Result<SocketAddr>;
}
pub enum ServerStrategy {
UnixSocket,
InternalTcpPort,
ExternalTcpPort(
u16,
),
Demux(HashMap<u32, ServerStrategy>),
Merge(Vec<ServerStrategy>),
Tagged(Box<ServerStrategy>, u32),
Null,
}
pub enum ClientStrategy<'a> {
UnixSocket(
usize,
),
InternalTcpPort(
&'a dyn Host,
),
ForwardedTcpPort(
&'a dyn Host,
),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum HostTargetType {
Local,
Linux,
}
pub type HostStrategyGetter = Box<dyn FnOnce(&mut dyn std::any::Any) -> ServerStrategy>;
#[async_trait]
pub trait Host: Send + Sync {
fn target_type(&self) -> HostTargetType;
fn request_port(&mut self, bind_type: &ServerStrategy);
fn id(&self) -> usize;
fn as_any(&self) -> &dyn std::any::Any;
fn as_any_mut(&mut self) -> &mut dyn std::any::Any;
fn request_custom_binary(&mut self);
fn collect_resources(&self, resource_batch: &mut ResourceBatch);
async fn provision(&mut self, resource_result: &Arc<ResourceResult>) -> Arc<dyn LaunchedHost>;
fn launched(&self) -> Option<Arc<dyn LaunchedHost>>;
fn strategy_as_server<'a>(
&'a self,
connection_from: &dyn Host,
) -> Result<(ClientStrategy<'a>, HostStrategyGetter)>;
fn can_connect_to(&self, typ: ClientStrategy) -> bool;
}
#[async_trait]
pub trait Service: Send + Sync {
fn collect_resources(&mut self, resource_batch: &mut ResourceBatch);
async fn deploy(&mut self, resource_result: &Arc<ResourceResult>);
async fn ready(&mut self) -> Result<()>;
async fn start(&mut self);
async fn stop(&mut self) -> Result<()>;
}