From 227f9814977ed57982704a0e8d4ffd417a27e305 Mon Sep 17 00:00:00 2001 From: yzqzss Date: Sat, 3 Jun 2023 22:36:24 +0800 Subject: [PATCH] =?UTF-8?q?=E4=B8=8A=E4=BC=A0=E6=97=B6=E5=8A=A0=E6=96=87?= =?UTF-8?q?=E4=BB=B6=E9=94=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- _biliarchiver_upload_bvid.py | 15 ++++++- _uploadingLock.py | 86 ++++++++++++++++++++++++++++++++++++ 2 files changed, 100 insertions(+), 1 deletion(-) create mode 100644 _uploadingLock.py diff --git a/_biliarchiver_upload_bvid.py b/_biliarchiver_upload_bvid.py index 765cbb5..eb31a83 100644 --- a/_biliarchiver_upload_bvid.py +++ b/_biliarchiver_upload_bvid.py @@ -3,11 +3,24 @@ import os import time from internetarchive import get_item from rich import print +from glob import glob from _biliarchiver_archive_bvid import BILIBILI_IDENTIFIER_PERFIX - +from _uploadingLock import UploadLock, AlreadyRunningError def upload_bvid(bvid): + try: + lock_dir = f'biliarchiver/.locks/{bvid}/' + os.makedirs(lock_dir, exist_ok=True) + with UploadLock(lock_dir): + _upload_bvid(bvid) + except AlreadyRunningError: + print(f'已经有一个上传 {bvid} 的进程在运行,跳过') + except Exception as e: + print(f'上传 {bvid} 时出错:') + raise e + +def _upload_bvid(bvid): if not os.path.exists('biliarchiver.home'): raise Exception('先创建 biliarchiver.home 文件') access_key, secret_key = read_ia_keys(os.path.expanduser('~/.bili_ia_keys.txt')) diff --git a/_uploadingLock.py b/_uploadingLock.py new file mode 100644 index 0000000..7f2f699 --- /dev/null +++ b/_uploadingLock.py @@ -0,0 +1,86 @@ +import os +import sys +import importlib.util + +class AlreadyRunningError(Exception): + def __init__(self, message: str=""): + self.message = message + super().__init__(self.message) + def __str__(self): + return self.message + + +LOCK_FILENAME = '_uploading.lock' + +class UploadLock_Basic: + def __init__(self, lock_dir): + self.lock_file = os.path.join(lock_dir, LOCK_FILENAME) + + def __enter__(self): + if os.path.exists(self.lock_file): + with open(self.lock_file, 'r', encoding='utf-8') as f: + print(f.read()) + print("Another instance is already running.") + raise AlreadyRunningError('Another instance is already running.') + else: + with open(self.lock_file, 'w', encoding='utf-8') as f: + f.write(f'PID: {os.getpid()}: Running') + print("Acquired lock, continuing.") + + def __exit__(self, exc_type, exc_val, exc_tb): + os.remove(self.lock_file) + print("Released lock.") + + # decorator + def __call__(self, func): + def wrapper(*args, **kwargs): + with self: + return func(*args, **kwargs) + return wrapper + + +class UploadLock_Fcntl(): + fcntl = None + try: + import fcntl + except ModuleNotFoundError: + pass + + def __init__(self, lock_dir): + if self.fcntl is None: + raise(ModuleNotFoundError("No module named 'fcntl'", name='fcntl')) + + self.lock_file = os.path.join(lock_dir, LOCK_FILENAME) + self.lock_file_fd = None + + def __enter__(self): + self.lock_file_fd = open(self.lock_file, 'w') + try: + self.fcntl.lockf(self.lock_file_fd, self.fcntl.LOCK_EX | self.fcntl.LOCK_NB) + print("Acquired lock, continuing.") + except IOError: + raise AlreadyRunningError("Another instance is already running.") + + + def __exit__(self, exc_type, exc_val, exc_tb): + if self.lock_file_fd is None: + raise IOError("Lock file not opened.") + self.fcntl.lockf(self.lock_file_fd, self.fcntl.LOCK_UN) + self.lock_file_fd.close() + os.remove(self.lock_file) + print("Released lock.") + + # decorator + def __call__(self, func): + def wrapper(*args, **kwargs): + with self: + return func(*args, **kwargs) + return wrapper + +class UploadLock(): + def __new__(cls, lock_dir): + fcntl_avaivable = importlib.util.find_spec('fcntl') + if fcntl_avaivable is not None: + return UploadLock_Fcntl(lock_dir) + else: + return UploadLock_Basic(lock_dir) \ No newline at end of file