mirror of
https://github.com/shiroyashik/sculptor.git
synced 2025-12-06 04:51:13 +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
41
.github/workflows/dev-release.yml
vendored
Normal file
41
.github/workflows/dev-release.yml
vendored
Normal 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
|
||||||
6
.github/workflows/release.yml
vendored
6
.github/workflows/release.yml
vendored
|
|
@ -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 .
|
||||||
12
.github/workflows/rust.yml
vendored
12
.github/workflows/rust.yml
vendored
|
|
@ -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
49
Cargo.lock
generated
|
|
@ -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",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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"
|
||||||
|
|
|
||||||
35
Dockerfile
35
Dockerfile
|
|
@ -1,22 +1,37 @@
|
||||||
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
|
||||||
|
|
||||||
CMD ["./sculptor"]
|
CMD [ "./sculptor" ]
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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) => {
|
||||||
|
|
|
||||||
|
|
@ -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(_) => {
|
||||||
|
|
|
||||||
38
src/main.rs
38
src/main.rs
|
|
@ -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 {
|
||||||
|
|
|
||||||
|
|
@ -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:?}"));
|
||||||
}
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue