mirror of
https://github.com/shiroyashik/sculptor.git
synced 2025-12-06 13:01:12 +03:00
The Assets update is now working properly on Linux
Also added a new Workflow and disabled the Rust workflow. Redesigned Dockerfile
This commit is contained in:
parent
f0599aec9e
commit
0103c31d69
13 changed files with 163 additions and 80 deletions
|
|
@ -7,7 +7,7 @@ use serde_json::Value;
|
|||
use tokio::{fs, io::AsyncReadExt as _};
|
||||
use walkdir::WalkDir;
|
||||
|
||||
use crate::{api::errors::internal_and_log, ApiError, ApiResult, AppState, ASSETS_ENV};
|
||||
use crate::{api::errors::internal_and_log, ApiError, ApiResult, AppState, ASSETS_VAR};
|
||||
|
||||
pub fn router() -> Router<AppState> {
|
||||
Router::new()
|
||||
|
|
@ -17,7 +17,7 @@ pub fn router() -> Router<AppState> {
|
|||
}
|
||||
|
||||
async fn versions() -> ApiResult<Json<Value>> {
|
||||
let dir_path = PathBuf::from(&std::env::var(ASSETS_ENV).unwrap());
|
||||
let dir_path = PathBuf::from(&*ASSETS_VAR);
|
||||
|
||||
let mut directories = Vec::new();
|
||||
|
||||
|
|
@ -43,7 +43,7 @@ async fn hashes(Path(version): Path<String>) -> ApiResult<Json<IndexMap<String,
|
|||
}
|
||||
|
||||
async fn download(Path((version, path)): Path<(String, String)>) -> ApiResult<Vec<u8>> {
|
||||
let mut file = if let Ok(file) = fs::File::open(format!("{}/{version}/{path}", std::env::var(ASSETS_ENV).unwrap())).await {
|
||||
let mut file = if let Ok(file) = fs::File::open(format!("{}/{version}/{path}", *ASSETS_VAR)).await {
|
||||
file
|
||||
} else {
|
||||
return Err(ApiError::NotFound)
|
||||
|
|
@ -57,7 +57,7 @@ async fn download(Path((version, path)): Path<(String, String)>) -> ApiResult<Ve
|
|||
|
||||
async fn index_assets(version: &str) -> anyhow::Result<IndexMap<String, Value>> {
|
||||
let mut map = IndexMap::new();
|
||||
let version_path = PathBuf::from(std::env::var(ASSETS_ENV).unwrap()).join(version);
|
||||
let version_path = PathBuf::from(&*ASSETS_VAR).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 {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,3 @@
|
|||
use std::env::var;
|
||||
|
||||
use axum::{
|
||||
body::Bytes, extract::{Path, State}, Json
|
||||
};
|
||||
|
|
@ -14,7 +12,7 @@ use uuid::Uuid;
|
|||
use crate::{
|
||||
api::errors::internal_and_log,
|
||||
auth::Token, utils::{calculate_file_sha256, format_uuid},
|
||||
ApiError, ApiResult, AppState, AVATARS_ENV
|
||||
ApiError, ApiResult, AppState, AVATARS_VAR
|
||||
};
|
||||
use super::types::S2CMessage;
|
||||
|
||||
|
|
@ -26,7 +24,7 @@ pub async fn user_info(
|
|||
|
||||
let formatted_uuid = format_uuid(&uuid);
|
||||
|
||||
let avatar_file = format!("{}/{}.moon", var(AVATARS_ENV).unwrap(), formatted_uuid);
|
||||
let avatar_file = format!("{}/{}.moon", *AVATARS_VAR, formatted_uuid);
|
||||
|
||||
let userinfo = if let Some(info) = state.user_manager.get_by_uuid(&uuid) { info } else {
|
||||
return Err(ApiError::BadRequest) // NOTE: Not Found (404) shows badge
|
||||
|
|
@ -81,7 +79,7 @@ pub async fn user_info(
|
|||
pub async fn download_avatar(Path(uuid): Path<Uuid>) -> ApiResult<Vec<u8>> {
|
||||
let uuid = format_uuid(&uuid);
|
||||
tracing::info!("Requesting an avatar: {}", uuid);
|
||||
let mut file = if let Ok(file) = fs::File::open(format!("{}/{}.moon", var(AVATARS_ENV).unwrap(), uuid)).await {
|
||||
let mut file = if let Ok(file) = fs::File::open(format!("{}/{}.moon", *AVATARS_VAR, uuid)).await {
|
||||
file
|
||||
} else {
|
||||
return Err(ApiError::NotFound)
|
||||
|
|
@ -104,7 +102,7 @@ pub async fn upload_avatar(
|
|||
user_info.uuid,
|
||||
user_info.username
|
||||
);
|
||||
let avatar_file = format!("{}/{}.moon", var(AVATARS_ENV).unwrap(), user_info.uuid);
|
||||
let avatar_file = format!("{}/{}.moon", *AVATARS_VAR, user_info.uuid);
|
||||
let mut file = BufWriter::new(fs::File::create(&avatar_file).await.map_err(|err| internal_and_log(err))?);
|
||||
io::copy(&mut request_data.as_ref(), &mut file).await.map_err(|err| internal_and_log(err))?;
|
||||
}
|
||||
|
|
@ -125,7 +123,7 @@ pub async fn delete_avatar(Token(token): Token, State(state): State<AppState>) -
|
|||
user_info.uuid,
|
||||
user_info.username
|
||||
);
|
||||
let avatar_file = format!("{}/{}.moon", var(AVATARS_ENV).unwrap(), user_info.uuid);
|
||||
let avatar_file = format!("{}/{}.moon", *AVATARS_VAR, user_info.uuid);
|
||||
fs::remove_file(avatar_file).await.map_err(|err| internal_and_log(err))?;
|
||||
send_event(&state, &user_info.uuid).await;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -76,6 +76,8 @@ async fn handle_socket(mut socket: WebSocket, state: AppState) {
|
|||
// Next is the code for processing msg
|
||||
let msg_vec = msg.clone().into_data();
|
||||
let msg_array = msg_vec.as_slice();
|
||||
|
||||
if msg_array.len() == 0 { tracing::debug!("[WebSocket{}] Deprecated len 0 msg", owner.name()); continue; };
|
||||
|
||||
let newmsg = match C2SMessage::try_from(msg_array) {
|
||||
Ok(data) => data,
|
||||
|
|
|
|||
|
|
@ -1,11 +1,9 @@
|
|||
use std::env::var;
|
||||
|
||||
use axum::{body::Bytes, extract::{Path, State}};
|
||||
use tokio::{fs, io::{self, BufWriter}};
|
||||
use tracing::warn;
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::{api::figura::profile::send_event, auth::Token, ApiResult, AppState, AVATARS_ENV};
|
||||
use crate::{api::figura::profile::send_event, auth::Token, ApiResult, AppState, AVATARS_VAR};
|
||||
|
||||
pub async fn upload_avatar(
|
||||
Path(uuid): Path<Uuid>,
|
||||
|
|
@ -22,7 +20,7 @@ pub async fn upload_avatar(
|
|||
uuid,
|
||||
);
|
||||
|
||||
let avatar_file = format!("{}/{}.moon", var(AVATARS_ENV).unwrap(), &uuid);
|
||||
let avatar_file = format!("{}/{}.moon", *AVATARS_VAR, &uuid);
|
||||
let mut file = BufWriter::new(fs::File::create(&avatar_file).await.unwrap());
|
||||
io::copy(&mut request_data.as_ref(), &mut file).await.unwrap();
|
||||
send_event(&state, &uuid).await;
|
||||
|
|
@ -42,7 +40,7 @@ pub async fn delete_avatar(
|
|||
uuid,
|
||||
);
|
||||
|
||||
let avatar_file = format!("{}/{}.moon", var(AVATARS_ENV).unwrap(), &uuid);
|
||||
let avatar_file = format!("{}/{}.moon", *AVATARS_VAR, &uuid);
|
||||
match fs::remove_file(avatar_file).await {
|
||||
Ok(_) => {},
|
||||
Err(_) => {
|
||||
|
|
|
|||
38
src/main.rs
38
src/main.rs
|
|
@ -5,10 +5,11 @@ use axum::{
|
|||
use dashmap::DashMap;
|
||||
use tracing_panic::panic_hook;
|
||||
use tracing_subscriber::{fmt::{self, time::ChronoLocal}, layer::SubscriberExt, util::SubscriberInitExt, EnvFilter};
|
||||
use std::{path::PathBuf, sync::Arc, env::{set_var, var}};
|
||||
use std::{path::PathBuf, sync::Arc, env::var};
|
||||
use tokio::{fs, sync::{broadcast, mpsc, RwLock}, time::Instant};
|
||||
use tower_http::trace::TraceLayer;
|
||||
use uuid::Uuid;
|
||||
use lazy_static::lazy_static;
|
||||
|
||||
// Consts
|
||||
mod consts;
|
||||
|
|
@ -52,21 +53,30 @@ pub struct AppState {
|
|||
figura_versions: Arc<RwLock<Option<FiguraVersions>>>,
|
||||
}
|
||||
|
||||
fn apply_default_environment() {
|
||||
if var(LOGGER_ENV).is_err() { set_var(LOGGER_ENV, "info") };
|
||||
if var(CONFIG_ENV).is_err() { set_var(CONFIG_ENV, "Config.toml") };
|
||||
if var(LOGS_ENV).is_err() { set_var(LOGS_ENV, "logs") };
|
||||
if var(ASSETS_ENV).is_err() { set_var(ASSETS_ENV, "data/assets") };
|
||||
if var(AVATARS_ENV).is_err() { set_var(ASSETS_ENV, "data/avatars") };
|
||||
lazy_static! {
|
||||
pub static ref LOGGER_VAR: String = {
|
||||
var(LOGGER_ENV).unwrap_or(String::from("info"))
|
||||
};
|
||||
pub static ref CONFIG_VAR: String = {
|
||||
var(CONFIG_ENV).unwrap_or(String::from("Config.toml"))
|
||||
};
|
||||
pub static ref LOGS_VAR: String = {
|
||||
var(LOGS_ENV).unwrap_or(String::from("logs"))
|
||||
};
|
||||
pub static ref ASSETS_VAR: String = {
|
||||
var(ASSETS_ENV).unwrap_or(String::from("data/assets"))
|
||||
};
|
||||
pub static ref AVATARS_VAR: String = {
|
||||
var(AVATARS_ENV).unwrap_or(String::from("data/avatars"))
|
||||
};
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<()> {
|
||||
let _ = dotenvy::dotenv();
|
||||
apply_default_environment();
|
||||
// "trace,axum=info,tower_http=info,tokio=info,tungstenite=info,tokio_tungstenite=info",
|
||||
|
||||
let file_appender = tracing_appender::rolling::never(&var(LOGS_ENV).unwrap(), get_log_file(&var(LOGS_ENV).unwrap()));
|
||||
let file_appender = tracing_appender::rolling::never(&*LOGS_VAR, get_log_file(&*LOGS_VAR));
|
||||
let timer = ChronoLocal::new(String::from("%Y-%m-%dT%H:%M:%S%.3f%:z"));
|
||||
|
||||
let file_layer = fmt::layer()
|
||||
|
|
@ -84,7 +94,7 @@ async fn main() -> Result<()> {
|
|||
|
||||
// Combine the layers and set the global subscriber
|
||||
tracing_subscriber::registry()
|
||||
.with(EnvFilter::from(var(LOGGER_ENV).unwrap()))
|
||||
.with(EnvFilter::from(&*LOGGER_VAR))
|
||||
.with(file_layer)
|
||||
.with(terminal_layer)
|
||||
.init();
|
||||
|
|
@ -100,7 +110,7 @@ async fn main() -> Result<()> {
|
|||
|
||||
// Preparing for launch
|
||||
{
|
||||
let path = PathBuf::from(var(AVATARS_ENV).unwrap());
|
||||
let path = PathBuf::from(&*AVATARS_VAR);
|
||||
if !path.exists() {
|
||||
fs::create_dir_all(path).await.expect("Can't create avatars folder!");
|
||||
tracing::info!("Created avatars directory");
|
||||
|
|
@ -108,12 +118,12 @@ async fn main() -> Result<()> {
|
|||
}
|
||||
|
||||
// Config
|
||||
let config = Arc::new(RwLock::new(Config::parse(var(CONFIG_ENV).unwrap().into())));
|
||||
let config = Arc::new(RwLock::new(Config::parse(CONFIG_VAR.clone().into())));
|
||||
let listen = config.read().await.listen.clone();
|
||||
|
||||
if config.read().await.assets_updater_enabled {
|
||||
// Force update assets if folder or hash file doesn't exists.
|
||||
if !(PathBuf::from(var(ASSETS_ENV).unwrap()).is_dir() && get_path_to_assets_hash().is_file()) {
|
||||
if !(PathBuf::from(&*ASSETS_VAR).is_dir() && get_path_to_assets_hash().is_file()) {
|
||||
tracing::debug!("Removing broken assets...");
|
||||
remove_assets().await
|
||||
}
|
||||
|
|
@ -153,7 +163,7 @@ async fn main() -> Result<()> {
|
|||
tokio::spawn(async move {
|
||||
loop {
|
||||
tokio::time::sleep(std::time::Duration::from_secs(10)).await;
|
||||
let new_config = Config::parse(var(CONFIG_ENV).unwrap().into());
|
||||
let new_config = Config::parse(CONFIG_VAR.clone().into());
|
||||
let mut config = config_update.write().await;
|
||||
|
||||
if new_config != *config {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use std::{env::{self, var}, path::{self, PathBuf}};
|
||||
use std::path::{self, PathBuf};
|
||||
|
||||
use anyhow::anyhow;
|
||||
use reqwest::Client;
|
||||
|
|
@ -7,7 +7,7 @@ use serde::{Deserialize, Serialize};
|
|||
use tokio::{fs::{self, File}, io::{AsyncReadExt as _, AsyncWriteExt as _}};
|
||||
use tracing::error;
|
||||
|
||||
use crate::{ASSETS_ENV, FIGURA_ASSETS_ZIP_URL, FIGURA_RELEASES_URL, TIMEOUT, USER_AGENT};
|
||||
use crate::{ASSETS_VAR, FIGURA_ASSETS_ZIP_URL, FIGURA_RELEASES_URL, TIMEOUT, USER_AGENT};
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
struct Tag {
|
||||
|
|
@ -116,7 +116,7 @@ struct Commit {
|
|||
}
|
||||
|
||||
pub fn get_path_to_assets_hash() -> PathBuf {
|
||||
path::PathBuf::from(&env::var(ASSETS_ENV).unwrap()).join("..").join("assets_last_commit")
|
||||
path::PathBuf::from(&*ASSETS_VAR).join("..").join("assets_last_commit")
|
||||
}
|
||||
|
||||
pub async fn get_commit_sha(url: &str) -> anyhow::Result<String> {
|
||||
|
|
@ -157,19 +157,22 @@ pub async fn is_assets_outdated(last_sha: &str) -> anyhow::Result<bool> {
|
|||
pub fn download_assets() -> anyhow::Result<()> {
|
||||
use std::{fs::{File, self}, io::Write as _};
|
||||
|
||||
let assets_folder = var(ASSETS_ENV).unwrap();
|
||||
let assets_folder = ASSETS_VAR.clone();
|
||||
|
||||
// Path to save the downloaded ZIP file
|
||||
let zip_file_path = path::PathBuf::from(&assets_folder).join("..").join("assets.zip");
|
||||
let mut zip_file_path = path::PathBuf::from(&*ASSETS_VAR);
|
||||
zip_file_path.pop();
|
||||
let zip_file_path = zip_file_path.join("assets.zip");
|
||||
|
||||
// Download the ZIP file
|
||||
|
||||
let response = reqwest::blocking::get(FIGURA_ASSETS_ZIP_URL)?;
|
||||
let client = reqwest::blocking::Client::builder().timeout(TIMEOUT).user_agent(USER_AGENT).build().unwrap();
|
||||
let response: reqwest::blocking::Response = client.get(FIGURA_ASSETS_ZIP_URL).send()?;
|
||||
let bytes = response.bytes()?;
|
||||
|
||||
// Save the downloaded ZIP file to disk
|
||||
let mut file = File::create(&zip_file_path)?;
|
||||
file.write_all(&bytes)?;
|
||||
file.flush()?;
|
||||
|
||||
// Open the downloaded ZIP file
|
||||
let file = File::open(&zip_file_path)?;
|
||||
|
|
@ -237,6 +240,6 @@ pub async fn write_sha_to_file(sha: &str) -> anyhow::Result<()> {
|
|||
}
|
||||
|
||||
pub async fn remove_assets() {
|
||||
fs::remove_dir_all(&var(ASSETS_ENV).unwrap()).await.unwrap_or_else(|err| tracing::debug!("Assets dir remove failed due {err:?}"));
|
||||
fs::remove_dir_all(&*ASSETS_VAR).await.unwrap_or_else(|err| tracing::debug!("Assets dir remove failed due {err:?}"));
|
||||
fs::remove_file(get_path_to_assets_hash()).await.unwrap_or_else(|err| tracing::debug!("Assets hash file remove failed due {err:?}"));
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue