Compare commits
13 Commits
6961c064c0
...
3c846f7b2c
| Author | SHA1 | Date |
|---|---|---|
|
|
3c846f7b2c | |
|
|
3782d3af2e | |
|
|
bef9698fc1 | |
|
|
f083d7e701 | |
|
|
3c5cdaef4f | |
|
|
49546a449e | |
|
|
7248ea8b90 | |
|
|
d0321f7ed1 | |
|
|
c5b579b8db | |
|
|
ec64638159 | |
|
|
826565dbae | |
|
|
d176fac420 | |
|
|
c177c04a74 |
|
|
@ -0,0 +1,2 @@
|
||||||
|
[alias]
|
||||||
|
runs = "run -- paper 1.19.4-545 --config data/config --backup data/backups --world data/worlds data/paper-1.19.4-545.jar"
|
||||||
|
|
@ -6,7 +6,7 @@ target/
|
||||||
|
|
||||||
# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
|
# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
|
||||||
# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html
|
# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html
|
||||||
Cargo.lock
|
#Cargo.lock
|
||||||
|
|
||||||
# These are backup files generated by rustfmt
|
# These are backup files generated by rustfmt
|
||||||
**/*.rs.bk
|
**/*.rs.bk
|
||||||
|
|
@ -16,3 +16,7 @@ Cargo.lock
|
||||||
# Added by cargo
|
# Added by cargo
|
||||||
|
|
||||||
/target
|
/target
|
||||||
|
|
||||||
|
# testing files
|
||||||
|
*.jar
|
||||||
|
data/
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
matrix:
|
||||||
|
ARCH:
|
||||||
|
- 'amd64'
|
||||||
|
- 'arm64'
|
||||||
|
|
||||||
|
platform: "linux/${ARCH}"
|
||||||
|
|
||||||
|
branches:
|
||||||
|
exclude: [main]
|
||||||
|
|
||||||
|
pipeline:
|
||||||
|
build:
|
||||||
|
image: 'rust:1.70-alpine3.18'
|
||||||
|
commands:
|
||||||
|
- apk add --no-cache build-base
|
||||||
|
- cargo build --verbose
|
||||||
|
- cargo test --verbose
|
||||||
|
# Binaries, even debug ones, should be statically compiled
|
||||||
|
- '[ "$(readelf -d target/debug/alex | grep NEEDED | wc -l)" = 0 ]'
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
platform: 'linux/amd64'
|
||||||
|
|
||||||
|
branches:
|
||||||
|
exclude: [main]
|
||||||
|
|
||||||
|
pipeline:
|
||||||
|
clippy:
|
||||||
|
image: 'rust:1.70'
|
||||||
|
commands:
|
||||||
|
- rustup component add clippy
|
||||||
|
- cargo clippy -- --no-deps -Dwarnings
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
platform: 'linux/amd64'
|
||||||
|
|
||||||
|
branches:
|
||||||
|
exclude: [main]
|
||||||
|
|
||||||
|
pipeline:
|
||||||
|
lint:
|
||||||
|
image: 'rust:1.70'
|
||||||
|
commands:
|
||||||
|
- rustup component add rustfmt
|
||||||
|
- cargo fmt -- --check
|
||||||
|
|
@ -0,0 +1,33 @@
|
||||||
|
matrix:
|
||||||
|
PLATFORM:
|
||||||
|
- 'linux/amd64'
|
||||||
|
# - 'linux/arm64'
|
||||||
|
|
||||||
|
platform: $PLATFORM
|
||||||
|
branches: [ main ]
|
||||||
|
|
||||||
|
pipeline:
|
||||||
|
build:
|
||||||
|
image: 'rust:1.70-alpine3.18'
|
||||||
|
commands:
|
||||||
|
- apk add --no-cache build-base
|
||||||
|
- cargo build --release --verbose
|
||||||
|
# Ensure the release binary is also statically compiled
|
||||||
|
- '[ "$(readelf -d target/release/alex | grep NEEDED | wc -l)" = 0 ]'
|
||||||
|
- du -h target/release/alex
|
||||||
|
- mv target/release/alex target/release/alex-$(echo '${PLATFORM}' | sed 's:/:-:g')"
|
||||||
|
when:
|
||||||
|
event: tag
|
||||||
|
|
||||||
|
publish:
|
||||||
|
image: 'plugins/gitea-release'
|
||||||
|
secrets:
|
||||||
|
- gitea_release_api_key
|
||||||
|
settings:
|
||||||
|
base_url: https://git.rustybever.be
|
||||||
|
files: target/release/alex-*
|
||||||
|
checksum:
|
||||||
|
- sha256
|
||||||
|
title: ${CI_COMMIT_TAG}
|
||||||
|
when:
|
||||||
|
event: tag
|
||||||
|
|
@ -0,0 +1,17 @@
|
||||||
|
# Changelog
|
||||||
|
|
||||||
|
All notable changes to this project will be documented in this file.
|
||||||
|
|
||||||
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||||
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
|
## [Unreleased](https://git.rustybever.be/Chewing_Bever/alex/src/branch/dev)
|
||||||
|
|
||||||
|
## [0.1.0](https://git.rustybever.be/Chewing_Bever/alex/src/tag/0.1.0)
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
* CLI interface
|
||||||
|
* Working backup command
|
||||||
|
* Thread for periodic backups
|
||||||
|
* Env var support
|
||||||
|
|
@ -0,0 +1,601 @@
|
||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
version = 3
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "adler"
|
||||||
|
version = "1.0.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "alex"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"chrono",
|
||||||
|
"clap",
|
||||||
|
"flate2",
|
||||||
|
"tar",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "android-tzdata"
|
||||||
|
version = "0.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "android_system_properties"
|
||||||
|
version = "0.1.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anstream"
|
||||||
|
version = "0.3.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0ca84f3628370c59db74ee214b3263d58f9aadd9b4fe7e711fd87dc452b7f163"
|
||||||
|
dependencies = [
|
||||||
|
"anstyle",
|
||||||
|
"anstyle-parse",
|
||||||
|
"anstyle-query",
|
||||||
|
"anstyle-wincon",
|
||||||
|
"colorchoice",
|
||||||
|
"is-terminal",
|
||||||
|
"utf8parse",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anstyle"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "41ed9a86bf92ae6580e0a31281f65a1b1d867c0cc68d5346e2ae128dddfa6a7d"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anstyle-parse"
|
||||||
|
version = "0.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e765fd216e48e067936442276d1d57399e37bce53c264d6fefbe298080cb57ee"
|
||||||
|
dependencies = [
|
||||||
|
"utf8parse",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anstyle-query"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b"
|
||||||
|
dependencies = [
|
||||||
|
"windows-sys",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "anstyle-wincon"
|
||||||
|
version = "1.0.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "180abfa45703aebe0093f79badacc01b8fd4ea2e35118747e5811127f926e188"
|
||||||
|
dependencies = [
|
||||||
|
"anstyle",
|
||||||
|
"windows-sys",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "autocfg"
|
||||||
|
version = "1.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bitflags"
|
||||||
|
version = "1.3.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bumpalo"
|
||||||
|
version = "3.13.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cc"
|
||||||
|
version = "1.0.79"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cfg-if"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "chrono"
|
||||||
|
version = "0.4.26"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ec837a71355b28f6556dbd569b37b3f363091c0bd4b2e735674521b4c5fd9bc5"
|
||||||
|
dependencies = [
|
||||||
|
"android-tzdata",
|
||||||
|
"iana-time-zone",
|
||||||
|
"js-sys",
|
||||||
|
"num-traits",
|
||||||
|
"time",
|
||||||
|
"wasm-bindgen",
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "clap"
|
||||||
|
version = "4.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b4ed2379f8603fa2b7509891660e802b88c70a79a6427a70abb5968054de2c28"
|
||||||
|
dependencies = [
|
||||||
|
"clap_builder",
|
||||||
|
"clap_derive",
|
||||||
|
"once_cell",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "clap_builder"
|
||||||
|
version = "4.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "72394f3339a76daf211e57d4bcb374410f3965dcc606dd0e03738c7888766980"
|
||||||
|
dependencies = [
|
||||||
|
"anstream",
|
||||||
|
"anstyle",
|
||||||
|
"bitflags",
|
||||||
|
"clap_lex",
|
||||||
|
"strsim",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "clap_derive"
|
||||||
|
version = "4.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "59e9ef9a08ee1c0e1f2e162121665ac45ac3783b0f897db7244ae75ad9a8f65b"
|
||||||
|
dependencies = [
|
||||||
|
"heck",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "clap_lex"
|
||||||
|
version = "0.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2da6da31387c7e4ef160ffab6d5e7f00c42626fe39aea70a7b0f1773f7dd6c1b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "colorchoice"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "core-foundation-sys"
|
||||||
|
version = "0.8.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crc32fast"
|
||||||
|
version = "1.3.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "errno"
|
||||||
|
version = "0.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a"
|
||||||
|
dependencies = [
|
||||||
|
"errno-dragonfly",
|
||||||
|
"libc",
|
||||||
|
"windows-sys",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "errno-dragonfly"
|
||||||
|
version = "0.1.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "filetime"
|
||||||
|
version = "0.2.21"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5cbc844cecaee9d4443931972e1289c8ff485cb4cc2767cb03ca139ed6885153"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"libc",
|
||||||
|
"redox_syscall",
|
||||||
|
"windows-sys",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "flate2"
|
||||||
|
version = "1.0.26"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3b9429470923de8e8cbd4d2dc513535400b4b3fef0319fb5c4e1f520a7bef743"
|
||||||
|
dependencies = [
|
||||||
|
"crc32fast",
|
||||||
|
"miniz_oxide",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "heck"
|
||||||
|
version = "0.4.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hermit-abi"
|
||||||
|
version = "0.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "iana-time-zone"
|
||||||
|
version = "0.1.56"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0722cd7114b7de04316e7ea5456a0bbb20e4adb46fd27a3697adb812cff0f37c"
|
||||||
|
dependencies = [
|
||||||
|
"android_system_properties",
|
||||||
|
"core-foundation-sys",
|
||||||
|
"iana-time-zone-haiku",
|
||||||
|
"js-sys",
|
||||||
|
"wasm-bindgen",
|
||||||
|
"windows",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "iana-time-zone-haiku"
|
||||||
|
version = "0.1.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "io-lifetimes"
|
||||||
|
version = "1.0.11"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2"
|
||||||
|
dependencies = [
|
||||||
|
"hermit-abi",
|
||||||
|
"libc",
|
||||||
|
"windows-sys",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "is-terminal"
|
||||||
|
version = "0.4.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "adcf93614601c8129ddf72e2d5633df827ba6551541c6d8c59520a371475be1f"
|
||||||
|
dependencies = [
|
||||||
|
"hermit-abi",
|
||||||
|
"io-lifetimes",
|
||||||
|
"rustix",
|
||||||
|
"windows-sys",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "js-sys"
|
||||||
|
version = "0.3.63"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2f37a4a5928311ac501dee68b3c7613a1037d0edb30c8e5427bd832d55d1b790"
|
||||||
|
dependencies = [
|
||||||
|
"wasm-bindgen",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libc"
|
||||||
|
version = "0.2.144"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2b00cc1c228a6782d0f076e7b232802e0c5689d41bb5df366f2a6b6621cfdfe1"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "linux-raw-sys"
|
||||||
|
version = "0.3.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "log"
|
||||||
|
version = "0.4.18"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "518ef76f2f87365916b142844c16d8fefd85039bc5699050210a7778ee1cd1de"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "miniz_oxide"
|
||||||
|
version = "0.7.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7"
|
||||||
|
dependencies = [
|
||||||
|
"adler",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-traits"
|
||||||
|
version = "0.2.15"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "once_cell"
|
||||||
|
version = "1.17.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9670a07f94779e00908f3e686eab508878ebb390ba6e604d3a284c00e8d0487b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "proc-macro2"
|
||||||
|
version = "1.0.59"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6aeca18b86b413c660b781aa319e4e2648a3e6f9eadc9b47e9038e6fe9f3451b"
|
||||||
|
dependencies = [
|
||||||
|
"unicode-ident",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "quote"
|
||||||
|
version = "1.0.28"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1b9ab9c7eadfd8df19006f1cf1a4aed13540ed5cbc047010ece5826e10825488"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "redox_syscall"
|
||||||
|
version = "0.2.16"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustix"
|
||||||
|
version = "0.37.19"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "acf8729d8542766f1b2cf77eb034d52f40d375bb8b615d0b147089946e16613d"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags",
|
||||||
|
"errno",
|
||||||
|
"io-lifetimes",
|
||||||
|
"libc",
|
||||||
|
"linux-raw-sys",
|
||||||
|
"windows-sys",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "strsim"
|
||||||
|
version = "0.10.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "syn"
|
||||||
|
version = "2.0.18"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "32d41677bcbe24c20c52e7c70b0d8db04134c5d1066bf98662e2871ad200ea3e"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"unicode-ident",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tar"
|
||||||
|
version = "0.4.38"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4b55807c0344e1e6c04d7c965f5289c39a8d94ae23ed5c0b57aabac549f871c6"
|
||||||
|
dependencies = [
|
||||||
|
"filetime",
|
||||||
|
"libc",
|
||||||
|
"xattr",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "time"
|
||||||
|
version = "0.1.45"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1b797afad3f312d1c66a56d11d0316f916356d11bd158fbc6ca6389ff6bf805a"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"wasi",
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-ident"
|
||||||
|
version = "1.0.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b15811caf2415fb889178633e7724bad2509101cde276048e013b9def5e51fa0"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "utf8parse"
|
||||||
|
version = "0.2.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wasi"
|
||||||
|
version = "0.10.0+wasi-snapshot-preview1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wasm-bindgen"
|
||||||
|
version = "0.2.86"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5bba0e8cb82ba49ff4e229459ff22a191bbe9a1cb3a341610c9c33efc27ddf73"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"wasm-bindgen-macro",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wasm-bindgen-backend"
|
||||||
|
version = "0.2.86"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "19b04bc93f9d6bdee709f6bd2118f57dd6679cf1176a1af464fca3ab0d66d8fb"
|
||||||
|
dependencies = [
|
||||||
|
"bumpalo",
|
||||||
|
"log",
|
||||||
|
"once_cell",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
"wasm-bindgen-shared",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wasm-bindgen-macro"
|
||||||
|
version = "0.2.86"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "14d6b024f1a526bb0234f52840389927257beb670610081360e5a03c5df9c258"
|
||||||
|
dependencies = [
|
||||||
|
"quote",
|
||||||
|
"wasm-bindgen-macro-support",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wasm-bindgen-macro-support"
|
||||||
|
version = "0.2.86"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e128beba882dd1eb6200e1dc92ae6c5dbaa4311aa7bb211ca035779e5efc39f8"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
"wasm-bindgen-backend",
|
||||||
|
"wasm-bindgen-shared",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wasm-bindgen-shared"
|
||||||
|
version = "0.2.86"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ed9d5b4305409d1fc9482fee2d7f9bcbf24b3972bf59817ef757e23982242a93"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winapi"
|
||||||
|
version = "0.3.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
|
||||||
|
dependencies = [
|
||||||
|
"winapi-i686-pc-windows-gnu",
|
||||||
|
"winapi-x86_64-pc-windows-gnu",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winapi-i686-pc-windows-gnu"
|
||||||
|
version = "0.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winapi-x86_64-pc-windows-gnu"
|
||||||
|
version = "0.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows"
|
||||||
|
version = "0.48.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f"
|
||||||
|
dependencies = [
|
||||||
|
"windows-targets",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-sys"
|
||||||
|
version = "0.48.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
|
||||||
|
dependencies = [
|
||||||
|
"windows-targets",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-targets"
|
||||||
|
version = "0.48.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5"
|
||||||
|
dependencies = [
|
||||||
|
"windows_aarch64_gnullvm",
|
||||||
|
"windows_aarch64_msvc",
|
||||||
|
"windows_i686_gnu",
|
||||||
|
"windows_i686_msvc",
|
||||||
|
"windows_x86_64_gnu",
|
||||||
|
"windows_x86_64_gnullvm",
|
||||||
|
"windows_x86_64_msvc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_aarch64_gnullvm"
|
||||||
|
version = "0.48.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_aarch64_msvc"
|
||||||
|
version = "0.48.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_i686_gnu"
|
||||||
|
version = "0.48.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_i686_msvc"
|
||||||
|
version = "0.48.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_x86_64_gnu"
|
||||||
|
version = "0.48.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_x86_64_gnullvm"
|
||||||
|
version = "0.48.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_x86_64_msvc"
|
||||||
|
version = "0.48.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "xattr"
|
||||||
|
version = "0.2.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6d1526bbe5aaeb5eb06885f4d987bcdfa5e23187055de9b83fe00156a821fabc"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
14
Cargo.toml
14
Cargo.toml
|
|
@ -1,19 +1,23 @@
|
||||||
[package]
|
[package]
|
||||||
name = "mc-wrapper"
|
name = "alex"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2018"
|
description = "Wrapper around Minecraft server processes, designed to complement Docker image installations."
|
||||||
|
authors = ["Jef Roosens"]
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
# Used for creating tarballs for backups
|
# Used for creating tarballs for backups
|
||||||
tar = "0.4.37"
|
tar = "0.4.38"
|
||||||
# Used to compress said tarballs using gzip
|
# Used to compress said tarballs using gzip
|
||||||
flate2 = "1.0.21"
|
flate2 = "1.0.26"
|
||||||
# Used for backup filenames
|
# Used for backup filenames
|
||||||
chrono = "0.4.19"
|
chrono = "0.4.26"
|
||||||
|
clap = { version = "4.3.1", features = ["derive", "env"] }
|
||||||
|
|
||||||
[profile.release]
|
[profile.release]
|
||||||
lto = "fat"
|
lto = "fat"
|
||||||
codegen-units = 1
|
codegen-units = 1
|
||||||
panic = "abort"
|
panic = "abort"
|
||||||
|
strip = true
|
||||||
|
|
|
||||||
92
src/main.rs
92
src/main.rs
|
|
@ -1,18 +1,98 @@
|
||||||
use std::io;
|
|
||||||
|
|
||||||
mod server;
|
mod server;
|
||||||
|
|
||||||
|
use clap::Parser;
|
||||||
|
use server::ServerType;
|
||||||
|
use std::io;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
|
#[derive(Parser)]
|
||||||
|
#[command(author, version, about, long_about = None)]
|
||||||
|
struct Cli {
|
||||||
|
/// Type of server
|
||||||
|
type_: ServerType,
|
||||||
|
/// Version string for the server, e.g. 1.19.4-545
|
||||||
|
server_version: String,
|
||||||
|
/// Server jar to execute
|
||||||
|
jar: PathBuf,
|
||||||
|
|
||||||
|
/// Directory where configs are stored, and where the server will run [default: .]
|
||||||
|
#[arg(long, value_name = "CONFIG_DIR", env = "ALEX_CONFIG_DIR")]
|
||||||
|
config: Option<PathBuf>,
|
||||||
|
/// Directory where world files will be saved [default: ../worlds]
|
||||||
|
#[arg(long, value_name = "WORLD_DIR", env = "ALEX_WORLD_DIR")]
|
||||||
|
world: Option<PathBuf>,
|
||||||
|
/// Directory where backups will be stored [default: ../backups]
|
||||||
|
#[arg(long, value_name = "BACKUP_DIR", env = "ALEX_WORLD_DIR")]
|
||||||
|
backup: Option<PathBuf>,
|
||||||
|
/// Java command to run the server jar with
|
||||||
|
#[arg(long, value_name = "JAVA_CMD", default_value_t = String::from("java"), env = "ALEX_JAVA")]
|
||||||
|
java: String,
|
||||||
|
|
||||||
|
/// XMS value in megabytes for the server instance
|
||||||
|
#[arg(long, default_value_t = 1024, env = "ALEX_XMS")]
|
||||||
|
xms: u64,
|
||||||
|
/// XMX value in megabytes for the server instance
|
||||||
|
#[arg(long, default_value_t = 2048, env = "ALEX_XMX")]
|
||||||
|
xmx: u64,
|
||||||
|
|
||||||
|
/// How many backups to keep
|
||||||
|
#[arg(short = 'n', long, default_value_t = 7, env = "ALEX_MAX_BACKUPS")]
|
||||||
|
max_backups: u64,
|
||||||
|
/// How frequently to perform a backup, in minutes; 0 to disable.
|
||||||
|
#[arg(short = 't', long, default_value_t = 0, env = "ALEX_FREQUENCY")]
|
||||||
|
frequency: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn backups_thread(counter: Arc<Mutex<server::ServerProcess>>, frequency: u64) {
|
||||||
|
loop {
|
||||||
|
std::thread::sleep(std::time::Duration::from_secs(frequency * 60));
|
||||||
|
|
||||||
|
{
|
||||||
|
let mut server = counter.lock().unwrap();
|
||||||
|
|
||||||
|
// We explicitely ignore the error here, as we don't want the thread to fail
|
||||||
|
let _ = server.backup();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let mut server = server::Server::spawn();
|
let cli = Cli::parse();
|
||||||
|
|
||||||
|
let cmd = server::ServerCommand::new(cli.type_, &cli.server_version)
|
||||||
|
.java(&cli.java)
|
||||||
|
.jar(cli.jar)
|
||||||
|
.config(cli.config.unwrap_or(".".into()))
|
||||||
|
.world(cli.world.unwrap_or("../worlds".into()))
|
||||||
|
.backup(cli.backup.unwrap_or("../backups".into()))
|
||||||
|
.xms(cli.xms)
|
||||||
|
.xmx(cli.xmx)
|
||||||
|
.max_backups(cli.max_backups);
|
||||||
|
let counter = Arc::new(Mutex::new(cmd.spawn().expect("Failed to start server.")));
|
||||||
|
|
||||||
|
if cli.frequency > 0 {
|
||||||
|
let clone = Arc::clone(&counter);
|
||||||
|
std::thread::spawn(move || backups_thread(clone, cli.frequency));
|
||||||
|
}
|
||||||
|
|
||||||
let stdin = io::stdin();
|
let stdin = io::stdin();
|
||||||
let input = &mut String::new();
|
let input = &mut String::new();
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
input.clear();
|
input.clear();
|
||||||
stdin.read_line(input);
|
|
||||||
println!("input: {}", input.trim());
|
if stdin.read_line(input).is_err() {
|
||||||
server.send_command(input);
|
continue;
|
||||||
|
};
|
||||||
|
|
||||||
|
{
|
||||||
|
let mut server = counter.lock().unwrap();
|
||||||
|
|
||||||
|
if let Err(e) = server.send_command(input) {
|
||||||
|
println!("{}", e);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
if input.trim() == "stop" {
|
if input.trim() == "stop" {
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
|
|
@ -1,60 +0,0 @@
|
||||||
use std::io;
|
|
||||||
use std::io::Write;
|
|
||||||
use std::process::{Child, Command, Stdio};
|
|
||||||
use std::fs::File;
|
|
||||||
use flate2::Compression;
|
|
||||||
use flate2::write::GzEncoder;
|
|
||||||
|
|
||||||
pub struct Server {
|
|
||||||
child: Child,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Server {
|
|
||||||
pub fn spawn() -> Server {
|
|
||||||
let child = Command::new("/usr/lib/jvm/java-16-openjdk/bin/java")
|
|
||||||
.arg("-jar")
|
|
||||||
.arg("paper-1.17.1-259.jar")
|
|
||||||
.arg("--universe")
|
|
||||||
.arg("worlds")
|
|
||||||
.arg("--nogui")
|
|
||||||
.stdin(Stdio::piped())
|
|
||||||
.spawn()
|
|
||||||
.expect("Couldn't start child process");
|
|
||||||
|
|
||||||
Server { child }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn send_command(&mut self, cmd: &str) {
|
|
||||||
match cmd.trim() {
|
|
||||||
"stop" | "exit" => self.stop(),
|
|
||||||
"backup" => self.backup(),
|
|
||||||
s => self.custom(s),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn custom(&mut self, cmd: &str) {
|
|
||||||
let mut stdin = self.child.stdin.as_ref().unwrap();
|
|
||||||
stdin.write_all(format!("{}\n", cmd.trim()).as_bytes()).unwrap();
|
|
||||||
stdin.flush().unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn stop(&mut self) {
|
|
||||||
self.custom("stop");
|
|
||||||
self.child.wait();
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn backup(&mut self) {
|
|
||||||
// Make sure the server isn't modifying the files during the backup
|
|
||||||
self.custom("save-off");
|
|
||||||
self.custom("save-all");
|
|
||||||
|
|
||||||
// Create a gzip-compressed tarball of the worlds folder
|
|
||||||
let filename = format!("{}", chrono::offset::Local::now().format("backups/%Y-%m-%d_%H-%M-%S.tar.gz"));
|
|
||||||
let tar_gz = std::fs::File::create(filename).unwrap();
|
|
||||||
let enc = GzEncoder::new(tar_gz, Compression::default());
|
|
||||||
let mut tar = tar::Builder::new(enc);
|
|
||||||
tar.append_dir_all("worlds", "worlds").unwrap();
|
|
||||||
|
|
||||||
self.custom("save-on");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1,137 @@
|
||||||
|
use crate::server::ServerProcess;
|
||||||
|
use clap::ValueEnum;
|
||||||
|
use std::fmt;
|
||||||
|
use std::fs::File;
|
||||||
|
use std::io::Write;
|
||||||
|
use std::path::{Path, PathBuf};
|
||||||
|
use std::process::{Command, Stdio};
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, ValueEnum)]
|
||||||
|
pub enum ServerType {
|
||||||
|
Paper,
|
||||||
|
Forge,
|
||||||
|
Vanilla,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for ServerType {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
let s = match self {
|
||||||
|
ServerType::Paper => "PaperMC",
|
||||||
|
ServerType::Forge => "Forge",
|
||||||
|
ServerType::Vanilla => "Vanilla",
|
||||||
|
};
|
||||||
|
|
||||||
|
write!(f, "{}", s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct ServerCommand {
|
||||||
|
type_: ServerType,
|
||||||
|
version: String,
|
||||||
|
java: String,
|
||||||
|
jar: PathBuf,
|
||||||
|
config_dir: PathBuf,
|
||||||
|
world_dir: PathBuf,
|
||||||
|
backup_dir: PathBuf,
|
||||||
|
xms: u64,
|
||||||
|
xmx: u64,
|
||||||
|
max_backups: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ServerCommand {
|
||||||
|
pub fn new(type_: ServerType, version: &str) -> Self {
|
||||||
|
ServerCommand {
|
||||||
|
type_,
|
||||||
|
version: String::from(version),
|
||||||
|
java: String::from("java"),
|
||||||
|
jar: PathBuf::from("server.jar"),
|
||||||
|
config_dir: PathBuf::from("config"),
|
||||||
|
world_dir: PathBuf::from("worlds"),
|
||||||
|
backup_dir: PathBuf::from("backups"),
|
||||||
|
xms: 1024,
|
||||||
|
xmx: 2048,
|
||||||
|
max_backups: 7,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn java(mut self, java: &str) -> Self {
|
||||||
|
self.java = String::from(java);
|
||||||
|
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn jar<T: AsRef<Path>>(mut self, path: T) -> Self {
|
||||||
|
self.jar = PathBuf::from(path.as_ref());
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn config<T: AsRef<Path>>(mut self, path: T) -> Self {
|
||||||
|
self.config_dir = PathBuf::from(path.as_ref());
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn world<T: AsRef<Path>>(mut self, path: T) -> Self {
|
||||||
|
self.world_dir = PathBuf::from(path.as_ref());
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn backup<T: AsRef<Path>>(mut self, path: T) -> Self {
|
||||||
|
self.backup_dir = PathBuf::from(path.as_ref());
|
||||||
|
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn xms(mut self, v: u64) -> Self {
|
||||||
|
self.xms = v;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn xmx(mut self, v: u64) -> Self {
|
||||||
|
self.xmx = v;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn max_backups(mut self, v: u64) -> Self {
|
||||||
|
self.max_backups = v;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
fn accept_eula(&self) -> std::io::Result<()> {
|
||||||
|
let mut eula_path = self.config_dir.clone();
|
||||||
|
eula_path.push("eula.txt");
|
||||||
|
let mut eula_file = File::create(eula_path)?;
|
||||||
|
eula_file.write_all(b"eula=true")?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn spawn(self) -> std::io::Result<ServerProcess> {
|
||||||
|
// To avoid any issues, we use absolute paths for everything when spawning the process
|
||||||
|
let jar = self.jar.canonicalize()?;
|
||||||
|
let config_dir = self.config_dir.canonicalize()?;
|
||||||
|
let world_dir = self.world_dir.canonicalize()?;
|
||||||
|
let backup_dir = self.backup_dir.canonicalize()?;
|
||||||
|
|
||||||
|
self.accept_eula()?;
|
||||||
|
|
||||||
|
let child = Command::new(&self.java)
|
||||||
|
.current_dir(&config_dir)
|
||||||
|
.arg("-jar")
|
||||||
|
.arg(&jar)
|
||||||
|
.arg("--universe")
|
||||||
|
.arg(&world_dir)
|
||||||
|
.arg("--nogui")
|
||||||
|
.stdin(Stdio::piped())
|
||||||
|
.spawn()?;
|
||||||
|
|
||||||
|
Ok(ServerProcess::new(
|
||||||
|
self.type_,
|
||||||
|
self.version,
|
||||||
|
config_dir,
|
||||||
|
world_dir,
|
||||||
|
backup_dir,
|
||||||
|
self.max_backups,
|
||||||
|
child,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
mod command;
|
||||||
|
mod process;
|
||||||
|
|
||||||
|
pub use command::{ServerCommand, ServerType};
|
||||||
|
pub use process::ServerProcess;
|
||||||
|
|
@ -0,0 +1,159 @@
|
||||||
|
use crate::server::ServerType;
|
||||||
|
use flate2::write::GzEncoder;
|
||||||
|
use flate2::Compression;
|
||||||
|
use std::io::Write;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
use std::process::Child;
|
||||||
|
|
||||||
|
#[link(name = "c")]
|
||||||
|
extern "C" {
|
||||||
|
fn geteuid() -> u32;
|
||||||
|
fn getegid() -> u32;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct ServerProcess {
|
||||||
|
type_: ServerType,
|
||||||
|
version: String,
|
||||||
|
config_dir: PathBuf,
|
||||||
|
world_dir: PathBuf,
|
||||||
|
backup_dir: PathBuf,
|
||||||
|
max_backups: u64,
|
||||||
|
child: Child,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ServerProcess {
|
||||||
|
pub fn new(
|
||||||
|
type_: ServerType,
|
||||||
|
version: String,
|
||||||
|
config_dir: PathBuf,
|
||||||
|
world_dir: PathBuf,
|
||||||
|
backup_dir: PathBuf,
|
||||||
|
max_backups: u64,
|
||||||
|
child: Child,
|
||||||
|
) -> ServerProcess {
|
||||||
|
ServerProcess {
|
||||||
|
type_,
|
||||||
|
version,
|
||||||
|
config_dir,
|
||||||
|
world_dir,
|
||||||
|
backup_dir,
|
||||||
|
max_backups,
|
||||||
|
child,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn send_command(&mut self, cmd: &str) -> std::io::Result<()> {
|
||||||
|
match cmd.trim() {
|
||||||
|
"stop" | "exit" => self.stop()?,
|
||||||
|
"backup" => self.backup()?,
|
||||||
|
s => self.custom(s)?,
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn custom(&mut self, cmd: &str) -> std::io::Result<()> {
|
||||||
|
let mut stdin = self.child.stdin.as_ref().unwrap();
|
||||||
|
stdin.write_all(format!("{}\n", cmd.trim()).as_bytes())?;
|
||||||
|
stdin.flush()?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn stop(&mut self) -> std::io::Result<()> {
|
||||||
|
self.custom("stop")?;
|
||||||
|
self.child.wait()?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Perform a backup by disabling the server's save feature and flushing its data, before
|
||||||
|
/// creating an archive file.
|
||||||
|
pub fn backup(&mut self) -> std::io::Result<()> {
|
||||||
|
self.custom("say backing up server")?;
|
||||||
|
|
||||||
|
// Make sure the server isn't modifying the files during the backup
|
||||||
|
self.custom("save-off")?;
|
||||||
|
self.custom("save-all")?;
|
||||||
|
|
||||||
|
// TODO implement a better mechanism
|
||||||
|
// We wait some time to (hopefully) ensure the save-all call has completed
|
||||||
|
std::thread::sleep(std::time::Duration::from_secs(10));
|
||||||
|
|
||||||
|
let res = self.create_backup_archive();
|
||||||
|
|
||||||
|
if res.is_ok() {
|
||||||
|
self.remove_old_backups()?;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The server's save feature needs to be enabled again even if the archive failed to create
|
||||||
|
self.custom("save-on")?;
|
||||||
|
|
||||||
|
self.custom("say server backed up successfully")?;
|
||||||
|
|
||||||
|
res
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a new compressed backup archive of the server's data.
|
||||||
|
fn create_backup_archive(&mut self) -> std::io::Result<()> {
|
||||||
|
// Create a gzip-compressed tarball of the worlds folder
|
||||||
|
let filename = format!(
|
||||||
|
"{}",
|
||||||
|
chrono::offset::Local::now().format("%Y-%m-%d_%H-%M-%S.tar.gz")
|
||||||
|
);
|
||||||
|
let path = self.backup_dir.join(filename);
|
||||||
|
let tar_gz = std::fs::File::create(path)?;
|
||||||
|
let enc = GzEncoder::new(tar_gz, Compression::default());
|
||||||
|
let mut tar = tar::Builder::new(enc);
|
||||||
|
|
||||||
|
tar.append_dir_all("worlds", &self.world_dir)?;
|
||||||
|
|
||||||
|
// We don't store all files in the config, as this would include caches
|
||||||
|
tar.append_path_with_name(
|
||||||
|
self.config_dir.join("server.properties"),
|
||||||
|
"config/server.properties",
|
||||||
|
)?;
|
||||||
|
|
||||||
|
// We add a file to the backup describing for what version it was made
|
||||||
|
let info = format!("{} {}", self.type_, self.version);
|
||||||
|
let info_bytes = info.as_bytes();
|
||||||
|
|
||||||
|
let mut header = tar::Header::new_gnu();
|
||||||
|
header.set_size(info_bytes.len().try_into().unwrap());
|
||||||
|
header.set_mode(0o100644);
|
||||||
|
unsafe {
|
||||||
|
header.set_gid(getegid().into());
|
||||||
|
header.set_uid(geteuid().into());
|
||||||
|
}
|
||||||
|
|
||||||
|
tar.append_data(&mut header, "info.txt", info_bytes)?;
|
||||||
|
|
||||||
|
// tar.append_dir_all("config", &self.config_dir)?;
|
||||||
|
|
||||||
|
// Backup file gets finalized in the drop
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Remove the oldest backups
|
||||||
|
fn remove_old_backups(&mut self) -> std::io::Result<()> {
|
||||||
|
// The naming format used allows us to sort the backups by name and still get a sorting by
|
||||||
|
// creation time
|
||||||
|
let mut backups = std::fs::read_dir(&self.backup_dir)?
|
||||||
|
.filter_map(|res| res.map(|e| e.path()).ok())
|
||||||
|
.collect::<Vec<PathBuf>>();
|
||||||
|
backups.sort();
|
||||||
|
|
||||||
|
let max_backups: usize = self.max_backups.try_into().unwrap();
|
||||||
|
|
||||||
|
if backups.len() > max_backups {
|
||||||
|
let excess_backups = backups.len() - max_backups;
|
||||||
|
|
||||||
|
for backup in &backups[0..excess_backups] {
|
||||||
|
std::fs::remove_file(backup)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue