diff --git a/.gitignore b/.gitignore
index bbc333f..9b3fc0c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -135,3 +135,4 @@ help_message.txt
count*
version.txt
*.exe
+logs/
diff --git a/README.md b/README.md
index 0ade451..3950207 100644
--- a/README.md
+++ b/README.md
@@ -41,7 +41,7 @@ _Всё очень легко и просто)_
## Система permissions
-В файле permissions.yam указаны все пользователи с "повышенным" уровнем доступа к боту
+В файле `permissions.yml` указаны все пользователи с "повышенным" уровнем доступа к боту
Пример
```yaml
noRole: Нет роли
@@ -67,8 +67,6 @@ perms:
# Интеграция с базой данных LuckPerms (Нужна именно внешняя база данных)
useLuckPerms: false
LuckPerms:
- # Смотрите настройку LuckPerms
- server: global
# Разрешенные варианты: MySQL, MariaDB, PostgreSQL
storage-method: PostgreSQL
data:
@@ -81,6 +79,7 @@ LuckPerms:
password: user
# Смотрите настройку LuckPerms
+ server: global
table-prefix: luckperms_
```
diff --git a/requirements.txt b/requirements.txt
index 9181b8f..5b902a9 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -2,4 +2,5 @@ mcstatus~=11.1.1
mcrcon~=0.7.0
vk~=3.0
ruamel.yaml~=0.18.5
-requests~=2.31.0
\ No newline at end of file
+requests~=2.31.0
+loguru~=0.7.2
\ No newline at end of file
diff --git a/src/main.py b/src/main.py
index 16bc44d..e097fcb 100644
--- a/src/main.py
+++ b/src/main.py
@@ -3,21 +3,22 @@ import traceback
import requests
import vk
+from loguru import logger
-from modules import log, config, rcon, perms, get_server_status
+from modules import config, rcon, perms, get_server_status, enter_to_exit
class Bot:
def __init__(self):
self.vk = vk.API(access_token=config.vk.token, v=5.199)
- self.group_id = vk.groups.getById()[0]['id']
+ self.group_id = self.vk.groups.getById()['groups'][0]['id']
with open('help_message.txt') as f:
self.help_message = f.read()
- log(f"[BOT] ID группы: {self.group_id}")
+ logger.info(f"[BOT] ID группы: {self.group_id}")
def get_lp_server(self):
- lp = vk.groups.getLongPollServer(group_id=self.group_id)
+ lp = self.vk.groups.getLongPollServer(group_id=self.group_id)
return lp.get('server'), lp.get('key'), lp.get('ts')
def write(self, peer_id, message):
@@ -25,7 +26,7 @@ class Bot:
messages = (len(message) // 4095)
for i in range(1, messages + 1):
if i > 30:
- log("[BOT] Сообщение слишком длинное...", 1)
+ logger.info("[BOT] Сообщение слишком длинное...")
break
self.write(peer_id, message[:4095 * i])
else:
@@ -37,13 +38,14 @@ class Bot:
r = cmd
if a or _allow:
answer = rcon(cmd)
- log(f"[BOT] User: {from_id}({r}) in Chat: {peer_id} use RCON cmd: \"{cmd}\", with answer: \"{answer}\"")
+ logger.info(f"[BOT] User: {from_id}({r}) in Chat: {peer_id} use RCON cmd: \"{cmd}\", "
+ f"with answer: \"{answer}\"")
if _write:
self.write(peer_id, f"RCON:\n{answer}")
else:
return answer
else:
- log(f"[BOT] User: {from_id}({r}) in Chat: {peer_id} no have rights RCON cmd: \"{cmd}\".")
+ logger.info(f"[BOT] User: {from_id}({r}) in Chat: {peer_id} no have rights RCON cmd: \"{cmd}\".")
def message_handle(self, message):
from_id = message['from_id']
@@ -56,13 +58,13 @@ class Bot:
self.write(peer_id, self.help_message)
case "!online":
online = get_server_status().online
- self.write(peer_id, f"На сервере сейчас {online} {""}")
+ self.write(peer_id, f"На сервере сейчас {online}")
case "!id":
self.write(peer_id, f"Твой ID: {from_id}\nРоль: {perms.get_role(from_id)}")
def listen(self):
server, key, ts = self.get_lp_server()
- log("[BOT] Начинаю получать сообщения..")
+ logger.info("[BOT] Начинаю получать сообщения..")
while True:
lp = requests.get(f'{server}?act=a_check&key={key}&ts={ts}&wait=25').json()
try:
@@ -75,41 +77,36 @@ class Bot:
ts = lp.get('ts')
- except KeyboardInterrupt as e:
- raise e
+ except KeyboardInterrupt:
+ raise KeyboardInterrupt
- except Exception as e:
+ except Exception as i:
ts = lp.get('ts')
- log(f"Found exception: {e}", 1)
- traceback.print_exc()
+ logger.exception(i)
if __name__ == '__main__':
if not config.vk.token:
- log("Токен ВК не найден.\nВыход...", 1)
- input("\n\nНажмите Enter для продолжения..")
- sys.exit(1)
+ logger.error("Токен ВК не найден.")
+ enter_to_exit()
try:
bot = Bot()
- try:
- # Test RCON
- bot.rcon_cmd_handle("list", 0, 0, False, True)
- log("RCON работает.")
- except Exception as e:
- log("RCON не отвечает. Проверьте блок \"rcon\" с config.json", 1)
- raise e
+ # Test RCON
+ if rcon("list").startswith("Rcon error"):
+ logger.error("RCON не отвечает. Проверьте блок \"rcon\" в config.json")
+ enter_to_exit()
+ logger.info("RCON доступен.")
try:
# Test Minecraft Server
- log(f"Проверка сервера. Онлайн: {get_server_status().online}")
+ players = get_server_status().players
+ logger.info(f"Проверка сервера. Онлайн: {players.online}/{players.max}")
except Exception as e:
- log("Сервер не отвечает. Проверьте блок \"minecraft\" с config.json", 1)
- raise e
+ logger.exception(e)
+ logger.info("Сервер не отвечает. Проверьте блок \"minecraft\" в config.json")
+ enter_to_exit()
bot.listen()
except KeyboardInterrupt:
pass
except Exception as e:
- log(f"Exception: {e}", 1)
- traceback.print_exc()
- finally:
- log("Выход..")
- input("\n\nНажмите Enter для продолжения..")
+ logger.exception(e)
+ enter_to_exit()
diff --git a/src/modules/__init__.py b/src/modules/__init__.py
index 45eee58..dbcb69c 100644
--- a/src/modules/__init__.py
+++ b/src/modules/__init__.py
@@ -1,20 +1,19 @@
+import glob
import json
import os
import re
+import sys
import traceback
+import zipfile
from collections import namedtuple
from datetime import datetime
from pathlib import Path
+from loguru import logger
from mcrcon import MCRcon
from .perms import Permissions
-
-def log(text, lvl=0):
- print(f"[{datetime.now()}] [{['INFO ', 'ERROR'][lvl]}] {text}")
-
-
raw_config = """\
{
"vk": {
@@ -41,24 +40,51 @@ raw_help = """\
Бот сделан кожанным петухом - админом, все вопросы к нему, я не причём.
"""
+
+def zip_logs():
+ log_file = "./logs/latest.log"
+ log_dir = os.path.dirname(log_file) + "/"
+ if not os.path.exists(log_dir):
+ os.makedirs(log_dir)
+ if os.path.exists(log_file):
+ ftime = os.path.getmtime(log_file)
+ zip_path = log_dir + datetime.fromtimestamp(ftime).strftime('%Y-%m-%d') + "-%s.zip"
+ index = 1
+ while True:
+ if not os.path.exists(zip_path % index):
+ break
+ index += 1
+ with zipfile.ZipFile(zip_path % index, "w") as zipf:
+ logs_files = glob.glob(f"{log_dir}/*.log")
+ for file in logs_files:
+ if os.path.exists(file):
+ zipf.write(file, os.path.basename(file))
+ os.remove(file)
+ logger.remove(0)
+ logger.add(log_file)
+ logger.add(sys.stdout, format="{time:YYYY-MM-DD HH:mm:ss.SSS} | "
+ "{level: <8} | {message}")
+
+
+zip_logs()
if not os.path.exists("config.json"):
- log("Создание: config.json...")
+ logger.info("Создание: config.json...")
with open("config.json", "w") as f:
f.write(raw_config)
with open('config.json') as f:
config = json.load(f, object_hook=lambda x: namedtuple('X', x.keys())(*x.values()))
-log("Запуск..")
+logger.info("Запуск..")
if not os.path.exists(config.vk.help_file):
- log(f"Создание: {config.vk.help_file}...")
+ logger.info(f"Создание: {config.vk.help_file}...")
with open(config.vk.help_file, "w") as f:
f.write(raw_help)
if config.minecraft.java:
- from mcstatus import JavaServer as mcs
+ from mcstatus import JavaServer as MineServer
else:
- from mcstatus import BedrockServer as mcs
+ from mcstatus import BedrockServer as MineServer
host = config.rcon.host
port = config.rcon.port
@@ -71,15 +97,21 @@ def rcon(cmd):
text = mcr.command(cmd)
return re.sub(r'§.', '', text)
except Exception as e:
- log(f"[RCON] ERROR with command: {cmd}", 1)
- print(traceback.format_exc())
+ logger.error(f"[RCON] ERROR with command: {cmd}")
+ logger.exception(e)
return f"Rcon error: {e}"
def get_server_status():
- server = mcs.lookup(config.minecraft.host, config.minecraft.port)
+ server = MineServer.lookup(config.minecraft.host, config.minecraft.port)
return server.status()
Permissions.perm_file = Path(config.permissions_file)
perms = Permissions.load()
+
+
+def enter_to_exit():
+ logger.info("Выход..")
+ input("\nНажмите Enter для продолжения..")
+ sys.exit(1)
diff --git a/win/metadata.yml b/win/metadata.yml
index 87df74c..3eda1d2 100644
--- a/win/metadata.yml
+++ b/win/metadata.yml
@@ -1,6 +1,6 @@
# pip install pyinstaller-versionfile
# create-version-file metadata.yml --outfile version.txt
-Version: 1.2.3
+Version: 1.3.0
CompanyName: anidev
FileDescription: Бот для майнкрафта, использует RCON и VK API. Исходники можно найти по "SantaSpeen/Rcon-VK-Bot"
InternalName: VkBot-Rcon