328 lines
11 KiB
Markdown
328 lines
11 KiB
Markdown
# 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
|
||
```
|