hikka_backup.py 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. # █ █ ▀ █▄▀ ▄▀█ █▀█ ▀
  2. # █▀█ █ █ █ █▀█ █▀▄ █
  3. # © Copyright 2022
  4. # https://t.me/hikariatama
  5. #
  6. # 🔒 Licensed under the GNU AGPLv3
  7. # 🌐 https://www.gnu.org/licenses/agpl-3.0.html
  8. # scope: inline
  9. import asyncio
  10. import datetime
  11. import io
  12. import json
  13. import logging
  14. import time
  15. from telethon.tl.types import Message
  16. from .. import loader, utils
  17. from ..inline.types import BotInlineCall
  18. logger = logging.getLogger(__name__)
  19. @loader.tds
  20. class HikkaBackupMod(loader.Module):
  21. """Automatic database backup"""
  22. strings = {
  23. "name": "HikkaBackup",
  24. "period": (
  25. "⌚️ <b>Unit «ALPHA»</b> creates database backups periodically. You can"
  26. " change this behavior later.\n\nPlease, select the periodicity of"
  27. " automatic database backups"
  28. ),
  29. "saved": (
  30. "✅ Backup period saved. You can re-configure it later with"
  31. " .set_backup_period"
  32. ),
  33. "never": (
  34. "✅ I will not make automatic backups. You can re-configure it later with"
  35. " .set_backup_period"
  36. ),
  37. "invalid_args": (
  38. "🚫 <b>Specify correct backup period in hours, or `0` to disable</b>"
  39. ),
  40. }
  41. strings_ru = {
  42. "period": (
  43. "⌚️ <b>Юнит «ALPHA»</b> создает регулярные резервные копии. Эти настройки"
  44. " можно изменить позже.\n\nПожалуйста, выберите периодичность резервного"
  45. " копирования"
  46. ),
  47. "saved": (
  48. "✅ Периодичность сохранена! Ее можно изменить с помощью .set_backup_period"
  49. ),
  50. "never": (
  51. "✅ Я не буду делать автоматические резервные копии. Можно отменить"
  52. " используя .set_backup_period"
  53. ),
  54. "invalid_args": (
  55. "🚫 <b>Укажи правильную периодичность в часах, или `0` для отключения</b>"
  56. ),
  57. }
  58. async def client_ready(self):
  59. if not self.get("period"):
  60. await self.inline.bot.send_photo(
  61. self.tg_id,
  62. photo="https://github.com/hikariatama/assets/raw/master/unit_alpha.png",
  63. caption=self.strings("period"),
  64. reply_markup=self.inline.generate_markup(
  65. utils.chunks(
  66. [
  67. {
  68. "text": f"🕰 {i} h",
  69. "callback": self._set_backup_period,
  70. "args": (i,),
  71. }
  72. for i in {1, 2, 4, 6, 8, 12, 24, 48, 168}
  73. ],
  74. 3,
  75. )
  76. + [
  77. [
  78. {
  79. "text": "🚫 Never",
  80. "callback": self._set_backup_period,
  81. "args": (0,),
  82. }
  83. ]
  84. ]
  85. ),
  86. )
  87. self._backup_channel, _ = await utils.asset_channel(
  88. self._client,
  89. "hikka-backups",
  90. "📼 Your database backups will appear there",
  91. silent=True,
  92. archive=True,
  93. avatar="https://github.com/hikariatama/assets/raw/master/hikka-backups.png",
  94. _folder="hikka",
  95. )
  96. self.handler.start()
  97. async def _set_backup_period(self, call: BotInlineCall, value: int):
  98. if not value:
  99. self.set("period", "disabled")
  100. await call.answer(self.strings("never"), show_alert=True)
  101. await call.delete()
  102. return
  103. self.set("period", value * 60 * 60)
  104. self.set("last_backup", round(time.time()))
  105. await call.answer(self.strings("saved"), show_alert=True)
  106. await call.delete()
  107. @loader.command(ru_doc="<время в часах> - Установить частоту бэкапов")
  108. async def set_backup_period(self, message: Message):
  109. """<time in hours> - Change backup frequency"""
  110. args = utils.get_args_raw(message)
  111. if not args or not args.isdigit() or int(args) not in range(200):
  112. await utils.answer(message, self.strings("invalid_args"))
  113. return
  114. if not int(args):
  115. self.set("period", "disabled")
  116. await utils.answer(message, f"<b>{self.strings('never')}</b>")
  117. return
  118. period = int(args) * 60 * 60
  119. self.set("period", period)
  120. self.set("last_backup", round(time.time()))
  121. await utils.answer(message, f"<b>{self.strings('saved')}</b>")
  122. @loader.loop(interval=1)
  123. async def handler(self):
  124. try:
  125. if not self.get("period"):
  126. await asyncio.sleep(3)
  127. return
  128. if not self.get("last_backup"):
  129. self.set("last_backup", round(time.time()))
  130. await asyncio.sleep(self.get("period"))
  131. return
  132. if self.get("period") == "disabled":
  133. raise loader.StopLoop
  134. await asyncio.sleep(
  135. self.get("last_backup") + self.get("period") - time.time()
  136. )
  137. backup = io.BytesIO(json.dumps(self._db).encode("utf-8"))
  138. backup.name = (
  139. f"hikka-db-backup-{getattr(datetime, 'datetime', datetime).now().strftime('%d-%m-%Y-%H-%M')}.json"
  140. )
  141. await self._client.send_file(
  142. self._backup_channel,
  143. backup,
  144. )
  145. self.set("last_backup", round(time.time()))
  146. except loader.StopLoop:
  147. raise
  148. except Exception:
  149. logger.exception("HikkaBackup failed")
  150. await asyncio.sleep(60)