+ 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

1
.gitignore vendored
View file

@ -2,6 +2,7 @@
/Assets-main
/avatars
/logs
/assets
output.log
docker-compose.yml
Config.toml

24
Cargo.lock generated
View file

@ -864,6 +864,7 @@ checksum = "68b900aa2f7301e21c36462b170ee99994de34dff39a4a6a528e80e7376d07e5"
dependencies = [
"equivalent",
"hashbrown 0.14.5",
"serde",
]
[[package]]
@ -1486,6 +1487,15 @@ version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f"
[[package]]
name = "same-file"
version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
dependencies = [
"winapi-util",
]
[[package]]
name = "schannel"
version = "0.1.24"
@ -1503,7 +1513,7 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
[[package]]
name = "sculptor"
version = "0.3.1"
version = "0.4.0-dev"
dependencies = [
"anyhow",
"axum",
@ -1513,6 +1523,7 @@ dependencies = [
"dashmap",
"dotenvy",
"hex",
"indexmap 2.5.0",
"rand",
"reqwest",
"ring",
@ -1528,6 +1539,7 @@ dependencies = [
"tracing-panic",
"tracing-subscriber",
"uuid",
"walkdir",
]
[[package]]
@ -2243,6 +2255,16 @@ version = "0.9.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
[[package]]
name = "walkdir"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b"
dependencies = [
"same-file",
"winapi-util",
]
[[package]]
name = "want"
version = "0.3.1"

View file

@ -1,7 +1,7 @@
[package]
name = "sculptor"
authors = ["Shiroyashik <shiroyashik@shsr.ru>"]
version = "0.3.1"
version = "0.4.0-dev"
edition = "2021"
publish = false
@ -28,6 +28,7 @@ base64 = "0.22.1"
reqwest = { version = "0.12.6", features = ["json"] }
dotenvy = "0.15.7"
semver = "1.0.23"
walkdir = "2.5.0"
# Crypto
ring = "0.17.8"
@ -37,6 +38,7 @@ rand = "0.8.5"
axum = { version = "0.7.5", features = ["ws", "macros", "http2"] }
tower-http = { version = "0.5.2", features = ["trace"] }
tokio = { version = "1.37.0", features = ["full"] }
indexmap = { version = "2.5.0", features = ["serde"] }
[dev-dependencies]
cross = "0.2.5"

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))