mod settings;
use settings::{ApiOidcSettings, ApiSettings, Settings};
use std::sync::Arc;
use dirs::data_local_dir;
use oparl_service_facade::OParlServiceHandle;
use oparl_types::DateTime;
use openidconnect::{ClientId, ClientSecret, IssuerUrl};
use pib_oparl_service::{PibOParlService, ServiceUrlBuilder, UrlBuilder};
use pib_service_api_auth::ApiAuth;
use pib_service_api_auth_oidc::OidcAuth;
use pib_service_api_permissions::Permissions;
use pib_service_api_permissions_inventory::InventoryPermissions;
use pib_service_api_types::config::{oidc::OidcConfig, oparl::OParlConfig};
use pib_service_backend::Backend;
use pib_service_inventory::InventoryProvider;
use pib_service_inventory_db::DatabaseInventoryProvider;
use tokio::{select, sync::RwLock};
#[derive(Default)]
pub struct RunParameters {
pub program_name: String,
pub suffix: Option<String>,
}
pub async fn run(
RunParameters {
program_name,
suffix,
}: RunParameters,
) -> anyhow::Result<()> {
env_logger::init();
let settings = Settings::load(&program_name, suffix.as_deref())?;
let data_dir = data_local_dir().unwrap().join(&program_name);
std::fs::create_dir_all(&data_dir)?;
let suffix = suffix.unwrap_or_default();
let db_path = data_dir.join(format!("inventory{suffix}.sqlite?mode=rwc"));
log::info!("using database {db_path:?}");
let db_url = format!("turso:{}", db_path.to_str().unwrap());
let db = toasty::Db::builder()
.models(pib_service_db_models::models())
.connect(&db_url)
.await?;
pib_service_db_migration::migrate(&db).await?;
let name = Some(program_name.into());
let vendor = Some("https://codeberg.org/pib".parse()?);
let product = Some("https://codeberg.org/pib/pib-service".parse()?);
let now = DateTime::now();
let created = now.clone();
let modified = now.clone();
let pib_about = Some(
"An experimental OParl service developed by the \"Politik im Blick\" developers".into(),
);
let database_inventory_provider: Arc<dyn InventoryProvider> = Arc::new(
DatabaseInventoryProvider::new(db, name, vendor, product, created, modified, pib_about),
);
let permissions: Arc<dyn Permissions> = Arc::new(InventoryPermissions::new(
database_inventory_provider.clone(),
));
let url_builder: Arc<dyn UrlBuilder> =
Arc::new(ServiceUrlBuilder::new(settings.oparl.base_url.clone()));
let service = OParlServiceHandle::new(Arc::new(RwLock::new(PibOParlService::new(
database_inventory_provider.clone(),
url_builder,
))));
let service_future = oparl_web_service_axum::run(service, settings.http.bind.as_slice());
if let Some(ApiSettings { oidc, http }) = settings.api.as_ref() {
let ApiOidcSettings {
issuer,
client_id,
client_secret,
} = oidc.clone();
let auth: Arc<dyn ApiAuth> = Arc::new(OidcAuth::new(
IssuerUrl::new(issuer.clone())?,
ClientId::new(client_id.clone()),
ClientSecret::new(client_secret.clone()),
database_inventory_provider.clone(),
));
let oidc = OidcConfig {
issuer,
client_id,
client_secret,
};
let oparl = Some(OParlConfig {
url: settings.oparl.base_url.clone(),
});
let service = Arc::new(Backend::new(
database_inventory_provider,
permissions,
oidc,
oparl,
));
let service_api_future = pib_service_api::run(http.bind.as_slice(), service, auth);
select! {
result = service_future => result?,
result = service_api_future => result?
}
} else {
service_future.await?;
}
Ok(())
}