quickpeep/quickpeep/src/bin/quickpeep.rs

112 lines
3.4 KiB
Rust

use anyhow::{bail, Context};
use axum::extract::Extension;
use axum::http::StatusCode;
use axum::routing::{get, get_service, post};
use axum::Router;
use env_logger::Env;
use log::info;
use quickpeep::config::WebConfig;
use quickpeep::web::icon_retrieval::retrieve_icon;
use quickpeep::web::metadata::get_opensearch_xml;
use quickpeep::web::searcher::{search_root, search_search};
use quickpeep::web::seed_collector::{seed_collection_root, seed_collection_root_post};
use quickpeep::web::IndexAccess;
use quickpeep_index::auxiliary::icon_store::IconStore;
use sqlx::sqlite::SqlitePoolOptions;
use std::net::SocketAddr;
use std::path::PathBuf;
use std::sync::Arc;
use tower_http::services::ServeDir;
#[tokio::main]
async fn main() -> anyhow::Result<()> {
env_logger::Builder::from_env(
Env::default().default_filter_or("info,quickpeep=debug,sqlx=warn"),
)
.init();
let config_path = PathBuf::from(
std::env::var("QUICKPEEP_CONFIG").unwrap_or_else(|_| "quickpeep.ron".to_owned()),
);
if !config_path.exists() {
bail!(
"Config path {:?} doesn't exist. QUICKPEEP_CONFIG env var overrides.",
config_path
);
}
let web_config = WebConfig::load(&config_path)?;
let pool = SqlitePoolOptions::new()
.min_connections(1)
.after_connect(|conn| {
Box::pin(async move {
// Use the WAL because it just makes more sense :)
sqlx::query("PRAGMA journal_mode = WAL")
.execute(&mut *conn)
.await?;
// Enable foreign keys because we like them!
sqlx::query("PRAGMA foreign_keys = ON")
.execute(&mut *conn)
.await?;
Ok(())
})
})
.connect(
&web_config
.web
.sqlite_db_path
.to_str()
.context("SQLite DB path should be UTF-8")?,
)
.await?;
sqlx::migrate!().run(&pool).await?;
let backend = Arc::new(web_config.open_indexer_backend()?);
let index_access = IndexAccess { backend };
let icon_store = IconStore::open(web_config.index.icon_store.as_path())?;
let app = Router::new()
.route("/seeds/", get(seed_collection_root))
.route("/seeds/", post(seed_collection_root_post))
.route("/", get(search_root))
.route("/search", get(search_search))
.route("/icon.webp", get(retrieve_icon))
.route("/opensearch.xml", get(get_opensearch_xml))
.layer(Extension(web_config))
.layer(Extension(pool))
.layer(Extension(index_access))
.layer(Extension(Arc::new(icon_store)))
.nest(
"/static",
get_service(ServeDir::new("./quickpeep_static/dist")).handle_error(
|error: std::io::Error| async move {
(
StatusCode::INTERNAL_SERVER_ERROR,
format!("Unhandled internal error: {}", error),
)
},
),
);
let bind_to: SocketAddr = std::env::args()
.skip(1)
.next()
.unwrap_or_else(|| String::from("127.0.0.1:9001"))
.parse()?;
info!("Starting QuickPeep Search UI on {:?}", bind_to);
axum::Server::bind(&bind_to)
.serve(app.into_make_service())
.await
.unwrap();
Ok(())
}