死代码移除: - whiteboard_hub.py: 移除未引用的 reset_hub 单例重置函数 - tunnel_service.py: 移除未引用的 is_port_allowed (逻辑已在 sftp_server 内联) - tunnel_session_dao.py: 移除未引用的 get_active_by_port - pdf_job_dao.py: 移除未用 datetime 导入 - pdf_converter.py: 移除未用 shutil 导入 - pdf_service.py: 移除未用 PdfSubmitResponse 导入 + _do_convert 内未用 hashlib 导入 - upload_html.py: 移除未用 escape 导入 (JS 侧自有 escapeHtml) - pdf_controller.py: 移除 _resolve_cookie 内未用 cfg 局部变量 提前失败/分层修复: - database.py init_db_schema: 建表后用 inspector 校验既有表列与模型一致, 缺列即抛 RuntimeError (fail-fast on schema drift), 避免运行期才暴露 - whiteboard_dao.get_or_create: 仅 IntegrityError 才回滚重读, 其他异常向上抛 (原 except Exception 会掩盖 schema/连接等真实故障) - pdf_service.admin_delete/_safe_delete_file: 改用 PdfJobDAO.delete / UploadedFileDAO.delete, 不再直接操作 job_dao.db / file_dao.db (修复分层契约: DAO 头注释声明 service 不直接操作 session) - PdfJobDAO 新增 delete(job) 方法 日志补全 (8 处 silent catch): - whiteboard_hub.py disconnect/close_board 关闭 ws: logger.debug - whiteboard_controller _safe_send/_safe_close: logger.debug - sftp_server _close_tunnel_dao/读用户名: logger.debug - sftp_server validate_public_key: logger.warning (auth 路径, 避免静默失败) 文档: - 新增 docs/routes.md, docs/configuration.md, docs/error-handling.md - README.md 精简为简介/结构/外部依赖/apache2 配置/Ubuntu 安装/docs 链接
125 lines
5.3 KiB
Markdown
125 lines
5.3 KiB
Markdown
# zTools2 - 个人 Web 服务后端
|
||
|
||
基于 FastAPI 的个人 Web 服务后端,提供文件上传/浏览/下载、共享记事本(实时协作)、主机监控、SFTP 暂存、反向隧道、PDF 转换。采用 Spring 风格分层架构(controller -> service -> dao -> ORM model -> MySQL),自带 API 文档。
|
||
|
||
所有入口统一挂在 `/api/` 前缀下,前端用同源相对路径调用,无需区分 dev/prod。前端子项目([timeTableFix](https://git.zikai.wang/zikai/timeTableFix)、[zPDF_package](https://git.zikai.wang/zikai/zPDF_package)、[zWhiteBoard](https://git.zikai.wang/zikai/zWhiteBoard))经 [zMainPage](https://git.zikai.wang/zikai/zMainPage) 构建期组件 import 集成,生产由 apache2 静态托管 + `/api` 反代到本服务。
|
||
|
||
## 项目结构
|
||
|
||
```
|
||
zTools2/
|
||
├── app/
|
||
│ ├── main.py # FastAPI 应用工厂、路由注册、生命周期(reaper)
|
||
│ ├── config.py # 从 config.yaml 加载的类型化 Settings(pydantic-settings)
|
||
│ ├── database.py # SQLAlchemy 引擎/Session/Base/get_db 依赖 + schema 校验
|
||
│ ├── security.py # Basic Auth(require_docs_auth,常量时间比较)
|
||
│ ├── controllers/ # 路由层:file/system/chunk/tunnel/whiteboard/pdf/admin
|
||
│ ├── services/ # 业务层:Upload/ChunkUpload/System/Whiteboard/Tunnel/Pdf/sftp
|
||
│ ├── dao/ # 数据访问层:唯一发 SQL 的层(SQLAlchemy ORM 参数化)
|
||
│ ├── models/ # ORM 实体:UploadedFile/UploadSession/Whiteboard/TunnelSession/PdfJob
|
||
│ ├── schemas/ # pydantic 请求/响应 DTO
|
||
│ ├── views/ # 服务端渲染 HTML(系统状态页、上传页)
|
||
│ ├── static/ # 前端静态资源
|
||
│ └── scripts/init_db.py # 数据库初始化(建库建账、随机密码写回 config.yaml)
|
||
├── sql/schema.sql # 建表 DDL(参考;实际由 ORM 自动建表)
|
||
├── config.example.yaml # 配置模板(含注释)
|
||
├── config.yaml # 实际配置(git-ignored,含密码)
|
||
├── requirements.txt
|
||
├── setup.sh # 一次性初始化:venv + 依赖 + 建库 + SFTP 密钥
|
||
├── start.sh / stop.sh # 启停 HTTP(127.0.0.1:6867)+ SFTP(2022)
|
||
└── deploy/ # systemd 持久化部署
|
||
```
|
||
|
||
**请求流程**:`controller -> service -> dao -> ORM model -> MySQL`。DB Session 由 `get_db` 依赖注入。
|
||
|
||
## 外部依赖
|
||
|
||
| 项 | 说明 |
|
||
|----|------|
|
||
| Python | ≥ 3.11(用 `.venv`) |
|
||
| MySQL | 8.x(独立库 `zikai_filesvc`,由 `setup.sh` 建账) |
|
||
| Apache2 | 反向代理对外提供 HTTPS;服务本身只绑 `127.0.0.1:6867` |
|
||
| 系统库 | `libpango/cairo`(weasyprint PDF 转换)、`build-essential`(bcrypt/asyncssh 编译) |
|
||
|
||
### Apache2 反向代理配置
|
||
|
||
服务只绑 `127.0.0.1:6867`,通过 Apache 对外提供 HTTPS。安装模块并配置 vhost:
|
||
|
||
```bash
|
||
a2enmod ssl proxy proxy_http proxy_wstunnel rewrite headers
|
||
```
|
||
|
||
创建 `/etc/apache2/sites-available/f.zikai.wang.conf`(关键部分):
|
||
|
||
```apache
|
||
<VirtualHost *:443>
|
||
ServerName f.zikai.wang
|
||
SSLEngine on
|
||
SSLCertificateFile /etc/letsencrypt/live/f.zikai.wang/fullchain.pem
|
||
SSLCertificateKeyFile /etc/letsencrypt/live/f.zikai.wang/privkey.pem
|
||
|
||
ProxyPreserveHost On
|
||
ProxyPass /fdata !
|
||
# 所有 zTools2 入口(页面/静态/探针/WS/API)统一在 /api/ 下,一条规则即可;
|
||
# WebSocket 走 /api/ws/wb/{id},靠 proxy_wstunnel 透传 Upgrade 头
|
||
ProxyPass /api/ http://127.0.0.1:6867/api/
|
||
ProxyPassReverse /api/ http://127.0.0.1:6867/api/
|
||
ProxyTimeout 300
|
||
</VirtualHost>
|
||
```
|
||
|
||
```bash
|
||
a2ensite f.zikai.wang
|
||
systemctl reload apache2
|
||
```
|
||
|
||
> **防火墙**:放开 443(HTTPS)与 2022(SFTP)。6867 不对外(仅 loopback)。
|
||
> **大文件上传**:Apache 全局 `Timeout 300`,慢链路建议走分片上传(`/api/upload`)或 SFTP。
|
||
|
||
## 从零安装(Ubuntu 22.04+)
|
||
|
||
### 1. 安装系统依赖
|
||
|
||
```bash
|
||
apt update
|
||
apt install -y python3-venv python3-pip mysql-server apache2 \
|
||
libssl-dev build-essential # build-essential 给 bcrypt/asyncssh 编译
|
||
# PDF 转换依赖 weasyprint,需 pango/cairo 系统库:
|
||
apt install -y libpango-1.0-0 libpangoft2-1.0-0 libcairo2 libgdk-pixbuf-2.0-0
|
||
```
|
||
|
||
### 2. 获取代码并初始化
|
||
|
||
```bash
|
||
git clone <repo> /root/zikai
|
||
cd /root/zikai/zTools2
|
||
./setup.sh # 创建 .venv + 装依赖 + 复制 config.yaml + 建 MySQL 库账 + 生成 SFTP 密钥
|
||
```
|
||
|
||
### 3. 配置凭据
|
||
|
||
编辑 `config.yaml`(详见 [`docs/configuration.md`](./docs/configuration.md)):`docs.username/password`(管理页 Basic Auth)、`sftp.users[].password_hash`(bcrypt)、可选 `tunnel.users[]`。
|
||
|
||
### 4. 启动
|
||
|
||
```bash
|
||
./start.sh # 启动 HTTP(127.0.0.1:6867) + SFTP(0.0.0.0:2022)
|
||
./stop.sh # 停止
|
||
```
|
||
|
||
### 5. 持久化部署(systemd)
|
||
|
||
```bash
|
||
./deploy/install-systemd.sh # 安装并启动 ztools2 服务(开机自启)
|
||
systemctl status ztools2
|
||
journalctl -u ztools2 -f
|
||
```
|
||
|
||
> 与 zMainPage 整体部署配合:systemd 管后端,`zMainPage/deploy.sh --no-restart` 部署前端。
|
||
|
||
## 了解更多
|
||
|
||
- [路由与访问入口](./docs/routes.md)
|
||
- [配置说明](./docs/configuration.md)
|
||
- [错误处理与日志约定](./docs/error-handling.md)
|