├── .gitignore ├── README.md ├── TellarBot ├── __init__.py ├── __main__.py ├── plugins │ ├── __init__.py │ ├── checker.py │ └── classes.py └── sample_config.py └── requirements.txt /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | pip-wheel-metadata/ 24 | share/python-wheels/ 25 | *.egg-info/ 26 | .installed.cfg 27 | *.egg 28 | MANIFEST 29 | 30 | # PyInstaller 31 | # Usually these files are written by a python script from a template 32 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 33 | *.manifest 34 | *.spec 35 | 36 | # Installer logs 37 | pip-log.txt 38 | pip-delete-this-directory.txt 39 | 40 | # Unit test / coverage reports 41 | htmlcov/ 42 | .tox/ 43 | .nox/ 44 | .coverage 45 | .coverage.* 46 | .cache 47 | nosetests.xml 48 | coverage.xml 49 | *.cover 50 | *.py,cover 51 | .hypothesis/ 52 | .pytest_cache/ 53 | 54 | # Translations 55 | *.mo 56 | *.pot 57 | 58 | # Django stuff: 59 | *.log 60 | local_settings.py 61 | db.sqlite3 62 | db.sqlite3-journal 63 | 64 | # Flask stuff: 65 | instance/ 66 | .webassets-cache 67 | 68 | # Scrapy stuff: 69 | .scrapy 70 | 71 | # Sphinx documentation 72 | docs/_build/ 73 | 74 | # PyBuilder 75 | target/ 76 | 77 | # Jupyter Notebook 78 | .ipynb_checkpoints 79 | 80 | # IPython 81 | profile_default/ 82 | ipython_config.py 83 | 84 | # pyenv 85 | .python-version 86 | 87 | # pipenv 88 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 89 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 90 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 91 | # install all needed dependencies. 92 | #Pipfile.lock 93 | 94 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 95 | __pypackages__/ 96 | 97 | # Celery stuff 98 | celerybeat-schedule 99 | celerybeat.pid 100 | 101 | # SageMath parsed files 102 | *.sage.py 103 | 104 | # Environments 105 | .env 106 | .venv 107 | env/ 108 | venv/ 109 | ENV/ 110 | env.bak/ 111 | venv.bak/ 112 | 113 | # Spyder project settings 114 | .spyderproject 115 | .spyproject 116 | 117 | # Rope project settings 118 | .ropeproject 119 | 120 | # mkdocs documentation 121 | /site 122 | 123 | # mypy 124 | .mypy_cache/ 125 | .dmypy.json 126 | dmypy.json 127 | 128 | # Pyre type checker 129 | .pyre/ 130 | 131 | # config file 132 | config.py 133 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # TellarRobot 2 | Check if bot(s) are down and send message in log channel 3 | 4 | 5 | > Was made in less than a day so don't expect stuff, Will improve stuff later 6 | -------------------------------------------------------------------------------- /TellarBot/__init__.py: -------------------------------------------------------------------------------- 1 | from telethon.sessions import StringSession 2 | from telethon.sync import TelegramClient 3 | from .config import API_ID, API_HASH, STRING_SESSION, BOTS_CONFIG, BOTS_LIST, LOG_CHANNEL 4 | 5 | LOG_CHANNEL = LOG_CHANNEL 6 | BOTS_LIST = BOTS_LIST 7 | BOTS_CONFIG = BOTS_CONFIG 8 | 9 | import logging 10 | logging.basicConfig(format='[%(levelname) 5s/%(asctime)s] %(name)s: %(message)s', 11 | level=logging.WARNING) 12 | 13 | client = TelegramClient(StringSession(STRING_SESSION), API_ID, API_HASH) 14 | -------------------------------------------------------------------------------- /TellarBot/__main__.py: -------------------------------------------------------------------------------- 1 | from TellarBot import client 2 | from TellarBot.plugins import TO_LOAD 3 | 4 | import importlib 5 | 6 | for LOAD in TO_LOAD: 7 | importlib.import_module("TellarBot.plugins." + LOAD) 8 | 9 | if __name__ == '__main__': 10 | client.start() 11 | client.run_until_disconnected() 12 | -------------------------------------------------------------------------------- /TellarBot/plugins/__init__.py: -------------------------------------------------------------------------------- 1 | TO_LOAD = ['checker', 'classes'] 2 | -------------------------------------------------------------------------------- /TellarBot/plugins/checker.py: -------------------------------------------------------------------------------- 1 | import time 2 | import logging 3 | from TellarBot import client 4 | from telethon.sync import events 5 | 6 | async def handler(client, bot, key_name, command): 7 | async with client.conversation(bot) as conv: 8 | from TellarBot.plugins.classes import Manager 9 | await conv.send_message(command) 10 | s_time = time.time() 11 | try: 12 | await conv.get_response() 13 | except: 14 | await Manager.set_status(key_name, bot, 'DOWN') 15 | logging.critical(f'{bot} is down!') 16 | return 17 | response_time = time.time() - s_time 18 | await Manager.set_status(key_name, bot,"UP", response_time) 19 | 20 | @client.on(events.NewMessage(pattern='.status ', outgoing = True)) 21 | async def status(event): 22 | from TellarBot.plugins.classes import Manager 23 | bot = await Manager.get_status(event.text.split(' ', 1)[1]) 24 | logging.critical(f"{bot}, {event.text.split(' ', 1)[1]}") 25 | if not bot: 26 | return 27 | msg = f"Status: **{bot['status']}**\n" 28 | msg += f"Is Slow: **{bot['slow']}**\n" 29 | msg += f"Response Time: `{bot['response_time']}`" 30 | await event.reply(msg) 31 | 32 | @client.on(events.NewMessage(pattern='.runtime', outgoing = True)) 33 | async def u(event): 34 | await event.reply('Uptime checker robot is running !') 35 | -------------------------------------------------------------------------------- /TellarBot/plugins/classes.py: -------------------------------------------------------------------------------- 1 | from apscheduler.schedulers.asyncio import AsyncIOScheduler 2 | from TellarBot import client 3 | from TellarBot.plugins.checker import handler 4 | from TellarBot import BOTS_LIST, BOTS_CONFIG, LOG_CHANNEL 5 | 6 | import asyncio 7 | import logging 8 | 9 | log_string = """ 10 | Username: @{username} 11 | Status: {status} 12 | Response Time: `{time}s` 13 | Speed: **{speed}** 14 | """ 15 | 16 | class Manager: 17 | 18 | def __init__(self): 19 | 20 | self.config = BOTS_CONFIG 21 | self.bot_details = {} 22 | self.scheduler = scheduler = AsyncIOScheduler() 23 | self.jobs = {} 24 | for bot in BOTS_LIST: 25 | config = self.config[bot] 26 | username = config['username'] 27 | self.bot_details[username] = {'username': username, 'status': 'UP', 'response_time': 0, 'slow': False, 'status_message': ''} 28 | self.jobs[bot] = self.scheduler.add_job( 29 | handler, 30 | 'interval', 31 | seconds = 60, 32 | name = username, 33 | kwargs = { 34 | 'client': client, 35 | 'bot': config['username'], 36 | 'key_name': bot, 37 | 'command': config.get('command', '/start') 38 | } 39 | ) 40 | self.scheduler.start() 41 | 42 | async def get_status(self, bot): 43 | config = self.bot_details.get(bot, None) 44 | if not config: 45 | return False 46 | return config 47 | 48 | async def set_status(self, key_name, username, status, response_time = False): 49 | config = self.config[key_name] 50 | if status == "DOWN": 51 | self.bot_details[username]['status'], status = "DOWN", "DOWN" 52 | self.bot_details[username]['response_time'], response_time = 0, 0 53 | self.bot_details[username]['slow'], slow = False, False 54 | else: 55 | if response_time > config['avg_response_time']: 56 | logging.warning(f'{username} is slow, Time taken to respond: {response_time}') 57 | self.bot_details[username]['status'], status = "UP", "UP" 58 | self.bot_details[username]['response_time'], response_time = response_time, response_time 59 | self.bot_details[username]['slow'], slow = True, True 60 | else: 61 | logging.info(f"{username} is performing normally.") 62 | self.bot_details[username]['status'], status = "UP", "UP" 63 | self.bot_details[username]['response_time'], response_time = response_time, response_time 64 | self.bot_details[username]['slow'], slow = True, True 65 | if not self.bot_details[username]['status_message']: 66 | self.bot_details[username]['status_message'] = await client.send_message(LOG_CHANNEL, log_string.format(username = username, status = '❌' if status == "DOWN" else '✅', time = round(response_time, 2), speed = "Normal" if not slow else "Slow")) 67 | else: 68 | text = log_string.format(username = username, status = '❌' if status == "DOWN" else '✅', time = round(response_time, 2), speed = "Normal" if not slow else "Slow") 69 | message = self.bot_details[username]['status_message'] 70 | if message.text == text: 71 | return 72 | await message.edit(text) 73 | Manager = Manager() 74 | -------------------------------------------------------------------------------- /TellarBot/sample_config.py: -------------------------------------------------------------------------------- 1 | LOG_CHANNEL = "Username" # Self explantory 2 | BOTS_LIST = ["MYAMAZINGBOT1", "MYNOTSOAMAZINGBOT1"] # List of bots to check 3 | BOTS_CONFIG = { 4 | "MYAMAZINGBOT1": { 5 | "username": "bot", # Username of bot 6 | "avg_response_time": 5 # How much time can bot take to respond 7 | }, 8 | "MYNOTSOAMAZINGBOT1": { 9 | "username": "bot", 10 | "avg_response_time": 5, 11 | "command": "/hello" # Command to test, Defaults to /start 12 | } 13 | } 14 | 15 | API_ID = 12345 # Self explantory 16 | API_HASH = "1234abcd" # Self explantory 17 | STRING_SESSIONS = "SUPER-LONG-STRING" 18 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | telethon 2 | apscheduler 3 | --------------------------------------------------------------------------------