use async_trait::async_trait; use loco_rs::{ app::{AppContext, Hooks, Initializer}, bgworker::{BackgroundWorker, Queue}, boot::{create_app, BootResult, StartMode}, config::Config, controller::AppRoutes, db::{self, truncate_table}, environment::Environment, storage::{self, Storage}, task::Tasks, Result, }; use migration::Migrator; use std::{path::Path, sync::Arc}; #[allow(unused_imports)] use crate::{ controllers::{ admin_categories, admin_dashboard, admin_form, admin_login, admin_orders, admin_products, admin_shipping, auth, cart, checkout, home, i18n, media, shop, }, initializers, models::_entities::users, tasks, workers::downloader::DownloadWorker, }; pub struct App; #[async_trait] impl Hooks for App { fn app_name() -> &'static str { env!("CARGO_CRATE_NAME") } fn app_version() -> String { format!( "{} ({})", env!("CARGO_PKG_VERSION"), option_env!("BUILD_SHA") .or(option_env!("GITHUB_SHA")) .unwrap_or("dev") ) } async fn boot( mode: StartMode, environment: &Environment, config: Config, ) -> Result { create_app::(mode, environment, config).await } async fn load_config(environment: &Environment) -> Result { dotenvy::dotenv().ok(); environment.load() } async fn initializers(_ctx: &AppContext) -> Result>> { Ok(vec![ Box::new(initializers::view_engine::ViewEngineInitializer), Box::new(initializers::admin_seeder::AdminSeeder), Box::new(initializers::shipping_seeder::ShippingSeeder), ]) } fn routes(_ctx: &AppContext) -> AppRoutes { AppRoutes::with_default_routes() // feature routes below // public .add_route(home::routes()) .add_route(shop::routes()) .add_route(cart::routes()) .add_route(checkout::routes()) // cross-cutting .add_route(auth::routes()) .add_route(i18n::routes()) .add_route(media::routes()) // admin .add_route(admin_dashboard::routes()) .add_route(admin_login::routes()) .add_route(admin_products::routes()) .add_route(admin_categories::routes()) .add_route(admin_orders::routes()) .add_route(admin_shipping::routes()) } async fn after_context(ctx: AppContext) -> Result { let upload_root = media::uploads_root(&ctx.config)?; tokio::fs::create_dir_all(upload_root.join(media::IMAGE_STORAGE_DIR)).await?; let driver = storage::drivers::local::new_with_prefix(&upload_root)?; Ok(AppContext { storage: Arc::new(Storage::single(driver)), ..ctx }) } async fn connect_workers(ctx: &AppContext, queue: &Queue) -> Result<()> { queue.register(DownloadWorker::build(ctx)).await?; Ok(()) } #[allow(unused_variables)] fn register_tasks(tasks: &mut Tasks) { // tasks-inject (do not remove) } async fn truncate(ctx: &AppContext) -> Result<()> { truncate_table(&ctx.db, users::Entity).await?; Ok(()) } async fn seed(ctx: &AppContext, base: &Path) -> Result<()> { db::seed::(&ctx.db, &base.join("users.yaml").display().to_string()) .await?; Ok(()) } }