starlane 0.3.19

Starlane -- An Orchestration and Infrastructure Framework for WebAssembly Components (https://starlane.io) This packaged manages `HyperSpace` which provides infrastructure for `Space` Apis (WebAssembly & external programs meant to provide custom behaviors in Starlane), This package references the `starlane-space` package and reuses of it to run the infrastructure and it also contains mechanisms (Drivers) for extending the Starlane Type system
Documentation
use tokio::fs;
use crate::env::{STARLANE_DATA_DIR, STARLANE_REGISTRY_PASSWORD, STARLANE_REGISTRY_USER};
use crate::registry::err::RegErr;
use crate::{Database, PgRegistryConfig, StarlaneConfig};
use derive_builder::Builder;
use serde::{Deserialize, Serialize};
use std::path::PathBuf;
use std::time::Duration;
use postgresql_embedded::{PostgreSQL, Settings};
use sqlx::PgPool;
use starlane::space::parse::set;

pub struct Postgres {
    config: Database<PgEmbedSettings>,
    postgres: PostgreSQL
}

impl Postgres {

    pub fn url(&self) -> String {
        self.postgres.settings().url("postgres")
    }


    /*
    fn postgresql(config: &Database<PgEmbedSettings> ) -> Settings
    {
        let mut settings = Settings::default();
        settings.temporary = false;
        settings.port = 5432;
        settings
    }

     */


    fn postgresql(config: &Database<PgEmbedSettings> ) -> Settings
    {
        let mut settings = Settings::default();
        settings.data_dir = format!("{}/registry",config.database_dir).to_string().into();
        settings.password_file = format!("{}/.password",config.database_dir).to_string().into();
        settings.port = 5432u16;
        settings.temporary = !config.persistent;
        settings.username = config.user.clone();
        settings.password = config.password.clone();
        settings
    }



    pub async fn install( config: &Database<PgEmbedSettings>) -> Result<(), RegErr> {

        let settings = Self::postgresql(config);
        fs::create_dir_all(&settings.data_dir).await?;

        let mut postgres = PostgreSQL::new(settings);

        postgres.setup().await?;
        postgres.start().await?;

        if !postgres.database_exists(&config.database).await? {
            postgres.create_database(&config.database).await?;
        }
       postgres.stop().await?;

        Ok(())
    }



    pub async fn new(config: &Database<PgEmbedSettings>) -> Result<Self, RegErr> {

        let mut postgres = PostgreSQL::new(Self::postgresql(config));

        let config = config.clone();
        Ok(Self { postgres, config })
    }

    /// as long as the Sender is alive
    ///
    pub async fn start(mut self) -> Result<tokio::sync::mpsc::Sender<()>, RegErr> {
        self.postgres.setup().await?;
        self.postgres.start().await?;
        let (tx, mut rx) = tokio::sync::mpsc::channel::<()>(1);
        let blah = self;
        tokio::spawn(
            async move {
                while let Some(_) = rx.recv().await {
                    blah.url();
                }
            }
        );


        Ok(tx)
    }

}

impl Drop for Postgres {
    fn drop(&mut self) {
        let handler = tokio::runtime::Handle::current();
        let mut postgres = self.postgres.clone();
        handler.block_on( async move{
            postgres.stop().await.unwrap_or_default();
        });
    }
}

#[derive(Builder, Clone, Serialize, Deserialize,Eq,PartialEq,Hash)]
pub struct PgEmbedSettings {
    pub port: u16,
    pub user: String,
    pub password: String,
    pub auth_method: PgEmbedAuthMethod,
    pub persistent: bool,
    pub database_dir: String,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub timeout: Option<Duration>,
}


impl Default for PgEmbedSettings {
    fn default() -> Self {
        Self {
            database_dir: format!("{}/postgres", STARLANE_DATA_DIR.to_string()).to_string(),
            port: 5432,
            user: STARLANE_REGISTRY_USER.to_string(),
            password: STARLANE_REGISTRY_PASSWORD.to_string(),
            auth_method: Default::default(),
            persistent: true,
            timeout: Some(Duration::from_secs(5)),
        }
    }
}

#[derive(Clone, Serialize, Deserialize,Eq,PartialEq,Hash)]
pub enum PgEmbedAuthMethod {
    Plain,
    MD5,
    ScramSha256,
}



impl Default for PgEmbedAuthMethod {
    fn default() -> Self {
        PgEmbedAuthMethod::Plain
    }
}