Files

178 lines
5.6 KiB
Plaintext

from PDAPI import *
import os
import json
import hashlib
import shutil
import time
RESOURCE_ROOT = os.path.join(os.path.abspath(os.path.join(os.getcwd(), "resource")))
TEMP_ROOT = os.path.join(RESOURCE_ROOT, ".tmp")
def _sha1_path(sha1_hex):
return os.path.join(RESOURCE_ROOT, sha1_hex[0:2], sha1_hex[2:4], sha1_hex[4:6], sha1_hex)
def _ensure_dir(path):
os.makedirs(os.path.dirname(path), exist_ok=True)
def _format_size(size):
if size < 1024:
return f"{size} B"
elif size < 1024 * 1024:
return f"{size / 1024:.1f} KB"
elif size < 1024 * 1024 * 1024:
return f"{size / (1024 * 1024):.1f} MB"
else:
return f"{size / (1024 * 1024 * 1024):.1f} GB"
def _cleanup_temp(temp_dir):
try:
shutil.rmtree(temp_dir, ignore_errors=True)
except:
pass
__metadata__ = {
"methods": ["POST"],
"blueprint": "GERP",
"permission": 3.0,
"attributes": [],
"limit": "10 per minute",
}
def HandleRequest(_CleanedData):
current_user = UGM.GetELTUser()
if not current_user:
return {"code": 401, "msg": "未登录"}, 401
data = flask.request.get_json(silent=True) or {}
upload_id = data.get("uploadId", "").strip()
if not upload_id:
return {"code": 1, "msg": "缺少uploadId"}, 400
temp_dir = os.path.join(TEMP_ROOT, upload_id)
if not os.path.isdir(temp_dir):
return {"code": 1, "msg": "上传会话不存在或已过期"}, 404
meta_path = os.path.join(temp_dir, "meta.json")
if not os.path.exists(meta_path):
_cleanup_temp(temp_dir)
return {"code": 1, "msg": "上传元数据不存在"}, 404
with open(meta_path, "r", encoding="utf-8") as f:
meta = json.load(f)
total_chunks = meta["totalChunks"]
received = sorted(meta.get("receivedChunks", []))
expected = list(range(total_chunks))
if received != expected:
missing = [i for i in expected if i not in received]
return {"code": 1, "msg": f"分片不完整,缺少: {missing}"}, 400
sha1 = hashlib.sha1()
merged_size = 0
final_path = os.path.join(temp_dir, "merged")
with open(final_path, "wb") as out_f:
for i in range(total_chunks):
chunk_path = os.path.join(temp_dir, str(i))
if not os.path.exists(chunk_path):
_cleanup_temp(temp_dir)
return {"code": 1, "msg": f"分片{i}文件丢失"}, 400
with open(chunk_path, "rb") as in_f:
while True:
block = in_f.read(65536)
if not block:
break
sha1.update(block)
out_f.write(block)
merged_size += len(block)
sha1_hex = sha1.hexdigest()
existing = GERPFileAsset.query.filter(GERPFileAsset.FileSHA1 == sha1_hex).first()
if existing:
_cleanup_temp(temp_dir)
return {
"code": 0,
"msg": "文件已存在(秒传)",
"data": {
"assetUUID": UUIDObj(existing.AssetUUID).UpperStr,
"fileName": existing.FileName,
"fileSize": existing.FileSize,
"fileSizeDisplay": _format_size(existing.FileSize),
"mimeType": existing.MimeType,
"sha1": existing.FileSHA1,
"refLink": f"https://api.gvsds.com/Asset/Download/{existing.FileSHA1}",
"createTime": existing.CreateTime.strftime("%Y-%m-%d %H:%M:%S") if existing.CreateTime else None,
}
}, 200
storage_path = _sha1_path(sha1_hex)
_ensure_dir(storage_path)
try:
shutil.move(final_path, storage_path)
except shutil.Error:
with open(final_path, "rb") as src, open(storage_path, "wb") as dst:
shutil.copyfileobj(src, dst)
os.remove(final_path)
for i in range(total_chunks):
chunk_path = os.path.join(temp_dir, str(i))
if os.path.exists(chunk_path):
os.remove(chunk_path)
asset_uuid = NewBUUID()
new_asset = GERPFileAsset()
new_asset.AssetUUID = asset_uuid
new_asset.FileName = meta["fileName"]
new_asset.FileSHA1 = sha1_hex
new_asset.FileSize = merged_size
new_asset.MimeType = meta["mimeType"]
new_asset.StoragePath = storage_path
new_asset.UploaderUUID = current_user.UserUUID
new_asset.RefCount = 0
current_role_uuid_str = flask.request.cookies.get("CurrentRoleUUID")
if current_role_uuid_str:
try:
role_uuid_bytes = UUIDObj(current_role_uuid_str).bytes
current_role = GERPRole.query.filter(GERPRole.RoleUUID == role_uuid_bytes).first()
if current_role and current_role.CompanyUUID:
new_asset.CompanyUUID = current_role.CompanyUUID
except:
pass
try:
db.session.add(new_asset)
db.session.commit()
except:
db.session.rollback()
if os.path.exists(storage_path):
os.remove(storage_path)
_cleanup_temp(temp_dir)
return {"code": 1, "msg": "数据库写入失败"}, 200
_cleanup_temp(temp_dir)
return {
"code": 0,
"msg": "上传成功",
"data": {
"assetUUID": UUIDObj(asset_uuid).UpperStr,
"fileName": new_asset.FileName,
"fileSize": new_asset.FileSize,
"fileSizeDisplay": _format_size(new_asset.FileSize),
"mimeType": new_asset.MimeType,
"sha1": new_asset.FileSHA1,
"refLink": f"https://api.gvsds.com/Asset/Download/{new_asset.FileSHA1}",
"createTime": new_asset.CreateTime.strftime("%Y-%m-%d %H:%M:%S") if new_asset.CreateTime else None,
}
}, 201