(*≧ω≦*) Preparing for 0.3.0 release!

~ README revised
~ updated Docker files
+ all const are placed in a separate file
+ auto creation for avatars folder
+ automatic retrieval of the latest Figura version for version request in api
This commit is contained in:
Shiroyasha 2024-08-19 22:54:45 +03:00
parent d45a495cbf
commit dabe176e0e
Signed by: shiroyashik
GPG key ID: E4953D3940D7860A
13 changed files with 355 additions and 224 deletions

View file

@ -1,13 +1,29 @@
use axum::{extract::State, Json};
use serde_json::{json, Value};
use tracing::error;
use crate::{utils::get_motd, AppState};
use crate::{
utils::{get_figura_versions, get_motd, FiguraVersions}, AppState, FIGURA_DEFAULT_VERSION
};
pub async fn version() -> Json<Value> {
Json(json!({
"release": "0.1.4",
"prerelease": "0.1.4"
}))
pub async fn version(State(state): State<AppState>) -> Json<FiguraVersions> {
let res = state.figura_versions.read().await.clone();
if let Some(res) = res {
Json(res)
} else {
let actual = get_figura_versions().await;
if let Ok(res) = actual {
let mut stored = state.figura_versions.write().await;
*stored = Some(res);
return Json(stored.clone().unwrap())
} else {
error!("get_figura_versions: {:?}", actual.unwrap_err());
}
Json(FiguraVersions {
release: FIGURA_DEFAULT_VERSION.to_string(),
prerelease: FIGURA_DEFAULT_VERSION.to_string()
})
}
}
pub async fn motd(State(state): State<AppState>) -> String {

View file

@ -13,7 +13,9 @@ use tokio::{
use uuid::Uuid;
use crate::{
api::errors::internal_and_log, auth::Token, utils::{calculate_file_sha256, format_uuid}, ApiError, ApiResult, AppState
api::errors::internal_and_log,
auth::Token, utils::{calculate_file_sha256, format_uuid},
ApiError, ApiResult, AppState
};
use super::types::S2CMessage;

View file

@ -1,4 +1,4 @@
use std::{sync::Arc, time::Duration};
use std::sync::Arc;
use anyhow::anyhow;
use axum::{
@ -8,12 +8,10 @@ use dashmap::DashMap;
use tracing::{debug, error, trace};
use uuid::Uuid;
use crate::{ApiError, ApiResult, AppState};
use crate::{ApiError, ApiResult, AppState, TIMEOUT, USER_AGENT};
use super::types::*;
const TIMEOUT: Duration = Duration::from_secs(5);
// It's an extractor that pulls a token from the Header.
#[derive(PartialEq, Debug)]
pub struct Token(pub String);
@ -63,7 +61,7 @@ async fn fetch_json(
server_id: &str,
username: &str,
) -> anyhow::Result<anyhow::Result<(Uuid, AuthProvider)>> {
let client = reqwest::Client::builder().timeout(TIMEOUT).build().unwrap();
let client = reqwest::Client::builder().timeout(TIMEOUT).user_agent(USER_AGENT).build().unwrap();
let url = auth_provider.url.clone();
let res = client

12
src/consts.rs Normal file
View file

@ -0,0 +1,12 @@
pub const LOGGER_ENV: &'static str = "RUST_LOG";
pub const CONFIG_ENV: &'static str = "RUST_CONFIG";
pub const LOGS_ENV: &'static str = "LOGS_FOLDER";
pub const SCULPTOR_VERSION: &'static str = env!("CARGO_PKG_VERSION");
pub const REPOSITORY: &'static str = "shiroyashik/sculptor";
pub const USER_AGENT: &'static str = "reqwest";
pub const TIMEOUT: std::time::Duration = std::time::Duration::from_secs(10);
pub const FIGURA_RELEASES_URL: &'static str = "https://api.github.com/repos/figuramc/figura/releases";
pub const FIGURA_DEFAULT_VERSION: &'static str = "0.1.4";

View file

@ -5,12 +5,16 @@ use axum::{
use dashmap::DashMap;
use tracing_panic::panic_hook;
use tracing_subscriber::{fmt::{self, time::ChronoLocal}, layer::SubscriberExt, util::SubscriberInitExt, EnvFilter};
use std::sync::Arc;
use tokio::{sync::{broadcast, mpsc, RwLock}, time::Instant};
use std::{path::PathBuf, sync::Arc};
use tokio::{fs, sync::{broadcast, mpsc, RwLock}, time::Instant};
use tower_http::trace::TraceLayer;
use tracing::info;
use uuid::Uuid;
// Consts
mod consts;
pub use consts::*;
// Errors
pub use api::errors::{ApiResult, ApiError};
@ -31,7 +35,7 @@ use state::Config;
// Utils
mod utils;
use utils::{check_updates, get_log_file, update_advanced_users, update_bans_from_minecraft};
use utils::{check_updates, get_log_file, update_advanced_users, update_bans_from_minecraft, FiguraVersions};
#[derive(Debug, Clone)]
pub struct AppState {
@ -45,14 +49,10 @@ pub struct AppState {
broadcasts: Arc<DashMap<Uuid, broadcast::Sender<Vec<u8>>>>,
/// Current configuration
config: Arc<RwLock<state::Config>>,
/// Figura Versions
figura_versions: Arc<RwLock<Option<FiguraVersions>>>,
}
const LOGGER_ENV: &'static str = "RUST_LOG";
const CONFIG_ENV: &'static str = "RUST_CONFIG";
const LOGS_ENV: &'static str = "LOGS_FOLDER";
const SCULPTOR_VERSION: &'static str = env!("CARGO_PKG_VERSION");
const REPOSITORY: &'static str = "shiroyashik/sculptor";
#[tokio::main]
async fn main() -> Result<()> {
let _ = dotenvy::dotenv();
@ -92,6 +92,14 @@ async fn main() -> Result<()> {
// }));
info!("The Sculptor v{}{}", SCULPTOR_VERSION, check_updates(REPOSITORY, &SCULPTOR_VERSION).await?);
{
let path = PathBuf::from("avatars");
if !path.exists() {
fs::create_dir(path).await.expect("Can't create avatars folder!");
info!("Created avatars directory");
}
}
// Config
let config = Arc::new(RwLock::new(Config::parse(config_file.clone().into())));
@ -103,6 +111,7 @@ async fn main() -> Result<()> {
user_manager: Arc::new(UManager::new()),
session: Arc::new(DashMap::new()),
broadcasts: Arc::new(DashMap::new()),
figura_versions: Arc::new(RwLock::new(None)),
config,
};

View file

@ -1,9 +1,11 @@
use anyhow::anyhow;
use reqwest::Client;
use semver::Version;
use serde::Deserialize;
use serde::{Deserialize, Serialize};
use tracing::error;
use crate::{FIGURA_RELEASES_URL, TIMEOUT, USER_AGENT};
#[derive(Deserialize, Debug)]
struct Tag {
name: String
@ -11,8 +13,8 @@ struct Tag {
async fn get_latest_version(repo: &str, current_version: Version) -> anyhow::Result<Option<String>> {
let url = format!("https://api.github.com/repos/{repo}/tags");
let client = Client::new();
let response = client.get(&url).header("User-Agent", "reqwest").send().await?;
let client = Client::builder().timeout(TIMEOUT).user_agent(USER_AGENT).build().unwrap();
let response = client.get(&url).send().await?;
if response.status().is_success() {
let tags: Vec<Tag> = response.json().await?;
@ -55,3 +57,50 @@ pub async fn check_updates(repo: &str, current_version: &str) -> anyhow::Result<
}
}
// Figura
#[derive(Deserialize, Debug)]
struct Release {
tag_name: String,
prerelease: bool
}
pub async fn get_figura_versions() -> anyhow::Result<FiguraVersions> {
let client = Client::builder().timeout(TIMEOUT).user_agent(USER_AGENT).build().unwrap();
let response = client.get(FIGURA_RELEASES_URL).send().await?;
let mut release_ver = Version::new(0, 0, 0);
let mut prerelease_ver = Version::new(0, 0, 0);
if response.status().is_success() {
let multiple_releases: Vec<Release> = response.json().await?;
for release in multiple_releases {
let tag_ver = if let Ok(res) = Version::parse(&release.tag_name) { res } else {
error!("Incorrect tag name! {release:?}");
continue;
};
if release.prerelease {
if tag_ver > prerelease_ver {
prerelease_ver = tag_ver
}
} else {
if tag_ver > release_ver {
release_ver = tag_ver
}
}
}
if release_ver > prerelease_ver {
prerelease_ver = release_ver.clone();
}
// Stop
Ok(FiguraVersions { release: release_ver.to_string(), prerelease: prerelease_ver.to_string() })
} else {
Err(anyhow!("Response status code: {}", response.status().as_u16()))
}
}
#[derive(Serialize, Debug, Clone)]
pub struct FiguraVersions {
pub release: String,
pub prerelease: String
}

View file

@ -4,4 +4,4 @@ mod motd;
pub use utils::*;
pub use motd::*;
pub use check_updates::check_updates;
pub use check_updates::*;