refactor: restructure project to modern Python layout, separate src, tests, docs, examples

This commit is contained in:
2025-08-07 16:57:41 +08:00
commit 4cb6c4eab7
27 changed files with 2580 additions and 0 deletions

190
.gitignore vendored Normal file
View File

@@ -0,0 +1,190 @@
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/
cover/
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
.pybuilder/
target/
# Jupyter Notebook
.ipynb_checkpoints
# IPython
profile_default/
ipython_config.py
# pyenv
# For a library or package, you might want to ignore these files since the code is
# intended to run in multiple environments; otherwise, check them in:
# .python-version
# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
#Pipfile.lock
# poetry
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
# This is especially recommended for binary packages to ensure reproducibility, and is more
# commonly ignored for libraries.
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
#poetry.lock
# pdm
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
#pdm.lock
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
# in version control.
# https://pdm.fming.dev/#use-with-ide
.pdm.toml
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
__pypackages__/
# Celery stuff
celerybeat-schedule
celerybeat.pid
# SageMath parsed files
*.sage.py
# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# mkdocs documentation
/site
# mypy
.mypy_cache/
.dmypy.json
dmypy.json
# Pyre type checker
.pyre/
# pytype static type analyzer
.pytype/
# Cython debug symbols
cython_debug/
# PyCharm
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
# be added to the global gitignore or merged into this project gitignore. For a PyCharm
# project, it is recommended to include the following files in version control:
# - .idea/modules.xml
# - .idea/*.iml
# - .idea/misc.xml
# - .idea/vcs.xml
# - .idea/workspace.xml
# - .idea/tasks.xml
# - .idea/usage.statistics.xml
# - .idea/shelf.xml
# - .idea/dictionaries
# - .idea/shelf
# - .idea/workspace.xml
# - .idea/tasks.xml
# - .idea/usage.statistics.xml
# - .idea/shelf.xml
# - .idea/dictionaries
# - .idea/shelf
.idea/
# VS Code
.vscode/
# macOS
.DS_Store
# Windows
Thumbs.db
ehthumbs.db
Desktop.ini
# Config-Man specific
test_data/
*.log

1
.python-version Normal file
View File

@@ -0,0 +1 @@
3.13

204
PROJECT_STRUCTURE.md Normal file
View File

@@ -0,0 +1,204 @@
# Config-Man 项目结构
## 概述
Config-Man 项目采用现代Python项目标准结构将源代码、测试、文档和示例分开组织便于维护和扩展。
## 目录结构
```
config-man/
├── src/ # 源代码目录
│ └── config_man/ # 主包
│ ├── __init__.py # 包初始化文件
│ ├── cli/ # CLI模块
│ │ ├── __init__.py
│ │ └── main.py # CLI主程序
│ ├── core/ # 核心功能模块
│ │ ├── __init__.py
│ │ ├── config_manager.py # 配置管理器
│ │ ├── display_manager.py # 显示管理器
│ │ └── view_command.py # 查看命令处理器
│ └── utils/ # 工具模块
│ ├── __init__.py
│ ├── crypto.py # 加密解密工具
│ └── mock_rclone.py # 模拟rclone环境
├── tests/ # 测试目录
│ ├── __init__.py
│ ├── unit/ # 单元测试
│ │ └── __init__.py
│ ├── integration/ # 集成测试
│ │ └── __init__.py
│ └── fixtures/ # 测试工具和数据
│ ├── __init__.py
│ ├── test_configs.py # 测试配置生成器
│ └── test_data/ # 测试数据目录
├── docs/ # 文档目录
│ ├── README.md # 文档说明
│ ├── USAGE.md # 使用说明
│ ├── progress-tracker.md # 进度跟踪
│ ├── requirements.md # 需求文档
│ └── workplan.md # 工作计划
├── examples/ # 示例目录
│ └── basic_usage.py # 基本使用示例
├── main.py # 主入口文件
├── pyproject.toml # 项目配置文件
├── README.md # 项目主文档
├── .gitignore # Git忽略文件
└── PROJECT_STRUCTURE.md # 项目结构说明(本文件)
```
## 模块说明
### 源代码模块 (src/config_man/)
#### CLI模块 (cli/)
- **main.py**: CLI主程序包含所有命令行命令的定义
- 使用Click框架实现命令行界面
- 支持view、suggest-update、force-update等命令
#### 核心模块 (core/)
- **config_manager.py**: 配置管理器,负责文件下载、解密、比较等核心功能
- **display_manager.py**: 显示管理器,负责格式化输出和表格显示
- **view_command.py**: 查看命令处理器,实现查看功能的核心逻辑
#### 工具模块 (utils/)
- **crypto.py**: 加密解密工具提供DES加密解密功能
- **mock_rclone.py**: 模拟rclone环境用于测试和开发
### 测试模块 (tests/)
#### 单元测试 (unit/)
- 测试各个模块的独立功能
- 测试边界条件和错误处理
#### 集成测试 (integration/)
- 测试模块间的集成功能
- 测试完整的工作流程
#### 测试工具 (fixtures/)
- **test_configs.py**: 测试配置生成器
- **test_data/**: 测试数据目录,包含模拟的配置文件
### 文档模块 (docs/)
- 包含所有项目文档
- 使用说明、需求文档、工作计划等
### 示例模块 (examples/)
- 提供使用示例和代码示例
- 帮助用户快速上手
## 设计原则
### 1. 分离关注点
- **源代码**: 只包含业务逻辑
- **测试**: 独立的测试代码和数据
- **文档**: 完整的使用和开发文档
- **示例**: 实际的使用示例
### 2. 模块化设计
- 每个模块职责单一
- 模块间依赖关系清晰
- 便于独立测试和维护
### 3. 可扩展性
- 新功能可以轻松添加到对应模块
- 测试可以独立添加
- 文档结构清晰,便于更新
### 4. 标准化
- 遵循Python项目标准结构
- 使用现代Python工具链
- 支持pip安装和开发模式
## 开发工作流
### 1. 开发新功能
```bash
# 在src/config_man/对应模块中添加代码
# 在tests/对应目录中添加测试
# 在docs/中添加文档
# 在examples/中添加示例
```
### 2. 运行测试
```bash
# 运行所有测试
pytest
# 运行单元测试
pytest tests/unit/
# 运行集成测试
pytest tests/integration/
# 生成覆盖率报告
pytest --cov=src/config_man
```
### 3. 代码质量检查
```bash
# 代码格式化
black src/ tests/
# 类型检查
mypy src/
# 代码检查
flake8 src/ tests/
```
### 4. 安装和发布
```bash
# 开发模式安装
pip install -e .
# 构建包
python -m build
# 发布到PyPI
twine upload dist/
```
## 最佳实践
### 1. 导入路径
- 使用相对导入在包内部
- 使用绝对导入从外部访问
- 避免循环导入
### 2. 测试组织
- 单元测试测试独立功能
- 集成测试测试模块协作
- 使用fixtures提供测试数据
### 3. 文档维护
- 代码和文档同步更新
- 提供完整的使用示例
- 保持文档结构清晰
### 4. 版本控制
- 合理的.gitignore配置
- 清晰的提交信息
- 版本号管理
## 扩展指南
### 添加新功能
1.`src/config_man/core/`中添加核心逻辑
2.`src/config_man/cli/main.py`中添加CLI命令
3.`tests/`中添加对应测试
4.`docs/`中更新文档
5.`examples/`中添加使用示例
### 添加新工具
1.`src/config_man/utils/`中添加工具函数
2.`tests/unit/`中添加单元测试
3.`docs/`中添加使用说明
### 添加新测试
1. 根据测试类型选择`tests/unit/``tests/integration/`
2. 使用`tests/fixtures/`中的测试数据
3. 遵循pytest最佳实践
这种项目结构确保了代码的可维护性、可测试性和可扩展性符合现代Python项目的标准。

168
README.md Normal file
View File

@@ -0,0 +1,168 @@
# Config-Man CLI 工具
## 项目概述
Config-Man 是一个Python CLI工具用于管理存储在对象存储中的加密静态资源配置文件。该工具支持多版本管理通过Cloudflare CDN进行分发主要用于游戏应用的配置管理。
### 项目目标
- 简化多版本配置文件的查看和管理
- 支持版本升级策略(建议更新和强制更新)
- 确保配置文件的加密存储和CDN缓存同步
- 提供直观的配置对比功能
## 系统架构
### 存储架构
```
对象存储服务器
├── ab/
│ ├── 0_29/
│ │ ├── androidconfig.json (加密)
│ │ └── iosconfig.json (加密)
│ ├── 0_30/
│ │ ├── androidconfig.json (加密)
│ │ └── iosconfig.json (加密)
│ └── 1_00/
│ ├── androidconfig.json (加密)
│ └── iosconfig.json (加密)
```
### 技术栈
- **开发语言**: Python 3.13+
- **CLI框架**: Click 或 Typer
- **存储同步**: rclone
- **CDN服务**: Cloudflare
- **文件加密**: AES-256
- **配置格式**: JSON
## 功能说明
### 功能1: 查看配置文件
对比显示对象存储和CDN中的配置内容支持Android和iOS平台。
```bash
config-man view --version <版本号>
```
**参数说明**:
- `--version`: 版本号,格式为 0.29, 0.30, 0.31 等
**功能特性**:
- 同时显示Android和iOS平台的配置文件
- 对比对象存储中的内容和CDN中的内容
- 使用表格格式漂亮地展示配置差异
- 支持JSON格式化输出
### 功能2: 建议更新
在目标版本的配置文件中添加 `Ver_New` 属性,提示用户有新版本可用。
```bash
config-man suggest-update --platform <平台> --target-version <目标版本> --update-version <更新版本>
```
**参数说明**:
- `--platform`: 平台类型,支持 android 或 ios
- `--target-version`: 目标版本号,如 0.29
- `--update-version`: 更新版本号,如 0.30
### 功能3: 强制更新
直接更新目标版本的 `Ver` 属性,强制用户升级到新版本。
```bash
config-man force-update --platform <平台> --target-version <目标版本> --update-version <更新版本>
```
**参数说明**:
- `--platform`: 平台类型,支持 android 或 ios
- `--target-version`: 目标版本号,如 0.29
- `--update-version`: 更新版本号,如 0.30
## 配置文件结构
### 配置项说明
```json
{
"EventApiURL": "https://n3backend.azurewebsites.net/",
"Ver": "0.28.2ece920695",
"PlayFabTitle": "B066F",
"Google_Play_URL": "https://play.google.com/store/apps/details?id=com.arkgame.ft",
"APP_Store_URL": "https://apps.apple.com/us/app/id6505145935",
"HeartBeat": "60",
"RTMPid": "80000586",
"RTMServerEndpoint": "rtm-intl-frontgate.ilivedata.com:13321",
"RTMHmacSecret": "57047697437f4f2c97a835e8d9a53358",
"FuncUrl": "https://leaderboardcreate.azurewebsites.net",
"FuncKey": "R5kU45fNBRd52Eqp3tEqfpZqrbFw53uSSEo7wraUSqIfAzFuRmLm_w=="
}
```
### 配置项分类
- **API端点**: EventApiURL, FuncUrl
- **版本信息**: Ver, Ver_New
- **应用商店链接**: Google_Play_URL, APP_Store_URL
- **实时通信**: RTMPid, RTMServerEndpoint, RTMHmacSecret
- **功能配置**: PlayFabTitle, HeartBeat, FuncKey
## 技术要求
### 安全要求
- 配置文件在对象存储中加密存储
- 支持AES-256加密算法
- 加密密钥安全管理
- 操作日志记录
### 性能要求
- 配置文件查看响应时间 < 3秒
- 配置文件修改响应时间 < 5秒
- CDN缓存刷新响应时间 < 10秒
### 兼容性要求
- 支持Python 3.13+
- 支持Windows、macOS、Linux
- 支持rclone命令行工具
## 安装和使用
### 安装依赖
```bash
pip install -r requirements.txt
```
### 配置环境
```bash
# 配置rclone
rclone config
# 配置Cloudflare API
export CLOUDFLARE_API_TOKEN=your_token
```
### 使用示例
```bash
# 查看配置
config-man view --version 0.30
# 建议更新
config-man suggest-update --platform android --target-version 0.29 --update-version 0.30
# 强制更新
config-man force-update --platform ios --target-version 0.29 --update-version 0.30
```
## 错误处理
### 常见错误场景
- 版本号不存在
- 平台类型错误
- 网络连接失败
- 文件加密/解密失败
- CDN刷新失败
### 错误处理策略
- 提供清晰的错误信息
- 支持重试机制
- 记录详细的操作日志
- 提供回滚功能

50
docs/README.md Normal file
View File

@@ -0,0 +1,50 @@
# Config-Man 文档
本目录包含 Config-Man 项目的所有文档。
## 文档结构
- `README.md` - 项目主文档
- `USAGE.md` - 使用说明文档
- `progress-tracker.md` - 进度跟踪文档
- `requirements.md` - 需求文档
- `workplan.md` - 工作计划文档
## 快速开始
1. 安装项目:
```bash
pip install -e .
```
2. 查看帮助:
```bash
python main.py --help
```
3. 使用查看功能:
```bash
python main.py view --version 0.30 --mock
```
## 开发指南
1. 安装开发依赖:
```bash
pip install -e ".[dev]"
```
2. 运行测试:
```bash
pytest
```
3. 代码格式化:
```bash
black src/ tests/
```
4. 类型检查:
```bash
mypy src/
```

221
docs/USAGE.md Normal file
View File

@@ -0,0 +1,221 @@
# Config-Man 查看功能使用说明
## 功能概述
Config-Man 的查看功能允许您对比显示对象存储和CDN中的配置内容支持Android和iOS平台。
## 安装依赖
首先安装项目依赖:
```bash
pip install -e .
```
## 基本用法
### 1. 查看配置文件
```bash
# 查看版本 0.30 的配置文件
python main.py view --version 0.30
# 以JSON格式输出
python main.py view --version 0.30 --json
# 使用模拟环境进行测试
python main.py view --version 0.30 --mock
```
### 2. 查看帮助信息
```bash
# 查看主命令帮助
python main.py --help
# 查看view命令帮助
python main.py view --help
```
## 参数说明
### view 命令参数
- `--version`: 版本号,格式为 0.29, 0.30, 0.31 等(必需)
- `--json`: 以JSON格式输出可选
- `--storage-path`: 对象存储路径前缀,默认为 'ab'(可选)
- `--cdn-url`: CDN基础URL可选
- `--mock`: 使用模拟环境进行测试(可选)
## 输出格式
### 表格格式(默认)
```
版本: 0.30 | 平台: Android
┌─────────────────┬─────────────────────┬─────────────────────┬──────────┐
│ 配置项 │ 对象存储内容 │ CDN内容 │ 状态 │
├─────────────────┼─────────────────────┼─────────────────────┼──────────┤
│ Ver │ 0.30.2ghi789 │ 0.30.2ghi789 │ ✅ 一致 │
│ EventApiURL │ https://n3backend. │ https://n3backend. │ ✅ 一致 │
│ NewFeature │ enabled │ N/A │ ❌ 不同 │
│ ... │ ... │ ... │ ... │
└─────────────────┴─────────────────────┴─────────────────────┴──────────┘
```
### JSON格式
```json
{
"version": "0.30",
"platform": "android",
"storage_config": {
"EventApiURL": "https://n3backend.azurewebsites.net/",
"Ver": "0.30.2ghi789",
"NewFeature": "enabled"
},
"cdn_config": {
"EventApiURL": "https://n3backend.azurewebsites.net/",
"Ver": "0.30.2ghi789"
}
}
```
## 模拟环境测试
为了方便测试,项目提供了模拟环境:
```bash
# 使用模拟环境测试
python main.py view --version 0.30 --mock
```
模拟环境会:
1. 自动创建测试配置文件
2. 模拟rclone命令
3. 提供完整的测试数据
## 错误处理
### 常见错误
1. **版本号格式错误**
```
错误: 无效的版本号格式: 1.2.3
```
2. **rclone未安装**
```
错误: rclone 未安装或不可用。请先安装 rclone。
```
3. **文件不存在**
```
警告: 无法从对象存储下载 ab/0_30/androidconfig.json: 文件不存在
```
4. **网络连接失败**
```
警告: 无法从CDN获取 https://cdn.example.com/ab/0_30/androidconfig.json
```
## 配置说明
### 配置文件结构
配置文件包含以下主要字段:
- **EventApiURL**: API端点URL
- **Ver**: 版本信息
- **PlayFabTitle**: PlayFab标题
- **Google_Play_URL**: Google Play商店链接
- **APP_Store_URL**: App Store链接
- **HeartBeat**: 心跳间隔
- **RTMPid**: RTM进程ID
- **RTMServerEndpoint**: RTM服务器端点
- **RTMHmacSecret**: RTM HMAC密钥
- **FuncUrl**: 功能URL
- **FuncKey**: 功能密钥
### 版本号转换
版本号会自动转换为存储路径格式:
- `0.29` → `0_29`
- `0.30` → `0_30`
- `1.00` → `1_00`
## 高级用法
### 自定义存储路径
```bash
python main.py view --version 0.30 --storage-path custom_path
```
### 指定CDN URL
```bash
python main.py view --version 0.30 --cdn-url https://cdn.example.com
```
### 组合使用
```bash
python main.py view --version 0.30 --json --mock --storage-path test_data/ab
```
## 故障排除
### 1. 安装问题
确保安装了所有依赖:
```bash
pip install click pycryptodome tabulate requests rich
```
### 2. rclone配置
如果使用真实环境需要配置rclone
```bash
rclone config
```
### 3. 权限问题
确保有足够的权限访问对象存储和CDN。
### 4. 网络问题
检查网络连接和防火墙设置。
## 开发说明
### 项目结构
```
config-man/
├── main.py # 主程序入口
├── appconfig_tool.py # 加密解密工具
├── config_manager.py # 配置管理器
├── display_manager.py # 显示管理器
├── view_command.py # 查看命令处理器
├── mock_rclone.py # 模拟rclone环境
└── test_configs.py # 测试配置生成器
```
### 扩展功能
要添加新的查看功能,可以:
1. 在 `config_manager.py` 中添加新的方法
2. 在 `display_manager.py` 中添加新的显示格式
3. 在 `view_command.py` 中添加新的处理逻辑
4. 在 `main.py` 中添加新的CLI命令
## 联系支持
如果遇到问题,请检查:
1. 版本号格式是否正确
2. 网络连接是否正常
3. rclone配置是否正确
4. 依赖是否完整安装

284
docs/progress-tracker.md Normal file
View File

@@ -0,0 +1,284 @@
# Config-Man CLI 工具进度追踪
## 项目状态概览
- **项目名称**: Config-Man CLI 工具
- **当前阶段**: 项目初始化
- **开始日期**: [待定]
- **预计结束日期**: [待定]
- **实际进度**: 0%
- **剩余时间**: [待定]
## 阶段进度追踪
### 阶段1: 项目初始化 (1-2天)
**状态**: 🔄 进行中
**进度**: 0%
**开始时间**: [待定]
**预计完成**: [待定]
#### 任务1.1: 环境搭建
- [ ] 创建Python虚拟环境
- [ ] 安装项目依赖
- [ ] 配置开发环境
- [ ] 设置代码仓库
- **状态**: ⏳ 待开始
- **负责人**: [待定]
- **预计时间**: 0.5天
- **实际时间**: [待定]
#### 任务1.2: 项目结构设计
- [ ] 设计项目目录结构
- [ ] 创建基础模块
- [ ] 配置CLI框架
- [ ] 设置配置文件管理
- **状态**: ⏳ 待开始
- **负责人**: [待定]
- **预计时间**: 0.5天
- **实际时间**: [待定]
#### 任务1.3: 配置文件管理
- [ ] 实现配置文件加密/解密功能
- [ ] 实现对象存储连接
- [ ] 实现rclone集成
- [ ] 实现基础文件操作
- **状态**: ⏳ 待开始
- **负责人**: [待定]
- **预计时间**: 1天
- **实际时间**: [待定]
### 阶段2: 核心功能开发 (3-4天)
**状态**: ⏳ 待开始
**进度**: 0%
**开始时间**: [待定]
**预计完成**: [待定]
#### 任务2.1: 查看配置文件功能
- [ ] 实现版本号转换逻辑 (0.29 → 0_29)
- [ ] 实现文件下载和解密
- [ ] 实现CDN内容获取
- [ ] 实现配置对比显示
- [ ] 实现格式化输出 (表格格式)
- [ ] 实现Android和iOS平台同时显示
- **状态**: ⏳ 待开始
- **负责人**: [待定]
- **预计时间**: 1.5天
- **实际时间**: [待定]
#### 任务2.2: 建议更新功能
- [ ] 实现配置文件读取和解析
- [ ] 实现Ver_New属性添加逻辑
- [ ] 实现文件加密和上传
- [ ] 实现CDN缓存刷新
- [ ] 实现错误处理和回滚
- **状态**: ⏳ 待开始
- **负责人**: [待定]
- **预计时间**: 1天
- **实际时间**: [待定]
#### 任务2.3: 强制更新功能
- [ ] 实现Ver属性更新逻辑
- [ ] 实现文件加密和上传
- [ ] 实现CDN缓存刷新
- [ ] 实现错误处理和回滚
- [ ] 实现安全确认机制
- **状态**: ⏳ 待开始
- **负责人**: [待定]
- **预计时间**: 1天
- **实际时间**: [待定]
#### 任务2.4: CLI框架完善
- [ ] 实现命令行参数解析
- [ ] 实现帮助信息
- [ ] 实现错误提示
- [ ] 实现日志记录
- **状态**: ⏳ 待开始
- **负责人**: [待定]
- **预计时间**: 0.5天
- **实际时间**: [待定]
### 阶段3: 集成测试 (2-3天)
**状态**: ⏳ 待开始
**进度**: 0%
**开始时间**: [待定]
**预计完成**: [待定]
#### 任务3.1: 单元测试
- [ ] 编写配置文件处理测试
- [ ] 编写加密解密测试
- [ ] 编写CLI命令测试
- [ ] 编写版本号转换测试
- [ ] 编写JSON处理测试
- **状态**: ⏳ 待开始
- **负责人**: [待定]
- **预计时间**: 1天
- **实际时间**: [待定]
#### 任务3.2: 集成测试
- [ ] 测试对象存储连接
- [ ] 测试CDN缓存刷新
- [ ] 测试完整工作流程
- [ ] 测试多版本场景
- [ ] 测试多平台场景
- **状态**: ⏳ 待开始
- **负责人**: [待定]
- **预计时间**: 1天
- **实际时间**: [待定]
#### 任务3.3: 错误处理测试
- [ ] 测试网络错误处理
- [ ] 测试文件不存在错误
- [ ] 测试参数验证错误
- [ ] 测试加密解密错误
- [ ] 测试CDN刷新错误
- **状态**: ⏳ 待开始
- **负责人**: [待定]
- **预计时间**: 1天
- **实际时间**: [待定]
### 阶段4: 文档和部署 (1-2天)
**状态**: ⏳ 待开始
**进度**: 0%
**开始时间**: [待定]
**预计完成**: [待定]
#### 任务4.1: 文档编写
- [ ] 编写用户使用手册
- [ ] 编写API文档
- [ ] 编写部署指南
- [ ] 编写故障排除指南
- [ ] 更新README文档
- **状态**: ⏳ 待开始
- **负责人**: [待定]
- **预计时间**: 1天
- **实际时间**: [待定]
#### 任务4.2: 部署准备
- [ ] 创建安装脚本
- [ ] 配置CI/CD流程
- [ ] 准备发布包
- [ ] 创建配置文件模板
- [ ] 设置环境变量配置
- **状态**: ⏳ 待开始
- **负责人**: [待定]
- **预计时间**: 1天
- **实际时间**: [待定]
### 阶段5: 验收测试 (1天)
**状态**: ⏳ 待开始
**进度**: 0%
**开始时间**: [待定]
**预计完成**: [待定]
#### 任务5.1: 功能验收
- [ ] 验证所有CLI命令
- [ ] 验证配置文件管理
- [ ] 验证CDN缓存刷新
- [ ] 验证错误处理
- [ ] 验证文档完整性
- **状态**: ⏳ 待开始
- **负责人**: [待定]
- **预计时间**: 0.5天
- **实际时间**: [待定]
#### 任务5.2: 性能验收
- [ ] 测试响应时间
- [ ] 测试并发处理
- [ ] 测试错误恢复
- [ ] 测试内存使用
- [ ] 测试CPU使用
- **状态**: ⏳ 待开始
- **负责人**: [待定]
- **预计时间**: 0.5天
- **实际时间**: [待定]
## 里程碑追踪
### 里程碑1: 项目初始化完成
- **状态**: ⏳ 待开始
- **计划时间**: 第2天
- **实际时间**: [待定]
- **交付物**: 基础框架和配置文件管理功能
- **验收标准**: 可以成功操作加密的配置文件
### 里程碑2: 核心功能完成
- **状态**: ⏳ 待开始
- **计划时间**: 第6天
- **实际时间**: [待定]
- **交付物**: 三个主要CLI功能
- **验收标准**: 所有命令正常工作
### 里程碑3: 测试完成
- **状态**: ⏳ 待开始
- **计划时间**: 第9天
- **实际时间**: [待定]
- **交付物**: 测试报告和修复的问题
- **验收标准**: 测试覆盖率 > 80%无严重bug
### 里程碑4: 项目交付
- **状态**: ⏳ 待开始
- **计划时间**: 第12天
- **实际时间**: [待定]
- **交付物**: 完整的CLI工具和文档
- **验收标准**: 满足所有需求,可以投入使用
## 问题追踪
### 已解决问题
| 问题ID | 问题描述 | 解决方案 | 解决时间 | 负责人 |
|--------|----------|----------|----------|--------|
| - | - | - | - | - |
### 待解决问题
| 问题ID | 问题描述 | 优先级 | 状态 | 负责人 | 预计解决时间 |
|--------|----------|--------|------|--------|--------------|
| - | - | - | - | - | - |
### 风险追踪
| 风险ID | 风险描述 | 影响程度 | 缓解措施 | 状态 | 负责人 |
|--------|----------|----------|----------|------|--------|
| R001 | 对象存储API集成复杂性 | 高 | 使用rclone作为统一接口 | 监控中 | [待定] |
| R002 | CDN缓存刷新API限制 | 中 | 实现重试机制和错误处理 | 监控中 | [待定] |
| R003 | CLI框架学习成本 | 低 | 选择文档完善的框架 | 监控中 | [待定] |
## 团队工作负载
### 本周工作负载
| 团队成员 | 当前任务 | 预计完成时间 | 工作负载 | 备注 |
|----------|----------|--------------|----------|------|
| [待定] | - | - | - | - |
### 下周工作计划
| 团队成员 | 计划任务 | 预计开始时间 | 预计完成时间 | 备注 |
|----------|----------|--------------|--------------|------|
| [待定] | - | - | - | - |
## 质量指标
### 代码质量
- **测试覆盖率**: 0% (目标: >80%)
- **代码审查**: 0% (目标: 100%)
- **静态分析**: 0% (目标: 100%)
### 性能指标
- **配置文件查看响应时间**: [待测试] (目标: <3秒)
- **配置文件修改响应时间**: [待测试] (目标: <5秒)
- **CDN缓存刷新响应时间**: [待测试] (目标: <10秒)
### 文档质量
- **用户手册**: 0% (目标: 100%)
- **API文档**: 0% (目标: 100%)
- **部署指南**: 0% (目标: 100%)
## 更新日志
### 2024年[待定]
- 创建项目进度追踪文档
- 初始化所有任务状态为待开始
- 设置里程碑和验收标准
---
**最后更新**: [待定]
**更新人**: [待定]
**下次更新**: [待定]

232
docs/requirements.md Normal file
View File

@@ -0,0 +1,232 @@
# Config-Man CLI 工具需求文档
## 1. 项目概述
### 1.1 项目背景
开发一个Python CLI工具用于管理存储在对象存储中的加密静态资源配置文件。该工具支持多版本管理通过Cloudflare CDN进行分发主要用于游戏应用的配置管理。
### 1.2 项目目标
- 简化多版本配置文件的查看和管理
- 支持版本升级策略(建议更新和强制更新)
- 确保配置文件的加密存储和CDN缓存同步
- 提供直观的配置对比功能
## 2. 系统架构
### 2.1 存储架构
```
对象存储服务器
├── ab/
│ ├── 0_29/
│ │ ├── androidconfig.json (加密)
│ │ └── iosconfig.json (加密)
│ ├── 0_30/
│ │ ├── androidconfig.json (加密)
│ │ └── iosconfig.json (加密)
│ └── 1_00/
│ ├── androidconfig.json (加密)
│ └── iosconfig.json (加密)
```
### 2.2 技术栈
- **开发语言**: Python 3.13+
- **CLI框架**: Click 或 Typer
- **存储同步**: rclone
- **CDN服务**: Cloudflare
- **文件加密**: AES-256
- **配置格式**: JSON
## 3. 功能需求
### 3.1 功能1: 查看配置文件
#### 3.1.1 功能描述
对比显示对象存储和CDN中的配置内容支持Android和iOS平台。
#### 3.1.2 命令行格式
```bash
config-man view --version <版本号>
```
#### 3.1.3 参数说明
- `--version`: 版本号,格式为 0.29, 0.30, 0.31 等
#### 3.1.4 功能特性
- 同时显示Android和iOS平台的配置文件
- 对比对象存储中的内容和CDN中的内容
- 使用表格格式漂亮地展示配置差异
- 支持JSON格式化输出
#### 3.1.5 输出示例
```
版本: 0.30
平台: Android
┌─────────────────┬─────────────────────┬─────────────────────┐
│ 配置项 │ 对象存储内容 │ CDN内容 │
├─────────────────┼─────────────────────┼─────────────────────┤
│ Ver │ 0.30.1abc123 │ 0.30.1abc123 │
│ EventApiURL │ https://... │ https://... │
│ PlayFabTitle │ B066F │ B066F │
│ ... │ ... │ ... │
└─────────────────┴─────────────────────┴─────────────────────┘
平台: iOS
┌─────────────────┬─────────────────────┬─────────────────────┐
│ 配置项 │ 对象存储内容 │ CDN内容 │
├─────────────────┼─────────────────────┼─────────────────────┤
│ Ver │ 0.30.1def456 │ 0.30.1def456 │
│ ... │ ... │ ... │
└─────────────────┴─────────────────────┴─────────────────────┘
```
### 3.2 功能2: 建议更新
#### 3.2.1 功能描述
在目标版本的配置文件中添加 `Ver_New` 属性,提示用户有新版本可用。
#### 3.2.2 命令行格式
```bash
config-man suggest-update --platform <平台> --target-version <目标版本> --update-version <更新版本>
```
#### 3.2.3 参数说明
- `--platform`: 平台类型,支持 android 或 ios
- `--target-version`: 目标版本号,如 0.29
- `--update-version`: 更新版本号,如 0.30
#### 3.2.4 功能特性
- 在目标版本配置中添加 `Ver_New` 属性
- `Ver_New` 的值设为更新版本的 `Ver` 属性值
- 自动加密并上传到对象存储
- 自动刷新CDN缓存
#### 3.2.5 配置变更示例
```json
// 修改前
{
"Ver": "0.29.1abc123",
"EventApiURL": "https://n3backend.azurewebsites.net/",
"PlayFabTitle": "B066F"
}
// 修改后
{
"Ver": "0.29.1abc123",
"Ver_New": "0.30.1def456",
"EventApiURL": "https://n3backend.azurewebsites.net/",
"PlayFabTitle": "B066F"
}
```
### 3.3 功能3: 强制更新
#### 3.3.1 功能描述
直接更新目标版本的 `Ver` 属性,强制用户升级到新版本。
#### 3.3.2 命令行格式
```bash
config-man force-update --platform <平台> --target-version <目标版本> --update-version <更新版本>
```
#### 3.3.3 参数说明
- `--platform`: 平台类型,支持 android 或 ios
- `--target-version`: 目标版本号,如 0.29
- `--update-version`: 更新版本号,如 0.30
#### 3.3.4 功能特性
- 将目标版本的 `Ver` 属性值改为更新版本的 `Ver` 属性值
- 自动加密并上传到对象存储
- 自动刷新CDN缓存
#### 3.3.5 配置变更示例
```json
// 修改前
{
"Ver": "0.29.1abc123",
"EventApiURL": "https://n3backend.azurewebsites.net/",
"PlayFabTitle": "B066F"
}
// 修改后
{
"Ver": "0.30.1def456",
"EventApiURL": "https://n3backend.azurewebsites.net/",
"PlayFabTitle": "B066F"
}
```
## 4. 配置文件结构
### 4.1 配置项说明
```json
{
"EventApiURL": "https://n3backend.azurewebsites.net/",
"Ver": "0.28.2ece920695",
"PlayFabTitle": "B066F",
"Google_Play_URL": "https://play.google.com/store/apps/details?id=com.arkgame.ft",
"APP_Store_URL": "https://apps.apple.com/us/app/id6505145935",
"HeartBeat": "60",
"RTMPid": "80000586",
"RTMServerEndpoint": "rtm-intl-frontgate.ilivedata.com:13321",
"RTMHmacSecret": "57047697437f4f2c97a835e8d9a53358",
"FuncUrl": "https://leaderboardcreate.azurewebsites.net",
"FuncKey": "R5kU45fNBRd52Eqp3tEqfpZqrbFw53uSSEo7wraUSqIfAzFuRmLm_w=="
}
```
### 4.2 配置项分类
- **API端点**: EventApiURL, FuncUrl
- **版本信息**: Ver, Ver_New
- **应用商店链接**: Google_Play_URL, APP_Store_URL
- **实时通信**: RTMPid, RTMServerEndpoint, RTMHmacSecret
- **功能配置**: PlayFabTitle, HeartBeat, FuncKey
## 5. 技术要求
### 5.1 安全要求
- 配置文件在对象存储中加密存储
- 支持AES-256加密算法
- 加密密钥安全管理
- 操作日志记录
### 5.2 性能要求
- 配置文件查看响应时间 < 3秒
- 配置文件修改响应时间 < 5秒
- CDN缓存刷新响应时间 < 10秒
### 5.3 兼容性要求
- 支持Python 3.13+
- 支持Windows、macOS、Linux
- 支持rclone命令行工具
## 6. 错误处理
### 6.1 常见错误场景
- 版本号不存在
- 平台类型错误
- 网络连接失败
- 文件加密/解密失败
- CDN刷新失败
### 6.2 错误处理策略
- 提供清晰的错误信息
- 支持重试机制
- 记录详细的操作日志
- 提供回滚功能
## 7. 非功能性需求
### 7.1 可用性
- 提供清晰的命令行帮助信息
- 支持命令自动补全
- 提供详细的错误提示
### 7.2 可维护性
- 模块化设计
- 完善的日志记录
- 清晰的代码注释
### 7.3 可扩展性
- 支持新的配置文件格式
- 支持新的存储后端
- 支持新的CDN服务商

246
docs/workplan.md Normal file
View File

@@ -0,0 +1,246 @@
# Config-Man CLI 工具工作计划
## 项目概览
- **项目名称**: Config-Man CLI 工具
- **预计工期**: 8-12天
- **开始日期**: [待定]
- **结束日期**: [待定]
- **项目经理**: [待定]
## 阶段1: 项目初始化 (1-2天)
### 任务1.1: 环境搭建
- [ ] 创建Python虚拟环境
- [ ] 安装项目依赖
- [ ] 配置开发环境
- [ ] 设置代码仓库
- **负责人**: [待定]
- **预计时间**: 0.5天
- **完成标准**: 开发环境可以正常运行
### 任务1.2: 项目结构设计
- [ ] 设计项目目录结构
- [ ] 创建基础模块
- [ ] 配置CLI框架
- [ ] 设置配置文件管理
- **负责人**: [待定]
- **预计时间**: 0.5天
- **完成标准**: 项目结构清晰,基础框架可用
### 任务1.3: 配置文件管理
- [ ] 实现配置文件加密/解密功能
- [ ] 实现对象存储连接
- [ ] 实现rclone集成
- [ ] 实现基础文件操作
- **负责人**: [待定]
- **预计时间**: 1天
- **完成标准**: 可以成功下载、解密、加密、上传配置文件
## 阶段2: 核心功能开发 (3-4天)
### 任务2.1: 查看配置文件功能
- [ ] 实现版本号转换逻辑 (0.29 → 0_29)
- [ ] 实现文件下载和解密
- [ ] 实现CDN内容获取
- [ ] 实现配置对比显示
- [ ] 实现格式化输出 (表格格式)
- [ ] 实现Android和iOS平台同时显示
- **负责人**: [待定]
- **预计时间**: 1.5天
- **完成标准**: `config-man view --version 0.30` 命令正常工作
### 任务2.2: 建议更新功能
- [ ] 实现配置文件读取和解析
- [ ] 实现Ver_New属性添加逻辑
- [ ] 实现文件加密和上传
- [ ] 实现CDN缓存刷新
- [ ] 实现错误处理和回滚
- **负责人**: [待定]
- **预计时间**: 1天
- **完成标准**: `config-man suggest-update` 命令正常工作
### 任务2.3: 强制更新功能
- [ ] 实现Ver属性更新逻辑
- [ ] 实现文件加密和上传
- [ ] 实现CDN缓存刷新
- [ ] 实现错误处理和回滚
- [ ] 实现安全确认机制
- **负责人**: [待定]
- **预计时间**: 1天
- **完成标准**: `config-man force-update` 命令正常工作
### 任务2.4: CLI框架完善
- [ ] 实现命令行参数解析
- [ ] 实现帮助信息
- [ ] 实现错误提示
- [ ] 实现日志记录
- **负责人**: [待定]
- **预计时间**: 0.5天
- **完成标准**: CLI界面友好错误提示清晰
## 阶段3: 集成测试 (2-3天)
### 任务3.1: 单元测试
- [ ] 编写配置文件处理测试
- [ ] 编写加密解密测试
- [ ] 编写CLI命令测试
- [ ] 编写版本号转换测试
- [ ] 编写JSON处理测试
- **负责人**: [待定]
- **预计时间**: 1天
- **完成标准**: 测试覆盖率 > 80%
### 任务3.2: 集成测试
- [ ] 测试对象存储连接
- [ ] 测试CDN缓存刷新
- [ ] 测试完整工作流程
- [ ] 测试多版本场景
- [ ] 测试多平台场景
- **负责人**: [待定]
- **预计时间**: 1天
- **完成标准**: 所有功能在真实环境中正常工作
### 任务3.3: 错误处理测试
- [ ] 测试网络错误处理
- [ ] 测试文件不存在错误
- [ ] 测试参数验证错误
- [ ] 测试加密解密错误
- [ ] 测试CDN刷新错误
- **负责人**: [待定]
- **预计时间**: 1天
- **完成标准**: 错误处理完善,用户体验良好
## 阶段4: 文档和部署 (1-2天)
### 任务4.1: 文档编写
- [ ] 编写用户使用手册
- [ ] 编写API文档
- [ ] 编写部署指南
- [ ] 编写故障排除指南
- [ ] 更新README文档
- **负责人**: [待定]
- **预计时间**: 1天
- **完成标准**: 文档完整,易于理解
### 任务4.2: 部署准备
- [ ] 创建安装脚本
- [ ] 配置CI/CD流程
- [ ] 准备发布包
- [ ] 创建配置文件模板
- [ ] 设置环境变量配置
- **负责人**: [待定]
- **预计时间**: 1天
- **完成标准**: 可以一键部署和安装
## 阶段5: 验收测试 (1天)
### 任务5.1: 功能验收
- [ ] 验证所有CLI命令
- [ ] 验证配置文件管理
- [ ] 验证CDN缓存刷新
- [ ] 验证错误处理
- [ ] 验证文档完整性
- **负责人**: [待定]
- **预计时间**: 0.5天
- **完成标准**: 所有功能按需求正常工作
### 任务5.2: 性能验收
- [ ] 测试响应时间
- [ ] 测试并发处理
- [ ] 测试错误恢复
- [ ] 测试内存使用
- [ ] 测试CPU使用
- **负责人**: [待定]
- **预计时间**: 0.5天
- **完成标准**: 性能指标达到要求
## 关键里程碑
### 里程碑1: 项目初始化完成
- **时间**: 第2天
- **交付物**: 基础框架和配置文件管理功能
- **验收标准**: 可以成功操作加密的配置文件
### 里程碑2: 核心功能完成
- **时间**: 第6天
- **交付物**: 三个主要CLI功能
- **验收标准**: 所有命令正常工作
### 里程碑3: 测试完成
- **时间**: 第9天
- **交付物**: 测试报告和修复的问题
- **验收标准**: 测试覆盖率 > 80%无严重bug
### 里程碑4: 项目交付
- **时间**: 第12天
- **交付物**: 完整的CLI工具和文档
- **验收标准**: 满足所有需求,可以投入使用
## 风险评估
### 高风险
- **对象存储API集成复杂性**
- 风险描述: 不同对象存储服务商的API差异较大
- 缓解措施: 使用rclone作为统一接口降低集成复杂度
- 影响: 可能延长开发时间1-2天
### 中风险
- **CDN缓存刷新API限制**
- 风险描述: Cloudflare API可能有调用频率限制
- 缓解措施: 实现重试机制和错误处理
- 影响: 可能影响用户体验
### 低风险
- **CLI框架学习成本**
- 风险描述: 团队成员可能需要学习Click或Typer框架
- 缓解措施: 选择文档完善的框架,提供学习资源
- 影响: 轻微影响开发进度
## 成功标准
### 功能标准
- [ ] 所有三个CLI功能正常工作
- [ ] 配置文件正确加密存储
- [ ] CDN缓存正确刷新
- [ ] 错误处理完善
- [ ] 文档完整清晰
### 性能标准
- [ ] 配置文件查看响应时间 < 3秒
- [ ] 配置文件修改响应时间 < 5秒
- [ ] CDN缓存刷新响应时间 < 10秒
- [ ] 内存使用 < 100MB
- [ ] CPU使用 < 10%
### 质量标准
- [ ] 代码测试覆盖率 > 80%
- [ ] 无严重bug
- [ ] 代码注释完整
- [ ] 符合Python编码规范
## 团队分工
### 开发团队
- **主开发**: [待定] - 负责核心功能开发
- **测试工程师**: [待定] - 负责测试和验收
- **文档工程师**: [待定] - 负责文档编写
### 支持团队
- **项目经理**: [待定] - 负责项目管理和进度跟踪
- **技术顾问**: [待定] - 负责技术指导和问题解决
## 沟通计划
### 日常沟通
- **每日站会**: 每天上午9:0015分钟
- **周报**: 每周五下午,总结本周进展和下周计划
### 里程碑沟通
- **里程碑评审**: 每个里程碑完成后进行评审
- **风险汇报**: 发现风险时立即汇报
### 文档更新
- **进度更新**: 每周更新工作计划进度
- **问题记录**: 及时记录和跟踪问题
- **经验总结**: 项目结束后进行经验总结

49
examples/basic_usage.py Normal file
View File

@@ -0,0 +1,49 @@
#!/usr/bin/env python3
"""
Config-Man 基本使用示例
演示如何使用 Config-Man CLI 工具的基本功能。
"""
import sys
import os
# 添加项目根目录到路径
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..'))
from config_man.core import ViewCommand
from config_man.utils import patch_rclone
def main():
"""基本使用示例"""
print("Config-Man 基本使用示例")
print("=" * 50)
# 启用模拟环境
patch_rclone()
# 创建查看命令处理器
view_cmd = ViewCommand()
# 查看版本 0.30 的配置
print("\n1. 查看版本 0.30 的配置:")
success = view_cmd.execute("0.30", json_format=False)
if success:
print("✅ 查看成功")
else:
print("❌ 查看失败")
# 查看版本 0.29 的配置JSON格式
print("\n2. 查看版本 0.29 的配置JSON格式:")
success = view_cmd.execute("0.29", json_format=True)
if success:
print("✅ 查看成功")
else:
print("❌ 查看失败")
if __name__ == "__main__":
main()

12
main.py Normal file
View File

@@ -0,0 +1,12 @@
#!/usr/bin/env python3
"""
Config-Man CLI 工具入口点
用于管理存储在对象存储中的加密静态资源配置文件。
支持多版本管理通过Cloudflare CDN进行分发。
"""
from config_man.cli.main import main
if __name__ == "__main__":
main()

111
pyproject.toml Normal file
View File

@@ -0,0 +1,111 @@
[project]
name = "config-man"
version = "0.1.0"
description = "CLI tool for managing encrypted configuration files"
readme = "README.md"
requires-python = ">=3.13"
authors = [
{name = "Config-Man Team", email = "team@config-man.com"}
]
license = {text = "MIT"}
keywords = ["cli", "config", "encryption", "cdn", "storage"]
classifiers = [
"Development Status :: 3 - Alpha",
"Intended Audience :: Developers",
"License :: OSI Approved :: MIT License",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.13",
"Topic :: Software Development :: Libraries :: Python Modules",
"Topic :: System :: Systems Administration",
]
dependencies = [
"click>=8.0.0",
"pycryptodome>=3.19.0",
"tabulate>=0.9.0",
"requests>=2.31.0",
"rich>=13.0.0",
]
[project.optional-dependencies]
dev = [
"pytest>=7.0.0",
"pytest-cov>=4.0.0",
"black>=23.0.0",
"flake8>=6.0.0",
"mypy>=1.0.0",
]
test = [
"pytest>=7.0.0",
"pytest-cov>=4.0.0",
]
[project.scripts]
config-man = "config_man.cli.main:main"
[project.urls]
Homepage = "https://github.com/config-man/config-man"
Documentation = "https://config-man.readthedocs.io"
Repository = "https://github.com/config-man/config-man"
Issues = "https://github.com/config-man/config-man/issues"
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
[tool.hatch.build.targets.wheel]
packages = ["src/config_man"]
[tool.pytest.ini_options]
testpaths = ["tests"]
python_files = ["test_*.py"]
python_classes = ["Test*"]
python_functions = ["test_*"]
addopts = [
"--strict-markers",
"--strict-config",
"--cov=src/config_man",
"--cov-report=term-missing",
"--cov-report=html",
]
[tool.black]
line-length = 88
target-version = ['py313']
include = '\.pyi?$'
extend-exclude = '''
/(
# directories
\.eggs
| \.git
| \.hg
| \.mypy_cache
| \.tox
| \.venv
| build
| dist
)/
'''
[tool.mypy]
python_version = "3.13"
warn_return_any = true
warn_unused_configs = true
disallow_untyped_defs = true
disallow_incomplete_defs = true
check_untyped_defs = true
disallow_untyped_decorators = true
no_implicit_optional = true
warn_redundant_casts = true
warn_unused_ignores = true
warn_no_return = true
warn_unreachable = true
strict_equality = true
[[tool.mypy.overrides]]
module = [
"click.*",
"rich.*",
"requests.*",
"Crypto.*",
]
ignore_missing_imports = true

View File

@@ -0,0 +1,10 @@
"""
Config-Man CLI 工具
用于管理存储在对象存储中的加密静态资源配置文件。
支持多版本管理通过Cloudflare CDN进行分发。
"""
__version__ = "0.1.0"
__author__ = "Config-Man Team"
__description__ = "CLI tool for managing encrypted configuration files"

View File

@@ -0,0 +1,9 @@
"""
CLI 模块
包含命令行界面相关的功能。
"""
from .main import cli, main
__all__ = ["cli", "main"]

109
src/config_man/cli/main.py Normal file
View File

@@ -0,0 +1,109 @@
import click
import os
from ..core.view_command import ViewCommand
from ..utils.mock_rclone import patch_rclone
@click.group()
@click.version_option(version="0.1.0")
def cli():
"""Config-Man CLI 工具
用于管理存储在对象存储中的加密静态资源配置文件。
支持多版本管理通过Cloudflare CDN进行分发。
"""
pass
@cli.command()
@click.option('--version', required=True, help='版本号,格式为 0.29, 0.30, 0.31 等')
@click.option('--json', 'json_format', is_flag=True, help='以JSON格式输出')
@click.option('--storage-path', default='ab', help='对象存储路径前缀')
@click.option('--cdn-url', default='', help='CDN基础URL')
@click.option('--mock', is_flag=True, help='使用模拟环境进行测试')
def view(version, json_format, storage_path, cdn_url, mock):
"""查看配置文件
对比显示对象存储和CDN中的配置内容支持Android和iOS平台。
示例:
config-man view --version 0.30
config-man view --version 0.30 --json
config-man view --version 0.30 --mock
"""
try:
# 如果使用模拟环境启用rclone模拟
if mock:
patch_rclone()
click.echo("使用模拟环境进行测试...")
else:
# 检查rclone是否可用
if not _check_rclone():
click.echo("错误: rclone 未安装或不可用。请先安装 rclone。")
return 1
# 创建查看命令处理器
view_cmd = ViewCommand(storage_path, cdn_url)
# 执行查看命令
success = view_cmd.execute(version, json_format)
return 0 if success else 1
except Exception as e:
click.echo(f"错误: {str(e)}")
return 1
@cli.command()
@click.option('--platform', required=True, type=click.Choice(['android', 'ios']),
help='平台类型')
@click.option('--target-version', required=True, help='目标版本号')
@click.option('--update-version', required=True, help='更新版本号')
def suggest_update(platform, target_version, update_version):
"""建议更新
在目标版本的配置文件中添加 Ver_New 属性,提示用户有新版本可用。
示例:
config-man suggest-update --platform android --target-version 0.29 --update-version 0.30
"""
click.echo("建议更新功能尚未实现")
return 1
@cli.command()
@click.option('--platform', required=True, type=click.Choice(['android', 'ios']),
help='平台类型')
@click.option('--target-version', required=True, help='目标版本号')
@click.option('--update-version', required=True, help='更新版本号')
def force_update(platform, target_version, update_version):
"""强制更新
直接更新目标版本的 Ver 属性,强制用户升级到新版本。
示例:
config-man force-update --platform ios --target-version 0.29 --update-version 0.30
"""
click.echo("强制更新功能尚未实现")
return 1
def _check_rclone():
"""检查rclone是否可用"""
import subprocess
try:
result = subprocess.run(['rclone', 'version'],
capture_output=True, text=True, timeout=5)
return result.returncode == 0
except (subprocess.TimeoutExpired, FileNotFoundError):
return False
def main():
"""主函数"""
cli()
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,11 @@
"""
核心功能模块
包含配置管理、加密解密、显示管理等核心功能。
"""
from .config_manager import ConfigManager
from .display_manager import DisplayManager
from .view_command import ViewCommand
__all__ = ["ConfigManager", "DisplayManager", "ViewCommand"]

View File

@@ -0,0 +1,119 @@
import json
import os
import subprocess
import requests
from typing import Dict, Optional, Tuple
from ..utils.crypto import encrypt, decrypt
class ConfigManager:
"""配置文件管理器"""
def __init__(self, storage_path: str = "ab", cdn_base_url: str = ""):
self.storage_path = storage_path
self.cdn_base_url = cdn_base_url
def version_to_path(self, version: str) -> str:
"""将版本号转换为存储路径格式"""
# 0.29 -> 0_29
return version.replace('.', '_')
def get_config_path(self, version: str, platform: str) -> str:
"""获取配置文件在对象存储中的路径"""
version_path = self.version_to_path(version)
filename = f"{platform}config.json"
return f"{self.storage_path}/{version_path}/{filename}"
def get_cdn_url(self, version: str, platform: str) -> str:
"""获取配置文件在CDN中的URL"""
if not self.cdn_base_url:
return ""
version_path = self.version_to_path(version)
filename = f"{platform}config.json"
return f"{self.cdn_base_url}/{self.storage_path}/{version_path}/{filename}"
def download_from_storage(self, version: str, platform: str) -> Optional[str]:
"""从对象存储下载并解密配置文件"""
try:
config_path = self.get_config_path(version, platform)
# 使用rclone下载文件
result = subprocess.run(
["rclone", "cat", config_path],
capture_output=True,
text=True,
timeout=30
)
if result.returncode != 0:
print(f"警告: 无法从对象存储下载 {config_path}: {result.stderr}")
return None
# 解密文件内容
encrypted_content = result.stdout.strip()
if not encrypted_content:
print(f"警告: 文件 {config_path} 为空")
return None
decrypted_content = decrypt(encrypted_content)
return decrypted_content
except subprocess.TimeoutExpired:
print(f"错误: 下载 {config_path} 超时")
return None
except Exception as e:
print(f"错误: 下载 {config_path} 失败: {str(e)}")
return None
def get_from_cdn(self, version: str, platform: str) -> Optional[str]:
"""从CDN获取配置文件内容"""
try:
cdn_url = self.get_cdn_url(version, platform)
if not cdn_url:
print(f"警告: CDN URL未配置跳过CDN内容获取")
return None
response = requests.get(cdn_url, timeout=10)
response.raise_for_status()
# CDN中的内容应该是解密后的JSON
return response.text
except requests.RequestException as e:
print(f"警告: 无法从CDN获取 {cdn_url}: {str(e)}")
return None
except Exception as e:
print(f"错误: 获取CDN内容失败: {str(e)}")
return None
def parse_config(self, content: str) -> Optional[Dict]:
"""解析配置文件内容"""
try:
return json.loads(content)
except json.JSONDecodeError as e:
print(f"错误: 配置文件格式错误: {str(e)}")
return None
def compare_configs(self, storage_config: Dict, cdn_config: Dict) -> Dict:
"""比较存储配置和CDN配置的差异"""
all_keys = set(storage_config.keys()) | set(cdn_config.keys())
differences = {}
for key in sorted(all_keys):
storage_value = storage_config.get(key, "N/A")
cdn_value = cdn_config.get(key, "N/A")
if storage_value != cdn_value:
differences[key] = {
"storage": storage_value,
"cdn": cdn_value,
"different": True
}
else:
differences[key] = {
"storage": storage_value,
"cdn": cdn_value,
"different": False
}
return differences

View File

@@ -0,0 +1,109 @@
from typing import Dict, List
from rich.console import Console
from rich.table import Table
from rich.panel import Panel
from rich.text import Text
import json
class DisplayManager:
"""显示管理器"""
def __init__(self):
self.console = Console()
def display_config_comparison(self, version: str, platform: str,
storage_config: Dict, cdn_config: Dict,
differences: Dict):
"""显示配置对比结果"""
# 创建标题
title = f"版本: {version} | 平台: {platform.title()}"
self.console.print(f"\n[bold blue]{title}[/bold blue]")
# 创建表格
table = Table(show_header=True, header_style="bold magenta")
table.add_column("配置项", style="cyan", width=20)
table.add_column("对象存储内容", style="green", width=30)
table.add_column("CDN内容", style="yellow", width=30)
table.add_column("状态", style="red", width=10)
# 添加数据行
for key, data in differences.items():
storage_value = str(data["storage"])
cdn_value = str(data["cdn"])
status = "❌ 不同" if data["different"] else "✅ 一致"
# 截断过长的值
if len(storage_value) > 25:
storage_value = storage_value[:22] + "..."
if len(cdn_value) > 25:
cdn_value = cdn_value[:22] + "..."
table.add_row(key, storage_value, cdn_value, status)
self.console.print(table)
def display_json_format(self, version: str, platform: str,
storage_config: Dict, cdn_config: Dict):
"""以JSON格式显示配置"""
title = f"版本: {version} | 平台: {platform.title()}"
self.console.print(f"\n[bold blue]{title}[/bold blue]")
# 创建对比JSON
comparison = {
"version": version,
"platform": platform,
"storage_config": storage_config,
"cdn_config": cdn_config
}
# 格式化JSON输出
json_str = json.dumps(comparison, indent=2, ensure_ascii=False)
# 使用面板显示
panel = Panel(
json_str,
title="JSON格式",
border_style="blue"
)
self.console.print(panel)
def display_summary(self, version: str, results: Dict):
"""显示总结信息"""
self.console.print(f"\n[bold green]配置查看总结[/bold green]")
self.console.print(f"版本: {version}")
for platform in ["android", "ios"]:
if platform in results:
result = results[platform]
if result["success"]:
storage_keys = len(result["storage_config"])
cdn_keys = len(result["cdn_config"])
differences = sum(1 for data in result["differences"].values()
if data["different"])
status = "✅ 正常" if differences == 0 else f"⚠️ {differences} 项不同"
self.console.print(
f" {platform.title()}: {status} "
f"(存储: {storage_keys}项, CDN: {cdn_keys}项)"
)
else:
self.console.print(f" {platform.title()}: ❌ 失败")
else:
self.console.print(f" {platform.title()}: ⚠️ 未检查")
def display_error(self, message: str):
"""显示错误信息"""
self.console.print(f"[bold red]错误: {message}[/bold red]")
def display_warning(self, message: str):
"""显示警告信息"""
self.console.print(f"[bold yellow]警告: {message}[/bold yellow]")
def display_info(self, message: str):
"""显示信息"""
self.console.print(f"[bold blue]信息: {message}[/bold blue]")

View File

@@ -0,0 +1,142 @@
from typing import Dict, Optional
from .config_manager import ConfigManager
from .display_manager import DisplayManager
class ViewCommand:
"""查看命令处理器"""
def __init__(self, storage_path: str = "ab", cdn_base_url: str = ""):
self.config_manager = ConfigManager(storage_path, cdn_base_url)
self.display_manager = DisplayManager()
def execute(self, version: str, json_format: bool = False) -> bool:
"""执行查看命令"""
# 验证版本号格式
if not self._validate_version(version):
self.display_manager.display_error(f"无效的版本号格式: {version}")
return False
self.display_manager.display_info(f"正在查看版本 {version} 的配置文件...")
results = {}
success = True
# 检查Android和iOS平台
for platform in ["android", "ios"]:
result = self._check_platform_config(version, platform)
results[platform] = result
if not result["success"]:
success = False
# 显示结果
if json_format:
self._display_json_results(version, results)
else:
self._display_table_results(version, results)
# 显示总结
self.display_manager.display_summary(version, results)
return success
def _validate_version(self, version: str) -> bool:
"""验证版本号格式"""
try:
# 检查版本号格式 (如 0.29, 0.30, 1.00)
parts = version.split('.')
if len(parts) != 2:
return False
major, minor = parts
if not major.isdigit() or not minor.isdigit():
return False
return True
except:
return False
def _check_platform_config(self, version: str, platform: str) -> Dict:
"""检查指定平台的配置"""
result = {
"success": False,
"storage_config": {},
"cdn_config": {},
"differences": {},
"error": None
}
try:
# 从对象存储获取配置
storage_content = self.config_manager.download_from_storage(version, platform)
if storage_content is None:
result["error"] = f"无法从对象存储获取 {platform} 配置"
return result
storage_config = self.config_manager.parse_config(storage_content)
if storage_config is None:
result["error"] = f"解析对象存储中的 {platform} 配置失败"
return result
result["storage_config"] = storage_config
# 从CDN获取配置
cdn_content = self.config_manager.get_from_cdn(version, platform)
if cdn_content is None:
# CDN获取失败使用空配置
result["cdn_config"] = {}
result["differences"] = self.config_manager.compare_configs(
storage_config, {}
)
else:
cdn_config = self.config_manager.parse_config(cdn_content)
if cdn_config is None:
result["error"] = f"解析CDN中的 {platform} 配置失败"
return result
result["cdn_config"] = cdn_config
result["differences"] = self.config_manager.compare_configs(
storage_config, cdn_config
)
result["success"] = True
except Exception as e:
result["error"] = f"检查 {platform} 配置时发生错误: {str(e)}"
return result
def _display_table_results(self, version: str, results: Dict):
"""以表格格式显示结果"""
for platform in ["android", "ios"]:
if platform in results:
result = results[platform]
if result["success"]:
self.display_manager.display_config_comparison(
version, platform,
result["storage_config"],
result["cdn_config"],
result["differences"]
)
else:
self.display_manager.display_error(
f"{platform.title()} 配置检查失败: {result['error']}"
)
def _display_json_results(self, version: str, results: Dict):
"""以JSON格式显示结果"""
for platform in ["android", "ios"]:
if platform in results:
result = results[platform]
if result["success"]:
self.display_manager.display_json_format(
version, platform,
result["storage_config"],
result["cdn_config"]
)
else:
self.display_manager.display_error(
f"{platform.title()} 配置检查失败: {result['error']}"
)

View File

@@ -0,0 +1,10 @@
"""
工具模块
包含加密解密、模拟环境等工具功能。
"""
from .crypto import encrypt, decrypt
from .mock_rclone import MockRclone, patch_rclone
__all__ = ["encrypt", "decrypt", "MockRclone", "patch_rclone"]

View File

@@ -0,0 +1,23 @@
import json
import os
from Crypto.Cipher import DES
from Crypto.Util.Padding import pad,unpad
import base64
def encrypt(text):
key = 'tbambooz'.encode('ascii')
des = DES.new(key, DES.MODE_CBC, IV=key)
padded_text = pad(text.encode('utf-8'), DES.block_size)
encrypted_text = des.encrypt(padded_text)
return base64.b64encode(encrypted_text).decode('utf-8')
def decrypt(encrypted_text):
key = 'tbambooz'
key = key.encode('ascii')
des = DES.new(key, DES.MODE_CBC, IV=key)
decoded_text = base64.b64decode(encrypted_text)
decrypted_text = des.decrypt(decoded_text)
unpadded_text = unpad(decrypted_text, DES.block_size)
return unpadded_text.decode('utf-8')

View File

@@ -0,0 +1,153 @@
import os
import json
import subprocess
from .crypto import encrypt, decrypt
class MockRclone:
"""模拟rclone环境用于测试"""
def __init__(self, test_data_path: str = "test_data"):
self.test_data_path = test_data_path
self._setup_mock_environment()
def _setup_mock_environment(self):
"""设置模拟环境"""
# 确保测试数据目录存在
os.makedirs(self.test_data_path, exist_ok=True)
# 创建测试配置文件
self._create_test_configs()
def _create_test_configs(self):
"""创建测试配置文件"""
test_configs = {
"0.29": {
"android": {
"EventApiURL": "https://n3backend.azurewebsites.net/",
"Ver": "0.29.1abc123",
"PlayFabTitle": "B066F",
"Google_Play_URL": "https://play.google.com/store/apps/details?id=com.arkgame.ft",
"APP_Store_URL": "https://apps.apple.com/us/app/id6505145935",
"HeartBeat": "60",
"RTMPid": "80000586",
"RTMServerEndpoint": "rtm-intl-frontgate.ilivedata.com:13321",
"RTMHmacSecret": "57047697437f4f2c97a835e8d9a53358",
"FuncUrl": "https://leaderboardcreate.azurewebsites.net",
"FuncKey": "R5kU45fNBRd52Eqp3tEqfpZqrbFw53uSSEo7wraUSqIfAzFuRmLm_w=="
},
"ios": {
"EventApiURL": "https://n3backend.azurewebsites.net/",
"Ver": "0.29.1def456",
"PlayFabTitle": "B066F",
"Google_Play_URL": "https://play.google.com/store/apps/details?id=com.arkgame.ft",
"APP_Store_URL": "https://apps.apple.com/us/app/id6505145935",
"HeartBeat": "60",
"RTMPid": "80000586",
"RTMServerEndpoint": "rtm-intl-frontgate.ilivedata.com:13321",
"RTMHmacSecret": "57047697437f4f2c97a835e8d9a53358",
"FuncUrl": "https://leaderboardcreate.azurewebsites.net",
"FuncKey": "R5kU45fNBRd52Eqp3tEqfpZqrbFw53uSSEo7wraUSqIfAzFuRmLm_w=="
}
},
"0.30": {
"android": {
"EventApiURL": "https://n3backend.azurewebsites.net/",
"Ver": "0.30.2ghi789",
"PlayFabTitle": "B066F",
"Google_Play_URL": "https://play.google.com/store/apps/details?id=com.arkgame.ft",
"APP_Store_URL": "https://apps.apple.com/us/app/id6505145935",
"HeartBeat": "60",
"RTMPid": "80000586",
"RTMServerEndpoint": "rtm-intl-frontgate.ilivedata.com:13321",
"RTMHmacSecret": "57047697437f4f2c97a835e8d9a53358",
"FuncUrl": "https://leaderboardcreate.azurewebsites.net",
"FuncKey": "R5kU45fNBRd52Eqp3tEqfpZqrbFw53uSSEo7wraUSqIfAzFuRmLm_w==",
"NewFeature": "enabled"
},
"ios": {
"EventApiURL": "https://n3backend.azurewebsites.net/",
"Ver": "0.30.2jkl012",
"PlayFabTitle": "B066F",
"Google_Play_URL": "https://play.google.com/store/apps/details?id=com.arkgame.ft",
"APP_Store_URL": "https://apps.apple.com/us/app/id6505145935",
"HeartBeat": "60",
"RTMPid": "80000586",
"RTMServerEndpoint": "rtm-intl-frontgate.ilivedata.com:13321",
"RTMHmacSecret": "57047697437f4f2c97a835e8d9a53358",
"FuncUrl": "https://leaderboardcreate.azurewebsites.net",
"FuncKey": "R5kU45fNBRd52Eqp3tEqfpZqrbFw53uSSEo7wraUSqIfAzFuRmLm_w==",
"NewFeature": "enabled"
}
}
}
# 创建测试目录结构
for version, platforms in test_configs.items():
version_path = f"{self.test_data_path}/ab/{version.replace('.', '_')}"
os.makedirs(version_path, exist_ok=True)
for platform, config in platforms.items():
filename = f"{platform}config.json"
filepath = os.path.join(version_path, filename)
# 加密配置并保存
config_json = json.dumps(config, indent=2, ensure_ascii=False)
encrypted_config = encrypt(config_json)
with open(filepath, 'w', encoding='utf-8') as f:
f.write(encrypted_config)
print(f"创建测试文件: {filepath}")
def mock_rclone_cat(self, path: str) -> str:
"""模拟rclone cat命令"""
# 将路径转换为本地文件路径
local_path = os.path.join(self.test_data_path, path)
if not os.path.exists(local_path):
raise FileNotFoundError(f"文件不存在: {path}")
with open(local_path, 'r', encoding='utf-8') as f:
return f.read().strip()
def patch_rclone():
"""修补rclone调用使用模拟环境"""
import subprocess
original_run = subprocess.run
def mock_run(cmd, *args, **kwargs):
if len(cmd) >= 2 and cmd[0] == 'rclone' and cmd[1] == 'cat':
# 模拟rclone cat命令
mock_rclone = MockRclone()
try:
content = mock_rclone.mock_rclone_cat(cmd[2])
# 返回模拟的subprocess结果
from types import SimpleNamespace
result = SimpleNamespace()
result.returncode = 0
result.stdout = content
result.stderr = ""
return result
except FileNotFoundError as e:
# 返回错误结果
from types import SimpleNamespace
result = SimpleNamespace()
result.returncode = 1
result.stdout = ""
result.stderr = str(e)
return result
else:
# 对于其他命令,使用原始实现
return original_run(cmd, *args, **kwargs)
subprocess.run = mock_run
print("已启用rclone模拟环境")
if __name__ == "__main__":
# 创建测试环境
mock = MockRclone()
print("模拟rclone环境设置完成")

5
tests/__init__.py Normal file
View File

@@ -0,0 +1,5 @@
"""
测试包
包含单元测试、集成测试和测试工具。
"""

5
tests/fixtures/__init__.py vendored Normal file
View File

@@ -0,0 +1,5 @@
"""
测试工具
包含测试数据、模拟环境和测试工具。
"""

97
tests/fixtures/test_configs.py vendored Normal file
View File

@@ -0,0 +1,97 @@
import json
import os
import sys
import os
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '..', 'src'))
from config_man.utils.crypto import encrypt
def create_test_configs():
"""创建测试配置文件"""
# 测试配置数据
test_configs = {
"0.29": {
"android": {
"EventApiURL": "https://n3backend.azurewebsites.net/",
"Ver": "0.29.1abc123",
"PlayFabTitle": "B066F",
"Google_Play_URL": "https://play.google.com/store/apps/details?id=com.arkgame.ft",
"APP_Store_URL": "https://apps.apple.com/us/app/id6505145935",
"HeartBeat": "60",
"RTMPid": "80000586",
"RTMServerEndpoint": "rtm-intl-frontgate.ilivedata.com:13321",
"RTMHmacSecret": "57047697437f4f2c97a835e8d9a53358",
"FuncUrl": "https://leaderboardcreate.azurewebsites.net",
"FuncKey": "R5kU45fNBRd52Eqp3tEqfpZqrbFw53uSSEo7wraUSqIfAzFuRmLm_w=="
},
"ios": {
"EventApiURL": "https://n3backend.azurewebsites.net/",
"Ver": "0.29.1def456",
"PlayFabTitle": "B066F",
"Google_Play_URL": "https://play.google.com/store/apps/details?id=com.arkgame.ft",
"APP_Store_URL": "https://apps.apple.com/us/app/id6505145935",
"HeartBeat": "60",
"RTMPid": "80000586",
"RTMServerEndpoint": "rtm-intl-frontgate.ilivedata.com:13321",
"RTMHmacSecret": "57047697437f4f2c97a835e8d9a53358",
"FuncUrl": "https://leaderboardcreate.azurewebsites.net",
"FuncKey": "R5kU45fNBRd52Eqp3tEqfpZqrbFw53uSSEo7wraUSqIfAzFuRmLm_w=="
}
},
"0.30": {
"android": {
"EventApiURL": "https://n3backend.azurewebsites.net/",
"Ver": "0.30.2ghi789",
"PlayFabTitle": "B066F",
"Google_Play_URL": "https://play.google.com/store/apps/details?id=com.arkgame.ft",
"APP_Store_URL": "https://apps.apple.com/us/app/id6505145935",
"HeartBeat": "60",
"RTMPid": "80000586",
"RTMServerEndpoint": "rtm-intl-frontgate.ilivedata.com:13321",
"RTMHmacSecret": "57047697437f4f2c97a835e8d9a53358",
"FuncUrl": "https://leaderboardcreate.azurewebsites.net",
"FuncKey": "R5kU45fNBRd52Eqp3tEqfpZqrbFw53uSSEo7wraUSqIfAzFuRmLm_w==",
"NewFeature": "enabled"
},
"ios": {
"EventApiURL": "https://n3backend.azurewebsites.net/",
"Ver": "0.30.2jkl012",
"PlayFabTitle": "B066F",
"Google_Play_URL": "https://play.google.com/store/apps/details?id=com.arkgame.ft",
"APP_Store_URL": "https://apps.apple.com/us/app/id6505145935",
"HeartBeat": "60",
"RTMPid": "80000586",
"RTMServerEndpoint": "rtm-intl-frontgate.ilivedata.com:13321",
"RTMHmacSecret": "57047697437f4f2c97a835e8d9a53358",
"FuncUrl": "https://leaderboardcreate.azurewebsites.net",
"FuncKey": "R5kU45fNBRd52Eqp3tEqfpZqrbFw53uSSEo7wraUSqIfAzFuRmLm_w==",
"NewFeature": "enabled"
}
}
}
# 创建测试目录结构
for version, platforms in test_configs.items():
version_path = f"test_data/ab/{version.replace('.', '_')}"
os.makedirs(version_path, exist_ok=True)
for platform, config in platforms.items():
filename = f"{platform}config.json"
filepath = os.path.join(version_path, filename)
# 加密配置并保存
config_json = json.dumps(config, indent=2, ensure_ascii=False)
encrypted_config = encrypt(config_json)
with open(filepath, 'w', encoding='utf-8') as f:
f.write(encrypted_config)
print(f"创建测试文件: {filepath}")
print("测试配置文件创建完成!")
if __name__ == "__main__":
create_test_configs()

View File

@@ -0,0 +1,5 @@
"""
集成测试
测试模块间的集成功能。
"""

5
tests/unit/__init__.py Normal file
View File

@@ -0,0 +1,5 @@
"""
单元测试
测试各个模块的独立功能。
"""