Skip to content

Commit f0a3628

Browse files
committed
feat: backup functionality (untested)
1 parent f92e8e9 commit f0a3628

File tree

2 files changed

+53
-38
lines changed

2 files changed

+53
-38
lines changed

src/pelit/plib/route_tool.py

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,7 @@
44
from typing import Optional, Any
55
from pathlib import Path
66
from flask import request
7-
8-
__all__ = ['authenticate', 'generate_file_name', 'enough_space',
9-
'join_url', 'list_dir', 'is_attempting_traversal']
7+
import shutil
108

119
def authenticate(cfg: dict[str, Any]) -> bool:
1210
"""
@@ -102,3 +100,17 @@ def is_attempting_traversal(comp: str) -> bool:
102100
if '..' in comp or '/' in comp or '\\' in comp:
103101
return True
104102
return False
103+
104+
def backup_to_file(path: Path, file: Path) -> None:
105+
"""
106+
创建全目录备份
107+
108+
Args:
109+
path: 需要备份的目录
110+
file: 备份保存的文件
111+
"""
112+
113+
try:
114+
shutil.make_archive(str(path), 'gztar', str(file))
115+
except Exception:
116+
pass

src/pelit/route.py

Lines changed: 38 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
from pathlib import Path
55
from pelit.plib.log import p_logger
66
from pelit.plib.route_tool import *
7+
from multiprocessing import Process
78

89
def create_route(cfg: dict[str, Any], lg: p_logger) -> Blueprint:
910
"""
@@ -172,45 +173,14 @@ def _delete(directory: str, file: str) -> tuple[Response, int]:
172173
}), 502
173174

174175
@main_route.route('/list', methods=['GET'])
175-
def _list_root() -> tuple[Response, int]:
176-
"""
177-
列出根目录下所有目录
178-
179-
Returns:
180-
JSON 格式的列表和响应码
181-
"""
182-
info_head = f"{request.remote_addr} {request.method} {request.path}"
183-
184-
if not authenticate(cfg):
185-
lg.warn(f"{info_head} 401: 认证失败")
186-
return jsonify({
187-
"success": False,
188-
"message": "认证失败"
189-
}), 401
190-
191-
try:
192-
storage_path = Path(cfg['storage']['path'])
193-
resp: dict[str, Any] = {
194-
"success": True,
195-
"message": "",
196-
"list": list_dir(storage_path)
197-
}
198-
lg.info(f'{info_head} 200 列举成功')
199-
return jsonify(resp), 200
200-
except Exception as e:
201-
lg.warn(f'{info_head} 502 列举失败')
202-
lg.warn('这是一个内部错误,请检查配置')
203-
lg.warn(f'{e}')
204-
return jsonify({
205-
"success": False,
206-
"message": "列举失败"
207-
}), 502
208-
209176
@main_route.route('/list/<directory>', methods=['GET'])
210-
def _list_dir(directory: str) -> tuple[Response, int]:
177+
def _list(directory: str = "/") -> tuple[Response, int]:
211178
"""
212179
列出指定目录下所有目录
213180
181+
Args:
182+
directory: 列举地址,未指定时默认为根目录
183+
214184
Returns:
215185
JSON 格式的列表和响应码
216186
"""
@@ -223,6 +193,10 @@ def _list_dir(directory: str) -> tuple[Response, int]:
223193
"message": "认证失败"
224194
}), 401
225195

196+
if is_attempting_traversal(directory):
197+
lg.warn(f"{info_head} 403 危险请求")
198+
return Response("禁止访问"), 403
199+
226200
try:
227201
path = Path(cfg['storage']['path']) / directory
228202
resp: dict[str, Any] = {
@@ -306,4 +280,33 @@ def _retrieve(directory: str, file: str) -> tuple[Response, int]:
306280
lg.warn(f"{e}")
307281
return Response("内部错误"), 502
308282

283+
@main_route.route('/backup', methods=['GET'])
284+
@main_route.route('/backup/<directory>', methods=['GET'])
285+
def _backup(directory: str = '/') -> tuple[Response, int]:
286+
"""
287+
创建一个备份任务,具体方式在配置文件中指定
288+
289+
Returns:
290+
包含响应和状态码
291+
"""
292+
info_head = f"{request.remote_addr} {request.method} {request.path}"
293+
294+
bak_name = generate_file_name(cfg['storage']['path'], '.tar.gz')
295+
bak_path = Path(cfg['storage']['path']) / (bak_name + '.tar.gz')
296+
bak_url = join_url(cfg['network']['base_url'], bak_name + '.tar.gz')
297+
298+
path = Path(cfg['storage']['path']) / directory
299+
300+
# 创建新进程压缩备份
301+
# FIXME: 由于是多进程的,这个任务失败了也不会有表示
302+
p = Process(target=backup_to_file, args=(path, bak_path))
303+
p.start()
304+
305+
lg.info(f"{info_head} 200 备份任务创建成功")
306+
return jsonify({
307+
"success": True,
308+
"url": bak_url,
309+
"message": "备份任务创建成功"
310+
}), 200
311+
309312
return main_route

0 commit comments

Comments
 (0)