mirror of
https://github.com/Xevion/Pac-Man.git
synced 2025-12-06 21:15:48 -06:00
feat: initial server config & Dockerfile
This commit is contained in:
16
.dockerignore
Normal file
16
.dockerignore
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
# Build artifacts
|
||||||
|
/target
|
||||||
|
/dist
|
||||||
|
/emsdk
|
||||||
|
*.exe
|
||||||
|
|
||||||
|
/pacman/assets
|
||||||
|
/assets
|
||||||
|
|
||||||
|
# Development files
|
||||||
|
/.git
|
||||||
|
/*.md
|
||||||
|
/Justfile
|
||||||
|
/bacon.toml
|
||||||
|
/rust-toolchain.toml
|
||||||
|
/rustfmt.toml
|
||||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -23,3 +23,6 @@ flamegraph.svg
|
|||||||
|
|
||||||
# Logs
|
# Logs
|
||||||
*.log
|
*.log
|
||||||
|
|
||||||
|
# Sensitive
|
||||||
|
*.env
|
||||||
|
|||||||
2245
Cargo.lock
generated
2245
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -14,15 +14,6 @@ categories = ["games", "emulators"]
|
|||||||
publish = false
|
publish = false
|
||||||
|
|
||||||
[workspace.dependencies]
|
[workspace.dependencies]
|
||||||
# Common dependencies that might be shared across crates
|
|
||||||
serde = { version = "1.0", features = ["derive"] }
|
|
||||||
serde_json = "1.0"
|
|
||||||
tokio = { version = "1.0", features = ["full"] }
|
|
||||||
axum = "0.7"
|
|
||||||
tower = "0.4"
|
|
||||||
tower-http = { version = "0.5", features = ["cors", "trace"] }
|
|
||||||
tracing = "0.1"
|
|
||||||
tracing-subscriber = "0.3"
|
|
||||||
|
|
||||||
|
|
||||||
# Release profile for profiling (essentially the default 'release' profile with debug enabled)
|
# Release profile for profiling (essentially the default 'release' profile with debug enabled)
|
||||||
|
|||||||
@@ -15,3 +15,23 @@ publish.workspace = true
|
|||||||
default-run = "pacman-server"
|
default-run = "pacman-server"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
axum = "0.8"
|
||||||
|
tokio = { version = "1", features = ["full"] }
|
||||||
|
oauth2 = "5"
|
||||||
|
reqwest = { version = "0.12", features = ["json"] }
|
||||||
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
|
serde_json = "1.0"
|
||||||
|
chrono = { version = "0.4", features = ["serde"] }
|
||||||
|
sqlx = { version = "0.8", features = [
|
||||||
|
"runtime-tokio-rustls",
|
||||||
|
"postgres",
|
||||||
|
"chrono",
|
||||||
|
] }
|
||||||
|
figment = { version = "0.10", features = ["env"] }
|
||||||
|
dotenvy = "0.15"
|
||||||
|
|
||||||
|
# Validation
|
||||||
|
# validator = { version = "0.16", features = ["derive"] }
|
||||||
|
|
||||||
|
# JWT for internal sessions
|
||||||
|
# jsonwebtoken = "8.3"
|
||||||
|
|||||||
46
pacman-server/Dockerfile
Normal file
46
pacman-server/Dockerfile
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
ARG RUST_VERSION=1.89.0
|
||||||
|
|
||||||
|
FROM lukemathwalker/cargo-chef:latest-rust-${RUST_VERSION} AS chef
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# -- Planner stage --
|
||||||
|
FROM chef AS planner
|
||||||
|
COPY . .
|
||||||
|
RUN cargo chef prepare --bin pacman-server --recipe-path recipe.json
|
||||||
|
|
||||||
|
# -- Builder stage --
|
||||||
|
FROM chef AS builder
|
||||||
|
COPY --from=planner /app/recipe.json recipe.json
|
||||||
|
RUN cargo chef cook --release --bin pacman-server --recipe-path recipe.json
|
||||||
|
|
||||||
|
# Copy the source code AFTER, so that dependencies are already cached
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
# Install build dependencies, then build the server
|
||||||
|
RUN apt-get update && apt-get install -y pkg-config libssl-dev && rm -rf /var/lib/apt/lists/*
|
||||||
|
RUN cargo build --package pacman-server --release --bin pacman-server
|
||||||
|
|
||||||
|
# -- Runtime stage --
|
||||||
|
FROM debian:bookworm-slim AS runtime
|
||||||
|
WORKDIR /app
|
||||||
|
COPY --from=builder /app/target/release/pacman-server /usr/local/bin/pacman-server
|
||||||
|
|
||||||
|
# Install runtime dependencies
|
||||||
|
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||||
|
ca-certificates \
|
||||||
|
tzdata \
|
||||||
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
ARG TZ=Etc/UTC
|
||||||
|
ENV TZ=${TZ}
|
||||||
|
|
||||||
|
# Optional build-time environment variable for embedding the Git commit SHA
|
||||||
|
ARG RAILWAY_GIT_COMMIT_SHA
|
||||||
|
ENV RAILWAY_GIT_COMMIT_SHA=${RAILWAY_GIT_COMMIT_SHA}
|
||||||
|
|
||||||
|
# Specify PORT at build-time or run-time, default to 3000
|
||||||
|
ARG PORT=3000
|
||||||
|
ENV PORT=${PORT}
|
||||||
|
EXPOSE ${PORT}
|
||||||
|
|
||||||
|
CMD ["sh", "-c", "exec /usr/local/bin/pacman-server"]
|
||||||
67
pacman-server/src/config.rs
Normal file
67
pacman-server/src/config.rs
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
use figment::{providers::Env, value::UncasedStr, Figment};
|
||||||
|
use serde::{Deserialize, Deserializer};
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize)]
|
||||||
|
pub struct Config {
|
||||||
|
// Database URL
|
||||||
|
pub database_url: String,
|
||||||
|
// Discord Credentials
|
||||||
|
#[serde(deserialize_with = "deserialize_string_from_any")]
|
||||||
|
pub discord_client_id: String,
|
||||||
|
pub discord_client_secret: String,
|
||||||
|
// GitHub Credentials
|
||||||
|
#[serde(deserialize_with = "deserialize_string_from_any")]
|
||||||
|
pub github_client_id: String,
|
||||||
|
pub github_client_secret: String,
|
||||||
|
// S3 Credentials
|
||||||
|
pub s3_access_key: String,
|
||||||
|
pub s3_secret_access_key: String,
|
||||||
|
pub s3_endpoint: String,
|
||||||
|
pub s3_region: String,
|
||||||
|
// Server Details
|
||||||
|
#[serde(default = "default_port")]
|
||||||
|
pub port: u16,
|
||||||
|
#[serde(default = "default_host")]
|
||||||
|
pub host: std::net::IpAddr,
|
||||||
|
#[serde(default = "default_shutdown_timeout")]
|
||||||
|
pub shutdown_timeout_seconds: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn default_host() -> std::net::IpAddr {
|
||||||
|
"0.0.0.0".parse().unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn default_port() -> u16 {
|
||||||
|
3000
|
||||||
|
}
|
||||||
|
|
||||||
|
fn default_shutdown_timeout() -> u32 {
|
||||||
|
5
|
||||||
|
}
|
||||||
|
|
||||||
|
fn deserialize_string_from_any<'de, D>(deserializer: D) -> Result<String, D::Error>
|
||||||
|
where
|
||||||
|
D: Deserializer<'de>,
|
||||||
|
{
|
||||||
|
use serde_json::Value;
|
||||||
|
|
||||||
|
let value = Value::deserialize(deserializer)?;
|
||||||
|
match value {
|
||||||
|
Value::String(s) => Ok(s),
|
||||||
|
Value::Number(n) => Ok(n.to_string()),
|
||||||
|
_ => Err(serde::de::Error::custom("Expected string or number")),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn load_config() -> Config {
|
||||||
|
Figment::new()
|
||||||
|
.merge(Env::raw().map(|key| {
|
||||||
|
if key == UncasedStr::new("RAILWAY_DEPLOYMENT_DRAINING_SECONDS") {
|
||||||
|
"SHUTDOWN_TIMEOUT".into()
|
||||||
|
} else {
|
||||||
|
key.into()
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
.extract()
|
||||||
|
.expect("Failed to load config")
|
||||||
|
}
|
||||||
1
pacman-server/src/lib.rs
Normal file
1
pacman-server/src/lib.rs
Normal file
@@ -0,0 +1 @@
|
|||||||
|
|
||||||
@@ -1,3 +1,23 @@
|
|||||||
fn main() {
|
use axum::Router;
|
||||||
println!("Hello, world!");
|
|
||||||
|
use crate::config::Config;
|
||||||
|
|
||||||
|
mod config;
|
||||||
|
|
||||||
|
#[tokio::main]
|
||||||
|
async fn main() {
|
||||||
|
// Load environment variables
|
||||||
|
#[cfg(debug_assertions)]
|
||||||
|
dotenvy::from_path(format!("{}.env", env!("CARGO_MANIFEST_DIR"))).ok();
|
||||||
|
#[cfg(not(debug_assertions))]
|
||||||
|
dotenvy::dotenv().ok();
|
||||||
|
|
||||||
|
// Load configuration
|
||||||
|
let config: Config = config::load_config();
|
||||||
|
|
||||||
|
let app = Router::new().fallback(|| async { "Hello, World!" });
|
||||||
|
|
||||||
|
let addr = std::net::SocketAddr::new(config.host, config.port);
|
||||||
|
let listener = tokio::net::TcpListener::bind(addr).await.unwrap();
|
||||||
|
axum::serve(listener, app).await.unwrap();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user