diff --git a/api/api.py b/ThousandHands/api/api.py similarity index 100% rename from api/api.py rename to ThousandHands/api/api.py diff --git a/core/__init__.py b/ThousandHands/core/__init__.py similarity index 100% rename from core/__init__.py rename to ThousandHands/core/__init__.py diff --git a/core/objects/backup_object.py b/ThousandHands/core/objects/backup_object.py similarity index 67% rename from core/objects/backup_object.py rename to ThousandHands/core/objects/backup_object.py index fc05f10..72fb1d4 100644 --- a/core/objects/backup_object.py +++ b/ThousandHands/core/objects/backup_object.py @@ -10,7 +10,7 @@ import asyncio from typing import List, Union from .tree_object import TreeObject from .blob_object import BlobObject -from utils.log import Logger +from ThousandHands.utils.log import Logger logger = Logger("BackupObject") @@ -19,16 +19,14 @@ class BackupObject: """ 备份对象,负责管理存储对象(tree、blob)对象、备份信息、恢复等操作 """ - backup_name: str backup_time_lately: str backup_time_create: str backup_size: int backup_version_number: int backup_trees: List[Union[TreeObject, BlobObject]] = [] - new_backup_flag: bool - def __init__(self, backup_name: str, backup_base_path: str): + def __init__(self, backup_name: str, backup_base_path: str, backup_dirs: List[str] = []): self.backup_name = backup_name # 获取备份路径的绝对路径 @@ -39,18 +37,18 @@ class BackupObject: os.path.abspath(backup_base_path), backup_name ) - logger.debug(f"Backup path: {self.backup_path}") + logger.debug(f"new backup object,Backup path: {self.backup_path}") - if not os.path.exists(self.backup_path): - self.new_backup_flag = True - else: - self.new_backup_flag = False - pass # TODO 读取备份信息 + if backup_dirs != []: + logger.info("load existing backups") + self.addBackup(backup_dirs) + - def createNewBackup(self, backup_dirs: List[str]): + def addBackup(self, backup_dirs: List[str]): """ 创建新的备份 + :param backup_dirs: 备份目录列表 :return """ for backup_dir in backup_dirs: @@ -62,19 +60,23 @@ class BackupObject: logger.info("New backup created successfully.") logger.debug(f"Backup trees: {self.backup_trees}") - def backup(self): - asyncio.run(self.__writeBlobs()) - - async def __writeBlobs(self): + async def __writeTree(self): """ 写入所有对象到备份路径 """ obj_save_path = os.path.join(self.backup_path, "objects") for obj in self.backup_trees: if isinstance(obj, TreeObject): - await obj.writeBlobs(obj_save_path) # 如果是TreeObject,则调用writeBlobs方法 + await obj.writeTree( + obj_save_path + ) # 如果是TreeObject,则调用writeTree方法 else: - await obj.writeBlob(obj_save_path) # 如果是BlobObject,则调用writeBlob方法 + await obj.writeBlob( + obj_save_path + ) # 如果是BlobObject,则调用writeBlob方法 + + def backup(self): + asyncio.run(self.__writeTree()) def recover(self, recover_path: str): """ @@ -91,3 +93,11 @@ class BackupObject: :return """ pass + + def writeBackupInfo(self): + """ + 写入备份信息 + + :return + """ + pass diff --git a/core/objects/blob_object.py b/ThousandHands/core/objects/blob_object.py similarity index 94% rename from core/objects/blob_object.py rename to ThousandHands/core/objects/blob_object.py index c78442a..4e9777b 100644 --- a/core/objects/blob_object.py +++ b/ThousandHands/core/objects/blob_object.py @@ -68,8 +68,4 @@ class BlobObject: if not data: break sha1.update(data) - return sha1.hexdigest() - - -def newBlobObject(file_path: str) -> BlobObject: - return BlobObject(file_path) \ No newline at end of file + return sha1.hexdigest() \ No newline at end of file diff --git a/core/objects/tree_object.py b/ThousandHands/core/objects/tree_object.py similarity index 95% rename from core/objects/tree_object.py rename to ThousandHands/core/objects/tree_object.py index a3b679c..5e6fcc1 100644 --- a/core/objects/tree_object.py +++ b/ThousandHands/core/objects/tree_object.py @@ -26,7 +26,7 @@ class TreeObject: self.__children.append(blob) self.__file_map[blob_path] = blob.object_id - async def writeBlobs(self, base_path: str): + async def writeTree(self, base_path: str): tasks = [] for child in self.__children: tasks.append(asyncio.create_task(child.writeBlob(base_path))) diff --git a/ThousandHands/core/plan/PlanBackup.py b/ThousandHands/core/plan/PlanBackup.py new file mode 100644 index 0000000..f3b8921 --- /dev/null +++ b/ThousandHands/core/plan/PlanBackup.py @@ -0,0 +1,21 @@ +from typing import List +from .PlanBase import PlanBase +from ThousandHands.core.objects.backup_object import BackupObject + + +class PlanBackup(PlanBase): + """ + 备份计划,负责管理存储对象的备份 + """ + + __backup_object: BackupObject + + def __init__( + self, backup_name: str, backup_base_path: str, backup_dirs: List[str] = [] + ): + super().__init__() + self.__backup_object = BackupObject(backup_name, backup_base_path, backup_dirs) + self.name = backup_name + + def execute(self): + self.__backup_object.backup() diff --git a/ThousandHands/core/plan/PlanBase.py b/ThousandHands/core/plan/PlanBase.py new file mode 100644 index 0000000..2fadb4f --- /dev/null +++ b/ThousandHands/core/plan/PlanBase.py @@ -0,0 +1,31 @@ +from abc import ABC, abstractmethod + + +class PlanBase(ABC): + __priority_factor: int # 优先级因子 + __executed: bool + __time_hour: int + __time_minute: int + + name: str + + def __init__(self): + self.__priority_factor = 0 + self.name = "" + + @abstractmethod + def execute(self): + pass + + def getPriorityFactor(self) -> int: + """ + 获取优先级因子 + """ + return self.__priority_factor + + def getNextTime(self) -> int: + # TODO: 实现计划执行 + return 0 + + def isExecuted(self) -> bool: + return self.__executed diff --git a/ThousandHands/core/plan/TimeHandler.py b/ThousandHands/core/plan/TimeHandler.py new file mode 100644 index 0000000..1b698bc --- /dev/null +++ b/ThousandHands/core/plan/TimeHandler.py @@ -0,0 +1,4 @@ + +class TimeHandler(object): + pass + diff --git a/core/plan/__init__.py b/ThousandHands/core/plan/__init__.py similarity index 100% rename from core/plan/__init__.py rename to ThousandHands/core/plan/__init__.py diff --git a/ThousandHands/core/scheduler/scheduler.py b/ThousandHands/core/scheduler/scheduler.py new file mode 100644 index 0000000..4d6124c --- /dev/null +++ b/ThousandHands/core/scheduler/scheduler.py @@ -0,0 +1,44 @@ +from typing import Dict +from ThousandHands.core.plan.PlanBase import PlanBase +import sched +import time +import concurrent.futures + + +class Scheduler: + __plans: Dict[str, sched.Event] + __scheduler: sched.scheduler + __executor: concurrent.futures.ThreadPoolExecutor + + def __init__(self): + self.__plans = {} + self.__scheduler = sched.scheduler(time.time, time.sleep) + self.__executor = concurrent.futures.ThreadPoolExecutor(max_workers=3) + + def add_plan(self, plan: PlanBase) -> None: + if plan.name in self.__plans: + raise ValueError("Plan already exists") + + event = self.__scheduler.enter( + plan.getNextTime(), plan.getPriorityFactor(), self.__execute_plan, (plan,) + ) + + self.__plans[plan.name] = event + + def remove_plan(self, plan_name: str) -> None: + if plan_name in self.__plans: + del self.__plans[plan_name] + + raise ValueError("Plan name not found") + + def run(self): + self.__scheduler.run() + + def stop(self): + self.__executor.shutdown(wait=True) + + def __execute_plan(self, plan: PlanBase): + """ + 执行计划,并在执行后重新安排(如果需要) + """ + self.__executor.submit(plan.execute) diff --git a/core/target/__init__.py b/ThousandHands/core/target/__init__.py similarity index 100% rename from core/target/__init__.py rename to ThousandHands/core/target/__init__.py diff --git a/core/target/targetBaidu.py b/ThousandHands/core/target/targetBaidu.py similarity index 100% rename from core/target/targetBaidu.py rename to ThousandHands/core/target/targetBaidu.py diff --git a/core/target/targetBase.py b/ThousandHands/core/target/targetBase.py similarity index 81% rename from core/target/targetBase.py rename to ThousandHands/core/target/targetBase.py index 779714a..7ef1cdb 100644 --- a/core/target/targetBase.py +++ b/ThousandHands/core/target/targetBase.py @@ -17,8 +17,4 @@ class TargetBase(ABC): :param :return """ - pass - - @abstractmethod - def back(self, back_object: BackupObject): - pass + pass \ No newline at end of file diff --git a/core/target/targetFTP.py b/ThousandHands/core/target/targetFTP.py similarity index 100% rename from core/target/targetFTP.py rename to ThousandHands/core/target/targetFTP.py diff --git a/core/target/targetNFS.py b/ThousandHands/core/target/targetNFS.py similarity index 100% rename from core/target/targetNFS.py rename to ThousandHands/core/target/targetNFS.py diff --git a/ThousandHands/core/target/targetNative.py b/ThousandHands/core/target/targetNative.py new file mode 100644 index 0000000..2c3d358 --- /dev/null +++ b/ThousandHands/core/target/targetNative.py @@ -0,0 +1,10 @@ +from .targetBase import TargetBase + + +class TargetNative(TargetBase): + + def __init__(self) -> None: + pass + + def test(self) -> bool: + return True diff --git a/utils/log.py b/ThousandHands/utils/log.py similarity index 100% rename from utils/log.py rename to ThousandHands/utils/log.py diff --git a/core/plan/Plan.py b/core/plan/Plan.py deleted file mode 100644 index a6a0c76..0000000 --- a/core/plan/Plan.py +++ /dev/null @@ -1,11 +0,0 @@ -class Plan: - __priority_factor: float # 优先级因子 - - def __init__(self): - pass - - def getPriorityFactor(self) -> float: - ''' - 获取优先级因子 - ''' - return self.__priority_factor diff --git a/core/plan/PlanBackup.py b/core/plan/PlanBackup.py deleted file mode 100644 index e69de29..0000000 diff --git a/core/plan/PlanMinHeap.py b/core/plan/PlanMinHeap.py deleted file mode 100644 index 4ba93e4..0000000 --- a/core/plan/PlanMinHeap.py +++ /dev/null @@ -1,15 +0,0 @@ -from typing import List -from .Plan import Plan - - -class PlanPriorityMinHeap: - """ - 计划优先小顶堆,按照优先级存储多个计划 - """ - - plans: List[Plan] - def __init__(self): - self.plans = [] - - def addPlan(self, plan: Plan): - pass diff --git a/core/timer/__init__.py b/core/timer/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/core/timer/timer.py b/core/timer/timer.py deleted file mode 100644 index 4a6e6d9..0000000 --- a/core/timer/timer.py +++ /dev/null @@ -1,11 +0,0 @@ -from typing import Callable - - -class Timer: - def __init__(self, name: str, interval: float, callback: Callable): - self.name = name - self.interval = interval - self.callback = callback - - def start(self): - pass diff --git a/script/build.sh b/script/build.sh deleted file mode 100644 index e69de29..0000000 diff --git a/tests/core/objects/test_backup_object.py b/tests/core/objects/test_backup_object.py index 0395baf..c1f6f3b 100644 --- a/tests/core/objects/test_backup_object.py +++ b/tests/core/objects/test_backup_object.py @@ -1,5 +1,5 @@ -from core.objects.backup_object import BackupObject +from ThousandHands.core.objects.backup_object import BackupObject import tempfile import os @@ -25,7 +25,7 @@ class TestBackup(): with tempfile.TemporaryDirectory() as tmpdir: temp_data_dir = self.createTempDataDir() b = BackupObject("testBackup", tmpdir) - b.createNewBackup([temp_data_dir.name]) + b.addBackup([temp_data_dir.name]) b.backup() temp_data_dir.cleanup() assert os.path.exists(b.backup_path+"/objects") diff --git a/tests/core/objects/test_blob_object.py b/tests/core/objects/test_blob_object.py index 773afe4..0fa1249 100644 --- a/tests/core/objects/test_blob_object.py +++ b/tests/core/objects/test_blob_object.py @@ -1,5 +1,5 @@ import asyncio -from core.objects.blob_object import BlobObject +from ThousandHands.core.objects.blob_object import BlobObject import hashlib import tempfile