158 lines
4.7 KiB
Python
158 lines
4.7 KiB
Python
"""
|
||
Telegram-бот для отображения состояния системы.
|
||
|
||
Функциональность:
|
||
- команда /start отправляет информацию о сервере
|
||
- отображаются CPU, RAM, диск, uptime и load average
|
||
- токен загружается из переменной окружения BOT_TOKEN или .env
|
||
|
||
Зависимости:
|
||
pip install aiogram psutil python-dotenv
|
||
"""
|
||
|
||
from __future__ import annotations
|
||
|
||
import asyncio
|
||
import os
|
||
from datetime import datetime
|
||
from platform import uname, system
|
||
from typing import Final
|
||
|
||
import psutil
|
||
from aiogram import Bot, Dispatcher
|
||
from aiogram.client.default import DefaultBotProperties
|
||
from aiogram.filters import CommandStart
|
||
from aiogram.types import Message
|
||
from dotenv import load_dotenv
|
||
|
||
|
||
# ---------------------------------------------------------------------
|
||
# Загрузка переменных окружения
|
||
# ---------------------------------------------------------------------
|
||
|
||
load_dotenv()
|
||
|
||
BOT_TOKEN: Final[str | None] = os.getenv("BOT_TOKEN")
|
||
|
||
if BOT_TOKEN is None:
|
||
raise RuntimeError(
|
||
"Переменная окружения BOT_TOKEN не найдена.\n"
|
||
"Создайте файл .env и добавьте:\n"
|
||
"BOT_TOKEN=your_telegram_token"
|
||
)
|
||
|
||
|
||
# ---------------------------------------------------------------------
|
||
# Инициализация Telegram-бота
|
||
# ---------------------------------------------------------------------
|
||
|
||
bot: Bot = Bot(
|
||
token=BOT_TOKEN,
|
||
default=DefaultBotProperties(parse_mode="HTML"),
|
||
)
|
||
|
||
dp: Dispatcher = Dispatcher()
|
||
|
||
|
||
# ---------------------------------------------------------------------
|
||
# Системная информация
|
||
# ---------------------------------------------------------------------
|
||
|
||
def get_system_info() -> str:
|
||
"""
|
||
Собирает информацию о состоянии системы.
|
||
|
||
Возвращает:
|
||
str: форматированная строка с информацией о системе
|
||
"""
|
||
|
||
# Информация о системе
|
||
system_info = uname()
|
||
|
||
# Время загрузки системы
|
||
boot_time_timestamp: float = psutil.boot_time()
|
||
boot_time: str = datetime.fromtimestamp(
|
||
boot_time_timestamp
|
||
).strftime("%Y-%m-%d %H:%M:%S")
|
||
|
||
# Память
|
||
memory = psutil.virtual_memory()
|
||
|
||
# CPU
|
||
cpu_percent: float = psutil.cpu_percent(interval=1)
|
||
physical_cores: int | None = psutil.cpu_count(logical=False)
|
||
logical_cores: int | None = psutil.cpu_count(logical=True)
|
||
|
||
# Определяем корневой диск
|
||
root_path: str = "C:\\" if system() == "Windows" else "/"
|
||
disk = psutil.disk_usage(root_path)
|
||
|
||
# Load average (только UNIX)
|
||
load_str: str = ""
|
||
if hasattr(os, "getloadavg"):
|
||
load_avg = os.getloadavg()
|
||
load_str = (
|
||
f"└ Load average: "
|
||
f"{load_avg[0]:.2f}, {load_avg[1]:.2f}, {load_avg[2]:.2f}\n"
|
||
)
|
||
|
||
# Формирование сообщения
|
||
info: str = f"""
|
||
<b>🖥️ Состояние сервера</b>
|
||
|
||
<b>OS:</b> {system_info.system} {system_info.release}
|
||
<b>Uptime:</b> {boot_time}
|
||
|
||
<b>CPU:</b>
|
||
├ Ядер: {physical_cores} (логических: {logical_cores})
|
||
├ Загрузка: {cpu_percent}%
|
||
{load_str}<b>RAM:</b>
|
||
├ Всего: {memory.total / 1024 ** 3:.2f} GB
|
||
├ Используется: {memory.used / 1024 ** 3:.2f} GB
|
||
└ Свободно: {memory.available / 1024 ** 3:.2f} GB
|
||
|
||
<b>Диск ({root_path}):</b>
|
||
├ Всего: {disk.total / 1024 ** 3:.2f} GB
|
||
├ Используется: {disk.used / 1024 ** 3:.2f} GB
|
||
└ Свободно: {disk.free / 1024 ** 3:.2f} GB
|
||
""".strip()
|
||
|
||
return info
|
||
|
||
|
||
# ---------------------------------------------------------------------
|
||
# Обработчики
|
||
# ---------------------------------------------------------------------
|
||
|
||
@dp.message(CommandStart())
|
||
async def start_handler(message: Message) -> None:
|
||
"""
|
||
Обработчик команды /start.
|
||
|
||
Отправляет пользователю текущее состояние системы.
|
||
"""
|
||
|
||
system_info: str = get_system_info()
|
||
await message.answer(system_info)
|
||
|
||
|
||
# ---------------------------------------------------------------------
|
||
# Основной запуск
|
||
# ---------------------------------------------------------------------
|
||
|
||
async def main() -> None:
|
||
"""
|
||
Основная функция запуска бота.
|
||
|
||
Запускает polling и корректно завершает соединение.
|
||
"""
|
||
|
||
try:
|
||
await dp.start_polling(bot)
|
||
finally:
|
||
await bot.session.close()
|
||
|
||
|
||
if __name__ == "__main__":
|
||
asyncio.run(main())
|