diff --git a/README.md b/README.md index e52eb67..32329b9 100644 --- a/README.md +++ b/README.md @@ -1,120 +1,153 @@ -# Temp File Transfer Service +# 临时文件传输服务 -A Flask-based personal temporary file sharing service with a Web UI, API access, and SQLite-backed metadata. +基于 Flask 的个人临时文件分享服务,支持 Web 界面、API 接口和 SQLite 数据库。 -What it does -- Upload files via a Web UI or an API endpoint -- Choose an expiry: 1 hour, 24 hours, or 7 days -- Generate a share URL (UUID) for downloaded access -- File data stored on disk; metadata stored in SQLite -- Web-based download page and a simple API for programmatic uploads +## 功能介绍 + +- 通过 Web 界面或 API 接口上传文件 +- 选择过期时间:1 小时、24 小时或 7 天 +- 生成分享链接(UUID)供下载使用 +- 文件数据存储在磁盘,元数据存储在 SQLite +- Web 下载页面和简单的 API 接口支持程序化上传 + +## 技术栈 -Tech stack - Flask (Python) -- SQLite (metadata) -- Filesystem storage for actual file data +- SQLite (元数据存储) +- 文件系统存储实际文件数据 -Local development setup -1. Prerequisites -- Python 3.8+ (the project currently uses Python 3.x in this environment) +## 本地开发环境搭建 + +### 1. 环境要求 + +- Python 3.8+ (当前环境使用 Python 3.x) - pip -2. Install dependencies +### 2. 安装依赖 + ```bash pip install -r requirements.txt ``` -3. Run the server +### 3. 运行服务 + ```bash python app.py ``` -4. Access -- Web UI: http://localhost:5000 -- API: see /api/upload and /api/file endpoints +### 4. 访问地址 -Deployment +- Web 界面: http://localhost:5000 +- API 接口: 详见 /api/upload 和 /api/file 接口 -The production instance runs at: -- **Domain**: `xiaji-temp.duckdns.org` -- **HTTPS**: Let's Encrypt SSL with auto-renewal (certbot timer) -- **Nginx**: reverse proxy with 500MB upload limit, 80→443 redirect -- **Gunicorn**: 4 workers, systemd-managed +## 部署说明 -Project layout -- app.py # Flask application -- config.py # Configuration constants -- database.py # SQLite helpers and data access -- requirements.txt # Python dependencies -- templates/ # Jinja templates (index.html, download.html) -- upload_client.py # Simple API client example for testing -- uploads/ # Storage for uploaded files (created at runtime) +生产环境部署信息: -Data model (SQLite) -- Table: files - - id TEXT PRIMARY KEY - - filename TEXT - - filepath TEXT - - filesize INTEGER - - expiry_hours INTEGER - - created_at TIMESTAMP - - expires_at TIMESTAMP +- **域名**: `xiaji-temp.duckdns.org` +- **HTTPS**: Let's Encrypt SSL 证书,自动续期 (certbot timer) +- **Nginx**: 反向代理,500MB 上传限制,80→443 自动跳转 +- **Gunicorn**: 4 个工作者进程,systemd 管理 -Expiry and cleanup -- Expiry options are defined as 1h, 24h, 7d in config -- A cleanup operation removes expired files from disk and deletes DB rows -- Cleanup is invoked on access endpoints (and can be wired to a cron/daemon later) +## 项目结构 -Traffic limits -- Maximum file size: 500 MB -- Per-IP daily traffic limit: 20 GB (upload + download combined) -- IP traffic tracked in SQLite `ip_traffic` table, reset daily +| 文件 | 说明 | +|------|------| +| `app.py` | Flask 应用程序主文件 | +| `config.py` | 配置常量 | +| `database.py` | SQLite 辅助函数和数据访问 | +| `requirements.txt` | Python 依赖包 | +| `templates/` | Jinja 模板 (index.html, download.html) | +| `upload_client.py` | 简单的 API 客户端示例,用于测试 | +| `uploads/` | 上传文件存储目录 (运行时创建) | +| `temp_file_trans_client/` | PySide6 桌面客户端 | -SSL certificate -- Let's Encrypt certificate deployed via certbot -- Auto-renewal via systemd timer: `certbot.timer` -- Manual renewal test: `certbot renew --dry-run` +## 桌面客户端 -Security notes -- Do not commit secrets. Secrets should be provided via environment variables in production. -- This repository currently avoids embedding credentials. +使用 Python + PySide6 + PyInstaller 构建的桌面客户端,支持拖拽上传文件。 -Next steps (optional) -- Add authentication for admin/API usage -- Add rate limiting and upload size limits per user -- Add automated tests and CI integration +### 客户端功能 -License -- MIT or your preferred license (update as needed) +- 拖拽文件到指定区域上传 +- 点击选择文件上传 +- 显示上传进度 +- 上传成功显示分享链接 +- 支持复制链接到剪贴板 +- 可配置服务器地址 -API Usage (Python) +### 运行客户端 -Upload a file via the API endpoint: - -```python -import requests - -BASE_URL = "https://xiaji-temp.duckdns.org" - -expiry = "24h" # 1h, 24h, 7d - -with open("/path/to/your/file.zip", "rb") as f: - resp = requests.post( - f"{BASE_URL}/api/upload", - files={"file": ("file.zip", f)}, - data={"expiry": expiry}, - ) - -if resp.status_code == 200: - data = resp.json() - print(f"Share URL: {data['share_url']}") - print(f"File ID: {data['id']}") - print(f"Size: {data['filesize']} bytes") -else: - print(f"Upload failed: {resp.json()['error']}") +```bash +cd temp_file_trans_client +pip install -r requirements.txt +python main.py ``` -Response format: +### 打包为 exe + +```bash +cd temp_file_trans_client +pip install pyinstaller +pyinstaller build.spec +``` + +打包后的可执行文件位于 `dist/temp_file_trans_client.exe` + +## 数据模型 (SQLite) + +**files 表结构:** + +| 字段 | 类型 | 说明 | +|------|------|------| +| id | TEXT PRIMARY KEY | 文件唯一标识 (UUID) | +| filename | TEXT | 原始文件名 | +| filepath | TEXT | 文件存储路径 | +| filesize | INTEGER | 文件大小 (字节) | +| expiry_hours | INTEGER | 过期时间 (小时) | +| created_at | TIMESTAMP | 创建时间 | +| expires_at | TIMESTAMP | 过期时间 | + +## 过期清理 + +- 过期选项在 config 中定义为 1h、24h、7d +- 清理操作会删除过期文件并清理数据库记录 +- 访问接口时自动触发清理 (后续可配置 cron/定时任务) + +## 流量限制 + +- 最大文件大小:500 MB +- 单 IP 每日流量限制:20 GB (上传 + 下载合计) +- IP 流量记录在 SQLite `ip_traffic` 表中,每日重置 + +## SSL 证书 + +- 使用 Let's Encrypt 证书,通过 certbot 部署 +- 自动续期通过 systemd timer: `certbot.timer` +- 手动测试续期: `certbot renew --dry-run` + +## 安全说明 + +- 请勿提交密钥等敏感信息。生产环境应通过环境变量提供 +- 当前仓库未嵌入任何凭证 + +## API 接口说明 + +### 上传文件 + +``` +POST /api/upload +Content-Type: multipart/form-data +``` + +**请求参数:** + +| 参数 | 类型 | 必填 | 说明 | +|------|------|------|------| +| file | File | 是 | 要上传的文件 | +| expiry | String | 否 | 过期时间: 1h / 24h / 7d (默认 24h) | + +**返回示例:** + ```json { "id": "550e8400-e29b-41d4-a716-446655440000", @@ -125,23 +158,91 @@ Response format: } ``` -Get file info via API: -```python -resp = requests.get(f"{BASE_URL}/api/file/{file_id}") -if resp.status_code == 200: - info = resp.json() - print(f"Daily upload: {info['daily_upload']} bytes") - print(f"Daily download: {info['daily_download']} bytes") - print(f"Traffic limit: {info['traffic_limit']} bytes (20GB)") +### 获取文件信息 + +``` +GET /api/file/{file_id} ``` -Or use the bundled client script: +**返回示例:** + +```json +{ + "id": "550e8400-e29b-41d4-a716-446655440000", + "filename": "file.zip", + "filesize": 1048576, + "created_at": "2024-01-15 10:30:00", + "expires_at": "2024-01-16 10:30:00", + "daily_upload": 1048576, + "daily_download": 0, + "traffic_limit": 21474836480 +} +``` + +### 下载文件 + +``` +GET /file/{file_id} +GET /download/{file_id} +``` + +## Python API 调用示例 + +### 上传文件 + +```python +import requests + +BASE_URL = "https://xiaji-temp.duckdns.org" + +expiry = "24h" # 可选: 1h, 24h, 7d + +with open("/path/to/your/file.zip", "rb") as f: + resp = requests.post( + f"{BASE_URL}/api/upload", + files={"file": ("file.zip", f)}, + data={"expiry": expiry}, + verify=False # 对于自签名证书 + ) + +if resp.status_code == 200: + data = resp.json() + print(f"分享链接: {data['share_url']}") + print(f"文件 ID: {data['id']}") + print(f"文件大小: {data['filesize']} bytes") +else: + print(f"上传失败: {resp.json()['error']}") +``` + +### 获取文件信息 + +```python +resp = requests.get(f"{BASE_URL}/api/file/{file_id}", verify=False) +if resp.status_code == 200: + info = resp.json() + print(f"每日上传: {info['daily_upload']} bytes") + print(f"每日下载: {info['daily_download']} bytes") + print(f"流量限制: {info['traffic_limit']} bytes (20GB)") +``` + +## 使用客户端脚本 + +也可以直接使用附带的客户端脚本上传文件: + ```bash python upload_client.py /path/to/file.zip 24h ``` -Contributing -- Pull requests are welcome. Please follow the project style and ensure tests pass. +## 后续计划 -Contact -- If you need to reach the maintainer, use your preferred channel. +- [ ] 添加管理员/API 认证 +- [ ] 添加用户级别的速率限制和上传大小限制 +- [ ] 添加自动化测试和 CI/CD 集成 + +## 许可证 + +MIT 许可证 (或您偏好的许可证,按需更新) + +## 联系方式 + +如需联系维护者,请使用您偏好的渠道。 \ No newline at end of file