use std::path::Path;
use frunk::{HCons, HNil, hlist, hlist::HList};
use sea_orm::DbErr;
use tower::{Layer, make::Shared};
use tower_http::normalize_path::NormalizePathLayer;
use crate::{
apps::{AppsCap, AppsTag, with_apps},
capability::{FoldMount, HasCapTag},
command::{
BuildCli, CommandCap, CommandCapability, CommandTag, DispatchCommands, RunCommand,
ServeCommand, with_commands,
},
components::slots::{
CoreTitle, CoreTitleTag, HeadSlotTag, SlotCap, SlotOf, SlotTag, with_slots,
},
config::{
AppConfig, AppConfigTag, BindTarget, ConfigCap, ConfigCapability, ConfigError, ConfigTag,
LoadFromToml, with_config,
},
db::{DbTag, connect, with_db},
export::{ExportCap, ExportTag, with_export},
grapesjs::{GrapesJsCap, GrapesJsTag, with_grapesjs},
hooks::{
FoldAttachState, FoldSeeds, FoldServeStartups, SeedRunner, SeedsCap, SeedsTag,
ServeStartupRunner, ServeStartupsCap, ServeStartupsTag, StateHooksCap, StateHooksTag,
with_seeds, with_serve_startups, with_state_hooks,
},
http::{
FoldMountRoutes, HttpCap, HttpCapability, HttpTag, MountRoutes, ProvideRequestCaps,
into_axum_router, with_http,
},
llm_tools::{LlmToolsCap, LlmToolsTag, with_llm_tools},
migration::{MigrationCap, MigrationCapability, MigrationTag, RunMigrations, with_migrations},
rune_env::{RuneEnvCap, RuneEnvTag, with_rune_env},
template::{TemplateCap, TemplateTag, with_templates},
traits::{
add::{AddCapability, CapTagAbsent},
get::{GetByCapTag, GetByTag},
replace::MapByCapTag,
},
views::{ViewCap, with_views},
};
#[derive(Clone)]
pub struct App<T> {
pub capabilities: T,
}
#[derive(Clone)]
pub struct MountedApp<M> {
pub capabilities: M,
}
pub type WebAppCaps = frunk::HList![
CommandCap<HNil, crate::command::DefaultCommands>,
ViewCap,
HttpCap<HNil, HttpCapability<HNil>>,
SlotCap<
HNil,
frunk::HList![crate::tag::Tagged<CoreTitleTag, SlotOf<HeadSlotTag, CoreTitle>>],
>,
TemplateCap<HNil, HNil>,
MigrationCap<HNil, HNil>,
RuneEnvCap<HNil>,
LlmToolsCap<HNil>,
GrapesJsCap<HNil>,
ExportCap<HNil>,
AppsCap<HNil>,
ServeStartupsCap<HNil>,
SeedsCap<HNil>,
StateHooksCap<HNil>,
ConfigCap<HNil, frunk::HList![crate::tag::Tagged<AppConfigTag, AppConfig>]>,
];
impl App<HNil> {
pub fn new() -> Self {
Self {
capabilities: hlist![],
}
}
pub fn new_web_app() -> App<WebAppCaps> {
let app = Self::new();
let app = with_config(app);
let app = with_state_hooks(app);
let app = with_seeds(app);
let app = with_serve_startups(app);
let app = with_apps(app);
let app = with_export(app);
let app = with_grapesjs(app);
let app = with_llm_tools(app);
let app = with_rune_env(app);
let app = with_migrations(app);
let app = with_templates(app);
let app = with_slots(app);
let app = with_http(app);
let app = with_views(app);
with_commands(app)
}
}
impl<L> App<L> {
pub fn with_db<Proof>(
self,
conn: sea_orm::DatabaseConnection,
) -> App<HCons<crate::db::DbCap, L>>
where
L: HList + CapTagAbsent<DbTag, Proof>,
{
with_db(self, conn)
}
pub fn attach_cap<C, Proof>(self, cap: C) -> App<HCons<C, L>>
where
C: HasCapTag,
L: HList + CapTagAbsent<C::Tag, Proof>,
{
self.add_capability(cap)
}
pub fn mount<
TplIdx,
TplHooks,
TplItems,
SlotIdx,
SlotHooks,
SlotItems,
MigIdx,
MigHooks,
MigItems,
CmdIdx,
CmdHooks,
CmdItems,
AppsIdx,
AppsHooks,
AppsProof,
ExportIdx,
ExportHooks,
ExportProof,
GjsIdx,
GjsHooks,
GjsProof,
ToolsIdx,
ToolsHooks,
ToolsProof,
RuneEnvIdx,
RuneEnvHooks,
RuneEnvProof,
HttpIdx,
HttpHooks,
HttpRoutes,
Proof,
>(
self,
) -> MountedApp<
<AfterHttpResolve<
L,
TplIdx,
TplHooks,
TplItems,
SlotIdx,
SlotHooks,
SlotItems,
MigIdx,
MigHooks,
MigItems,
CmdIdx,
CmdHooks,
CmdItems,
AppsIdx,
ExportIdx,
GjsIdx,
ToolsIdx,
RuneEnvIdx,
HttpIdx,
HttpHooks,
HttpRoutes,
Proof,
> as FoldMount>::Output,
>
where
L: GetByCapTag<TemplateTag, TplIdx, Value = TemplateCap<TplHooks, TplItems>>,
L: MapByCapTag<
TemplateTag,
TemplateCap<
HNil,
<TplHooks as crate::capability::FoldRegistrarHooks<
crate::template::TemplateTag,
TplItems,
>>::Output,
>,
TplIdx,
OldValue = TemplateCap<TplHooks, TplItems>,
>,
TplHooks: crate::capability::FoldRegistrarHooks<crate::template::TemplateTag, TplItems>,
AfterTemplates<L, TplIdx, TplHooks, TplItems>:
GetByCapTag<SlotTag, SlotIdx, Value = SlotCap<SlotHooks, SlotItems>>,
AfterTemplates<L, TplIdx, TplHooks, TplItems>: MapByCapTag<
SlotTag,
SlotCap<
HNil,
<SlotHooks as crate::capability::FoldRegistrarHooks<
crate::components::SlotTag,
SlotItems,
>>::Output,
>,
SlotIdx,
OldValue = SlotCap<SlotHooks, SlotItems>,
>,
SlotHooks: crate::capability::FoldRegistrarHooks<crate::components::SlotTag, SlotItems>,
AfterSlots<L, TplIdx, TplHooks, TplItems, SlotIdx, SlotHooks, SlotItems>:
GetByCapTag<MigrationTag, MigIdx, Value = MigrationCap<MigHooks, MigItems>>,
AfterSlots<L, TplIdx, TplHooks, TplItems, SlotIdx, SlotHooks, SlotItems>: MapByCapTag<
MigrationTag,
MigrationCap<
HNil,
<MigHooks as crate::capability::FoldRegistrarHooks<
crate::migration::MigrationTag,
MigItems,
>>::Output,
>,
MigIdx,
OldValue = MigrationCap<MigHooks, MigItems>,
>,
MigHooks: crate::capability::FoldRegistrarHooks<crate::migration::MigrationTag, MigItems>,
AfterMigrations<
L,
TplIdx,
TplHooks,
TplItems,
SlotIdx,
SlotHooks,
SlotItems,
MigIdx,
MigHooks,
MigItems,
>: GetByCapTag<CommandTag, CmdIdx, Value = CommandCap<CmdHooks, CmdItems>>,
AfterMigrations<
L,
TplIdx,
TplHooks,
TplItems,
SlotIdx,
SlotHooks,
SlotItems,
MigIdx,
MigHooks,
MigItems,
>: MapByCapTag<
CommandTag,
CommandCap<
HNil,
<CmdHooks as crate::capability::FoldRegistrarHooks<
crate::command::CommandTag,
CmdItems,
>>::Output,
>,
CmdIdx,
OldValue = CommandCap<CmdHooks, CmdItems>,
>,
CmdHooks: crate::capability::FoldRegistrarHooks<crate::command::CommandTag, CmdItems>,
AfterCommands<
L,
TplIdx,
TplHooks,
TplItems,
SlotIdx,
SlotHooks,
SlotItems,
MigIdx,
MigHooks,
MigItems,
CmdIdx,
CmdHooks,
CmdItems,
>: GetByCapTag<AppsTag, AppsIdx, Value = AppsCap<AppsHooks>>,
AfterCommands<
L,
TplIdx,
TplHooks,
TplItems,
SlotIdx,
SlotHooks,
SlotItems,
MigIdx,
MigHooks,
MigItems,
CmdIdx,
CmdHooks,
CmdItems,
>: MapByCapTag<AppsTag, AppsCap<HNil>, AppsIdx, OldValue = AppsCap<AppsHooks>>,
AppsHooks: crate::capability::ApplyHooks<
crate::apps::AppsCapability,
AppsProof,
Output = crate::apps::AppsCapability,
>,
AfterApps<
L,
TplIdx,
TplHooks,
TplItems,
SlotIdx,
SlotHooks,
SlotItems,
MigIdx,
MigHooks,
MigItems,
CmdIdx,
CmdHooks,
CmdItems,
AppsIdx,
>: GetByCapTag<ExportTag, ExportIdx, Value = ExportCap<ExportHooks>>,
AfterApps<
L,
TplIdx,
TplHooks,
TplItems,
SlotIdx,
SlotHooks,
SlotItems,
MigIdx,
MigHooks,
MigItems,
CmdIdx,
CmdHooks,
CmdItems,
AppsIdx,
>: MapByCapTag<ExportTag, ExportCap<HNil>, ExportIdx, OldValue = ExportCap<ExportHooks>>,
ExportHooks: crate::capability::ApplyHooks<
crate::export::ExportCapability,
ExportProof,
Output = crate::export::ExportCapability,
>,
AfterExport<
L,
TplIdx,
TplHooks,
TplItems,
SlotIdx,
SlotHooks,
SlotItems,
MigIdx,
MigHooks,
MigItems,
CmdIdx,
CmdHooks,
CmdItems,
AppsIdx,
ExportIdx,
>: GetByCapTag<GrapesJsTag, GjsIdx, Value = GrapesJsCap<GjsHooks>>,
AfterExport<
L,
TplIdx,
TplHooks,
TplItems,
SlotIdx,
SlotHooks,
SlotItems,
MigIdx,
MigHooks,
MigItems,
CmdIdx,
CmdHooks,
CmdItems,
AppsIdx,
ExportIdx,
>: MapByCapTag<GrapesJsTag, GrapesJsCap<HNil>, GjsIdx, OldValue = GrapesJsCap<GjsHooks>>,
GjsHooks: crate::capability::ApplyHooks<
crate::grapesjs::GrapesJsCapability,
GjsProof,
Output = crate::grapesjs::GrapesJsCapability,
>,
AfterGrapesJs<
L,
TplIdx,
TplHooks,
TplItems,
SlotIdx,
SlotHooks,
SlotItems,
MigIdx,
MigHooks,
MigItems,
CmdIdx,
CmdHooks,
CmdItems,
AppsIdx,
ExportIdx,
GjsIdx,
>: GetByCapTag<LlmToolsTag, ToolsIdx, Value = LlmToolsCap<ToolsHooks>>,
AfterGrapesJs<
L,
TplIdx,
TplHooks,
TplItems,
SlotIdx,
SlotHooks,
SlotItems,
MigIdx,
MigHooks,
MigItems,
CmdIdx,
CmdHooks,
CmdItems,
AppsIdx,
ExportIdx,
GjsIdx,
>: MapByCapTag<
LlmToolsTag,
LlmToolsCap<HNil>,
ToolsIdx,
OldValue = LlmToolsCap<ToolsHooks>,
>,
ToolsHooks: crate::capability::ApplyHooks<
crate::llm_tools::LlmToolsCapability,
ToolsProof,
Output = crate::llm_tools::LlmToolsCapability,
>,
AfterTools<
L,
TplIdx,
TplHooks,
TplItems,
SlotIdx,
SlotHooks,
SlotItems,
MigIdx,
MigHooks,
MigItems,
CmdIdx,
CmdHooks,
CmdItems,
AppsIdx,
ExportIdx,
GjsIdx,
ToolsIdx,
>: GetByCapTag<RuneEnvTag, RuneEnvIdx, Value = RuneEnvCap<RuneEnvHooks>>,
AfterTools<
L,
TplIdx,
TplHooks,
TplItems,
SlotIdx,
SlotHooks,
SlotItems,
MigIdx,
MigHooks,
MigItems,
CmdIdx,
CmdHooks,
CmdItems,
AppsIdx,
ExportIdx,
GjsIdx,
ToolsIdx,
>: MapByCapTag<
RuneEnvTag,
RuneEnvCap<HNil>,
RuneEnvIdx,
OldValue = RuneEnvCap<RuneEnvHooks>,
>,
RuneEnvHooks: crate::capability::ApplyHooks<
crate::rune_env::RuneEnvCapability,
RuneEnvProof,
Output = crate::rune_env::RuneEnvCapability,
>,
AfterRuneEnv<
L,
TplIdx,
TplHooks,
TplItems,
SlotIdx,
SlotHooks,
SlotItems,
MigIdx,
MigHooks,
MigItems,
CmdIdx,
CmdHooks,
CmdItems,
AppsIdx,
ExportIdx,
GjsIdx,
ToolsIdx,
RuneEnvIdx,
>: GetByCapTag<HttpTag, HttpIdx, Value = HttpCap<HttpHooks, HttpCapability<HttpRoutes>>>,
AfterRuneEnv<
L,
TplIdx,
TplHooks,
TplItems,
SlotIdx,
SlotHooks,
SlotItems,
MigIdx,
MigHooks,
MigItems,
CmdIdx,
CmdHooks,
CmdItems,
AppsIdx,
ExportIdx,
GjsIdx,
ToolsIdx,
RuneEnvIdx,
>: MapByCapTag<
HttpTag,
HttpCap<
HNil,
<HttpHooks as FoldMountRoutes<HttpCapability<HttpRoutes>, Proof>>::Output,
>,
HttpIdx,
OldValue = HttpCap<HttpHooks, HttpCapability<HttpRoutes>>,
>,
HttpHooks: FoldMountRoutes<HttpCapability<HttpRoutes>, Proof>,
AfterHttpResolve<
L,
TplIdx,
TplHooks,
TplItems,
SlotIdx,
SlotHooks,
SlotItems,
MigIdx,
MigHooks,
MigItems,
CmdIdx,
CmdHooks,
CmdItems,
AppsIdx,
ExportIdx,
GjsIdx,
ToolsIdx,
RuneEnvIdx,
HttpIdx,
HttpHooks,
HttpRoutes,
Proof,
>: FoldMount,
{
let app = self.replace_capability::<TemplateTag, TplIdx, _>(
|c: TemplateCap<TplHooks, TplItems>| c.resolve_hooks(),
);
let app =
app.replace_capability::<SlotTag, SlotIdx, _>(|c: SlotCap<SlotHooks, SlotItems>| {
c.resolve_hooks()
});
let app = app.replace_capability::<MigrationTag, MigIdx, _>(
|c: MigrationCap<MigHooks, MigItems>| c.resolve_hooks(),
);
let app =
app.replace_capability::<CommandTag, CmdIdx, _>(|c: CommandCap<CmdHooks, CmdItems>| {
c.resolve_hooks()
});
let app = app
.replace_capability::<AppsTag, AppsIdx, _>(|c: AppsCap<AppsHooks>| c.resolve_hooks());
let app = app.replace_capability::<ExportTag, ExportIdx, _>(|c: ExportCap<ExportHooks>| {
c.resolve_hooks()
});
let app = app.replace_capability::<GrapesJsTag, GjsIdx, _>(|c: GrapesJsCap<GjsHooks>| {
c.resolve_hooks()
});
let app =
app.replace_capability::<LlmToolsTag, ToolsIdx, _>(|c: LlmToolsCap<ToolsHooks>| {
c.resolve_hooks()
});
let app =
app.replace_capability::<RuneEnvTag, RuneEnvIdx, _>(|c: RuneEnvCap<RuneEnvHooks>| {
c.resolve_hooks()
});
let app = app.replace_capability::<HttpTag, HttpIdx, _>(
|c: HttpCap<HttpHooks, HttpCapability<HttpRoutes>>| c.resolve_route_hooks::<Proof>(),
);
MountedApp {
capabilities: app.capabilities.fold_mount(),
}
}
pub async fn load_config<
CfgIdx,
Configs,
AppCfgIdx,
DbProof,
StateIdx,
StateHooks,
StateProof,
>(
self,
path: impl AsRef<Path>,
) -> Result<
App<<StateHooks as FoldAttachState<HCons<crate::db::DbCap, L>, StateProof>>::Output>,
ConfigError,
>
where
L: GetByCapTag<ConfigTag, CfgIdx, Value = ConfigCap<HNil, Configs>>,
L: MapByCapTag<
ConfigTag,
ConfigCap<HNil, Configs>,
CfgIdx,
OldValue = ConfigCap<HNil, Configs>,
Output = L,
>,
Configs: LoadFromToml + Clone,
Configs: GetByTag<AppConfigTag, AppCfgIdx, Value = AppConfig>,
Configs: crate::traits::replace::MapByTag<
AppConfigTag,
AppConfig,
AppCfgIdx,
OldValue = AppConfig,
Output = Configs,
>,
L: HList + CapTagAbsent<DbTag, DbProof>,
L: GetByCapTag<StateHooksTag, StateIdx, Value = StateHooksCap<StateHooks>>,
StateHooks: FoldAttachState<HCons<crate::db::DbCap, L>, StateProof> + Clone,
{
let path = path.as_ref();
let mut items = self.get_capability::<ConfigTag, CfgIdx>().items.clone();
if path.exists() {
let raw = std::fs::read_to_string(path)?;
let root: toml::Value = toml::from_str(&raw)?;
items.load_from_toml(&root)?;
}
items = items.map_by_tag(|mut app_cfg: AppConfig| {
if let Ok(url) = std::env::var("DATABASE_URL") {
app_cfg.database_url = url;
}
if let Ok(bind) = std::env::var("BIND") {
app_cfg.bind = Some(bind);
}
if let Ok(uds) = std::env::var("UDS") {
if !uds.is_empty() {
app_cfg.uds = Some(uds);
}
}
app_cfg
});
let database_url = <Configs as GetByTag<AppConfigTag, AppCfgIdx>>::get_by_tag(&items)
.database_url
.clone();
let state_hooks = self
.get_capability::<StateHooksTag, StateIdx>()
.hooks
.clone();
let app = self.replace_capability::<ConfigTag, CfgIdx, _>(|_| {
crate::capability::CapStore::with_items(items)
});
let conn = connect(&database_url)
.await
.map_err(|e| ConfigError::Db(e.to_string()))?;
let app = app.with_db(conn);
Ok(state_hooks.fold_attach_state(app))
}
}
type AfterTemplates<L, TplIdx, TplHooks, TplItems> = <L as MapByCapTag<
TemplateTag,
TemplateCap<
HNil,
<TplHooks as crate::capability::FoldRegistrarHooks<
crate::template::TemplateTag,
TplItems,
>>::Output,
>,
TplIdx,
>>::Output;
type AfterSlots<L, TplIdx, TplHooks, TplItems, SlotIdx, SlotHooks, SlotItems> =
<AfterTemplates<L, TplIdx, TplHooks, TplItems> as MapByCapTag<
SlotTag,
SlotCap<
HNil,
<SlotHooks as crate::capability::FoldRegistrarHooks<
crate::components::SlotTag,
SlotItems,
>>::Output,
>,
SlotIdx,
>>::Output;
type AfterMigrations<
L,
TplIdx,
TplHooks,
TplItems,
SlotIdx,
SlotHooks,
SlotItems,
MigIdx,
MigHooks,
MigItems,
> = <AfterSlots<L, TplIdx, TplHooks, TplItems, SlotIdx, SlotHooks, SlotItems> as MapByCapTag<
MigrationTag,
MigrationCap<
HNil,
<MigHooks as crate::capability::FoldRegistrarHooks<
crate::migration::MigrationTag,
MigItems,
>>::Output,
>,
MigIdx,
>>::Output;
type AfterCommands<
L,
TplIdx,
TplHooks,
TplItems,
SlotIdx,
SlotHooks,
SlotItems,
MigIdx,
MigHooks,
MigItems,
CmdIdx,
CmdHooks,
CmdItems,
> =
<AfterMigrations<
L,
TplIdx,
TplHooks,
TplItems,
SlotIdx,
SlotHooks,
SlotItems,
MigIdx,
MigHooks,
MigItems,
> as MapByCapTag<
CommandTag,
CommandCap<
HNil,
<CmdHooks as crate::capability::FoldRegistrarHooks<
crate::command::CommandTag,
CmdItems,
>>::Output,
>,
CmdIdx,
>>::Output;
type AfterApps<
L,
TplIdx,
TplHooks,
TplItems,
SlotIdx,
SlotHooks,
SlotItems,
MigIdx,
MigHooks,
MigItems,
CmdIdx,
CmdHooks,
CmdItems,
AppsIdx,
> = <AfterCommands<
L,
TplIdx,
TplHooks,
TplItems,
SlotIdx,
SlotHooks,
SlotItems,
MigIdx,
MigHooks,
MigItems,
CmdIdx,
CmdHooks,
CmdItems,
> as MapByCapTag<AppsTag, AppsCap<HNil>, AppsIdx>>::Output;
type AfterExport<
L,
TplIdx,
TplHooks,
TplItems,
SlotIdx,
SlotHooks,
SlotItems,
MigIdx,
MigHooks,
MigItems,
CmdIdx,
CmdHooks,
CmdItems,
AppsIdx,
ExportIdx,
> = <AfterApps<
L,
TplIdx,
TplHooks,
TplItems,
SlotIdx,
SlotHooks,
SlotItems,
MigIdx,
MigHooks,
MigItems,
CmdIdx,
CmdHooks,
CmdItems,
AppsIdx,
> as MapByCapTag<ExportTag, ExportCap<HNil>, ExportIdx>>::Output;
type AfterGrapesJs<
L,
TplIdx,
TplHooks,
TplItems,
SlotIdx,
SlotHooks,
SlotItems,
MigIdx,
MigHooks,
MigItems,
CmdIdx,
CmdHooks,
CmdItems,
AppsIdx,
ExportIdx,
GjsIdx,
> = <AfterExport<
L,
TplIdx,
TplHooks,
TplItems,
SlotIdx,
SlotHooks,
SlotItems,
MigIdx,
MigHooks,
MigItems,
CmdIdx,
CmdHooks,
CmdItems,
AppsIdx,
ExportIdx,
> as MapByCapTag<GrapesJsTag, GrapesJsCap<HNil>, GjsIdx>>::Output;
type AfterTools<
L,
TplIdx,
TplHooks,
TplItems,
SlotIdx,
SlotHooks,
SlotItems,
MigIdx,
MigHooks,
MigItems,
CmdIdx,
CmdHooks,
CmdItems,
AppsIdx,
ExportIdx,
GjsIdx,
ToolsIdx,
> = <AfterGrapesJs<
L,
TplIdx,
TplHooks,
TplItems,
SlotIdx,
SlotHooks,
SlotItems,
MigIdx,
MigHooks,
MigItems,
CmdIdx,
CmdHooks,
CmdItems,
AppsIdx,
ExportIdx,
GjsIdx,
> as MapByCapTag<LlmToolsTag, LlmToolsCap<HNil>, ToolsIdx>>::Output;
type AfterRuneEnv<
L,
TplIdx,
TplHooks,
TplItems,
SlotIdx,
SlotHooks,
SlotItems,
MigIdx,
MigHooks,
MigItems,
CmdIdx,
CmdHooks,
CmdItems,
AppsIdx,
ExportIdx,
GjsIdx,
ToolsIdx,
RuneEnvIdx,
> = <AfterTools<
L,
TplIdx,
TplHooks,
TplItems,
SlotIdx,
SlotHooks,
SlotItems,
MigIdx,
MigHooks,
MigItems,
CmdIdx,
CmdHooks,
CmdItems,
AppsIdx,
ExportIdx,
GjsIdx,
ToolsIdx,
> as MapByCapTag<RuneEnvTag, RuneEnvCap<HNil>, RuneEnvIdx>>::Output;
type AfterHttpResolve<
L,
TplIdx,
TplHooks,
TplItems,
SlotIdx,
SlotHooks,
SlotItems,
MigIdx,
MigHooks,
MigItems,
CmdIdx,
CmdHooks,
CmdItems,
AppsIdx,
ExportIdx,
GjsIdx,
ToolsIdx,
RuneEnvIdx,
HttpIdx,
HttpHooks,
HttpRoutes,
Proof,
> = <AfterRuneEnv<
L,
TplIdx,
TplHooks,
TplItems,
SlotIdx,
SlotHooks,
SlotItems,
MigIdx,
MigHooks,
MigItems,
CmdIdx,
CmdHooks,
CmdItems,
AppsIdx,
ExportIdx,
GjsIdx,
ToolsIdx,
RuneEnvIdx,
> as MapByCapTag<
HttpTag,
HttpCap<HNil, <HttpHooks as FoldMountRoutes<HttpCapability<HttpRoutes>, Proof>>::Output>,
HttpIdx,
>>::Output;
impl<M> MountedApp<M> {
pub async fn run_migrations<MigIdx, DbIdx, Migrators>(&self) -> Result<(), DbErr>
where
M: GetByTag<MigrationTag, MigIdx, Value = MigrationCapability<Migrators>>,
M: GetByTag<DbTag, DbIdx, Value = crate::db::DbState>,
Migrators: RunMigrations + Clone,
{
crate::migration::run_migrations(self).await
}
pub async fn mark_migrations<MigIdx, DbIdx, Migrators>(&self) -> Result<usize, DbErr>
where
M: GetByTag<MigrationTag, MigIdx, Value = MigrationCapability<Migrators>>,
M: GetByTag<DbTag, DbIdx, Value = crate::db::DbState>,
Migrators: crate::migration::CollectMigrations + Clone + Send,
{
crate::migration::mark_migrations(self).await
}
pub async fn run_seeds<SeedsIdx, Seeds, SeedProof>(&self) -> anyhow::Result<()>
where
M: GetByTag<SeedsTag, SeedsIdx, Value = SeedRunner<Seeds>> + Sync,
Seeds: FoldSeeds<M, SeedProof> + Clone + Send,
{
let runner = self.get_capability_output::<SeedsTag, SeedsIdx>().clone();
runner.seeds.fold_seeds(self).await
}
pub async fn run_serve_startups<ServeIdx, ServeHooks, ServeProof>(&self) -> anyhow::Result<()>
where
M: GetByTag<ServeStartupsTag, ServeIdx, Value = ServeStartupRunner<ServeHooks>> + Sync,
ServeHooks: FoldServeStartups<M, ServeProof> + Clone + Send,
{
let runner = self
.get_capability_output::<ServeStartupsTag, ServeIdx>()
.clone();
runner.hooks.fold_serve_startups(self).await
}
pub async fn serve<
CfgIdx,
Configs,
AppCfgIdx,
HttpIdx,
Routes,
SlotIdx,
ServeIdx,
ServeHooks,
ServeProof,
>(
self,
) -> anyhow::Result<()>
where
M: GetByTag<ConfigTag, CfgIdx, Value = ConfigCapability<Configs>>,
Configs: GetByTag<AppConfigTag, AppCfgIdx, Value = AppConfig>,
M: GetByTag<HttpTag, HttpIdx, Value = std::sync::Arc<HttpCapability<Routes>>>,
M: GetByTag<SlotTag, SlotIdx, Value = crate::components::SharedChromeFolder>,
M: GetByTag<ServeStartupsTag, ServeIdx, Value = ServeStartupRunner<ServeHooks>>,
ServeHooks: FoldServeStartups<M, ServeProof> + Clone + Send,
M: ProvideRequestCaps + Clone + Send + Sync + 'static,
Routes: MountRoutes + Clone,
{
self.run_serve_startups::<ServeIdx, ServeHooks, ServeProof>()
.await?;
let bind = self
.get_capability_output::<ConfigTag, CfgIdx>()
.get::<AppConfigTag, AppCfgIdx>()
.bind_target()?;
match bind {
BindTarget::Tcp(addr) => {
let listener = tokio::net::TcpListener::bind(addr).await?;
tracing::info!(%addr, "listening");
let make_service = {
let router = into_axum_router(&self);
let service = NormalizePathLayer::trim_trailing_slash().layer(router);
Shared::new(service)
};
axum::serve(listener, make_service).await?;
}
BindTarget::Uds(path) => {
if let Some(parent) = path.parent().filter(|p| !p.as_os_str().is_empty()) {
std::fs::create_dir_all(parent)?;
}
match std::fs::remove_file(&path) {
Ok(()) => {}
Err(e) if e.kind() == std::io::ErrorKind::NotFound => {}
Err(e) => return Err(e.into()),
}
let listener = tokio::net::UnixListener::bind(&path)?;
{
use std::os::unix::fs::PermissionsExt;
std::fs::set_permissions(&path, std::fs::Permissions::from_mode(0o777))?;
}
tracing::info!(path = %path.display(), "listening");
let make_service = {
let router = into_axum_router(&self);
let service = NormalizePathLayer::trim_trailing_slash().layer(router);
Shared::new(service)
};
axum::serve(listener, make_service).await?;
}
}
Ok(())
}
pub async fn run<CmdIdx, Cmds, DispatchProof, ServeProof>(self) -> anyhow::Result<()>
where
M: GetByTag<CommandTag, CmdIdx, Value = CommandCapability<Cmds>> + Send + 'static,
Cmds: BuildCli<M, DispatchProof> + DispatchCommands<M, DispatchProof> + Clone + Send,
CmdIdx: Send + Sync + 'static,
ServeCommand: RunCommand<M, ServeProof>,
<ServeCommand as RunCommand<M, ServeProof>>::Args: Default,
{
let cli = self
.get_capability_output::<CommandTag, CmdIdx>()
.build_cli();
let matches = cli.get_matches();
match matches.subcommand() {
Some((name, sub_matches)) => {
let cmds = self
.get_capability_output::<CommandTag, CmdIdx>()
.commands
.clone();
cmds.dispatch(name, sub_matches, self).await
}
None => {
let args = <ServeCommand as RunCommand<M, ServeProof>>::Args::default();
<ServeCommand as RunCommand<M, ServeProof>>::run(args, self).await
}
}
}
}
impl Default for App<HNil> {
fn default() -> Self {
Self::new()
}
}