# MrixsCraft Private Minecraft server project with a web-based launcher. Consists of two independent Go repositories unified via git submodules: - **`server/`** — backend (Go + net/http + PostgreSQL) - **`launcher/`** — desktop launcher (Go + Fyne GUI) Domain: `minecraft.mrixs.me` · CDN: `cdn.mrixs.me` --- ## Architecture ``` ┌─────────────┐ HTTP/API ┌──────────────┐ │ Launcher │ ◄──────────────► │ Server │ │ (Go+Fyne) │ Yggdrasil+REST │ (Go+pgx) │ └─────────────┘ └──────┬──────┘ │ ┌──────┴──────┐ │ PostgreSQL │ │ 16 │ └─────────────┘ cdn.mrixs.me minecraft.mrixs.me ┌──────────┐ ┌────────────────┐ │ Caddy │ │ Caddy │ │ file srv │ │ reverse proxy │ │ (CAS) │ │ + HTTPS │ └──────────┘ └────────────────┘ ``` **Infrastructure (Docker Compose):** Caddy · Go backend · PostgreSQL 16 · Watchtower (auto-update) --- ## Directory Structure ``` MC-server/ ├── .gitmodules # Submodules: launcher, server ├── docs/ │ ├── state.md # Project status and detailed architecture │ ├── launcher/Specification.md # Launcher specification (RU) │ └── server/Specification.md # Server specification (RU) ├── launcher/ # Git submodule — MrixsCraft-launcher │ ├── cmd/launcher/main.go │ └── internal/ │ ├── auth/ # Yggdrasil client │ ├── config/ # Launcher settings & system paths │ ├── fetcher/ # HTTP downloader with SHA-1 verification │ ├── java/ # JRE detection/download │ ├── launch/ # Manifest parsing, game launch, classpath assembly │ ├── selfupdate/# Binary auto-updater (SHA-256) │ └── ui/ # Fyne GUI (screens, components, theme) └── server/ # Git submodule — MrixsCraft-server ├── cmd/ │ ├── server/main.go # HTTP routes, middleware, graceful shutdown │ └── ci-release/main.go # CI release uploader ├── Dockerfile # Multi-stage (~20 MB) ├── docker-compose.yml # Caddy + backend + postgres + watchtower ├── Caddyfile # Reverse proxy, CDN, HTTPS ├── .gitea/workflows/ci.yml # CI: lint → test → build → docker push ├── migrations/ │ ├── 001_init.sql # Full schema: 6 tables + indexes │ └── 002_migration_history.sql # Migration tracking └── internal/ ├── admin/ # Modpack CRUD, file upload, manifests ├── api/ # Public API: auth, skins, capes, launcher ├── auth/ # Yggdrasil: authenticate/refresh/validate ├── cas/ # Content-Addressable Storage (SHA-1) ├── config/ # ENV configuration ├── database/ # PostgreSQL (pgx/pgxpool), data models ├── middleware/ # CORS, Logging, Recovery, RateLimiter ├── session/ # Background expired-session cleanup └── templates/ # Go html/template (dark theme) ``` --- ## Tech Stack | Component | Technology | |-----------|-----------| | Language | Go 1.25 (server) · Go 1.22 (launcher) | | HTTP | net/http (stdlib) | | Database | PostgreSQL 16 + pgx/v5 | | Hashing | SHA-1 (CAS) · SHA-256 (launcher releases) · bcrypt (passwords) | | GUI | Fyne v2.4.5 | | Auth | Custom Yggdrasil server + authlib-injector | | Proxy | Caddy 2 (auto-HTTPS) | | Containers | Docker + Docker Compose | | Registry | Gitea Container Registry | | CI/CD | Gitea Actions | | Auto-update | Watchtower | --- ## Getting Started ### Prerequisites - Go 1.25+ (server) / Go 1.22+ (launcher) - Docker & Docker Compose (production) - PostgreSQL 16 (if running without Docker) ### Clone with Submodules ```bash git clone --recurse-submodules gitea.mrixs.me:mrixs/mrixscraft.git MC-server ``` If already cloned without submodules: ```bash git submodule update --init --recursive ``` ### Server ```bash cd server/ # Configure cp .env.example .env # edit .env: DATABASE_URL, JWT_SECRET, etc. # Run locally go run ./cmd/server # Or via Docker Compose docker compose up -d ``` **Required environment variables:** | Variable | Default | Required | |----------|---------|----------| | `SERVER_PORT` | `8080` | No | | `DATABASE_URL` | — | **Yes** | | `CAS_DIR` | `/var/www/cdn/files` | No | | `JWT_SECRET` | — | **Yes** | ### Launcher ```bash cd launcher/ go build -o mrixscraft-launcher ./cmd/launcher ./mrixscraft-launcher ``` Or: `go run ./cmd/launcher` --- ## Server API ### Yggdrasil (Mojang-compatible) | Method | Path | Description | |--------|------|-------------| | POST | `/authserver/authenticate` | Login with credentials | | POST | `/authserver/refresh` | Refresh token | | POST | `/authserver/validate` | Validate token (204) | | POST | `/authserver/invalidate` | Invalidate token | | POST | `/authserver/signout` | Sign out (delete all sessions) | | GET | `/sessionserver/session/minecraft/profile/{uuid}` | Player profile with textures | ### Public API | Method | Path | Description | |--------|------|-------------| | POST | `/api/web/register` | Player registration | | POST | `/api/web/login` | Website login | | POST | `/api/web/profile/skin` | Upload skin (PNG) | | POST | `/api/web/profile/cape` | Upload cape (PNG) | | DELETE | `/api/web/profile/skin` | Delete skin | | GET | `/api/web/profile/{uuid}` | Player profile | ### Launcher API | Method | Path | Description | |--------|------|-------------| | GET | `/api/launcher/latest` | Latest launcher version | | GET | `/api/servers.json` | Active modpack list | | GET | `/api/instances/{slug}/manifest.json` | Modpack manifest | ### CAS (File Server) | Method | Path | Description | |--------|------|-------------| | GET | `/files/{sha1}` | File by SHA-1 hash | | GET | `/files/launcher/{version}/{os}/{arch}/{filename}` | Launcher binary | | GET | `/skins/{hash}` | Skin/cape by hash | ### Admin (Bearer token + role=admin) | Method | Path | Description | |--------|------|-------------| | GET | `/api/admin/modpacks` | List modpacks | | POST | `/api/admin/modpacks` | Create modpack | | PUT | `/api/admin/modpacks/{id}` | Update modpack | | DELETE | `/api/admin/modpacks/{id}` | Deactivate modpack | | POST | `/api/admin/modpacks/{slug}/upload` | Upload files (≤500 MB) | | POST | `/api/admin/modpacks/{slug}/manifest` | Generate manifest.json | | POST | `/api/admin/launcher/release` | Upload launcher release (X-CI-Token) | | GET | `/admin` | Web admin interface (requires admin role) | --- ## Content-Addressable Storage (CAS) All files (mods, libraries, assets) are stored by their SHA-1 hash: ``` /var/www/cdn/files/ab/abcdef1234... (first 2 chars as subdirectory) ``` - **Immutable** — files are never overwritten - **Cache-Control:** `public, max-age=31536000, immutable` (1 year) - **Deduplication** — automatic (same hash = same file) - **Concurrent-safe** — per-hash `sync.Mutex` prevents race conditions - **Verification** — constant-time SHA-1 comparison --- ## Database Schema 7 tables: | Table | Purpose | |-------|---------| | `users` | Players (username, email, password_hash, uuid, role) | | `player_textures` | Skins & capes (skin_hash, cape_hash → CAS) | | `yggdrasil_sessions` | Auth sessions (access_token, client_token, expires_at) | | `modpacks` | Modpacks/servers (slug, name, minecraft_version, java_version, server_ip) | | `global_files` | CAS file registry (sha1 PK, size_bytes, file_name, mime_type) | | `launcher_releases` | Launcher releases (version, os, arch, sha256, file_path) | | `migration_history` | Applied migration tracking | Migrations are applied manually: `psql $DATABASE_URL -f migrations/001_init.sql` --- ## Launcher Client File Structure | OS | Root Directory | |----|---------------| | Windows | `%APPDATA%\MrixsCraft\` | | macOS | `~/Library/Application Support/MrixsCraft/` | | Linux | `~/.MrixsCraft/` | ``` MrixsCraft/ ├── launcher.json # Settings (RAM, server URL, window) ├── session.json # Yggdrasil tokens ├── authlib-injector.jar # Auth interceptor ├── Java/{8,17,21}/ # Portable JREs ├── assets/ # Game assets ├── libraries/ # Shared libraries (LWJGL, etc.) └── instances/{slug}/ # Isolated modpack clients ├── mods/ ├── mods_backup/ # Unknown mods moved here (soft delete) ├── config/ └── resourcepacks/ ``` --- ## Testing ```bash # Server cd server/ go test ./... -v -race -cover # Launcher — no tests (GUI testing is impractical) ``` Server test coverage: `cas`, `auth`, `api`, `session` packages. --- ## CI/CD Gitea Actions pipeline (`.gitea/workflows/ci.yml`): ``` lint (go vet + gofmt) → test (race detector) → build → docker push (master only) ``` Images: `gitea.mrixs.me/mrixs/mrixscraft-server:latest` + `:sha` Watchtower on VPS polls every 5 minutes and auto-deploys new images. --- ## Known TODOs ### Server - Full-text file search in DB - SIGHUP config reload (requires `config.Atomic` refactor) ### Launcher - PLAY button wired to `launch.Prepare` + `Game.Start` (stub) - Server list hardcoded (not loaded from `/api/servers.json`) - Java auto-download not implemented - Skin avatar rendering (8×64 face crop) - News/patchnotes on MainScreen - `servers.dat` NBT manipulation ### Infrastructure - CI deploy step (SSH + docker compose up) — needs secrets - Automatic Go migration runner (currently manual) - Backup script not in cron --- ## Commands Reference ```bash # Server cd server/ go build -o mrixscraft-server ./cmd/server go test ./... go run ./cmd/server docker compose up -d # Launcher cd launcher/ go build -o mrixscraft-launcher ./cmd/launcher go run ./cmd/launcher ```