feat: add private journals and centralized Baidu media storage for v0.1.28
This commit is contained in:
+29
-11
@@ -17,12 +17,13 @@ class Backups:
|
||||
self.a = app
|
||||
self.guard = threading.Lock()
|
||||
self.running = False
|
||||
self.stage = ''
|
||||
|
||||
def config(self):
|
||||
return self.a.setting('backup_config', dict(enabled=False, time='03:00', keep=14, networkPath='', revision=0))
|
||||
return {'baidu': False, **self.a.setting('backup_config', dict(enabled=False, time='03:00', keep=14, networkPath='', revision=0))}
|
||||
|
||||
def status(self):
|
||||
return dict(config=self.config(), running=self.running,
|
||||
return dict(config=self.config(), running=self.running, stage=self.stage,
|
||||
localPath=str(self.a.DATA/'managed-backups'),
|
||||
last=self.a.setting('backup_last', None),
|
||||
history=self.a.setting('backup_history', [])[-20:][::-1])
|
||||
@@ -73,11 +74,14 @@ class Backups:
|
||||
return folder
|
||||
|
||||
def save(self, data):
|
||||
if set(data) != {'enabled','time','keep','networkPath','revision'}:
|
||||
data = {'baidu': False, **data}
|
||||
if set(data) != {'enabled','time','keep','networkPath','revision','baidu'}:
|
||||
raise self.a.Problem('备份设置字段不完整')
|
||||
with self.guard:
|
||||
if self.running:
|
||||
raise self.a.Problem('备份正在执行,请完成后再调整设置', 409)
|
||||
if not isinstance(data['baidu'], bool): raise self.a.Problem('网盘备份设置不正确')
|
||||
if data['baidu']: self.a.BAIDU.token('shared')
|
||||
with self.a.LOCK:
|
||||
old = self.config()
|
||||
if type(data['revision']) is not int or data['revision'] != old['revision']:
|
||||
@@ -96,7 +100,10 @@ class Backups:
|
||||
if self.running:
|
||||
raise self.a.Problem('已有备份正在执行', 409)
|
||||
self.running = True
|
||||
threading.Thread(target=self.run, args=(reason,), daemon=True).start()
|
||||
try: threading.Thread(target=self.run, args=(reason,), daemon=True).start()
|
||||
except Exception:
|
||||
with self.guard: self.running = False
|
||||
raise
|
||||
return dict(started=True)
|
||||
|
||||
def prune(self, folder, prefix, keep):
|
||||
@@ -106,11 +113,13 @@ class Backups:
|
||||
|
||||
def run(self, reason='manual'):
|
||||
a = self.a
|
||||
config = self.config()
|
||||
result = dict(at=dt.datetime.now(dt.timezone.utc).isoformat(), reason=reason,
|
||||
localOk=False, networkOk=False, networkRequested=bool(config['networkPath']))
|
||||
localOk=False, networkOk=False, baiduOk=False, networkRequested=False, baiduRequested=False)
|
||||
temporary = network_temp = None
|
||||
try:
|
||||
config = self.config()
|
||||
result.update(networkRequested=bool(config['networkPath']), baiduRequested=config['baidu'])
|
||||
self.stage = '正在生成本机数据库副本'
|
||||
local = a.DATA/'managed-backups'
|
||||
local.mkdir(mode=0o700, exist_ok=True)
|
||||
instance = a.setting('backup_instance')
|
||||
@@ -133,6 +142,7 @@ class Backups:
|
||||
result.update(localOk=True, file=name, bytes=target.stat().st_size, sha256=digest)
|
||||
self.prune(local, prefix, config['keep'])
|
||||
if config['networkPath']:
|
||||
self.stage = '正在复制到网络目录'
|
||||
network = self.network_folder(config['networkPath'])
|
||||
network_temp = network/(name+'.partial')
|
||||
shutil.copyfile(target, network_temp)
|
||||
@@ -143,6 +153,11 @@ class Backups:
|
||||
os.replace(network_temp, network/name)
|
||||
result['networkOk'] = True
|
||||
self.prune(network, prefix, config['keep'])
|
||||
if config['baidu']:
|
||||
self.stage = '正在上传百度网盘'
|
||||
remote = '/apps/'+a.BAIDU.public_config()['appFolder']+'/数据库备份/'+instance+'/'+name+'/'+name
|
||||
uploaded = a.BAIDU.upload('shared', target, remote)
|
||||
result.update(baiduOk=True, baiduPath=remote, baiduFileId=str(uploaded['fs_id']))
|
||||
except Exception as error:
|
||||
result['error'] = str(error)[:300] or '备份未完成'
|
||||
finally:
|
||||
@@ -151,11 +166,14 @@ class Backups:
|
||||
if temporary_path and temporary_path.exists(): temporary_path.unlink()
|
||||
except OSError:
|
||||
pass
|
||||
with a.LOCK:
|
||||
a.set_setting('backup_last', result)
|
||||
history = a.setting('backup_history', [])
|
||||
a.set_setting('backup_history', (history+[result])[-100:])
|
||||
self.running = False
|
||||
try:
|
||||
with a.LOCK:
|
||||
a.set_setting('backup_last', result)
|
||||
history = a.setting('backup_history', [])
|
||||
a.set_setting('backup_history', (history+[result])[-100:])
|
||||
finally:
|
||||
with self.guard:
|
||||
self.running = False; self.stage = ''
|
||||
return result
|
||||
|
||||
def tick(self, now=None):
|
||||
|
||||
Reference in New Issue
Block a user