+ Assets support

This commit is contained in:
Shiroyasha 2024-09-13 08:08:59 +03:00
parent d5433101f1
commit 7a37ce8a6b
6 changed files with 105 additions and 9 deletions

69
src/api/figura/assets.rs Normal file
View file

@ -0,0 +1,69 @@
use std::path::PathBuf;
use axum::{extract::Path, routing::get, Json, Router};
use indexmap::IndexMap;
use ring::digest::{digest, SHA256};
use serde_json::{json, Value};
use tokio::{fs, io::AsyncReadExt as _};
use walkdir::WalkDir;
use crate::{api::errors::internal_and_log, ApiError, ApiResult, AppState};
pub fn router() -> Router<AppState> {
Router::new()
.route("/", get(versions))
.route("/v1", get(v1))
.route("/v2", get(v2))
.route("/*path", get(download))
}
async fn versions() -> Json<Value> {
Json(json!(["v1", "v2"]))
}
async fn v1() -> ApiResult<Json<IndexMap<String, Value>>> {
let map = index_assets("v1").await.map_err(|err| internal_and_log(err))?;
Ok(Json(map))
}
async fn v2() -> ApiResult<Json<IndexMap<String, Value>>> {
let map = index_assets("v2").await.map_err(|err| internal_and_log(err))?;
Ok(Json(map))
}
async fn download(Path(path): Path<String>) -> ApiResult<Vec<u8>> {
let mut file = if let Ok(file) = fs::File::open(format!("assets/{path}")).await {
file
} else {
return Err(ApiError::NotFound)
};
let mut buffer = Vec::new();
file.read_to_end(&mut buffer).await.map_err(|err| internal_and_log(err))?;
Ok(buffer)
}
// non web
async fn index_assets(version: &str) -> anyhow::Result<IndexMap<String, Value>> {
let mut map = IndexMap::new();
let version_path = PathBuf::from("assets/").join(version);
for entry in WalkDir::new(version_path.clone()).into_iter().filter_map(|e| e.ok()) {
let data = match fs::read(entry.path()).await {
Ok(d) => d,
Err(_) => continue
};
let path: String;
if cfg!(windows) {
path = entry.path().strip_prefix(version_path.clone())?.to_string_lossy().to_string().replace("\\", "/");
} else {
path = entry.path().strip_prefix(version_path.clone())?.to_string_lossy().to_string();
}
map.insert(path, Value::from(hex::encode(digest(&SHA256, &data).as_ref())));
}
Ok(map)
}

View file

@ -3,5 +3,6 @@ mod websocket;
pub mod auth;
pub mod profile;
pub mod info;
pub mod assets;
pub use websocket::handler as ws;

View file

@ -21,7 +21,7 @@ pub use api::errors::{ApiResult, ApiError};
// API
mod api;
use api::{
figura::{ws, info as api_info, profile as api_profile, auth as api_auth},
figura::{ws, info as api_info, profile as api_profile, auth as api_auth, assets as api_assets},
// v1::{},
};
@ -84,12 +84,12 @@ async fn main() -> Result<()> {
.with(terminal_layer)
.init();
std::panic::set_hook(Box::new(panic_hook));
// let prev_hook = std::panic::take_hook();
// std::panic::set_hook(Box::new(move |panic_info| {
// panic_hook(panic_info);
// prev_hook(panic_info);
// }));
// std::panic::set_hook(Box::new(panic_hook));
let prev_hook = std::panic::take_hook();
std::panic::set_hook(Box::new(move |panic_info| {
panic_hook(panic_info);
prev_hook(panic_info);
}));
info!("The Sculptor v{}{}", SCULPTOR_VERSION, check_updates(REPOSITORY, &SCULPTOR_VERSION).await?);
@ -141,6 +141,7 @@ async fn main() -> Result<()> {
let api = Router::new()
.nest("//auth", api_auth::router()) // => /api//auth ¯\_(ツ)_/¯
.nest("//assets", api_assets::router())
.nest("/v1", api::v1::router())
.route("/limits", get(api_info::limits))
.route("/version", get(api_info::version))