mod config; mod meilisearch; mod page; use meilisearch_sdk::client::Client as MeilisearchClient; use rocket::fairing::{self, AdHoc}; use rocket::form::Form; use rocket::serde::json::Json; use rocket::{Rocket, State}; use tracing::error; use config::Config; struct Context { #[allow(dead_code)] config: Config, client: MeilisearchClient, } #[derive(Debug, thiserror::Error)] enum InitError { #[error("Meilisearch error: {0}")] Meilisearch(#[from] meilisearch::Error), } impl Context { pub fn init(config: Config) -> Result { let client = MeilisearchClient::try_from(&config)?; Ok(Self { config, client }) } } /// Save page form #[derive(rocket::FromForm)] pub struct SavePageForm { /// Page URL url: String, /// Page content (SingleFile HTML) data: String, } /// Save a visited page in SingleFile format #[rocket::post("/save", data = "
")] async fn save_page( form: Form, ctx: &State, ) -> Result, String> { match page::save_page(&form.url, &form.data, ctx).await { Ok(p) => Ok(Json(p)), Err(e) => { error!("Failed to save page: {}", e); Err(e.to_string()) }, } } /// Set up Meilisearch async fn meilisearch_setup(rocket: Rocket) -> fairing::Result { let ctx: &Context = rocket.state().unwrap(); let client = &ctx.client; let config = &ctx.config; if let Err(e) = meilisearch::ensure_index(client, &config.meilisearch.index).await { error!("Failed to create Meilisearch index: {}", e); Err(rocket) } else { Ok(rocket) } } #[rocket::launch] async fn rocket() -> _ { tracing_subscriber::fmt() .with_env_filter(tracing_subscriber::EnvFilter::from_default_env()) .with_writer(std::io::stderr) .init(); let rocket = rocket::build(); let config: Config = rocket.figment().extract().unwrap(); let ctx = Context::init(config).unwrap(); rocket .manage(ctx) .mount("/", rocket::routes![save_page]) .attach(AdHoc::try_on_ignite("Meilisearch Setup", meilisearch_setup)) }