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:
Shiroyasha 2024-09-21 15:37:16 +03:00
parent f0599aec9e
commit 0103c31d69
Signed by: shiroyashik
GPG key ID: E4953D3940D7860A
13 changed files with 163 additions and 80 deletions

41
.github/workflows/dev-release.yml vendored Normal file
View file

@ -0,0 +1,41 @@
name: Push Dev
on:
push:
branches: [ "dev" ]
jobs:
docker:
runs-on: ubuntu-latest
steps:
# - name: Checkout code
# uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
# - name: Login to Docker Hub
# uses: docker/login-action@v3
# with:
# username: ${{ vars.DOCKERHUB_USERNAME }}
# password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Login to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Get short SHA
id: short_sha
run: echo "::set-output name=sha::$(echo ${GITHUB_SHA} | cut -c1-7)"
- name: Build and push
uses: docker/build-push-action@v6
with:
push: true
# context: .
tags: ghcr.io/${{ github.repository_owner }}/sculptor:${{ steps.short_sha.outputs.sha }}
cache-from: type=registry,ref=ghcr.io/${{ github.repository_owner }}/sculptor:buildcache
cache-to: type=registry,ref=ghcr.io/${{ github.repository_owner }}/sculptor:buildcache,mode=max

View file

@ -130,10 +130,6 @@ jobs:
# username: ${{ secrets.DOCKERHUB_USERNAME }} # username: ${{ secrets.DOCKERHUB_USERNAME }}
# password: ${{ secrets.DOCKERHUB_TOKEN }} # password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Write release version to env
run: |
CURRENT_SEMVER=${GITHUB_REF_NAME}
echo "CURRENT_SEMVER=$CURRENT_SEMVER" >> $GITHUB_ENV
- uses: docker/setup-buildx-action@v3 - uses: docker/setup-buildx-action@v3
id: buildx id: buildx
with: with:
@ -142,7 +138,7 @@ jobs:
run: | run: |
docker build --platform linux/amd64 \ docker build --platform linux/amd64 \
-t ghcr.io/${{ github.repository_owner }}/sculptor:latest \ -t ghcr.io/${{ github.repository_owner }}/sculptor:latest \
-t ghcr.io/${{ github.repository_owner }}/sculptor:${{env.CURRENT_SEMVER}} \ -t ghcr.io/${{ github.repository_owner }}/sculptor:${{ github.ref_name }} \
--provenance=false --sbom=false \ --provenance=false --sbom=false \
--push \ --push \
-f Dockerfile . -f Dockerfile .

View file

@ -1,10 +1,10 @@
name: Rust name: Rust
on: on: workflow_dispatch
push: # push:
branches: [ "master" ] # branches: [ "master" ]
pull_request: # pull_request:
branches: [ "master" ] # branches: [ "master" ]
env: env:
CARGO_TERM_COLOR: always CARGO_TERM_COLOR: always
@ -16,7 +16,9 @@ jobs:
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- name: Build - name: Build
run: cargo build --verbose run: cargo build --verbose
- name: Run tests - name: Run tests
run: cargo test --verbose run: cargo test --verbose

49
Cargo.lock generated
View file

@ -109,9 +109,9 @@ checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0"
[[package]] [[package]]
name = "axum" name = "axum"
version = "0.7.5" version = "0.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3a6c9af12842a67734c9a2e355436e5d03b22383ed60cf13cd0c18fbfe3dcbcf" checksum = "8f43644eed690f5374f1af436ecd6aea01cd201f6fbdf0178adaf6907afb2cec"
dependencies = [ dependencies = [
"async-trait", "async-trait",
"axum-core", "axum-core",
@ -139,7 +139,7 @@ dependencies = [
"sync_wrapper 1.0.1", "sync_wrapper 1.0.1",
"tokio", "tokio",
"tokio-tungstenite", "tokio-tungstenite",
"tower", "tower 0.5.1",
"tower-layer", "tower-layer",
"tower-service", "tower-service",
"tracing", "tracing",
@ -147,9 +147,9 @@ dependencies = [
[[package]] [[package]]
name = "axum-core" name = "axum-core"
version = "0.4.3" version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a15c63fd72d41492dc4f497196f5da1fb04fb7529e631d73630d1b491e47a2e3" checksum = "5e6b8ba012a258d63c9adfa28b9ddcf66149da6f986c5b5452e629d5ee64bf00"
dependencies = [ dependencies = [
"async-trait", "async-trait",
"bytes", "bytes",
@ -160,7 +160,7 @@ dependencies = [
"mime", "mime",
"pin-project-lite", "pin-project-lite",
"rustversion", "rustversion",
"sync_wrapper 0.1.2", "sync_wrapper 1.0.1",
"tower-layer", "tower-layer",
"tower-service", "tower-service",
"tracing", "tracing",
@ -168,11 +168,10 @@ dependencies = [
[[package]] [[package]]
name = "axum-macros" name = "axum-macros"
version = "0.4.1" version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "00c055ee2d014ae5981ce1016374e8213682aa14d9bf40e48ab48b5f3ef20eaa" checksum = "57d123550fa8d071b7255cb0cc04dc302baa6c8c4a79f55701552684d8399bce"
dependencies = [ dependencies = [
"heck",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.77", "syn 2.0.77",
@ -948,7 +947,7 @@ dependencies = [
"pin-project-lite", "pin-project-lite",
"socket2", "socket2",
"tokio", "tokio",
"tower", "tower 0.4.13",
"tower-service", "tower-service",
"tracing", "tracing",
] ]
@ -1724,6 +1723,7 @@ dependencies = [
"dotenvy", "dotenvy",
"hex", "hex",
"indexmap 2.5.0", "indexmap 2.5.0",
"lazy_static",
"rand", "rand",
"reqwest", "reqwest",
"ring", "ring",
@ -2164,9 +2164,9 @@ dependencies = [
[[package]] [[package]]
name = "tokio-tungstenite" name = "tokio-tungstenite"
version = "0.21.0" version = "0.23.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c83b561d025642014097b66e6c1bb422783339e0909e4429cde4749d1990bc38" checksum = "c6989540ced10490aaf14e6bad2e3d33728a2813310a0c71d1574304c49631cd"
dependencies = [ dependencies = [
"futures-util", "futures-util",
"log", "log",
@ -2243,20 +2243,34 @@ dependencies = [
"tokio", "tokio",
"tower-layer", "tower-layer",
"tower-service", "tower-service",
]
[[package]]
name = "tower"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2873938d487c3cfb9aed7546dc9f2711d867c9f90c46b889989a2cb84eba6b4f"
dependencies = [
"futures-core",
"futures-util",
"pin-project-lite",
"sync_wrapper 0.1.2",
"tokio",
"tower-layer",
"tower-service",
"tracing", "tracing",
] ]
[[package]] [[package]]
name = "tower-http" name = "tower-http"
version = "0.5.2" version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e9cd434a998747dd2c4276bc96ee2e0c7a2eadf3cae88e52be55a05fa9053f5" checksum = "41515cc9e193536d93fd0dbbea0c73819c08eca76e0b30909a325c3ec90985bb"
dependencies = [ dependencies = [
"bitflags 2.6.0", "bitflags 2.6.0",
"bytes", "bytes",
"http", "http",
"http-body", "http-body",
"http-body-util",
"pin-project-lite", "pin-project-lite",
"tower-layer", "tower-layer",
"tower-service", "tower-service",
@ -2368,9 +2382,9 @@ checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b"
[[package]] [[package]]
name = "tungstenite" name = "tungstenite"
version = "0.21.0" version = "0.23.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ef1a641ea34f399a848dea702823bbecfb4c486f911735368f1f137cb8257e1" checksum = "6e2e2ce1e47ed2994fd43b04c8f618008d4cabdd5ee34027cf14f9d918edd9c8"
dependencies = [ dependencies = [
"byteorder", "byteorder",
"bytes", "bytes",
@ -2381,7 +2395,6 @@ dependencies = [
"rand", "rand",
"sha1", "sha1",
"thiserror", "thiserror",
"url",
"utf-8", "utf-8",
] ]

View file

@ -18,7 +18,7 @@ thiserror = "1.0.63"
chrono = { version = "0.4.38", features = ["now", "serde"] } chrono = { version = "0.4.38", features = ["now", "serde"] }
serde = { version = "1.0.201", features = ["derive"] } serde = { version = "1.0.201", features = ["derive"] }
serde_json = "1.0.117" serde_json = "1.0.117"
toml = "0.8.13" toml = "0.8.19"
# Other # Other
dashmap = { version = "6.0.1", features = ["serde"] } dashmap = { version = "6.0.1", features = ["serde"] }
@ -35,11 +35,12 @@ ring = "0.17.8"
rand = "0.8.5" rand = "0.8.5"
# Web framework # Web framework
axum = { version = "0.7.5", features = ["ws", "macros", "http2"] } axum = { version = "0.7.6", features = ["ws", "macros", "http2"] }
tower-http = { version = "0.5.2", features = ["trace"] } tower-http = { version = "0.6.0", features = ["trace"] }
tokio = { version = "1.37.0", features = ["full"] } tokio = { version = "1.37.0", features = ["full"] }
indexmap = { version = "2.5.0", features = ["serde"] } indexmap = { version = "2.5.0", features = ["serde"] }
zip = "2.2.0" zip = "2.2.0"
lazy_static = "1.5.0"
[dev-dependencies] [dev-dependencies]
cross = "0.2.5" cross = "0.2.5"

View file

@ -1,21 +1,36 @@
FROM rust:1.80.1-alpine3.20 as builder ## Chef
# FROM clux/muslrust:stable AS chef
FROM rust:1.81.0-alpine3.20 as chef
USER root
RUN apk add musl-dev libressl-dev
RUN cargo install cargo-chef
WORKDIR /build WORKDIR /build
RUN apk add musl-dev libressl-dev ## Planner
FROM chef AS planner
COPY Cargo.toml Cargo.lock ./ COPY Cargo.toml Cargo.lock ./
COPY src src COPY src src
RUN cargo chef prepare --recipe-path recipe.json
RUN cargo build --release ## Builder
FROM chef AS builder
FROM alpine:3.20.0 COPY --from=planner /build/recipe.json recipe.json
# Build dependencies - this is the caching Docker layer!
RUN cargo chef cook --release --target x86_64-unknown-linux-musl --recipe-path recipe.json
# Build application
COPY Cargo.toml Cargo.lock ./
COPY src src
RUN cargo build --release --target x86_64-unknown-linux-musl --bin sculptor
## Runtime
FROM alpine:3.20.0 AS runtime
WORKDIR /app WORKDIR /app
COPY --from=builder /build/target/x86_64-unknown-linux-musl/release/sculptor /app/sculptor
COPY --from=builder /build/target/release/sculptor /app/sculptor RUN apk add --no-cache tzdata
ENV TZ=Etc/UTC
VOLUME [ "/app/avatars" ] VOLUME [ "/app/data" ]
VOLUME [ "/app/logs" ] VOLUME [ "/app/logs" ]
EXPOSE 6665/tcp EXPOSE 6665/tcp

View file

@ -14,13 +14,17 @@ services:
restart: unless-stopped restart: unless-stopped
volumes: volumes:
- ./Config.toml:/app/Config.toml:ro - ./Config.toml:/app/Config.toml:ro
- ./avatars:/app/avatars - ./data:/app/data
- ./logs:/app/logs - ./logs:/app/logs
# You can specify the path to the server folder # You can specify the path to the server folder
# for Sculptor to use the ban list from it # for Sculptor to use the ban list from it
# - ./minecraft-server:/app/mc # - ./minecraft-server:/app/mc
environment: environment:
- RUST_LOG=info - RUST_LOG=info
# Set your timezone. https://en.wikipedia.org/wiki/List_of_tz_database_time_zones
- TZ=Europe/Moscow
# ports:
# - 6665
## Recommended for use with reverse proxy. ## Recommended for use with reverse proxy.
# networks: # networks:
# - traefik # - traefik

View file

@ -7,7 +7,7 @@ use serde_json::Value;
use tokio::{fs, io::AsyncReadExt as _}; use tokio::{fs, io::AsyncReadExt as _};
use walkdir::WalkDir; 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> { pub fn router() -> Router<AppState> {
Router::new() Router::new()
@ -17,7 +17,7 @@ pub fn router() -> Router<AppState> {
} }
async fn versions() -> ApiResult<Json<Value>> { 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(); 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>> { 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 file
} else { } else {
return Err(ApiError::NotFound) 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>> { async fn index_assets(version: &str) -> anyhow::Result<IndexMap<String, Value>> {
let mut map = IndexMap::new(); 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()) { for entry in WalkDir::new(version_path.clone()).into_iter().filter_map(|e| e.ok()) {
let data = match fs::read(entry.path()).await { let data = match fs::read(entry.path()).await {

View file

@ -1,5 +1,3 @@
use std::env::var;
use axum::{ use axum::{
body::Bytes, extract::{Path, State}, Json body::Bytes, extract::{Path, State}, Json
}; };
@ -14,7 +12,7 @@ use uuid::Uuid;
use crate::{ use crate::{
api::errors::internal_and_log, api::errors::internal_and_log,
auth::Token, utils::{calculate_file_sha256, format_uuid}, auth::Token, utils::{calculate_file_sha256, format_uuid},
ApiError, ApiResult, AppState, AVATARS_ENV ApiError, ApiResult, AppState, AVATARS_VAR
}; };
use super::types::S2CMessage; use super::types::S2CMessage;
@ -26,7 +24,7 @@ pub async fn user_info(
let formatted_uuid = format_uuid(&uuid); 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 { 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 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>> { pub async fn download_avatar(Path(uuid): Path<Uuid>) -> ApiResult<Vec<u8>> {
let uuid = format_uuid(&uuid); let uuid = format_uuid(&uuid);
tracing::info!("Requesting an avatar: {}", 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 file
} else { } else {
return Err(ApiError::NotFound) return Err(ApiError::NotFound)
@ -104,7 +102,7 @@ pub async fn upload_avatar(
user_info.uuid, user_info.uuid,
user_info.username 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))?); 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))?; 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.uuid,
user_info.username 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))?; fs::remove_file(avatar_file).await.map_err(|err| internal_and_log(err))?;
send_event(&state, &user_info.uuid).await; send_event(&state, &user_info.uuid).await;
} }

View file

@ -77,6 +77,8 @@ async fn handle_socket(mut socket: WebSocket, state: AppState) {
let msg_vec = msg.clone().into_data(); let msg_vec = msg.clone().into_data();
let msg_array = msg_vec.as_slice(); 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) { let newmsg = match C2SMessage::try_from(msg_array) {
Ok(data) => data, Ok(data) => data,
Err(e) => { Err(e) => {

View file

@ -1,11 +1,9 @@
use std::env::var;
use axum::{body::Bytes, extract::{Path, State}}; use axum::{body::Bytes, extract::{Path, State}};
use tokio::{fs, io::{self, BufWriter}}; use tokio::{fs, io::{self, BufWriter}};
use tracing::warn; use tracing::warn;
use uuid::Uuid; 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( pub async fn upload_avatar(
Path(uuid): Path<Uuid>, Path(uuid): Path<Uuid>,
@ -22,7 +20,7 @@ pub async fn upload_avatar(
uuid, 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()); let mut file = BufWriter::new(fs::File::create(&avatar_file).await.unwrap());
io::copy(&mut request_data.as_ref(), &mut file).await.unwrap(); io::copy(&mut request_data.as_ref(), &mut file).await.unwrap();
send_event(&state, &uuid).await; send_event(&state, &uuid).await;
@ -42,7 +40,7 @@ pub async fn delete_avatar(
uuid, 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 { match fs::remove_file(avatar_file).await {
Ok(_) => {}, Ok(_) => {},
Err(_) => { Err(_) => {

View file

@ -5,10 +5,11 @@ use axum::{
use dashmap::DashMap; use dashmap::DashMap;
use tracing_panic::panic_hook; use tracing_panic::panic_hook;
use tracing_subscriber::{fmt::{self, time::ChronoLocal}, layer::SubscriberExt, util::SubscriberInitExt, EnvFilter}; 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 tokio::{fs, sync::{broadcast, mpsc, RwLock}, time::Instant};
use tower_http::trace::TraceLayer; use tower_http::trace::TraceLayer;
use uuid::Uuid; use uuid::Uuid;
use lazy_static::lazy_static;
// Consts // Consts
mod consts; mod consts;
@ -52,21 +53,30 @@ pub struct AppState {
figura_versions: Arc<RwLock<Option<FiguraVersions>>>, figura_versions: Arc<RwLock<Option<FiguraVersions>>>,
} }
fn apply_default_environment() { lazy_static! {
if var(LOGGER_ENV).is_err() { set_var(LOGGER_ENV, "info") }; pub static ref LOGGER_VAR: String = {
if var(CONFIG_ENV).is_err() { set_var(CONFIG_ENV, "Config.toml") }; var(LOGGER_ENV).unwrap_or(String::from("info"))
if var(LOGS_ENV).is_err() { set_var(LOGS_ENV, "logs") }; };
if var(ASSETS_ENV).is_err() { set_var(ASSETS_ENV, "data/assets") }; pub static ref CONFIG_VAR: String = {
if var(AVATARS_ENV).is_err() { set_var(ASSETS_ENV, "data/avatars") }; 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] #[tokio::main]
async fn main() -> Result<()> { async fn main() -> Result<()> {
let _ = dotenvy::dotenv(); let _ = dotenvy::dotenv();
apply_default_environment();
// "trace,axum=info,tower_http=info,tokio=info,tungstenite=info,tokio_tungstenite=info", // "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 timer = ChronoLocal::new(String::from("%Y-%m-%dT%H:%M:%S%.3f%:z"));
let file_layer = fmt::layer() let file_layer = fmt::layer()
@ -84,7 +94,7 @@ async fn main() -> Result<()> {
// Combine the layers and set the global subscriber // Combine the layers and set the global subscriber
tracing_subscriber::registry() tracing_subscriber::registry()
.with(EnvFilter::from(var(LOGGER_ENV).unwrap())) .with(EnvFilter::from(&*LOGGER_VAR))
.with(file_layer) .with(file_layer)
.with(terminal_layer) .with(terminal_layer)
.init(); .init();
@ -100,7 +110,7 @@ async fn main() -> Result<()> {
// Preparing for launch // Preparing for launch
{ {
let path = PathBuf::from(var(AVATARS_ENV).unwrap()); let path = PathBuf::from(&*AVATARS_VAR);
if !path.exists() { if !path.exists() {
fs::create_dir_all(path).await.expect("Can't create avatars folder!"); fs::create_dir_all(path).await.expect("Can't create avatars folder!");
tracing::info!("Created avatars directory"); tracing::info!("Created avatars directory");
@ -108,12 +118,12 @@ async fn main() -> Result<()> {
} }
// Config // 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(); let listen = config.read().await.listen.clone();
if config.read().await.assets_updater_enabled { if config.read().await.assets_updater_enabled {
// Force update assets if folder or hash file doesn't exists. // 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..."); tracing::debug!("Removing broken assets...");
remove_assets().await remove_assets().await
} }
@ -153,7 +163,7 @@ async fn main() -> Result<()> {
tokio::spawn(async move { tokio::spawn(async move {
loop { loop {
tokio::time::sleep(std::time::Duration::from_secs(10)).await; 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; let mut config = config_update.write().await;
if new_config != *config { if new_config != *config {

View file

@ -1,4 +1,4 @@
use std::{env::{self, var}, path::{self, PathBuf}}; use std::path::{self, PathBuf};
use anyhow::anyhow; use anyhow::anyhow;
use reqwest::Client; use reqwest::Client;
@ -7,7 +7,7 @@ use serde::{Deserialize, Serialize};
use tokio::{fs::{self, File}, io::{AsyncReadExt as _, AsyncWriteExt as _}}; use tokio::{fs::{self, File}, io::{AsyncReadExt as _, AsyncWriteExt as _}};
use tracing::error; 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)] #[derive(Deserialize, Debug)]
struct Tag { struct Tag {
@ -116,7 +116,7 @@ struct Commit {
} }
pub fn get_path_to_assets_hash() -> PathBuf { 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> { 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<()> { pub fn download_assets() -> anyhow::Result<()> {
use std::{fs::{File, self}, io::Write as _}; 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 // 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 // Download the ZIP file
let client = reqwest::blocking::Client::builder().timeout(TIMEOUT).user_agent(USER_AGENT).build().unwrap();
let response = reqwest::blocking::get(FIGURA_ASSETS_ZIP_URL)?; let response: reqwest::blocking::Response = client.get(FIGURA_ASSETS_ZIP_URL).send()?;
let bytes = response.bytes()?; let bytes = response.bytes()?;
// Save the downloaded ZIP file to disk // Save the downloaded ZIP file to disk
let mut file = File::create(&zip_file_path)?; let mut file = File::create(&zip_file_path)?;
file.write_all(&bytes)?; file.write_all(&bytes)?;
file.flush()?;
// Open the downloaded ZIP file // Open the downloaded ZIP file
let file = File::open(&zip_file_path)?; 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() { 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:?}")); fs::remove_file(get_path_to_assets_hash()).await.unwrap_or_else(|err| tracing::debug!("Assets hash file remove failed due {err:?}"));
} }