support backup and recovery

This commit is contained in:
xtaodada 2022-01-30 15:35:37 +08:00
parent 53b65965b7
commit 2e958dbbf5
No known key found for this signature in database
GPG Key ID: EE4DC37B55E24736
5 changed files with 145 additions and 0 deletions

1
.gitignore vendored
View File

@ -119,6 +119,7 @@ config.yml
pagermaid.session
pagermaid.session-journal
*.pagermaid
pagermaid_backup.tar.gz
docker-compose.yml
plugins/
data/*

View File

@ -126,6 +126,19 @@ parseqr_nofile: There are no attachments in the message.
parseqr_content: Content
parseqr_e_noqr: Target is not a QR Code.
parseqr_log: Parsed QR Code with content
# backup
# backup
backup_des: Backup data files to local as well as log channels, support full backup of database, safe and reliable.
backup_process: It may take some time to complete the backup.
backup_success_channel: Backup is complete! And it has been packaged and sent to the Log channel!
backup_success: Backup is complete!
# recovery
recovery_des: Restore data from local backup or replied backup file, and support full database recovery easily and quickly.
recovery_file_error: Unknown file that may not be the type of file backed up by pagermaid.
recovery_down: Downloading backup file to local...
recovery_process: It may take some time to complete the recovery.
recovery_file_not_found: No backup file found.
recovery_success: Data file recovery is complete! You may need to restart manually for this to take effect.
# captions
# convert
convert_des: Reply to an attachment message and convert it to image output

View File

@ -133,6 +133,20 @@ parseqr_content: 内容
parseqr_e_noqr: 回复的附件不是 QR 码。
parseqr_log: 已解析一张带有 QR 码的消息,内容:
# backup
## backup
backup_des: 备份数据文件到本地以及日志频道,支持数据库的全量备份,安全可靠。
backup_process: 开始备份,可能需要一定的时间。。。
backup_success_channel: 数据文件备份完成!并且已经打包发送到 Log 频道!
backup_success: 数据文件备份完成!
## recovery
recovery_des: 从本地备份或者所回复的备份文件中恢复数据,支持数据库的全量恢复,方便快速。
recovery_file_error: 未知的文件,可能并不是通过 pagermaid 所备份的文件类型。
recovery_down: 正在下载备份文件到本地。。。
recovery_process: 开始恢复,可能需要一定的时间。。
recovery_file_not_found: 没有找到备份文件。
recovery_success: 数据文件恢复完成!您可能需要手动重新启动才能生效。
# captions
## convert
convert_des: 回复某条附件消息然后转换为图片输出

View File

@ -126,6 +126,19 @@ parseqr_nofile: 回覆的訊息裡面沒有附件。
parseqr_content: 內容
parseqr_e_noqr: 回覆的附件錯誤!
parseqr_log: 已解析QR 扣的內容,如下:
# backup
# backup
backup_des: 備份數據文件到本地以及日誌頻道,支持數據庫的全量備份,安全可靠。
backup_process: 開始備份,可能需要一定的時間。。。
backup_success_channel: 數據文件備份完成!並且已經打包發送到 Log 頻道!
backup_success: 數據文件備份完成!
# recovery
recovery_des: 從本地備份或者所回复的備份文件中恢復數據,支持數據庫的全量恢復,方便快速。
recovery_file_error: 未知的文件,可能並不是通過 pagermaid 所備份的文件類型。
recovery_down: 正在下載備份文件到本地。。。
recovery_process: 開始恢復,可能需要一定的時間。。
recovery_file_not_found: 沒有找到備份文件。
recovery_success: 數據文件恢復完成!您可能需要手動重新啟動才能生效。
# captions
# convert
convert_des: 回覆附件訊息並轉換為圖片

104
pagermaid/modules/backup.py Normal file
View File

@ -0,0 +1,104 @@
""" Pagermaid backup and recovery plugin. """
import json
import os
import tarfile
from distutils.util import strtobool
from io import BytesIO
from pagermaid import config, redis_status, redis, silent
from pagermaid.listener import listener
from pagermaid.utils import alias_command, upload_attachment, lang
from telethon.tl.types import MessageMediaDocument
def make_tar_gz(output_filename, source_dirs: list):
"""
压缩 tar.gz 文件
:param output_filename: 压缩文件名
:param source_dirs: 需要压缩的文件列表
:return: None
"""
with tarfile.open(output_filename, "w:gz") as tar:
for i in source_dirs:
tar.add(i, arcname=os.path.basename(i))
def un_tar_gz(filename, dirs):
"""
解压 tar.gz 文件
:param filename: 压缩文件名
:param dirs: 解压后的存放路径
:return: bool
"""
try:
t = tarfile.open(filename, "r:gz")
t.extractall(path=dirs)
return True
except Exception as e:
print(e)
return False
@listener(is_plugin=True, outgoing=True, command=alias_command("backup"),
description=lang('back_des'))
async def backup(context):
if not silent:
await context.edit(lang('backup_process'))
if os.path.exists("pagermaid_backup.tar.gz"):
os.remove("pagermaid_backup.tar.gz")
# remove mp3 , they are so big !
for i in os.listdir("data"):
if i.find(".mp3") != -1 or i.find(".jpg") != -1 or i.find(".flac") != -1 or i.find(".ogg") != -1:
os.remove(f"data{os.sep}{i}")
# backup redis
redis_data = {}
if redis_status():
for k in redis.keys():
data_type = redis.type(k)
if data_type == b'string':
v = redis.get(k)
redis_data[k.decode()] = v.decode()
with open(f"data{os.sep}redis.json", "w", encoding='utf-8') as f:
json.dump(redis_data, f, indent=4)
# run backup function
make_tar_gz("pagermaid_backup.tar.gz", ["data", "plugins", "config.yml"])
if strtobool(config['log']):
await upload_attachment("pagermaid_backup.tar.gz", int(config['log_chatid']), None)
await context.edit(lang("backup_success_channel"))
else:
await context.edit(lang("backup_success"))
@listener(is_plugin=True, outgoing=True, command=alias_command("recovery"),
description=lang('recovery_des'))
async def recovery(context):
message = await context.get_reply_message()
if message and message.media:
if isinstance(message.media, MessageMediaDocument):
try:
file_name = message.media.document.attributes[0].file_name
except:
return await context.edit(lang('recovery_file_error'))
if file_name.find(".tar.gz") != -1:
await context.edit(lang('recovery_down'))
else:
return await context.edit(lang('recovery_file_error'))
else:
return await context.edit(lang('recovery_file_error'))
_file = BytesIO()
await context.client.download_file(message.media.document, _file)
with open("pagermaid_backup.tar.gz", "wb") as f:
f.write(_file.getvalue())
if not silent:
await context.edit(lang('recovery_process'))
if not os.path.exists("pagermaid_backup.tar.gz"):
return await context.edit(lang('recovery_file_not_found'))
un_tar_gz("pagermaid_backup.tar.gz", "")
# recovery redis
if redis_status():
if os.path.exists(f"data{os.sep}redis.json"):
with open(f"data{os.sep}redis.json", "r", encoding='utf-8') as f:
redis_data = json.load(f)
for k, v in redis_data.items():
redis.set(k, v)
await context.edit(lang('recovery_success'))