112 lines
3.4 KiB
Rust
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(())
|
|
}
|