refactor: 推进后端分层架构治理

This commit is contained in:
jxxghp
2026-08-18 00:29:14 +08:00
parent 5d0bacabd5
commit 5128ae9e1e
363 changed files with 34179 additions and 6019 deletions
+25 -23
View File
@@ -4,7 +4,9 @@ from typing import Optional, List, Dict, Tuple, Callable, Union
from tqdm import tqdm
from app import schemas
from app.schemas.file import StorageUsage as _SchemaStorageUsage
from app.schemas.system import StorageConf as _SchemaStorageConf
from app.schemas.workflow import FileItem as _SchemaFileItem
from app.runtime.progress import ProgressHelper
from app.application.storage import StorageHelper
from app.runtime.log import logger
@@ -69,7 +71,7 @@ class StorageBase(metaclass=ABCMeta):
"""检查存储登录状态"""
pass
def get_config(self) -> Optional[schemas.StorageConf]:
def get_config(self) -> Optional[_SchemaStorageConf]:
"""
获取配置
"""
@@ -122,7 +124,7 @@ class StorageBase(metaclass=ABCMeta):
return safe_name
def _build_download_path(
self, fileitem: schemas.FileItem, path: Path
self, fileitem: _SchemaFileItem, path: Path
) -> Optional[Path]:
"""
构造本地下载路径,避免远端文件名携带目录片段时越过目标目录。
@@ -148,14 +150,14 @@ class StorageBase(metaclass=ABCMeta):
pass
@abstractmethod
def list(self, fileitem: schemas.FileItem) -> List[schemas.FileItem]:
def list(self, fileitem: _SchemaFileItem) -> List[_SchemaFileItem]:
"""
浏览文件
"""
pass
@abstractmethod
def create_folder(self, fileitem: schemas.FileItem, name: str) -> Optional[schemas.FileItem]:
def create_folder(self, fileitem: _SchemaFileItem, name: str) -> Optional[_SchemaFileItem]:
"""
创建目录
:param fileitem: 父目录
@@ -164,20 +166,20 @@ class StorageBase(metaclass=ABCMeta):
pass
@abstractmethod
def get_folder(self, path: Path) -> Optional[schemas.FileItem]:
def get_folder(self, path: Path) -> Optional[_SchemaFileItem]:
"""
获取目录,如目录不存在则创建
"""
pass
@abstractmethod
def get_item(self, path: Path) -> Optional[schemas.FileItem]:
def get_item(self, path: Path) -> Optional[_SchemaFileItem]:
"""
获取文件或目录,不存在返回None
"""
pass
def get_item_strict(self, path: Path) -> Optional[schemas.FileItem]:
def get_item_strict(self, path: Path) -> Optional[_SchemaFileItem]:
"""
获取文件或目录,确认不存在返回None;无法确认状态时抛出 StorageQueryError。
@@ -188,28 +190,28 @@ class StorageBase(metaclass=ABCMeta):
"""
raise StorageQueryError(f"存储 {self.schema} 未实现严格查询,无法确认目标状态: {path}")
def get_parent(self, fileitem: schemas.FileItem) -> Optional[schemas.FileItem]:
def get_parent(self, fileitem: _SchemaFileItem) -> Optional[_SchemaFileItem]:
"""
获取父目录
"""
return self.get_item(Path(fileitem.path).parent)
@abstractmethod
def delete(self, fileitem: schemas.FileItem) -> bool:
def delete(self, fileitem: _SchemaFileItem) -> bool:
"""
删除文件
"""
pass
@abstractmethod
def rename(self, fileitem: schemas.FileItem, name: str) -> bool:
def rename(self, fileitem: _SchemaFileItem, name: str) -> bool:
"""
重命名文件
"""
pass
@abstractmethod
def download(self, fileitem: schemas.FileItem, path: Path = None) -> Path:
def download(self, fileitem: _SchemaFileItem, path: Path = None) -> Path:
"""
下载文件,保存到本地,返回本地临时文件地址
:param fileitem: 文件项
@@ -218,8 +220,8 @@ class StorageBase(metaclass=ABCMeta):
pass
@abstractmethod
def upload(self, fileitem: schemas.FileItem, path: Path,
new_name: Optional[str] = None) -> Optional[schemas.FileItem]:
def upload(self, fileitem: _SchemaFileItem, path: Path,
new_name: Optional[str] = None) -> Optional[_SchemaFileItem]:
"""
上传文件
:param fileitem: 上传目录项
@@ -229,14 +231,14 @@ class StorageBase(metaclass=ABCMeta):
pass
@abstractmethod
def detail(self, fileitem: schemas.FileItem) -> Optional[schemas.FileItem]:
def detail(self, fileitem: _SchemaFileItem) -> Optional[_SchemaFileItem]:
"""
获取文件详情
"""
pass
@abstractmethod
def copy(self, fileitem: schemas.FileItem, path: Path, new_name: str) -> bool:
def copy(self, fileitem: _SchemaFileItem, path: Path, new_name: str) -> bool:
"""
复制文件
:param fileitem: 文件项
@@ -246,7 +248,7 @@ class StorageBase(metaclass=ABCMeta):
pass
@abstractmethod
def move(self, fileitem: schemas.FileItem, path: Path, new_name: str) -> bool:
def move(self, fileitem: _SchemaFileItem, path: Path, new_name: str) -> bool:
"""
移动文件
:param fileitem: 文件项
@@ -256,21 +258,21 @@ class StorageBase(metaclass=ABCMeta):
pass
@abstractmethod
def link(self, fileitem: schemas.FileItem, target_file: Path) -> bool:
def link(self, fileitem: _SchemaFileItem, target_file: Path) -> bool:
"""
硬链接文件
"""
pass
@abstractmethod
def softlink(self, fileitem: schemas.FileItem, target_file: Path) -> bool:
def softlink(self, fileitem: _SchemaFileItem, target_file: Path) -> bool:
"""
软链接文件
"""
pass
@abstractmethod
def usage(self) -> Optional[schemas.StorageUsage]:
def usage(self) -> Optional[_SchemaStorageUsage]:
"""
存储使用情况
"""
@@ -292,8 +294,8 @@ class StorageBase(metaclass=ABCMeta):
if PurePosixPath(file_path).is_relative_to(root_path)
}
def __remove_deleted_children(_fileitm: schemas.FileItem,
sub_files: List[schemas.FileItem]) -> None:
def __remove_deleted_children(_fileitm: _SchemaFileItem,
sub_files: List[_SchemaFileItem]) -> None:
"""
清理已确认遍历目录中不再存在的直接子项。
未变化的子目录仍保留旧基线,避免增量遍历将其误删。
@@ -311,7 +313,7 @@ class StorageBase(metaclass=ABCMeta):
if direct_child_path not in child_paths:
files_info.pop(old_file_path, None)
def __snapshot_file(_fileitm: schemas.FileItem, current_depth: int = 0):
def __snapshot_file(_fileitm: _SchemaFileItem, current_depth: int = 0):
"""
递归获取文件信息
"""
+29 -28
View File
@@ -8,7 +8,8 @@ from typing import List, Optional, Tuple, Union
import requests
from app import schemas
from app.schemas.file import StorageUsage as _SchemaStorageUsage
from app.schemas.workflow import FileItem as _SchemaFileItem
from app.runtime.config import settings, global_vars
from app.runtime.log import logger
from app.modules.filemanager import StorageBase
@@ -287,16 +288,16 @@ class AliPan(StorageBase, metaclass=WeakSingleton):
return ret_data.get(result_key)
return ret_data
def __get_fileitem(self, fileinfo: dict, parent: str = "/") -> schemas.FileItem:
def __get_fileitem(self, fileinfo: dict, parent: str = "/") -> _SchemaFileItem:
"""
获取文件信息
"""
if not fileinfo:
return schemas.FileItem()
return _SchemaFileItem()
if not parent.endswith("/"):
parent += "/"
if fileinfo.get("type") == "folder":
return schemas.FileItem(
return _SchemaFileItem(
storage=self.schema.value,
fileid=fileinfo.get("file_id"),
parent_fileid=fileinfo.get("parent_file_id"),
@@ -309,7 +310,7 @@ class AliPan(StorageBase, metaclass=WeakSingleton):
drive_id=fileinfo.get("drive_id"),
)
else:
return schemas.FileItem(
return _SchemaFileItem(
storage=self.schema.value,
fileid=fileinfo.get("file_id"),
parent_fileid=fileinfo.get("parent_file_id"),
@@ -343,7 +344,7 @@ class AliPan(StorageBase, metaclass=WeakSingleton):
def init_storage(self):
pass
def list(self, fileitem: schemas.FileItem) -> List[schemas.FileItem]:
def list(self, fileitem: _SchemaFileItem) -> List[_SchemaFileItem]:
"""
目录遍历实现
"""
@@ -386,7 +387,7 @@ class AliPan(StorageBase, metaclass=WeakSingleton):
break
return items
def _delay_get_item(self, path: Path) -> Optional[schemas.FileItem]:
def _delay_get_item(self, path: Path) -> Optional[_SchemaFileItem]:
"""
自动延迟重试 get_item 模块
"""
@@ -398,8 +399,8 @@ class AliPan(StorageBase, metaclass=WeakSingleton):
return None
def create_folder(
self, parent_item: schemas.FileItem, name: str
) -> Optional[schemas.FileItem]:
self, parent_item: _SchemaFileItem, name: str
) -> Optional[_SchemaFileItem]:
"""
创建目录
"""
@@ -588,10 +589,10 @@ class AliPan(StorageBase, metaclass=WeakSingleton):
def upload(
self,
target_dir: schemas.FileItem,
target_dir: _SchemaFileItem,
local_path: Path,
new_name: Optional[str] = None,
) -> Optional[schemas.FileItem]:
) -> Optional[_SchemaFileItem]:
"""
文件上传:分片、支持秒传
"""
@@ -721,7 +722,7 @@ class AliPan(StorageBase, metaclass=WeakSingleton):
)
return self.__get_fileitem(result, parent=target_dir.path)
def download(self, fileitem: schemas.FileItem, path: Path = None) -> Optional[Path]:
def download(self, fileitem: _SchemaFileItem, path: Path = None) -> Optional[Path]:
"""
带实时进度显示的下载
"""
@@ -801,7 +802,7 @@ class AliPan(StorageBase, metaclass=WeakSingleton):
def check(self) -> bool:
return self.access_token is not None
def delete(self, fileitem: schemas.FileItem) -> bool:
def delete(self, fileitem: _SchemaFileItem) -> bool:
"""
删除文件/目录
"""
@@ -815,7 +816,7 @@ class AliPan(StorageBase, metaclass=WeakSingleton):
except requests.exceptions.HTTPError:
return False
def rename(self, fileitem: schemas.FileItem, name: str) -> bool:
def rename(self, fileitem: _SchemaFileItem, name: str) -> bool:
"""
重命名文件/目录
"""
@@ -835,7 +836,7 @@ class AliPan(StorageBase, metaclass=WeakSingleton):
return False
return True
def __get_by_path_item(self, path: Path, drive_id: str = None) -> Optional[schemas.FileItem]:
def __get_by_path_item(self, path: Path, drive_id: str = None) -> Optional[_SchemaFileItem]:
"""
按路径查询文件/目录项,无法确认状态时抛出 StorageQueryError。
NotFound 系列错误码表示确认不存在,其余错误(网络失败、限流、
@@ -861,7 +862,7 @@ class AliPan(StorageBase, metaclass=WeakSingleton):
f"【阿里云盘】查询文件信息出错: {path} - {code} {resp.get('message')}")
return self.__get_fileitem(resp, parent=str(path.parent))
def get_item(self, path: Path, drive_id: str = None) -> Optional[schemas.FileItem]:
def get_item(self, path: Path, drive_id: str = None) -> Optional[_SchemaFileItem]:
"""
获取指定路径的文件/目录项
"""
@@ -871,7 +872,7 @@ class AliPan(StorageBase, metaclass=WeakSingleton):
logger.debug(f"【阿里云盘】获取文件信息失败: {str(e)}")
return None
def get_item_strict(self, path: Path) -> Optional[schemas.FileItem]:
def get_item_strict(self, path: Path) -> Optional[_SchemaFileItem]:
"""
获取指定路径的文件/目录项,无法确认状态时抛出 StorageQueryError。
"""
@@ -882,14 +883,14 @@ class AliPan(StorageBase, metaclass=WeakSingleton):
except Exception as e:
raise StorageQueryError(f"【阿里云盘】查询文件信息失败: {path} - {e}") from e
def get_folder(self, path: Path) -> Optional[schemas.FileItem]:
def get_folder(self, path: Path) -> Optional[_SchemaFileItem]:
"""
获取指定路径的文件夹,如不存在则创建
"""
def __find_dir(
_fileitem: schemas.FileItem, _name: str
) -> Optional[schemas.FileItem]:
_fileitem: _SchemaFileItem, _name: str
) -> Optional[_SchemaFileItem]:
"""
查找下级目录中匹配名称的目录
"""
@@ -905,7 +906,7 @@ class AliPan(StorageBase, metaclass=WeakSingleton):
if folder:
return folder
# 逐级查找和创建目录
fileitem = schemas.FileItem(
fileitem = _SchemaFileItem(
storage=self.schema.value, path="/", drive_id=self._default_drive_id
)
for part in path.parts[1:]:
@@ -920,13 +921,13 @@ class AliPan(StorageBase, metaclass=WeakSingleton):
fileitem = dir_file
return fileitem
def detail(self, fileitem: schemas.FileItem) -> Optional[schemas.FileItem]:
def detail(self, fileitem: _SchemaFileItem) -> Optional[_SchemaFileItem]:
"""
获取文件/目录详细信息
"""
return self.get_item(Path(fileitem.path))
def copy(self, fileitem: schemas.FileItem, path: Path, new_name: str) -> bool:
def copy(self, fileitem: _SchemaFileItem, path: Path, new_name: str) -> bool:
"""
复制文件到指定路径
:param fileitem: 要复制的文件项
@@ -958,7 +959,7 @@ class AliPan(StorageBase, metaclass=WeakSingleton):
self.rename(new_file, new_name)
return True
def move(self, fileitem: schemas.FileItem, path: Path, new_name: str) -> bool:
def move(self, fileitem: _SchemaFileItem, path: Path, new_name: str) -> bool:
"""
移动文件到指定路径
:param fileitem: 要移动的文件项
@@ -988,13 +989,13 @@ class AliPan(StorageBase, metaclass=WeakSingleton):
return False
return True
def link(self, fileitem: schemas.FileItem, target_file: Path) -> bool:
def link(self, fileitem: _SchemaFileItem, target_file: Path) -> bool:
pass
def softlink(self, fileitem: schemas.FileItem, target_file: Path) -> bool:
def softlink(self, fileitem: _SchemaFileItem, target_file: Path) -> bool:
pass
def usage(self) -> Optional[schemas.StorageUsage]:
def usage(self) -> Optional[_SchemaStorageUsage]:
"""
获取带有企业级配额信息的存储使用情况
"""
@@ -1005,7 +1006,7 @@ class AliPan(StorageBase, metaclass=WeakSingleton):
space = resp.get("personal_space_info") or {}
total_size = space.get("total_size") or 0
used_size = space.get("used_size") or 0
return schemas.StorageUsage(
return _SchemaStorageUsage(
total=total_size, available=total_size - used_size
)
except NoCheckInException:
+34 -33
View File
@@ -5,7 +5,8 @@ from datetime import datetime
from pathlib import Path
from typing import Optional, List
from app import schemas
from app.schemas.file import StorageUsage as _SchemaStorageUsage
from app.schemas.workflow import FileItem as _SchemaFileItem
from app.runtime.cache import cached
from app.runtime.config import settings, global_vars
from app.runtime.log import logger
@@ -54,7 +55,7 @@ class Alist(StorageBase, metaclass=WeakSingleton):
def _delay_get_item(
self, path: Path, /, refresh: bool = False
) -> Optional[schemas.FileItem]:
) -> Optional[_SchemaFileItem]:
"""
自动延迟重试 get_item 模块
@@ -70,8 +71,8 @@ class Alist(StorageBase, metaclass=WeakSingleton):
return None
def __build_transfer_item(
self, source_item: schemas.FileItem, target_path: Path
) -> schemas.FileItem:
self, source_item: _SchemaFileItem, target_path: Path
) -> _SchemaFileItem:
"""
根据目标路径构造文件项,用于 OpenList 操作成功但元数据短时间不可见的场景。
目录项路径需要遵循 FileItem 以斜杠结尾的约定。
@@ -80,7 +81,7 @@ class Alist(StorageBase, metaclass=WeakSingleton):
if source_item.type == "dir" and not target_path_str.endswith("/"):
target_path_str = f"{target_path_str}/"
return schemas.FileItem(
return _SchemaFileItem(
storage=self.schema.value,
type=source_item.type,
path=target_path_str,
@@ -197,12 +198,12 @@ class Alist(StorageBase, metaclass=WeakSingleton):
def list(
self,
fileitem: schemas.FileItem,
fileitem: _SchemaFileItem,
password: Optional[str] = "",
page: int = 1,
per_page: int = 0,
refresh: bool = False,
) -> List[schemas.FileItem]:
) -> List[_SchemaFileItem]:
"""
浏览文件
:param fileitem: 文件项
@@ -291,7 +292,7 @@ class Alist(StorageBase, metaclass=WeakSingleton):
page_content = page_data.get("content") or []
items.extend(
[
schemas.FileItem(
_SchemaFileItem(
storage=self.schema.value,
type="dir" if item["is_dir"] else "file",
path=(Path(fileitem.path) / item["name"]).as_posix()
@@ -321,8 +322,8 @@ class Alist(StorageBase, metaclass=WeakSingleton):
current_page += 1
def create_folder(
self, fileitem: schemas.FileItem, name: str
) -> Optional[schemas.FileItem]:
self, fileitem: _SchemaFileItem, name: str
) -> Optional[_SchemaFileItem]:
"""
创建目录
:param fileitem: 父目录
@@ -364,7 +365,7 @@ class Alist(StorageBase, metaclass=WeakSingleton):
return self._delay_get_item(
path, refresh=True
) or self.__build_transfer_item(
schemas.FileItem(
_SchemaFileItem(
storage=self.schema.value,
type="dir",
path=fileitem.path,
@@ -374,7 +375,7 @@ class Alist(StorageBase, metaclass=WeakSingleton):
path,
)
def get_folder(self, path: Path) -> Optional[schemas.FileItem]:
def get_folder(self, path: Path) -> Optional[_SchemaFileItem]:
"""
获取目录,如目录不存在则创建
@@ -386,7 +387,7 @@ class Alist(StorageBase, metaclass=WeakSingleton):
return folder
if not folder:
folder = self.create_folder(
schemas.FileItem(
_SchemaFileItem(
storage=self.schema.value,
type="dir",
path=path.parent.as_posix(),
@@ -404,7 +405,7 @@ class Alist(StorageBase, metaclass=WeakSingleton):
page: int = 1,
per_page: int = 0,
refresh: bool = False,
) -> Optional[schemas.FileItem]:
) -> Optional[_SchemaFileItem]:
"""
获取文件或目录,不存在返回None
:param path: 文件路径
@@ -473,14 +474,14 @@ class Alist(StorageBase, metaclass=WeakSingleton):
return self.__build_fileitem(path, result["data"])
def __build_fileitem(self, path: Path, data: dict) -> schemas.FileItem:
def __build_fileitem(self, path: Path, data: dict) -> _SchemaFileItem:
"""
根据接口返回数据构建文件项。
:param path: 文件路径
:param data: 接口返回的 data 字段
:return: 文件项
"""
return schemas.FileItem(
return _SchemaFileItem(
storage=self.schema.value,
type="dir" if data["is_dir"] else "file",
path=path.as_posix() + ("/" if data["is_dir"] else ""),
@@ -492,7 +493,7 @@ class Alist(StorageBase, metaclass=WeakSingleton):
thumbnail=data["thumb"],
)
def get_item_strict(self, path: Path) -> Optional[schemas.FileItem]:
def get_item_strict(self, path: Path) -> Optional[_SchemaFileItem]:
"""
获取文件或目录,确认不存在返回None;无法确认状态时抛出 StorageQueryError。
只有接口明确回报「对象不存在」才是确定结果,连接失败、HTTP 异常与其他
@@ -523,7 +524,7 @@ class Alist(StorageBase, metaclass=WeakSingleton):
raise StorageQueryError(f"【OpenList】查询文件 {path} 失败:{message}")
return self.__build_fileitem(path, result["data"])
def get_parent(self, fileitem: schemas.FileItem) -> Optional[schemas.FileItem]:
def get_parent(self, fileitem: _SchemaFileItem) -> Optional[_SchemaFileItem]:
"""
获取父目录
@@ -532,7 +533,7 @@ class Alist(StorageBase, metaclass=WeakSingleton):
"""
return self.get_folder(Path(fileitem.path).parent)
def delete(self, fileitem: schemas.FileItem) -> bool:
def delete(self, fileitem: _SchemaFileItem) -> bool:
"""
删除文件或目录
@@ -570,7 +571,7 @@ class Alist(StorageBase, metaclass=WeakSingleton):
return False
return True
def rename(self, fileitem: schemas.FileItem, name: str) -> bool:
def rename(self, fileitem: _SchemaFileItem, name: str) -> bool:
"""
重命名文件
@@ -619,7 +620,7 @@ class Alist(StorageBase, metaclass=WeakSingleton):
def download(
self,
fileitem: schemas.FileItem,
fileitem: _SchemaFileItem,
path: Path = None,
password: Optional[str] = "",
) -> Optional[Path]:
@@ -712,11 +713,11 @@ class Alist(StorageBase, metaclass=WeakSingleton):
def upload(
self,
fileitem: schemas.FileItem,
fileitem: _SchemaFileItem,
path: Path,
new_name: Optional[str] = None,
task: bool = False,
) -> Optional[schemas.FileItem]:
) -> Optional[_SchemaFileItem]:
"""
上传文件(带进度)
:param fileitem: 上传目录项
@@ -830,13 +831,13 @@ class Alist(StorageBase, metaclass=WeakSingleton):
"X-File-Sha256": sha256_hash.hexdigest(),
}
def detail(self, fileitem: schemas.FileItem) -> Optional[schemas.FileItem]:
def detail(self, fileitem: _SchemaFileItem) -> Optional[_SchemaFileItem]:
"""
获取文件详情
"""
return self.get_item(Path(fileitem.path))
def copy(self, fileitem: schemas.FileItem, path: Path, new_name: str) -> bool:
def copy(self, fileitem: _SchemaFileItem, path: Path, new_name: str) -> bool:
"""
复制文件
:param fileitem: 文件项
@@ -892,8 +893,8 @@ class Alist(StorageBase, metaclass=WeakSingleton):
return True
def copy_item(
self, fileitem: schemas.FileItem, path: Path, new_name: str
) -> Optional[schemas.FileItem]:
self, fileitem: _SchemaFileItem, path: Path, new_name: str
) -> Optional[_SchemaFileItem]:
"""
复制文件并返回目标文件项,兼容 OpenList 成功响应不携带目标对象的格式。
"""
@@ -913,7 +914,7 @@ class Alist(StorageBase, metaclass=WeakSingleton):
) or self.__build_transfer_item(fileitem, target_path)
return None
def move(self, fileitem: schemas.FileItem, path: Path, new_name: str) -> bool:
def move(self, fileitem: _SchemaFileItem, path: Path, new_name: str) -> bool:
"""
移动文件
:param fileitem: 文件项
@@ -967,8 +968,8 @@ class Alist(StorageBase, metaclass=WeakSingleton):
return True
def move_item(
self, fileitem: schemas.FileItem, path: Path, new_name: str
) -> Optional[schemas.FileItem]:
self, fileitem: _SchemaFileItem, path: Path, new_name: str
) -> Optional[_SchemaFileItem]:
"""
移动文件并返回目标文件项,兼容 OpenList 成功响应不携带目标对象的格式。
"""
@@ -979,19 +980,19 @@ class Alist(StorageBase, metaclass=WeakSingleton):
fileitem, target_path
)
def link(self, fileitem: schemas.FileItem, target_file: Path) -> bool:
def link(self, fileitem: _SchemaFileItem, target_file: Path) -> bool:
"""
硬链接文件
"""
pass
def softlink(self, fileitem: schemas.FileItem, target_file: Path) -> bool:
def softlink(self, fileitem: _SchemaFileItem, target_file: Path) -> bool:
"""
软链接文件
"""
pass
def usage(self) -> Optional[schemas.StorageUsage]:
def usage(self) -> Optional[_SchemaStorageUsage]:
"""
存储使用情况
"""
+24 -23
View File
@@ -4,7 +4,8 @@ import time
from pathlib import Path
from typing import Optional, List
from app import schemas
from app.schemas.file import StorageUsage as _SchemaStorageUsage
from app.schemas.workflow import FileItem as _SchemaFileItem
from app.runtime.config import global_vars, settings
from app.application.directory import DirectoryHelper
from app.runtime.log import logger
@@ -45,7 +46,7 @@ class LocalStorage(StorageBase):
"""
return True
def __get_fileitem(self, path: Path) -> schemas.FileItem:
def __get_fileitem(self, path: Path) -> _SchemaFileItem:
"""
获取文件项
"""
@@ -53,7 +54,7 @@ class LocalStorage(StorageBase):
# 顺带只 stat 一次——原先 size 与 modify_time 各 stat 一次,在网络挂载上
# 等于把这个热点路径的开销翻倍
info = fsproxy.stat(path)
return schemas.FileItem(
return _SchemaFileItem(
storage=self.schema.value,
type="file",
path=path.as_posix(),
@@ -64,11 +65,11 @@ class LocalStorage(StorageBase):
modify_time=info["mtime"],
)
def __get_diritem(self, path: Path) -> schemas.FileItem:
def __get_diritem(self, path: Path) -> _SchemaFileItem:
"""
获取目录项
"""
return schemas.FileItem(
return _SchemaFileItem(
storage=self.schema.value,
type="dir",
path=path.as_posix() + "/",
@@ -77,7 +78,7 @@ class LocalStorage(StorageBase):
modify_time=fsproxy.stat(path)["mtime"],
)
def list(self, fileitem: schemas.FileItem) -> List[schemas.FileItem]:
def list(self, fileitem: _SchemaFileItem) -> List[_SchemaFileItem]:
"""
浏览文件
"""
@@ -88,7 +89,7 @@ class LocalStorage(StorageBase):
if SystemUtils.is_windows():
partitions = SystemUtils.get_windows_drives() or ["C:/"]
for partition in partitions:
ret_items.append(schemas.FileItem(
ret_items.append(_SchemaFileItem(
storage=self.schema.value,
type="dir",
path=partition + "/",
@@ -126,7 +127,7 @@ class LocalStorage(StorageBase):
ret_items.append(self.__get_fileitem(item))
return ret_items
def create_folder(self, fileitem: schemas.FileItem, name: str) -> Optional[schemas.FileItem]:
def create_folder(self, fileitem: _SchemaFileItem, name: str) -> Optional[_SchemaFileItem]:
"""
创建目录
:param fileitem: 父目录
@@ -139,7 +140,7 @@ class LocalStorage(StorageBase):
path_obj.mkdir(parents=True, exist_ok=True)
return self.__get_diritem(path_obj)
def get_folder(self, path: Path) -> Optional[schemas.FileItem]:
def get_folder(self, path: Path) -> Optional[_SchemaFileItem]:
"""
获取目录
"""
@@ -147,7 +148,7 @@ class LocalStorage(StorageBase):
path.mkdir(parents=True, exist_ok=True)
return self.__get_diritem(path)
def get_item(self, path: Path) -> Optional[schemas.FileItem]:
def get_item(self, path: Path) -> Optional[_SchemaFileItem]:
"""
获取文件或目录,不存在返回None
"""
@@ -159,7 +160,7 @@ class LocalStorage(StorageBase):
return self.__get_fileitem(path)
return self.__get_diritem(path)
def get_item_strict(self, path: Path) -> Optional[schemas.FileItem]:
def get_item_strict(self, path: Path) -> Optional[_SchemaFileItem]:
"""
获取文件或目录,无法确认状态时抛出 StorageQueryError。
Path.exists() 会把部分 errno(如 EBADF/ELOOP)归入「不存在」,
@@ -178,7 +179,7 @@ class LocalStorage(StorageBase):
except OSError as e:
raise StorageQueryError(f"【本地】读取文件信息失败: {path} - {e}") from e
def detail(self, fileitem: schemas.FileItem) -> Optional[schemas.FileItem]:
def detail(self, fileitem: _SchemaFileItem) -> Optional[_SchemaFileItem]:
"""
获取文件详情
"""
@@ -187,7 +188,7 @@ class LocalStorage(StorageBase):
return None
return self.__get_fileitem(path_obj)
def delete(self, fileitem: schemas.FileItem) -> bool:
def delete(self, fileitem: _SchemaFileItem) -> bool:
"""
删除文件
"""
@@ -211,7 +212,7 @@ class LocalStorage(StorageBase):
return False
return True
def rename(self, fileitem: schemas.FileItem, name: str) -> bool:
def rename(self, fileitem: _SchemaFileItem, name: str) -> bool:
"""
重命名文件
"""
@@ -225,7 +226,7 @@ class LocalStorage(StorageBase):
return False
return True
def download(self, fileitem: schemas.FileItem, path: Path = None) -> Optional[Path]:
def download(self, fileitem: _SchemaFileItem, path: Path = None) -> Optional[Path]:
"""
下载文件
"""
@@ -370,10 +371,10 @@ class LocalStorage(StorageBase):
def upload(
self,
fileitem: schemas.FileItem,
fileitem: _SchemaFileItem,
path: Path,
new_name: Optional[str] = None
) -> Optional[schemas.FileItem]:
) -> Optional[_SchemaFileItem]:
"""
上传文件(带进度)
"""
@@ -402,7 +403,7 @@ class LocalStorage(StorageBase):
def copy(
self,
fileitem: schemas.FileItem,
fileitem: _SchemaFileItem,
path: Path,
new_name: str
) -> bool:
@@ -413,7 +414,7 @@ class LocalStorage(StorageBase):
def move(
self,
fileitem: schemas.FileItem,
fileitem: _SchemaFileItem,
path: Path,
new_name: str
) -> bool:
@@ -443,7 +444,7 @@ class LocalStorage(StorageBase):
logger.warn(f"【本地】移动已完成但删除源文件失败:{src} - {err}")
return True
def link(self, fileitem: schemas.FileItem, target_file: Path) -> bool:
def link(self, fileitem: _SchemaFileItem, target_file: Path) -> bool:
"""
硬链接文件
"""
@@ -454,7 +455,7 @@ class LocalStorage(StorageBase):
return False
return True
def softlink(self, fileitem: schemas.FileItem, target_file: Path) -> bool:
def softlink(self, fileitem: _SchemaFileItem, target_file: Path) -> bool:
"""
软链接文件
"""
@@ -465,7 +466,7 @@ class LocalStorage(StorageBase):
return False
return True
def usage(self) -> Optional[schemas.StorageUsage]:
def usage(self) -> Optional[_SchemaStorageUsage]:
"""
存储使用情况
"""
@@ -475,7 +476,7 @@ class LocalStorage(StorageBase):
[Path(d.library_path) for d in directory_helper.get_local_library_dirs() if d.library_path],
btrfs_fsid_dedup=settings.BTRFS_FSID_DEDUP,
)
return schemas.StorageUsage(
return _SchemaStorageUsage(
total=total_storage,
available=free_storage
)
+25 -24
View File
@@ -6,7 +6,8 @@ from collections import OrderedDict
from pathlib import Path
from typing import Optional, List, Union
from app import schemas
from app.schemas.file import StorageUsage as _SchemaStorageUsage
from app.schemas.workflow import FileItem as _SchemaFileItem
from app.runtime.config import settings
from app.runtime.log import logger
from app.modules.filemanager.storages import StorageBase, transfer_process
@@ -114,14 +115,14 @@ class Rclone(StorageBase):
return None
def __get_rcloneitem(self, item: dict, parent: Optional[str] = "/") -> schemas.FileItem:
def __get_rcloneitem(self, item: dict, parent: Optional[str] = "/") -> _SchemaFileItem:
"""
获取rclone文件项
"""
if not item:
return schemas.FileItem()
return _SchemaFileItem()
if item.get("IsDir"):
return schemas.FileItem(
return _SchemaFileItem(
storage=self.schema.value,
type="dir",
path=f"{parent}{item.get('Name')}" + "/",
@@ -130,7 +131,7 @@ class Rclone(StorageBase):
modify_time=time_tools.parse_timestamp(item.get("ModTime"))
)
else:
return schemas.FileItem(
return _SchemaFileItem(
storage=self.schema.value,
type="file",
path=f"{parent}{item.get('Name')}",
@@ -171,7 +172,7 @@ class Rclone(StorageBase):
def __wait_for_item(
self, path: Path, retries: int = 3, delay: float = 0.2
) -> Optional[schemas.FileItem]:
) -> Optional[_SchemaFileItem]:
"""
等待目录或文件在远端可见,兼容云盘最终一致性延迟。
"""
@@ -198,7 +199,7 @@ class Rclone(StorageBase):
logger.error(f"【rclone】存储检查失败:{err}")
return False
def list(self, fileitem: schemas.FileItem) -> List[schemas.FileItem]:
def list(self, fileitem: _SchemaFileItem) -> List[_SchemaFileItem]:
"""
浏览文件
"""
@@ -220,7 +221,7 @@ class Rclone(StorageBase):
logger.error(f"【rclone】浏览文件失败:{err}")
return []
def create_folder(self, fileitem: schemas.FileItem, name: str) -> Optional[schemas.FileItem]:
def create_folder(self, fileitem: _SchemaFileItem, name: str) -> Optional[_SchemaFileItem]:
"""
创建目录
:param fileitem: 父目录
@@ -253,7 +254,7 @@ class Rclone(StorageBase):
return folder
return None
def get_folder(self, path: Path) -> Optional[schemas.FileItem]:
def get_folder(self, path: Path) -> Optional[_SchemaFileItem]:
"""
根据文件路程获取目录,不存在则创建
"""
@@ -264,7 +265,7 @@ class Rclone(StorageBase):
if folder:
return folder
# 逐级查找和创建目录
fileitem = schemas.FileItem(storage=self.schema.value, type="dir", path="/")
fileitem = _SchemaFileItem(storage=self.schema.value, type="dir", path="/")
for part in normalized.parts[1:]:
current_path = Path(self.__normalize_remote_path(Path(fileitem.path) / part))
with self.__get_path_lock(current_path):
@@ -277,7 +278,7 @@ class Rclone(StorageBase):
fileitem = dir_file
return fileitem
def get_item(self, path: Path) -> Optional[schemas.FileItem]:
def get_item(self, path: Path) -> Optional[_SchemaFileItem]:
"""
获取文件或目录,不存在返回None
"""
@@ -300,7 +301,7 @@ class Rclone(StorageBase):
logger.debug(f"【rclone】获取文件项失败:{err}")
return None
def get_item_strict(self, path: Path) -> Optional[schemas.FileItem]:
def get_item_strict(self, path: Path) -> Optional[_SchemaFileItem]:
"""
获取文件或目录,确认不存在返回None;无法确认状态时抛出 StorageQueryError。
rclone 用退出码 3/4 表示目录/文件不存在,其余非零退出无法区分
@@ -332,7 +333,7 @@ class Rclone(StorageBase):
return self.__get_rcloneitem(item, parent=str(path.parent) + "/")
return None
def delete(self, fileitem: schemas.FileItem) -> bool:
def delete(self, fileitem: _SchemaFileItem) -> bool:
"""
删除文件
"""
@@ -350,7 +351,7 @@ class Rclone(StorageBase):
logger.error(f"【rclone】删除文件失败:{err}")
return False
def rename(self, fileitem: schemas.FileItem, name: str) -> bool:
def rename(self, fileitem: _SchemaFileItem, name: str) -> bool:
"""
重命名文件
"""
@@ -369,7 +370,7 @@ class Rclone(StorageBase):
logger.error(f"【rclone】重命名文件失败:{err}")
return False
def download(self, fileitem: schemas.FileItem, path: Path = None) -> Optional[Path]:
def download(self, fileitem: _SchemaFileItem, path: Path = None) -> Optional[Path]:
"""
带实时进度显示的下载
"""
@@ -426,8 +427,8 @@ class Rclone(StorageBase):
local_path.unlink()
return None
def upload(self, fileitem: schemas.FileItem, path: Path,
new_name: Optional[str] = None) -> Optional[schemas.FileItem]:
def upload(self, fileitem: _SchemaFileItem, path: Path,
new_name: Optional[str] = None) -> Optional[_SchemaFileItem]:
"""
带实时进度显示的上传
:param fileitem: 上传目录项
@@ -483,7 +484,7 @@ class Rclone(StorageBase):
logger.error(f"【rclone】上传失败: {target_name} - {err}")
return None
def detail(self, fileitem: schemas.FileItem) -> Optional[schemas.FileItem]:
def detail(self, fileitem: _SchemaFileItem) -> Optional[_SchemaFileItem]:
"""
获取文件详情
"""
@@ -503,7 +504,7 @@ class Rclone(StorageBase):
logger.error(f"【rclone】获取文件详情失败:{err}")
return None
def move(self, fileitem: schemas.FileItem, path: Path, new_name: str) -> bool:
def move(self, fileitem: _SchemaFileItem, path: Path, new_name: str) -> bool:
"""
移动文件
:param fileitem: 文件项
@@ -558,7 +559,7 @@ class Rclone(StorageBase):
logger.error(f"【rclone】移动失败: {fileitem.name} - {err}")
return False
def copy(self, fileitem: schemas.FileItem, path: Path, new_name: str) -> bool:
def copy(self, fileitem: _SchemaFileItem, path: Path, new_name: str) -> bool:
"""
复制文件
:param fileitem: 文件项
@@ -613,13 +614,13 @@ class Rclone(StorageBase):
logger.error(f"【rclone】复制失败: {fileitem.name} - {err}")
return False
def link(self, fileitem: schemas.FileItem, target_file: Path) -> bool:
def link(self, fileitem: _SchemaFileItem, target_file: Path) -> bool:
pass
def softlink(self, fileitem: schemas.FileItem, target_file: Path) -> bool:
def softlink(self, fileitem: _SchemaFileItem, target_file: Path) -> bool:
pass
def usage(self) -> Optional[schemas.StorageUsage]:
def usage(self) -> Optional[_SchemaStorageUsage]:
"""
存储使用情况
"""
@@ -647,7 +648,7 @@ class Rclone(StorageBase):
)
if ret.returncode == 0:
items = json.loads(ret.stdout)
return schemas.StorageUsage(
return _SchemaStorageUsage(
total=items.get("total"),
available=items.get("free")
)
+27 -26
View File
@@ -12,7 +12,8 @@ from smbprotocol.exceptions import (
SMBAuthenticationError,
)
from app import schemas
from app.schemas.file import StorageUsage as _SchemaStorageUsage
from app.schemas.workflow import FileItem as _SchemaFileItem
from app.runtime.config import settings, global_vars
from app.runtime.log import logger
from app.modules.filemanager import StorageBase
@@ -172,7 +173,7 @@ class SMB(StorageBase, metaclass=WeakSingleton):
def _create_fileitem(
self, stat_result, file_path: str, name: str
) -> schemas.FileItem:
) -> _SchemaFileItem:
"""
创建文件项
"""
@@ -195,7 +196,7 @@ class SMB(StorageBase, metaclass=WeakSingleton):
modify_time = int(time.time())
if is_directory:
return schemas.FileItem(
return _SchemaFileItem(
storage=self.schema.value,
type="dir",
path=relative_path,
@@ -204,7 +205,7 @@ class SMB(StorageBase, metaclass=WeakSingleton):
modify_time=modify_time,
)
else:
return schemas.FileItem(
return _SchemaFileItem(
storage=self.schema.value,
type="file",
path=relative_path,
@@ -217,7 +218,7 @@ class SMB(StorageBase, metaclass=WeakSingleton):
except Exception as e:
logger.error(f"【SMB】创建文件项失败:{e}")
# 返回基本的文件项信息
return schemas.FileItem(
return _SchemaFileItem(
storage=self.schema.value,
type="file",
path=file_path.replace(self._server_path, "").replace("\\", "/"),
@@ -249,7 +250,7 @@ class SMB(StorageBase, metaclass=WeakSingleton):
self._connected = False
return False
def list(self, fileitem: schemas.FileItem) -> List[schemas.FileItem]:
def list(self, fileitem: _SchemaFileItem) -> List[_SchemaFileItem]:
"""
浏览文件
"""
@@ -295,8 +296,8 @@ class SMB(StorageBase, metaclass=WeakSingleton):
return []
def create_folder(
self, fileitem: schemas.FileItem, name: str
) -> Optional[schemas.FileItem]:
self, fileitem: _SchemaFileItem, name: str
) -> Optional[_SchemaFileItem]:
"""
创建目录
"""
@@ -310,7 +311,7 @@ class SMB(StorageBase, metaclass=WeakSingleton):
smbclient.mkdir(new_path)
# 返回创建的目录信息
return schemas.FileItem(
return _SchemaFileItem(
storage=self.schema.value,
type="dir",
path=f"{fileitem.path.rstrip('/')}/{name}/",
@@ -322,7 +323,7 @@ class SMB(StorageBase, metaclass=WeakSingleton):
logger.error(f"【SMB】创建目录失败: {e}")
return None
def get_folder(self, path: Path) -> Optional[schemas.FileItem]:
def get_folder(self, path: Path) -> Optional[_SchemaFileItem]:
"""
获取目录,如目录不存在则创建
"""
@@ -349,7 +350,7 @@ class SMB(StorageBase, metaclass=WeakSingleton):
return folder
def get_item(self, path: Path) -> Optional[schemas.FileItem]:
def get_item(self, path: Path) -> Optional[_SchemaFileItem]:
"""
获取文件或目录,不存在返回None
"""
@@ -358,7 +359,7 @@ class SMB(StorageBase, metaclass=WeakSingleton):
# 处理根目录
if str(path) == "/":
return schemas.FileItem(
return _SchemaFileItem(
storage=self.schema.value,
type="dir",
path="/",
@@ -382,7 +383,7 @@ class SMB(StorageBase, metaclass=WeakSingleton):
logger.debug(f"【SMB】获取文件项失败: {e}")
return None
def get_item_strict(self, path: Path) -> Optional[schemas.FileItem]:
def get_item_strict(self, path: Path) -> Optional[_SchemaFileItem]:
"""
获取文件或目录,确认不存在返回None;无法确认状态时抛出 StorageQueryError。
只有 ENOENT/ENOTDIR 才是「确认不存在」,连接中断、认证失败等都无法确认
@@ -393,7 +394,7 @@ class SMB(StorageBase, metaclass=WeakSingleton):
# 处理根目录
if str(path) == "/":
return schemas.FileItem(
return _SchemaFileItem(
storage=self.schema.value,
type="dir",
path="/",
@@ -415,13 +416,13 @@ class SMB(StorageBase, metaclass=WeakSingleton):
except Exception as e:
raise StorageQueryError(f"【SMB】查询文件项失败: {path} - {e}") from e
def detail(self, fileitem: schemas.FileItem) -> Optional[schemas.FileItem]:
def detail(self, fileitem: _SchemaFileItem) -> Optional[_SchemaFileItem]:
"""
获取文件详情
"""
return self.get_item(Path(fileitem.path))
def delete(self, fileitem: schemas.FileItem) -> bool:
def delete(self, fileitem: _SchemaFileItem) -> bool:
"""
删除文件或目录
"""
@@ -523,7 +524,7 @@ class SMB(StorageBase, metaclass=WeakSingleton):
logger.error(f"【SMB】递归删除失败: {smb_path} - {e}")
raise SMBConnectionError(f"递归删除失败 {smb_path}: {e}")
def rename(self, fileitem: schemas.FileItem, name: str) -> bool:
def rename(self, fileitem: _SchemaFileItem, name: str) -> bool:
"""
重命名文件
"""
@@ -543,7 +544,7 @@ class SMB(StorageBase, metaclass=WeakSingleton):
logger.error(f"【SMB】重命名失败: {e}")
return False
def download(self, fileitem: schemas.FileItem, path: Path = None) -> Optional[Path]:
def download(self, fileitem: _SchemaFileItem, path: Path = None) -> Optional[Path]:
"""
带实时进度显示的下载
"""
@@ -595,8 +596,8 @@ class SMB(StorageBase, metaclass=WeakSingleton):
return None
def upload(
self, fileitem: schemas.FileItem, path: Path, new_name: Optional[str] = None
) -> Optional[schemas.FileItem]:
self, fileitem: _SchemaFileItem, path: Path, new_name: Optional[str] = None
) -> Optional[_SchemaFileItem]:
"""
带实时进度显示的上传
"""
@@ -643,7 +644,7 @@ class SMB(StorageBase, metaclass=WeakSingleton):
logger.error(f"【SMB】上传失败: {target_name} - {e}")
return None
def copy(self, fileitem: schemas.FileItem, path: Path, new_name: str) -> bool:
def copy(self, fileitem: _SchemaFileItem, path: Path, new_name: str) -> bool:
"""
复制文件
"""
@@ -670,7 +671,7 @@ class SMB(StorageBase, metaclass=WeakSingleton):
logger.error(f"【SMB】复制失败: {e}")
return False
def move(self, fileitem: schemas.FileItem, path: Path, new_name: str) -> bool:
def move(self, fileitem: _SchemaFileItem, path: Path, new_name: str) -> bool:
"""
移动文件
"""
@@ -689,7 +690,7 @@ class SMB(StorageBase, metaclass=WeakSingleton):
logger.error(f"【SMB】移动失败: {e}")
return False
def link(self, fileitem: schemas.FileItem, target_file: Path) -> bool:
def link(self, fileitem: _SchemaFileItem, target_file: Path) -> bool:
"""
硬链接文件
Samba服务器需要开启 unix extensions 支持
@@ -722,17 +723,17 @@ class SMB(StorageBase, metaclass=WeakSingleton):
logger.error(f"【SMB】创建硬链接失败: {e}")
return False
def softlink(self, fileitem: schemas.FileItem, target_file: Path) -> bool:
def softlink(self, fileitem: _SchemaFileItem, target_file: Path) -> bool:
pass
def usage(self) -> Optional[schemas.StorageUsage]:
def usage(self) -> Optional[_SchemaStorageUsage]:
"""
存储使用情况
"""
try:
self._check_connection()
volume_stat = smbclient.stat_volume(self._server_path)
return schemas.StorageUsage(
return _SchemaStorageUsage(
total=volume_stat.total_size,
available=volume_stat.caller_available_size,
)
+30 -29
View File
@@ -12,7 +12,8 @@ from oss2 import SizedFileAdapter, determine_part_size
from oss2.models import PartInfo
from cryptography.hazmat.primitives import hashes
from app import schemas
from app.schemas.file import StorageUsage as _SchemaStorageUsage
from app.schemas.workflow import FileItem as _SchemaFileItem
from app.runtime.config import settings, global_vars
from app.runtime.log import logger
from app.modules.filemanager import StorageBase
@@ -474,7 +475,7 @@ class U115Pan(StorageBase, metaclass=WeakSingleton):
def init_storage(self):
pass
def list(self, fileitem: schemas.FileItem) -> List[schemas.FileItem]:
def list(self, fileitem: _SchemaFileItem) -> List[_SchemaFileItem]:
"""
目录遍历实现
"""
@@ -520,7 +521,7 @@ class U115Pan(StorageBase, metaclass=WeakSingleton):
item_name = item["fn"]
full_path = parent_path / item_name
items.append(
schemas.FileItem(
_SchemaFileItem(
storage=self.schema.value,
fileid=str(item["fid"]),
parent_fileid=cid,
@@ -542,8 +543,8 @@ class U115Pan(StorageBase, metaclass=WeakSingleton):
return items
def create_folder(
self, parent_item: schemas.FileItem, name: str
) -> Optional[schemas.FileItem]:
self, parent_item: _SchemaFileItem, name: str
) -> Optional[_SchemaFileItem]:
"""
创建目录
"""
@@ -564,7 +565,7 @@ class U115Pan(StorageBase, metaclass=WeakSingleton):
return self.get_item(new_path)
logger.warn(f"【115】创建目录失败: {resp.get('error')}")
return None
return schemas.FileItem(
return _SchemaFileItem(
storage=self.schema.value,
fileid=str(resp["data"]["file_id"]),
path=new_path.as_posix() + "/",
@@ -576,10 +577,10 @@ class U115Pan(StorageBase, metaclass=WeakSingleton):
def upload(
self,
target_dir: schemas.FileItem,
target_dir: _SchemaFileItem,
local_path: Path,
new_name: Optional[str] = None,
) -> Optional[schemas.FileItem]:
) -> Optional[_SchemaFileItem]:
"""
实现带秒传、断点续传和二次认证的文件上传
"""
@@ -678,7 +679,7 @@ class U115Pan(StorageBase, metaclass=WeakSingleton):
params={"file_id": int(file_id)},
)
if info_resp:
return schemas.FileItem(
return _SchemaFileItem(
storage=self.schema.value,
fileid=str(info_resp["file_id"]),
path=target_path.as_posix()
@@ -872,11 +873,11 @@ class U115Pan(StorageBase, metaclass=WeakSingleton):
def __build_uploaded_fileitem(
self, target_path: Path, local_path: Path, file_size: int
) -> schemas.FileItem:
) -> _SchemaFileItem:
"""
构造已上传文件项,用于兼容 115 上传成功后目录索引延迟刷新。
"""
return schemas.FileItem(
return _SchemaFileItem(
storage=self.schema.value,
path=target_path.as_posix(),
type="file",
@@ -887,7 +888,7 @@ class U115Pan(StorageBase, metaclass=WeakSingleton):
modify_time=local_path.stat().st_mtime if local_path.exists() else None,
)
def download(self, fileitem: schemas.FileItem, path: Path = None) -> Optional[Path]:
def download(self, fileitem: _SchemaFileItem, path: Path = None) -> Optional[Path]:
"""
带实时进度显示的下载
"""
@@ -957,7 +958,7 @@ class U115Pan(StorageBase, metaclass=WeakSingleton):
def check(self) -> bool:
return self.access_token is not None
def delete(self, fileitem: schemas.FileItem) -> bool:
def delete(self, fileitem: _SchemaFileItem) -> bool:
"""
删除文件/目录
"""
@@ -969,7 +970,7 @@ class U115Pan(StorageBase, metaclass=WeakSingleton):
except httpx.HTTPError:
return False
def rename(self, fileitem: schemas.FileItem, name: str) -> bool:
def rename(self, fileitem: _SchemaFileItem, name: str) -> bool:
"""
重命名文件/目录
"""
@@ -984,7 +985,7 @@ class U115Pan(StorageBase, metaclass=WeakSingleton):
return True
return False
def __get_info_item(self, path: Path) -> Optional[schemas.FileItem]:
def __get_info_item(self, path: Path) -> Optional[_SchemaFileItem]:
"""
查询指定路径的文件/目录项,无法确认状态时抛出 StorageQueryError。
接口业务码 20004(记录不存在)、430004(路径不存在)与 0 一样
@@ -1004,7 +1005,7 @@ class U115Pan(StorageBase, metaclass=WeakSingleton):
if not data or not data.get("file_id"):
# 115 对记录不存在和路径不存在返回不同业务码,两者都可确认目标不存在
return None
return schemas.FileItem(
return _SchemaFileItem(
storage=self.schema.value,
fileid=str(data["file_id"]),
path=path.as_posix() + ("/" if data["file_category"] == "0" else ""),
@@ -1019,7 +1020,7 @@ class U115Pan(StorageBase, metaclass=WeakSingleton):
modify_time=data["utime"],
)
def get_item(self, path: Path) -> Optional[schemas.FileItem]:
def get_item(self, path: Path) -> Optional[_SchemaFileItem]:
"""
获取指定路径的文件/目录项
"""
@@ -1029,7 +1030,7 @@ class U115Pan(StorageBase, metaclass=WeakSingleton):
logger.debug(f"【115】获取文件信息失败: {str(e)}")
return None
def get_item_strict(self, path: Path) -> Optional[schemas.FileItem]:
def get_item_strict(self, path: Path) -> Optional[_SchemaFileItem]:
"""
获取指定路径的文件/目录项,无法确认状态时抛出 StorageQueryError。
"""
@@ -1040,14 +1041,14 @@ class U115Pan(StorageBase, metaclass=WeakSingleton):
except Exception as e:
raise StorageQueryError(f"【115】查询文件信息失败: {path} - {e}") from e
def get_folder(self, path: Path) -> Optional[schemas.FileItem]:
def get_folder(self, path: Path) -> Optional[_SchemaFileItem]:
"""
获取指定路径的文件夹,如不存在则创建
"""
def __find_dir(
_fileitem: schemas.FileItem, _name: str
) -> Optional[schemas.FileItem]:
_fileitem: _SchemaFileItem, _name: str
) -> Optional[_SchemaFileItem]:
"""
查找下级目录中匹配名称的目录
"""
@@ -1063,7 +1064,7 @@ class U115Pan(StorageBase, metaclass=WeakSingleton):
if folder:
return folder
# 逐级查找和创建目录
fileitem = schemas.FileItem(storage=self.schema.value, path="/")
fileitem = _SchemaFileItem(storage=self.schema.value, path="/")
for part in path.parts[1:]:
dir_file = __find_dir(fileitem, part)
if dir_file:
@@ -1076,13 +1077,13 @@ class U115Pan(StorageBase, metaclass=WeakSingleton):
fileitem = dir_file
return fileitem
def detail(self, fileitem: schemas.FileItem) -> Optional[schemas.FileItem]:
def detail(self, fileitem: _SchemaFileItem) -> Optional[_SchemaFileItem]:
"""
获取文件/目录详细信息
"""
return self.get_item(Path(fileitem.path))
def copy(self, fileitem: schemas.FileItem, path: Path, new_name: str) -> bool:
def copy(self, fileitem: _SchemaFileItem, path: Path, new_name: str) -> bool:
"""
复制
"""
@@ -1115,7 +1116,7 @@ class U115Pan(StorageBase, metaclass=WeakSingleton):
return True
return False
def move(self, fileitem: schemas.FileItem, path: Path, new_name: str) -> bool:
def move(self, fileitem: _SchemaFileItem, path: Path, new_name: str) -> bool:
"""
移动
"""
@@ -1147,13 +1148,13 @@ class U115Pan(StorageBase, metaclass=WeakSingleton):
return True
return False
def link(self, fileitem: schemas.FileItem, target_file: Path) -> bool:
def link(self, fileitem: _SchemaFileItem, target_file: Path) -> bool:
pass
def softlink(self, fileitem: schemas.FileItem, target_file: Path) -> bool:
def softlink(self, fileitem: _SchemaFileItem, target_file: Path) -> bool:
pass
def usage(self) -> Optional[schemas.StorageUsage]:
def usage(self) -> Optional[_SchemaStorageUsage]:
"""
存储使用情况
"""
@@ -1162,7 +1163,7 @@ class U115Pan(StorageBase, metaclass=WeakSingleton):
if not resp:
return None
space = resp["rt_space_info"]
return schemas.StorageUsage(
return _SchemaStorageUsage(
total=space["all_total"]["size"], available=space["all_remain"]["size"]
)
except NoCheckInException: