refactor: 重构Minecraft服务器自动化管理方案

## 重构内容

### 新增自动化脚本系统 (scripts/)
- utils.sh: 通用工具库(日志、Docker操作、备份、网络检查)
- setup.sh: 环境初始化脚本(目录结构、权限、配置验证)
- mod-manager.sh: Mods管理(Modrinth下载、更新、清理)
- backup.sh: 备份管理(世界/配置/mods备份、恢复、清理)
- monitor.sh: 服务器监控(状态、资源、玩家、日志分析)

### 增强Makefile集成
新增命令:
- minecraft-status: 服务器状态检查
- minecraft-setup: 环境初始化
- minecraft-mods-*: Mods管理命令
- minecraft-backup-*: 备份管理命令

### 完善文档
- 重写README: 详细的使用指南、故障排查、迁移指南
- 新增CHANGELOG: 完整的重构说明和技术细节

## 架构改进

### 整合原有设计
- 继承src/automatic/的日志系统设计
- 改进Modrinth API集成逻辑
- 优化部署流程和备份机制

### 新增优势
- Docker优先的容器化方案
- 模块化脚本设计,职责单一
- Makefile统一管理入口
- 完整的生命周期自动化

## 技术特性

- 完善的错误处理和日志记录
- macOS/Linux跨平台兼容
- 敏感信息安全管理
- 持续监控模式

## 向后兼容

- 保留src/automatic/旧脚本(供参考)
- 配置文件格式完全兼容
- Docker Compose配置无变化
This commit is contained in:
m1ngsama 2025-12-09 10:00:00 +08:00
parent 4ff60014df
commit 0fe7ed79ad
8 changed files with 2098 additions and 16 deletions

View file

@ -16,10 +16,19 @@ help:
@echo " all-down Stop all services"
@echo ""
@echo "Service-specific Commands:"
@echo " minecraft-up Start Minecraft server"
@echo " minecraft-down Stop Minecraft server"
@echo " minecraft-logs View Minecraft logs"
@echo " minecraft-restart Restart Minecraft server"
@echo " Minecraft:"
@echo " minecraft-up Start Minecraft server"
@echo " minecraft-down Stop Minecraft server"
@echo " minecraft-logs View Minecraft logs"
@echo " minecraft-restart Restart Minecraft server"
@echo " minecraft-status Show server status"
@echo " minecraft-setup Initialize environment"
@echo " minecraft-mods-download Download mods from Modrinth"
@echo " minecraft-mods-list List installed mods"
@echo " minecraft-mods-update Update all mods"
@echo " minecraft-backup Create full backup"
@echo " minecraft-backup-world Backup world data only"
@echo " minecraft-backup-list List available backups"
@echo ""
@echo " teamspeak-up Start TeamSpeak server"
@echo " teamspeak-down Stop TeamSpeak server"
@ -87,6 +96,36 @@ minecraft-restart:
@cd minecraft && docker compose restart
@echo "✓ Minecraft server restarted"
minecraft-status:
@cd minecraft && ./scripts/monitor.sh status
minecraft-setup:
@cd minecraft && ./scripts/setup.sh
minecraft-mods-download:
@cd minecraft && ./scripts/mod-manager.sh download
minecraft-mods-list:
@cd minecraft && ./scripts/mod-manager.sh list
minecraft-mods-update:
@cd minecraft && ./scripts/mod-manager.sh update
minecraft-mods-check:
@cd minecraft && ./scripts/mod-manager.sh check
minecraft-backup:
@cd minecraft && ./scripts/backup.sh backup all
minecraft-backup-world:
@cd minecraft && ./scripts/backup.sh backup world
minecraft-backup-list:
@cd minecraft && ./scripts/backup.sh list
minecraft-backup-cleanup:
@cd minecraft && ./scripts/backup.sh cleanup
# TeamSpeak
teamspeak-up:
@cd teamspeak && docker compose up -d

184
minecraft/CHANGELOG.md Normal file
View file

@ -0,0 +1,184 @@
# Minecraft 自动化方案重构日志
## 2025-12-09 - 自动化架构重构
### 🎯 重构目标
整合原有的本地部署方案(`src/automatic/`)和 Docker Compose 方案,提供统一的自动化管理系统。
### ✨ 新增功能
#### 1. 统一的脚本体系
创建 `scripts/` 目录,包含以下模块:
- **utils.sh** - 通用工具库
- 彩色日志输出
- Docker 环境检查
- 容器状态管理
- 文件备份工具
- 网络连接检测
- **setup.sh** - 环境初始化
- 系统环境检查
- 目录结构初始化
- 配置文件验证
- 权限自动修复
- **mod-manager.sh** - Mods 管理
- 从 Modrinth 自动下载
- 批量更新 mods
- 列出已安装 mods
- 清理和状态检查
- **backup.sh** - 备份管理
- 世界数据备份
- 配置文件备份
- Mods 备份
- 备份恢复功能
- 自动清理旧备份
- **monitor.sh** - 服务器监控
- 容器状态检查
- 资源使用监控
- 在线玩家查询
- 日志分析
- 持续监控模式
#### 2. Makefile 集成
在根目录 `Makefile` 中新增命令:
**服务器管理**
- `make minecraft-status` - 查看服务器状态
- `make minecraft-setup` - 初始化环境
**Mods 管理**
- `make minecraft-mods-download` - 下载 mods
- `make minecraft-mods-list` - 列出 mods
- `make minecraft-mods-update` - 更新 mods
- `make minecraft-mods-check` - 检查状态
**备份管理**
- `make minecraft-backup` - 完整备份
- `make minecraft-backup-world` - 备份世界
- `make minecraft-backup-list` - 列出备份
- `make minecraft-backup-cleanup` - 清理备份
#### 3. 完整的文档
重写 `minecraft/README.md`
- 详细的快速开始指南
- 完整的命令参考
- 高级用法示例
- 故障排查指南
- 迁移指南
### 🔄 架构改进
#### 从旧方案继承的优点
1. **日志系统**
- 保留了 `logger.sh` 的彩色输出设计
- 增强了日志功能(系统信息、时间戳、文件记录)
2. **Mods 下载逻辑**
- 基于 `download-mods.sh` 改进
- 统一使用 `extras/mods.txt` 格式
- 增加错误处理和重试机制
3. **部署流程**
- 参考 `deploy.sh` 的备份逻辑
- 适配 Docker Compose 环境
#### 新增的优势
1. **Docker 优先**
- 完全容器化部署
- 一致的运行环境
- 简化依赖管理
2. **模块化设计**
- 每个脚本职责单一
- 通过 `utils.sh` 共享通用功能
- 易于维护和扩展
3. **统一管理**
- Makefile 统一入口
- 一致的命令格式
- 与其他服务TeamSpeak、Nextcloud集成
### 📂 目录变更
```
旧结构:
minecraft/
├── src/automatic/
│ ├── deploy.sh
│ ├── download-mods.sh
│ ├── logger.sh
│ └── requirements.txt
新结构:
minecraft/
├── scripts/ # 新增:统一的脚本目录
│ ├── utils.sh
│ ├── setup.sh
│ ├── mod-manager.sh
│ ├── backup.sh
│ └── monitor.sh
├── extras/
│ └── mods.txt # 统一的 mods 配置
├── backups/ # 新增:自动备份目录
├── logs/ # 新增:脚本日志目录
└── src/automatic/ # 保留(供参考)
```
### 🔧 技术细节
1. **错误处理**
- 所有脚本使用 `set -e`
- 完善的返回码检查
- 详细的错误消息
2. **跨平台兼容**
- macOS 和 Linux 兼容的命令
- 自动检测 `docker compose` vs `docker-compose`
- 处理不同的 `stat` 命令格式
3. **安全性**
- 敏感信息通过 `.env` 管理
- RCON 密码验证
- 备份前的确认机制
### 📋 迁移建议
如果使用旧的 `src/automatic/` 脚本:
1. 旧脚本仍可使用(未删除)
2. 建议迁移到新的 Docker 方案
3. 新方案提供更多自动化功能
4. 通过 Makefile 统一管理更便捷
### 🎯 后续计划
- [ ] 添加定时备份的 systemd/cron 模板
- [ ] 集成 Prometheus 指标监控
- [ ] 添加自动更新检查
- [ ] Web 控制面板集成
- [ ] 多服务器管理支持
### 📝 配置兼容性
- ✅ `docker-compose.yml` - 无变化
- ✅ `.env` - 无变化
- ✅ `configs/` - 无变化
- ✅ `mods/` - 无变化
- ✅ `extras/mods.txt` - 格式与旧 `requirements.txt` 兼容
### 🙏 致谢
重构整合了原有设计的精华:
- 日志系统的设计理念
- Modrinth API 集成逻辑
- 部署流程的最佳实践

View file

@ -1,15 +1,316 @@
# Automa Minecraft
# Automa Minecraft 服务器
基于 Docker Compose 的 Minecraft Fabric 1.21.1 服务器,提供完整的自动化管理方案。
## 📁 目录结构
```
mc-fabric-docker/
├── docker-compose.yml
├── .env # 必改UID、GID、RCON_PASSWORD、TZ
├── mods/ # 放你的所有 mods jar
├── configs/
│ ├── server.properties # 服务器配置
│ ├── whitelist.json # 白名单(示例)
│ └── ops.json # OP示例
├── data/ # 自动生成:世界、备份、日志
└── extras/
└── mods.txt # 可选Modrinth 自动下载模组
minecraft/
├── docker-compose.yml # Docker Compose 配置
├── .env # 环境变量配置(需自定义)
├── configs/ # 服务器配置文件
│ ├── server.properties # 服务器属性配置
│ └── whitelist.json # 白名单配置
├── mods/ # Mods 存放目录
├── data/ # 持久化数据(世界、日志等)
├── backups/ # 自动备份目录
├── logs/ # 自动化脚本日志
├── extras/
│ └── mods.txt # Modrinth Mods 列表
└── scripts/ # 自动化脚本
├── utils.sh # 工具库
├── setup.sh # 环境初始化
├── mod-manager.sh # Mods 管理
├── backup.sh # 备份管理
└── monitor.sh # 服务器监控
```
## 🚀 快速开始
### 1. 环境初始化
```bash
# 检查环境并初始化目录结构
make minecraft-setup
```
### 2. 配置服务器
编辑 `.env` 文件,设置必要的配置:
```bash
# 用户权限(使用 id 命令查看)
UID=1000
GID=1000
# RCON 密码(远程管理)
RCON_PASSWORD=your_secure_password
# 时区
TZ=Asia/Shanghai
```
### 3. 下载 Mods可选
```bash
# 从 Modrinth 下载 mods根据 extras/mods.txt
make minecraft-mods-download
# 或手动将 mods 放入 mods/ 目录
```
### 4. 启动服务器
```bash
# 启动服务器
make minecraft-up
# 查看日志
make minecraft-logs
```
## 📋 常用命令
### 服务器管理
```bash
make minecraft-up # 启动服务器
make minecraft-down # 停止服务器
make minecraft-restart # 重启服务器
make minecraft-logs # 查看实时日志
make minecraft-status # 查看服务器状态
```
### Mods 管理
```bash
make minecraft-mods-download # 下载所有 mods
make minecraft-mods-list # 列出已安装的 mods
make minecraft-mods-update # 更新所有 mods
make minecraft-mods-check # 检查 mods 状态
```
Mods 配置在 `extras/mods.txt` 中,每行一个 Modrinth slug
```
fabric-api
sodium
lithium
iris
```
### 备份管理
```bash
make minecraft-backup # 完整备份世界、配置、mods
make minecraft-backup-world # 仅备份世界数据
make minecraft-backup-list # 列出所有备份
make minecraft-backup-cleanup # 清理旧备份
```
备份存储在 `backups/` 目录,按类型分类:
- `backups/worlds/` - 世界数据备份
- `backups/configs/` - 配置文件备份
- `backups/mods/` - Mods 备份
## 🔧 高级用法
### 直接使用脚本
所有自动化脚本位于 `scripts/` 目录:
```bash
# 环境初始化
./scripts/setup.sh
# Mods 管理
./scripts/mod-manager.sh download # 下载 mods
./scripts/mod-manager.sh list # 列出 mods
./scripts/mod-manager.sh update # 更新 mods
./scripts/mod-manager.sh clean # 清理 mods
# 备份管理
./scripts/backup.sh backup all # 完整备份
./scripts/backup.sh backup world # 仅备份世界
./scripts/backup.sh list # 列出备份
./scripts/backup.sh restore <file> # 恢复备份
./scripts/backup.sh cleanup 10 # 保留最近10个备份
# 服务器监控
./scripts/monitor.sh status # 完整状态
./scripts/monitor.sh resources # 资源使用
./scripts/monitor.sh players # 在线玩家
./scripts/monitor.sh logs 50 # 最近50行日志
./scripts/monitor.sh watch 10 # 持续监控每10秒
```
### 自定义配置
#### 修改服务器配置
编辑 `configs/server.properties`,然后重启服务器:
```bash
vim configs/server.properties
make minecraft-restart
```
#### 添加新 Mods
1. 在 Modrinth 找到 mod 的 slugURL中的ID
2. 添加到 `extras/mods.txt`
3. 运行下载命令:
```bash
make minecraft-mods-download
make minecraft-restart
```
#### 配置白名单
编辑 `configs/whitelist.json`,并在 `.env``configs/server.properties` 中启用白名单:
```properties
white-list=true
enforce-whitelist=true
```
## 🔍 监控与维护
### 实时监控
```bash
# 查看完整状态(容器、资源、玩家、错误)
make minecraft-status
# 持续监控模式每5秒刷新
cd minecraft && ./scripts/monitor.sh watch 5
```
### 日志管理
```bash
# 查看 Docker 容器日志
make minecraft-logs
# 查看自动化脚本日志
ls -lh logs/
tail -f logs/automation-*.log
```
### 定期备份
建议配置 cron 任务定期备份:
```bash
# 每天凌晨3点备份世界数据
0 3 * * * cd /path/to/automa && make minecraft-backup-world
# 每周清理旧备份保留最近10个
0 4 * * 0 cd /path/to/automa/minecraft && ./scripts/backup.sh cleanup 10
```
## 📊 性能优化
项目已包含性能优化 mods
- **Sodium** - 渲染优化
- **Lithium** - 服务器性能优化
- **Iris** - 着色器支持
内存配置在 `docker-compose.yml` 中:
```yaml
environment:
MEMORY: "4G" # 最大内存
INIT_MEMORY: "2G" # 初始内存
```
## 🛡️ 安全建议
1. **修改 RCON 密码**:在 `.env` 中设置强密码
2. **配置防火墙**仅开放必要端口25565, 25575
3. **启用白名单**:在 `configs/server.properties` 中配置
4. **定期备份**:使用自动化备份脚本
5. **监控日志**:定期检查错误日志
## 🔄 迁移指南
### 从旧版本迁移
如果你使用的是 `src/automatic/` 下的旧脚本:
1. 新方案使用 Docker Compose更易部署和维护
2. Mods 管理统一使用 `extras/mods.txt` 格式
3. 所有自动化功能集成到 `scripts/` 目录
4. 通过 Makefile 统一管理
迁移步骤:
```bash
# 1. 备份旧数据
cp -r old_server_dir/world minecraft/data/
# 2. 复制 mods如果手动管理
cp -r old_mods_dir/* minecraft/mods/
# 3. 初始化新环境
make minecraft-setup
# 4. 启动服务器
make minecraft-up
```
## 📝 故障排查
### 容器无法启动
```bash
# 检查 Docker 服务
docker info
# 查看容器日志
make minecraft-logs
# 检查环境配置
cat .env
```
### Mods 下载失败
```bash
# 检查网络连接
curl -I https://api.modrinth.com
# 查看详细日志
cat logs/automation-*.log
# 手动下载 mods 放入 mods/ 目录
```
### 性能问题
```bash
# 查看资源使用
cd minecraft && ./scripts/monitor.sh resources
# 调整内存配置
vim docker-compose.yml # 修改 MEMORY 和 INIT_MEMORY
# 重启服务器
make minecraft-restart
```
## 📚 相关资源
- [Docker 文档](https://docs.docker.com/)
- [itzg/minecraft-server 镜像](https://github.com/itzg/docker-minecraft-server)
- [Modrinth](https://modrinth.com/) - Mods 下载平台
- [Fabric](https://fabricmc.net/) - Mod 加载器
## 🤝 贡献
欢迎提交 Issue 和 Pull Request
## 📄 许可
MIT License

376
minecraft/scripts/backup.sh Executable file
View file

@ -0,0 +1,376 @@
#!/usr/bin/env bash
# Minecraft 服务器备份管理
# 支持世界数据、配置文件、mods 的备份和恢复
set -e
# 加载工具库
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "$SCRIPT_DIR/utils.sh"
# ============================================
# 配置变量
# ============================================
readonly PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
readonly BACKUP_DIR="$PROJECT_ROOT/backups"
readonly DATA_DIR="$PROJECT_ROOT/data"
readonly MODS_DIR="$PROJECT_ROOT/mods"
readonly CONFIGS_DIR="$PROJECT_ROOT/configs"
readonly CONTAINER_NAME="mc-fabric-1.21.1"
# ============================================
# 备份函数
# ============================================
# 备份世界数据
backup_world() {
log_info "备份世界数据..."
local world_dir="$DATA_DIR/world"
if [[ ! -d "$world_dir" ]]; then
log_warning "世界数据不存在: $world_dir"
return 1
fi
# 通知服务器保存
if docker ps --format '{{.Names}}' | grep -q "^${CONTAINER_NAME}$"; then
log_info "通知服务器保存世界..."
docker exec "$CONTAINER_NAME" rcon-cli save-all flush 2>/dev/null || true
sleep 3
fi
# 创建备份
local backup_file=$(create_backup "$world_dir" "$BACKUP_DIR/worlds")
if [[ -n "$backup_file" ]]; then
log_success "世界备份完成"
return 0
else
log_error "世界备份失败"
return 1
fi
}
# 备份配置文件
backup_configs() {
log_info "备份配置文件..."
if [[ ! -d "$CONFIGS_DIR" ]]; then
log_warning "配置目录不存在: $CONFIGS_DIR"
return 1
fi
local backup_file=$(create_backup "$CONFIGS_DIR" "$BACKUP_DIR/configs")
if [[ -n "$backup_file" ]]; then
log_success "配置备份完成"
return 0
else
log_error "配置备份失败"
return 1
fi
}
# 备份 mods
backup_mods() {
log_info "备份 Mods..."
if [[ ! -d "$MODS_DIR" || -z "$(ls -A "$MODS_DIR" 2>/dev/null)" ]]; then
log_warning "Mods 目录为空"
return 1
fi
local backup_file=$(create_backup "$MODS_DIR" "$BACKUP_DIR/mods")
if [[ -n "$backup_file" ]]; then
log_success "Mods 备份完成"
return 0
else
log_error "Mods 备份失败"
return 1
fi
}
# 完整备份
backup_all() {
log_info "开始完整备份..."
log_separator
local success=0
local failed=0
# 备份世界
if backup_world; then
((success++))
else
((failed++))
fi
log_separator
# 备份配置
if backup_configs; then
((success++))
else
((failed++))
fi
log_separator
# 备份 mods
if backup_mods; then
((success++))
else
((failed++))
fi
log_separator
log_info "备份完成 - 成功: $success, 失败: $failed"
return $failed
}
# ============================================
# 恢复函数
# ============================================
# 列出可用备份
list_backups() {
local type="${1:-all}"
log_info "可用备份:"
case "$type" in
world | worlds)
list_backup_type "worlds" "世界数据"
;;
config | configs)
list_backup_type "configs" "配置文件"
;;
mods)
list_backup_type "mods" "Mods"
;;
all | *)
list_backup_type "worlds" "世界数据"
list_backup_type "configs" "配置文件"
list_backup_type "mods" "Mods"
;;
esac
}
# 列出特定类型的备份
list_backup_type() {
local subdir="$1"
local name="$2"
local backup_path="$BACKUP_DIR/$subdir"
echo ""
log_info "=== $name ==="
if [[ ! -d "$backup_path" ]]; then
log_warning "无可用备份"
return
fi
local count=0
while IFS= read -r file; do
local filename=$(basename "$file")
local size=$(du -h "$file" | cut -f1)
local date=$(echo "$filename" | grep -oP '\d{8}-\d{6}' || echo "未知")
printf " ${CYAN}${NC} %-60s %8s\n" "$filename" "$size"
((count++))
done < <(find "$backup_path" -name "*.tar.gz" -type f 2>/dev/null | sort -r)
if [[ $count -eq 0 ]]; then
log_warning "无可用备份"
else
log_info "$count 个备份"
fi
}
# 恢复备份
restore_backup() {
local backup_file="$1"
if [[ ! -f "$backup_file" ]]; then
log_error "备份文件不存在: $backup_file"
return 1
fi
log_warning "恢复备份将覆盖现有数据"
log_info "备份文件: $(basename "$backup_file")"
# 确定恢复目标
local target_dir=""
if [[ "$backup_file" =~ /worlds/ ]]; then
target_dir="$DATA_DIR"
elif [[ "$backup_file" =~ /configs/ ]]; then
target_dir=$(dirname "$CONFIGS_DIR")
elif [[ "$backup_file" =~ /mods/ ]]; then
target_dir=$(dirname "$MODS_DIR")
else
log_error "无法确定备份类型"
return 1
fi
log_info "恢复目标: $target_dir"
# 解压备份
if tar -xzf "$backup_file" -C "$target_dir"; then
log_success "备份恢复完成"
return 0
else
log_error "备份恢复失败"
return 1
fi
}
# ============================================
# 清理函数
# ============================================
# 清理旧备份
cleanup_backups() {
local keep="${1:-5}"
log_info "清理旧备份(保留最近 $keep 个)..."
log_separator
cleanup_old_backups "$BACKUP_DIR/worlds" "$keep"
cleanup_old_backups "$BACKUP_DIR/configs" "$keep"
cleanup_old_backups "$BACKUP_DIR/mods" "$keep"
log_success "备份清理完成"
}
# 显示备份统计
show_backup_stats() {
log_info "备份统计信息"
log_separator
local types=("worlds:世界数据" "configs:配置文件" "mods:Mods")
for type_pair in "${types[@]}"; do
local type="${type_pair%%:*}"
local name="${type_pair##*:}"
local backup_path="$BACKUP_DIR/$type"
if [[ -d "$backup_path" ]]; then
local count=$(find "$backup_path" -name "*.tar.gz" 2>/dev/null | wc -l)
local total_size=$(du -sh "$backup_path" 2>/dev/null | cut -f1)
log_info "$name: $count 个备份, 总大小: $total_size"
else
log_info "$name: 无备份"
fi
done
log_separator
if [[ -d "$BACKUP_DIR" ]]; then
local total_size=$(du -sh "$BACKUP_DIR" 2>/dev/null | cut -f1)
log_info "备份总大小: $total_size"
fi
}
# ============================================
# 主函数
# ============================================
show_usage() {
cat <<EOF
Minecraft 服务器备份管理
用法: $(basename "$0") [命令] [选项]
命令:
backup [type] 创建备份
type:
world 仅备份世界数据
config 仅备份配置文件
mods 仅备份 mods
all 完整备份(默认)
list [type] 列出可用备份
restore <file> 恢复指定备份
cleanup [num] 清理旧备份默认保留5个
stats 显示备份统计信息
help 显示此帮助信息
示例:
$(basename "$0") backup all # 完整备份
$(basename "$0") backup world # 仅备份世界
$(basename "$0") list # 列出所有备份
$(basename "$0") cleanup 10 # 保留最近10个备份
备份位置: $BACKUP_DIR
EOF
}
main() {
local command="${1:-help}"
shift || true
# 初始化日志
init_log "Minecraft 备份管理"
log_system_info
case "$command" in
backup)
local type="${1:-all}"
case "$type" in
world | worlds)
backup_world
;;
config | configs)
backup_configs
;;
mods)
backup_mods
;;
all | *)
backup_all
;;
esac
;;
list)
list_backups "${1:-all}"
;;
restore)
local file="$1"
if [[ -z "$file" ]]; then
log_error "请指定备份文件"
exit 1
fi
restore_backup "$file"
;;
cleanup)
cleanup_backups "${1:-5}"
;;
stats)
show_backup_stats
;;
help | --help | -h)
show_usage
;;
*)
log_error "未知命令: $command"
echo ""
show_usage
exit 1
;;
esac
show_log_file
}
# 执行主函数
main "$@"

344
minecraft/scripts/mod-manager.sh Executable file
View file

@ -0,0 +1,344 @@
#!/usr/bin/env bash
# Minecraft Mods 管理器
# 支持从 Modrinth 下载、更新、清理 mods
set -e
# 加载工具库
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "$SCRIPT_DIR/utils.sh"
# ============================================
# 配置变量
# ============================================
readonly PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
readonly MODS_DIR="$PROJECT_ROOT/mods"
readonly MODS_LIST="$PROJECT_ROOT/extras/mods.txt"
readonly MC_VERSION="1.21.1"
readonly LOADER="fabric"
readonly MODRINTH_API="https://api.modrinth.com/v2"
# ============================================
# Modrinth API 函数
# ============================================
# 获取项目信息
get_project_info() {
local slug="$1"
local response
response=$(curl -s "$MODRINTH_API/project/$slug")
if [[ $? -ne 0 || -z "$response" ]]; then
return 1
fi
echo "$response"
}
# 获取最新版本
get_latest_version() {
local slug="$1"
local game_version="$2"
local loader="$3"
local url="$MODRINTH_API/project/$slug/version"
url+="?game_versions=%5B%22${game_version}%22%5D"
url+="&loaders=%5B%22${loader}%22%5D"
local response=$(curl -s "$url")
if [[ $? -ne 0 || -z "$response" || "$response" == "[]" ]]; then
return 1
fi
echo "$response"
}
# 解析下载信息
parse_download_info() {
local json="$1"
# 提取文件名和下载链接
local filename=$(echo "$json" | grep -o '"filename":"[^"]*"' | head -1 | cut -d'"' -f4)
local url=$(echo "$json" | grep -o '"url":"[^"]*"' | head -1 | cut -d'"' -f4)
if [[ -z "$filename" || -z "$url" ]]; then
return 1
fi
echo "$filename|$url"
}
# ============================================
# Mods 下载函数
# ============================================
# 下载单个 mod
download_mod() {
local slug="$1"
local mod_name="${2:-$slug}"
log_info "处理: $mod_name ($slug)"
# 获取版本信息
local versions=$(get_latest_version "$slug" "$MC_VERSION" "$LOADER")
if [[ $? -ne 0 ]]; then
log_error "未找到适配版本: $slug"
return 1
fi
# 解析下载信息
local download_info=$(parse_download_info "$versions")
if [[ $? -ne 0 ]]; then
log_error "解析下载信息失败: $slug"
return 1
fi
local filename=$(echo "$download_info" | cut -d'|' -f1)
local download_url=$(echo "$download_info" | cut -d'|' -f2)
# 检查文件是否已存在
if [[ -f "$MODS_DIR/$filename" ]]; then
log_info "已存在: $filename"
return 0
fi
# 下载文件
log_info "下载: $filename"
if curl -L -o "$MODS_DIR/$filename" "$download_url" 2>/dev/null; then
# 验证文件大小
local size=$(stat -f%z "$MODS_DIR/$filename" 2>/dev/null || stat -c%s "$MODS_DIR/$filename" 2>/dev/null)
if [[ $size -gt 1000 ]]; then
log_success "下载完成: $filename ($(($size / 1024)) KB)"
return 0
else
log_error "文件大小异常: $filename ($size bytes)"
rm -f "$MODS_DIR/$filename"
return 1
fi
else
log_error "下载失败: $slug"
return 1
fi
}
# 从列表下载所有 mods
download_all_mods() {
if [[ ! -f "$MODS_LIST" ]]; then
log_error "Mods 列表不存在: $MODS_LIST"
return 1
fi
log_info "开始批量下载 mods"
log_info "Minecraft 版本: $MC_VERSION"
log_info "加载器: $LOADER"
log_info "目标目录: $MODS_DIR"
mkdir -p "$MODS_DIR"
local success_count=0
local fail_count=0
local skip_count=0
while IFS= read -r line; do
# 跳过空行和注释
line=$(echo "$line" | xargs)
if [[ -z "$line" || "$line" =~ ^# ]]; then
continue
fi
log_separator
if download_mod "$line"; then
((success_count++))
else
((fail_count++))
fi
# 限流避免API限制
sleep 1
done <"$MODS_LIST"
log_separator
log_info "下载完成 - 成功: $success_count, 失败: $fail_count"
return 0
}
# ============================================
# Mods 管理函数
# ============================================
# 列出已安装的 mods
list_mods() {
log_info "已安装的 Mods:"
if [[ ! -d "$MODS_DIR" || -z "$(ls -A "$MODS_DIR" 2>/dev/null)" ]]; then
log_warning "未找到任何 mods"
return 0
fi
local count=0
while IFS= read -r file; do
local filename=$(basename "$file")
local size=$(stat -f%z "$file" 2>/dev/null || stat -c%s "$file" 2>/dev/null)
local size_kb=$(($size / 1024))
printf " ${GREEN}${NC} %-50s %8s KB\n" "$filename" "$size_kb"
((count++))
done < <(find "$MODS_DIR" -name "*.jar" -type f 2>/dev/null | sort)
log_info "总计: $count 个 mods"
}
# 清理 mods
clean_mods() {
local backup="${1:-true}"
if [[ ! -d "$MODS_DIR" ]]; then
log_info "Mods 目录不存在,无需清理"
return 0
fi
local count=$(find "$MODS_DIR" -name "*.jar" 2>/dev/null | wc -l)
if [[ $count -eq 0 ]]; then
log_info "没有 mods 需要清理"
return 0
fi
log_warning "准备清理 $count 个 mods"
# 创建备份
if [[ "$backup" == "true" ]]; then
create_backup "$MODS_DIR"
fi
# 删除所有 jar 文件
find "$MODS_DIR" -name "*.jar" -type f -delete
log_success "Mods 清理完成"
}
# 更新所有 mods
update_mods() {
log_info "更新所有 mods"
# 备份并清理现有 mods
clean_mods true
# 重新下载
download_all_mods
}
# 检查 mods 状态
check_mods() {
log_info "检查 Mods 状态"
if [[ ! -d "$MODS_DIR" ]]; then
log_warning "Mods 目录不存在"
return 1
fi
local jar_count=$(find "$MODS_DIR" -name "*.jar" 2>/dev/null | wc -l)
local total_size=$(du -sh "$MODS_DIR" 2>/dev/null | cut -f1)
log_info "Mods 数量: $jar_count"
log_info "总大小: $total_size"
# 检查必需的核心 mods
local required_mods=("fabric-api")
local missing_count=0
for mod in "${required_mods[@]}"; do
if ! find "$MODS_DIR" -name "*${mod}*.jar" | grep -q .; then
log_warning "缺少核心 mod: $mod"
((missing_count++))
fi
done
if [[ $missing_count -gt 0 ]]; then
log_warning "缺少 $missing_count 个核心 mods建议运行下载命令"
else
log_success "核心 mods 完整"
fi
return 0
}
# ============================================
# 主函数
# ============================================
show_usage() {
cat <<EOF
Minecraft Mods 管理器
用法: $(basename "$0") [命令]
命令:
download 下载所有 mods根据 extras/mods.txt
list 列出已安装的 mods
update 更新所有 mods备份、清理、重新下载
clean 清理所有 mods自动备份
check 检查 mods 状态
help 显示此帮助信息
示例:
$(basename "$0") download # 下载所有 mods
$(basename "$0") list # 列出已安装的 mods
$(basename "$0") update # 更新所有 mods
配置文件:
Mods 列表: $MODS_LIST
Mods 目录: $MODS_DIR
EOF
}
main() {
local command="${1:-help}"
# 初始化日志
init_log "Minecraft Mods 管理器"
log_system_info
case "$command" in
download)
check_network || exit 1
download_all_mods
;;
list)
list_mods
;;
update)
check_network || exit 1
update_mods
;;
clean)
clean_mods true
;;
check)
check_mods
;;
help | --help | -h)
show_usage
;;
*)
log_error "未知命令: $command"
echo ""
show_usage
exit 1
;;
esac
show_log_file
}
# 执行主函数
main "$@"

315
minecraft/scripts/monitor.sh Executable file
View file

@ -0,0 +1,315 @@
#!/usr/bin/env bash
# Minecraft 服务器监控脚本
# 监控容器状态、资源使用、玩家在线等信息
set -e
# 加载工具库
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "$SCRIPT_DIR/utils.sh"
# ============================================
# 配置变量
# ============================================
readonly PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
readonly CONTAINER_NAME="mc-fabric-1.21.1"
# ============================================
# 容器状态检查
# ============================================
check_container() {
log_info "检查容器状态..."
local status=$(check_container_status "$CONTAINER_NAME")
case "$status" in
running)
log_success "容器正在运行"
return 0
;;
stopped)
log_warning "容器已停止"
return 1
;;
not_found)
log_error "容器不存在"
return 2
;;
esac
}
# ============================================
# 资源使用监控
# ============================================
show_resource_usage() {
log_info "资源使用情况"
log_separator
if ! docker ps --format '{{.Names}}' | grep -q "^${CONTAINER_NAME}$"; then
log_warning "容器未运行"
return 1
fi
# 获取容器统计信息
local stats=$(docker stats --no-stream --format "{{.CPUPerc}}|{{.MemUsage}}|{{.NetIO}}|{{.BlockIO}}" "$CONTAINER_NAME")
local cpu=$(echo "$stats" | cut -d'|' -f1)
local mem=$(echo "$stats" | cut -d'|' -f2)
local net=$(echo "$stats" | cut -d'|' -f3)
local disk=$(echo "$stats" | cut -d'|' -f4)
printf "${CYAN}CPU 使用:${NC} %s\n" "$cpu"
printf "${CYAN}内存使用:${NC} %s\n" "$mem"
printf "${CYAN}网络 I/O:${NC} %s\n" "$net"
printf "${CYAN}磁盘 I/O:${NC} %s\n" "$disk"
log_separator
}
# ============================================
# 服务器信息
# ============================================
show_server_info() {
log_info "服务器信息"
log_separator
if ! docker ps --format '{{.Names}}' | grep -q "^${CONTAINER_NAME}$"; then
log_warning "容器未运行"
return 1
fi
# 容器运行时间
local uptime=$(docker inspect --format='{{.State.StartedAt}}' "$CONTAINER_NAME")
uptime=$(date -j -f "%Y-%m-%dT%H:%M:%S" "${uptime:0:19}" "+%Y-%m-%d %H:%M:%S" 2>/dev/null || echo "$uptime")
printf "${CYAN}启动时间:${NC} %s\n" "$uptime"
# 端口映射
local ports=$(docker port "$CONTAINER_NAME" 2>/dev/null | grep "25565" | head -1)
printf "${CYAN}服务端口:${NC} %s\n" "${ports:-未映射}"
# 容器 IP
local container_ip=$(docker inspect --format='{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' "$CONTAINER_NAME")
printf "${CYAN}容器 IP:${NC} %s\n" "${container_ip:-未知}"
log_separator
}
# ============================================
# 玩家信息
# ============================================
show_players() {
log_info "在线玩家"
log_separator
if ! docker ps --format '{{.Names}}' | grep -q "^${CONTAINER_NAME}$"; then
log_warning "容器未运行"
return 1
fi
# 尝试使用 rcon 获取玩家列表
local player_list=$(docker exec "$CONTAINER_NAME" rcon-cli list 2>/dev/null || echo "无法获取玩家信息")
if [[ "$player_list" =~ "There are" ]]; then
echo "$player_list"
else
log_warning "无法获取玩家信息(可能需要配置 RCON"
fi
log_separator
}
# ============================================
# 日志监控
# ============================================
show_recent_logs() {
local lines="${1:-20}"
log_info "最近 $lines 行日志"
log_separator
if ! docker ps --format '{{.Names}}' | grep -q "^${CONTAINER_NAME}$"; then
log_warning "容器未运行"
return 1
fi
docker logs --tail "$lines" "$CONTAINER_NAME" 2>&1
log_separator
}
# 监控日志中的错误
check_errors() {
log_info "检查错误日志"
log_separator
if ! docker ps --format '{{.Names}}' | grep -q "^${CONTAINER_NAME}$"; then
log_warning "容器未运行"
return 1
fi
local error_count=$(docker logs --tail 1000 "$CONTAINER_NAME" 2>&1 | grep -ic "error" || echo "0")
local warn_count=$(docker logs --tail 1000 "$CONTAINER_NAME" 2>&1 | grep -ic "warn" || echo "0")
if [[ $error_count -gt 0 ]]; then
log_warning "发现 $error_count 个错误"
else
log_success "无错误日志"
fi
if [[ $warn_count -gt 0 ]]; then
log_warning "发现 $warn_count 个警告"
fi
log_separator
}
# ============================================
# 完整状态报告
# ============================================
show_full_status() {
log_info "=== Minecraft 服务器完整状态 ==="
log_separator
# 检查容器
if ! check_container; then
return 1
fi
log_separator
# 服务器信息
show_server_info
# 资源使用
show_resource_usage
# 玩家信息
show_players
# 错误检查
check_errors
log_success "状态检查完成"
}
# ============================================
# 持续监控
# ============================================
watch_mode() {
local interval="${1:-5}"
log_info "开始持续监控(每 ${interval}s 刷新Ctrl+C 退出)"
log_separator
while true; do
clear
echo "=== Minecraft 服务器监控 ==="
echo "刷新时间: $(date '+%Y-%m-%d %H:%M:%S')"
echo ""
show_server_info 2>/dev/null || true
show_resource_usage 2>/dev/null || true
show_players 2>/dev/null || true
sleep "$interval"
done
}
# ============================================
# 主函数
# ============================================
show_usage() {
cat <<EOF
Minecraft 服务器监控工具
用法: $(basename "$0") [命令] [选项]
命令:
status 显示完整状态(默认)
container 检查容器状态
resources 显示资源使用情况
server 显示服务器信息
players 显示在线玩家
logs [n] 显示最近 n 行日志默认20行
errors 检查错误日志
watch [sec] 持续监控模式默认每5秒刷新
help 显示此帮助信息
示例:
$(basename "$0") # 显示完整状态
$(basename "$0") resources # 仅显示资源使用
$(basename "$0") logs 50 # 显示最近50行日志
$(basename "$0") watch 10 # 每10秒刷新一次
容器名称: $CONTAINER_NAME
EOF
}
main() {
local command="${1:-status}"
shift || true
# 初始化日志
init_log "Minecraft 服务器监控"
case "$command" in
status)
show_full_status
;;
container)
check_container
;;
resources | res)
show_resource_usage
;;
server | info)
show_server_info
;;
players | player)
show_players
;;
logs | log)
show_recent_logs "${1:-20}"
;;
errors | error)
check_errors
;;
watch)
watch_mode "${1:-5}"
;;
help | --help | -h)
show_usage
;;
*)
log_error "未知命令: $command"
echo ""
show_usage
exit 1
;;
esac
if [[ "$command" != "watch" ]]; then
show_log_file
fi
}
# 执行主函数
main "$@"

184
minecraft/scripts/setup.sh Executable file
View file

@ -0,0 +1,184 @@
#!/usr/bin/env bash
# Minecraft 服务器初始化脚本
# 用于首次部署或环境重置
set -e
# 加载工具库
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "$SCRIPT_DIR/utils.sh"
# ============================================
# 配置变量
# ============================================
readonly PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
# ============================================
# 初始化检查
# ============================================
check_prerequisites() {
log_info "检查系统环境..."
# 检查 Docker
if ! check_docker; then
log_error "Docker 环境检查失败"
exit 1
fi
# 检查必需文件
local required_files=(
"$PROJECT_ROOT/docker-compose.yml"
"$PROJECT_ROOT/.env"
)
for file in "${required_files[@]}"; do
if ! check_file "$file"; then
log_error "缺少必需文件"
exit 1
fi
done
log_success "环境检查通过"
}
# ============================================
# 目录结构初始化
# ============================================
init_directories() {
log_info "初始化目录结构..."
local dirs=(
"$PROJECT_ROOT/data"
"$PROJECT_ROOT/mods"
"$PROJECT_ROOT/configs"
"$PROJECT_ROOT/backups"
"$PROJECT_ROOT/logs"
)
for dir in "${dirs[@]}"; do
if [[ ! -d "$dir" ]]; then
mkdir -p "$dir"
log_success "创建目录: $(basename "$dir")"
else
log_info "目录已存在: $(basename "$dir")"
fi
done
}
# ============================================
# 配置文件初始化
# ============================================
check_env_config() {
log_info "检查环境配置..."
local env_file="$PROJECT_ROOT/.env"
# 检查关键配置
if grep -q "your_rcon_password_here" "$env_file"; then
log_warning ".env 中的 RCON_PASSWORD 未配置"
log_warning "请编辑 .env 文件并设置安全的密码"
fi
# 检查 UID/GID
local current_uid=$(id -u)
local current_gid=$(id -g)
if ! grep -q "UID=$current_uid" "$env_file"; then
log_info "当前用户 UID: $current_uid"
log_warning "建议更新 .env 中的 UID 为: $current_uid"
fi
if ! grep -q "GID=$current_gid" "$env_file"; then
log_info "当前用户 GID: $current_gid"
log_warning "建议更新 .env 中的 GID 为: $current_gid"
fi
}
# ============================================
# Mods 初始化
# ============================================
init_mods() {
log_info "检查 Mods 状态..."
local mods_count=$(find "$PROJECT_ROOT/mods" -name "*.jar" 2>/dev/null | wc -l)
if [[ $mods_count -eq 0 ]]; then
log_warning "未找到任何 mods"
log_info "建议运行: make minecraft-mods-download"
else
log_success "发现 $mods_count 个 mods"
fi
}
# ============================================
# 权限设置
# ============================================
fix_permissions() {
log_info "修复文件权限..."
# 确保脚本可执行
find "$PROJECT_ROOT/scripts" -name "*.sh" -type f -exec chmod +x {} \;
# 确保数据目录可写
if [[ -d "$PROJECT_ROOT/data" ]]; then
chmod -R 755 "$PROJECT_ROOT/data"
fi
log_success "权限修复完成"
}
# ============================================
# 显示配置摘要
# ============================================
show_summary() {
log_separator
log_success "初始化完成!"
echo ""
log_info "配置摘要:"
log_info " 项目目录: $PROJECT_ROOT"
log_info " Docker Compose: $(get_docker_compose_cmd)"
log_info " Mods 数量: $(find "$PROJECT_ROOT/mods" -name "*.jar" 2>/dev/null | wc -l)"
echo ""
log_info "后续步骤:"
log_info " 1. 检查并编辑 .env 文件,设置 RCON_PASSWORD"
log_info " 2. 如需下载 mods: make minecraft-mods-download"
log_info " 3. 启动服务器: make minecraft-up"
log_info " 4. 查看日志: make minecraft-logs"
echo ""
show_log_file
}
# ============================================
# 主函数
# ============================================
main() {
# 初始化日志
init_log "Minecraft 服务器初始化"
log_system_info
log_info "开始初始化 Minecraft 服务器环境..."
log_separator
# 执行初始化步骤
check_prerequisites
init_directories
check_env_config
init_mods
fix_permissions
# 显示摘要
show_summary
}
# 执行主函数
main "$@"

339
minecraft/scripts/utils.sh Executable file
View file

@ -0,0 +1,339 @@
#!/usr/bin/env bash
# Minecraft 自动化工具 - 通用工具库
# 提供日志、环境检查、Docker操作等通用函数
# ============================================
# 颜色定义
# ============================================
readonly RED='\033[0;31m'
readonly GREEN='\033[0;32m'
readonly YELLOW='\033[1;33m'
readonly BLUE='\033[0;34m'
readonly CYAN='\033[0;36m'
readonly NC='\033[0m' # No Color
# ============================================
# 全局变量
# ============================================
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
LOG_DIR="$PROJECT_ROOT/logs"
LOG_FILE="$LOG_DIR/automation-$(date +%Y%m%d).log"
# 确保日志目录存在
mkdir -p "$LOG_DIR"
# ============================================
# 日志函数
# ============================================
# 初始化日志文件
init_log() {
local title="${1:-Minecraft 自动化任务}"
{
echo "=========================================="
echo "$title"
echo "开始时间: $(date '+%Y-%m-%d %H:%M:%S')"
echo "工作目录: $(pwd)"
echo "用户: $(whoami)"
echo "=========================================="
echo ""
} >>"$LOG_FILE"
}
# 记录信息
log_info() {
local msg="$1"
local timestamp=$(date '+%H:%M:%S')
echo -e "${BLUE}[INFO]${NC} ${timestamp} $msg"
echo "[$(date '+%Y-%m-%d %H:%M:%S')] [INFO] $msg" >>"$LOG_FILE"
}
# 记录成功
log_success() {
local msg="$1"
local timestamp=$(date '+%H:%M:%S')
echo -e "${GREEN}[✓]${NC} ${timestamp} $msg"
echo "[$(date '+%Y-%m-%d %H:%M:%S')] [SUCCESS] $msg" >>"$LOG_FILE"
}
# 记录警告
log_warning() {
local msg="$1"
local timestamp=$(date '+%H:%M:%S')
echo -e "${YELLOW}[⚠]${NC} ${timestamp} $msg"
echo "[$(date '+%Y-%m-%d %H:%M:%S')] [WARNING] $msg" >>"$LOG_FILE"
}
# 记录错误
log_error() {
local msg="$1"
local timestamp=$(date '+%H:%M:%S')
echo -e "${RED}[✗]${NC} ${timestamp} $msg"
echo "[$(date '+%Y-%m-%d %H:%M:%S')] [ERROR] $msg" >>"$LOG_FILE"
}
# 记录命令执行
log_command() {
local cmd="$1"
echo "[$(date '+%Y-%m-%d %H:%M:%S')] [COMMAND] $cmd" >>"$LOG_FILE"
}
# 记录分隔线
log_separator() {
echo "" | tee -a "$LOG_FILE"
echo "==========================================">>"$LOG_FILE"
echo "" | tee -a "$LOG_FILE"
}
# 显示日志位置
show_log_file() {
log_info "详细日志: $LOG_FILE"
}
# ============================================
# 环境检查函数
# ============================================
# 检查命令是否存在
check_command() {
local cmd="$1"
if ! command -v "$cmd" &>/dev/null; then
log_error "未找到命令: $cmd"
return 1
fi
return 0
}
# 检查Docker环境
check_docker() {
log_info "检查 Docker 环境..."
if ! check_command docker; then
log_error "Docker 未安装。请访问: https://docs.docker.com/get-docker/"
return 1
fi
if ! docker info &>/dev/null; then
log_error "Docker 服务未运行"
return 1
fi
if ! command -v docker compose &>/dev/null && ! command -v docker-compose &>/dev/null; then
log_error "Docker Compose 未安装"
return 1
fi
log_success "Docker 环境正常"
return 0
}
# 检查文件是否存在
check_file() {
local file="$1"
local desc="${2:-文件}"
if [[ ! -f "$file" ]]; then
log_error "$desc 不存在: $file"
return 1
fi
return 0
}
# 检查目录是否存在
check_dir() {
local dir="$1"
local desc="${2:-目录}"
if [[ ! -d "$dir" ]]; then
log_error "$desc 不存在: $dir"
return 1
fi
return 0
}
# ============================================
# Docker操作函数
# ============================================
# 获取Docker Compose命令
get_docker_compose_cmd() {
if command -v docker &>/dev/null && docker compose version &>/dev/null; then
echo "docker compose"
elif command -v docker-compose &>/dev/null; then
echo "docker-compose"
else
log_error "未找到 Docker Compose"
return 1
fi
}
# 检查容器状态
check_container_status() {
local container_name="${1:-mc-fabric-1.21.1}"
if docker ps --format '{{.Names}}' | grep -q "^${container_name}$"; then
echo "running"
return 0
elif docker ps -a --format '{{.Names}}' | grep -q "^${container_name}$"; then
echo "stopped"
return 1
else
echo "not_found"
return 2
fi
}
# 等待容器启动
wait_for_container() {
local container_name="${1:-mc-fabric-1.21.1}"
local timeout="${2:-60}"
local elapsed=0
log_info "等待容器启动: $container_name"
while [[ $elapsed -lt $timeout ]]; do
if docker ps --format '{{.Names}}' | grep -q "^${container_name}$"; then
log_success "容器已启动"
return 0
fi
sleep 2
((elapsed += 2))
echo -n "."
done
echo ""
log_error "容器启动超时"
return 1
}
# 执行Docker Compose命令
docker_compose_exec() {
local cmd="$1"
shift
local compose_cmd=$(get_docker_compose_cmd)
if [[ -z "$compose_cmd" ]]; then
return 1
fi
log_command "$compose_cmd $cmd $*"
cd "$PROJECT_ROOT" && $compose_cmd $cmd "$@"
}
# ============================================
# 文件操作函数
# ============================================
# 创建备份
create_backup() {
local source="$1"
local backup_dir="${2:-$PROJECT_ROOT/backups}"
local name=$(basename "$source")
local timestamp=$(date +%Y%m%d-%H%M%S)
local backup_file="$backup_dir/${name}-${timestamp}.tar.gz"
mkdir -p "$backup_dir"
log_info "创建备份: $name"
if [[ -d "$source" ]]; then
if tar -czf "$backup_file" -C "$(dirname "$source")" "$name" 2>/dev/null; then
local size=$(du -h "$backup_file" | cut -f1)
log_success "备份完成: $(basename "$backup_file") ($size)"
echo "$backup_file"
return 0
fi
elif [[ -f "$source" ]]; then
if cp "$source" "$backup_file"; then
log_success "备份完成: $(basename "$backup_file")"
echo "$backup_file"
return 0
fi
fi
log_error "备份失败: $source"
return 1
}
# 清理旧备份
cleanup_old_backups() {
local backup_dir="$1"
local keep_count="${2:-5}"
if [[ ! -d "$backup_dir" ]]; then
return 0
fi
log_info "清理旧备份(保留最近 $keep_count 个)"
local backup_count=$(find "$backup_dir" -name "*.tar.gz" | wc -l)
if [[ $backup_count -le $keep_count ]]; then
log_info "当前备份数: $backup_count,无需清理"
return 0
fi
find "$backup_dir" -name "*.tar.gz" -type f -printf '%T@ %p\n' | \
sort -rn | \
tail -n +$((keep_count + 1)) | \
cut -d' ' -f2- | \
while read -r file; do
rm -f "$file"
log_info "删除旧备份: $(basename "$file")"
done
log_success "备份清理完成"
}
# ============================================
# 网络检查函数
# ============================================
# 检查网络连接
check_network() {
local url="${1:-https://api.modrinth.com/v2/project/fabric-api}"
if curl -s --connect-timeout 5 "$url" >/dev/null; then
return 0
else
log_warning "网络连接失败: $url"
return 1
fi
}
# ============================================
# 系统信息函数
# ============================================
# 记录系统信息
log_system_info() {
{
echo "=== 系统信息 ==="
echo "主机: $(hostname)"
echo "系统: $(uname -s) $(uname -r)"
echo "架构: $(uname -m)"
if command -v docker &>/dev/null; then
echo "Docker: $(docker --version 2>/dev/null || echo '未安装')"
fi
if command -v free &>/dev/null; then
echo "内存: $(free -h | grep Mem: | awk '{print $3 "/" $2}')"
fi
echo "磁盘: $(df -h "$PROJECT_ROOT" | tail -1 | awk '{print $3 "/" $2 " (已用 " $5 ")"}')"
echo "===================="
} >>"$LOG_FILE"
}
# ============================================
# 主函数
# ============================================
# 如果直接执行此脚本
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
echo "这是一个工具库,请通过 source 命令加载"
echo "用法: source $(basename "$0")"
exit 1
fi