diff --git a/apps/api/api/app.py b/apps/api/api/app.py index 65aa1cf..bca4a16 100644 --- a/apps/api/api/app.py +++ b/apps/api/api/app.py @@ -3,7 +3,7 @@ from gevent.pywsgi import WSGIServer from helpers import access_token_required import config -from checkers import HttpChecker, ICMPChecker, TCPPortChecker +from checkers import HttpChecker, ICMPChecker, TCPPortChecker, MinecraftChecker app = Flask(__name__) @@ -13,12 +13,9 @@ app = Flask(__name__) def http_check(): target = request.args.get("target", None) port = int(request.args.get("port", 80)) - if not target: abort(400) - checker = HttpChecker(target, port) - return jsonify(checker.check()) @@ -27,12 +24,20 @@ def http_check(): def tcp_port_check(): target = request.args.get("target", None) port = int(request.args.get("port", None)) - if not target or not port: abort(400) - checker = TCPPortChecker(target, port) + return jsonify(checker.check()) + +@app.route('/minecraft') +@access_token_required +def minecraft_check(): + target = request.args.get("target", None) + port = int(request.args.get("port", 25565)) + if not target: + abort(400) + checker = MinecraftChecker(target, port) return jsonify(checker.check()) @@ -40,12 +45,9 @@ def tcp_port_check(): @access_token_required def icmp_check(): target = request.args.get("target", None) - if not target: abort(400) - checker = ICMPChecker(target) - return jsonify(checker.check()) diff --git a/apps/api/api/checkers/__init__.py b/apps/api/api/checkers/__init__.py index bf6f8b1..8023227 100644 --- a/apps/api/api/checkers/__init__.py +++ b/apps/api/api/checkers/__init__.py @@ -1,3 +1,4 @@ from .http import HttpChecker from .icmp import ICMPChecker from .tcp_port import TCPPortChecker +from .minecraft import MinecraftChecker diff --git a/apps/api/pyproject.toml b/apps/api/pyproject.toml index 7781a92..d336cfd 100644 --- a/apps/api/pyproject.toml +++ b/apps/api/pyproject.toml @@ -10,6 +10,7 @@ Flask = "^1.1.2" gevent = "^20.12.1" requests = "^2.25.1" icmplib = "^2.0.1" +mcstatus = "^4.1.0" core = {path = "../core"} [tool.poetry.dev-dependencies] diff --git a/apps/core/core/coretypes.py b/apps/core/core/coretypes.py index 9aabf66..1d896d9 100644 --- a/apps/core/core/coretypes.py +++ b/apps/core/core/coretypes.py @@ -45,6 +45,12 @@ class APINodeInfo: location: str +@dataclass +class MinecraftResponse(Payload): + latency: float + max_players: int + online: int + @dataclass class PortResponse(Payload): open: bool diff --git a/apps/core/pyproject.toml b/apps/core/pyproject.toml index 4d44170..741b6ce 100644 --- a/apps/core/pyproject.toml +++ b/apps/core/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "core" -version = "0.7.0" +version = "0.10.0" description = "Types and other core functionality" authors = ["kiriharu "] diff --git a/apps/tgbot/pyproject.toml b/apps/tgbot/pyproject.toml index dcd8538..d090d43 100644 --- a/apps/tgbot/pyproject.toml +++ b/apps/tgbot/pyproject.toml @@ -7,9 +7,9 @@ authors = ["kiriharu "] [tool.poetry.dependencies] python = "^3.8" aiogram = "^2.11.2" -core = {path = "../core"} httpx = "^0.16.1" python-whois = "^0.7.3" +core = {path = "../core"} [tool.poetry.dev-dependencies] diff --git a/apps/tgbot/tgbot/handlers/base.py b/apps/tgbot/tgbot/handlers/base.py index 193ebfd..99b68f8 100644 --- a/apps/tgbot/tgbot/handlers/base.py +++ b/apps/tgbot/tgbot/handlers/base.py @@ -6,7 +6,7 @@ from httpx import Response from aiogram.bot import Bot from datetime import datetime from core.coretypes import APINodeInfo -from .helpers import send_api_requests +from .helpers import send_api_requests, check_int header = "Отчет о проверке хоста:" \ "\n\n— Хост: {target_fq}"\ @@ -58,3 +58,18 @@ class CheckerBaseHandler: async def prepare_message(self, res: Response) -> str: raise NotImplemented + + +def process_args_for_host_port(text: str, default_port: int) -> list: + port = None + args = text.split(" ") + if len(args) < 2: + raise NotEnoughArgs() + if len(args) == 2: + port = default_port + if len(args) == 3: + port = args[2] + if not check_int(port): + raise InvalidPort() + host = args[1] + return [host, port] diff --git a/apps/tgbot/tgbot/handlers/default/__init__.py b/apps/tgbot/tgbot/handlers/default/__init__.py index 0d3746d..19403ae 100644 --- a/apps/tgbot/tgbot/handlers/default/__init__.py +++ b/apps/tgbot/tgbot/handlers/default/__init__.py @@ -5,6 +5,7 @@ from .web import WebCheckerHandler from .whois import whois_cmd from .icmp import ICMPCheckerHandler from .tcp import TCPCheckerHandler +from .minecraft import MinecraftCheckerHandler def setup(dp: Dispatcher): @@ -13,3 +14,4 @@ def setup(dp: Dispatcher): dp.register_message_handler(whois_cmd, is_forwarded=False, commands=['whois']) dp.register_message_handler(ICMPCheckerHandler().handler, is_forwarded=False, commands=['icmp', 'ping']) dp.register_message_handler(TCPCheckerHandler().handler, is_forwarded=False, commands=['tcp']) + dp.register_message_handler(MinecraftCheckerHandler().handler, is_forwarded=False, commands=['minecraft']) \ No newline at end of file diff --git a/apps/tgbot/tgbot/handlers/default/minecraft.py b/apps/tgbot/tgbot/handlers/default/minecraft.py new file mode 100644 index 0000000..78794f9 --- /dev/null +++ b/apps/tgbot/tgbot/handlers/default/minecraft.py @@ -0,0 +1,50 @@ +from aiogram.types import Message +from core.coretypes import ResponseStatus, ErrorPayload, MinecraftResponse +from httpx import Response + +from tgbot.handlers.base import CheckerBaseHandler, NotEnoughArgs, InvalidPort, process_args_for_host_port + +minecraft_help_message = """ +❓ Получает статистику о Minecraft сервере + +Использование: + `/minecraft ` + `/minecraft ` - автоматически выставит порт 25565 +""" + + +invalid_port = """❗Неправильный порт. Напишите /minecraft чтобы увидеть справку к данному способу проверки.""" + + +class MinecraftCheckerHandler(CheckerBaseHandler): + help_message = minecraft_help_message + api_endpoint = "minecraft" + + def __init__(self): + super().__init__() + + async def handler(self, message: Message): + try: + args = await self.process_args(message.text) + except NotEnoughArgs: + return await message.answer(self.help_message, parse_mode="Markdown") + except InvalidPort: + return await message.answer(invalid_port, parse_mode="Markdown") + await self.check( + message.chat.id, + message.bot, + dict(target=args[0], port=args[1], target_fq=f"{args[0]}:{args[1]}") + ) + + async def process_args(self, text: str) -> list: + return process_args_for_host_port(text, 25565) + + async def prepare_message(self, res: Response): + message, status = await self.message_std_vals(res) + if status == ResponseStatus.OK: + payload = MinecraftResponse(**res.json().get("payload")) + message += f"✅ 👤{payload.online}/{payload.max_players} 📶{payload.latency}ms" + if status == ResponseStatus.ERROR: + payload = ErrorPayload(**res.json().get("payload")) + message += f"❌️ {payload.message}" + return message diff --git a/apps/tgbot/tgbot/handlers/default/web.py b/apps/tgbot/tgbot/handlers/default/web.py index ec5847f..b5fbf8a 100644 --- a/apps/tgbot/tgbot/handlers/default/web.py +++ b/apps/tgbot/tgbot/handlers/default/web.py @@ -1,8 +1,7 @@ from aiogram.types import Message -from tgbot.handlers.helpers import check_int from httpx import Response from core.coretypes import ResponseStatus, HTTP_EMOJI, HttpCheckerResponse, ErrorPayload -from ..base import CheckerBaseHandler, NotEnoughArgs, InvalidPort +from ..base import CheckerBaseHandler, NotEnoughArgs, InvalidPort, process_args_for_host_port web_help_message = """ ❓ Производит проверку хоста по протоколу HTTP. @@ -36,18 +35,7 @@ class WebCheckerHandler(CheckerBaseHandler): ) async def process_args(self, text: str) -> list: - port = None - args = text.split(" ") - if len(args) < 2: - raise NotEnoughArgs() - if len(args) == 3: - port = args[2] - if not check_int(port): - raise InvalidPort() - if len(args) == 2: - port = 80 - host = args[1] - return [host, port] + return process_args_for_host_port(text, 80) async def prepare_message(self, res: Response): message, status = await self.message_std_vals(res)