Skip to content

Commit

Permalink
fix: misc updates to make the bot work with containers (#43)
Browse files Browse the repository at this point in the history
* fix: misc updates to make the bot work with containers

* chore: config is now a volume
  • Loading branch information
domenicoblanco authored Mar 3, 2024
1 parent 90c30e9 commit 0122a39
Show file tree
Hide file tree
Showing 8 changed files with 43 additions and 33 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -130,5 +130,5 @@ dmypy.json

# Custom
config/settings.yaml
src/healthcheck_user_client.session
healthcheck_user_client.session
.vscode
15 changes: 15 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
FROM python:3.10-slim
WORKDIR /healthcheckbot/

VOLUME config

RUN apt update
RUN apt install -y iputils-ping

COPY requirements.txt .
RUN pip3 install -r requirements.txt


COPY . .

ENTRYPOINT ["python3", "__init__.py"]
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ In order to setup this module, obtain an `api_id` and `api_hash` following the [
The last step is to add the bot(s) to check in the same settings file, completing the value for each key:
- Set `username`, the bot to be checked username without the prepending '@'
- Set `command`, the command that will be sent to your bot
- Set `expected_response`, the expected response from your bot. Any special character should be replaced with their equivalent character (a new line should be replaced with `\n`)
- Set `expected_response`, the expected response from your bot or a substring. Any special character should be replaced with their equivalent character (a new line should be replaced with `\n`)
Multiple bots could be added by added just by repeating the same structure of a sequence of objects in yaml.

### Example
Expand All @@ -30,9 +30,9 @@ chat_ids: ["10000000", "10000001", "10000002"] # Single ID or Multiple IDs
api_id: "123456"
api_hash: "123456:ABC-DEF1234ghIkl-zyx57W2v"
bots_to_check:
- username: "@WebpageBot"
- username: "WebpageBot"
command: "/start"
expected_response: "Hello, I'm the Webpage Bot!\nPlease send me up to 10 links and I will update previews for them."
expected_response: "Hello, I'm the Webpage Bot!"
```
### Run it every 5 minutes using crontab
Expand Down
4 changes: 4 additions & 0 deletions __init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
from src.main import main

if __name__ == '__main__':
main()
5 changes: 2 additions & 3 deletions src/main.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#!/usr/bin/python3

from httpx import AsyncClient, codes # Yes, we could use requests but httpx supports async tasks and HTTP/2!
from src.telegram_checker import bot_checker
from .telegram_checker import bot_checker
from asyncio import run
import platform # For getting the operating system name
import subprocess # For executing a shell command
Expand Down Expand Up @@ -94,8 +94,7 @@ def main() -> None:
for url in urls:
handle_urls(url, method)

bot_checker(config_map)

run(bot_checker(config_map))


def init() -> None:
Expand Down
20 changes: 11 additions & 9 deletions src/telegram_checker.py
Original file line number Diff line number Diff line change
@@ -1,26 +1,27 @@
from pyrogram import Client, filters
from pyrogram.handlers import MessageHandler
from pyrogram.errors import RPCError
from pyrogram.types import Message
from os.path import exists
from asyncio import sleep
from asyncio import sleep, run

config_map = None
app = Client('healthcheck_user_client')
received_answer = []

@app.on_message(filters.text & filters.bot)
async def check_welcome(client: Client, message: Message) -> None:
async def check_welcome(_: Client, message: Message) -> None:
global received_answer

for bots_to_check in config_map['bots_to_check']:
if message.from_user.username == bots_to_check['username']:
if message.text == bots_to_check['expected_response']:
if bots_to_check['expected_response'] in message.text:
received_answer.insert(0, message.from_user.username)
return


def bot_checker(config: dict) -> None:
async def bot_checker(config: dict) -> None:
global config_map
app = Client('healthcheck_user_client')
app.add_handler(MessageHandler(check_welcome), filters.text & filters.bot)
config_map = config

# No bots to check
Expand All @@ -40,10 +41,11 @@ def bot_checker(config: dict) -> None:

print('Starting login, after the client is connected you can exit with CTRL+C')

app.run(main())
async with app:
await main(app)


async def main() -> None:
async def main(app: Client) -> None:
for bot in config_map['bots_to_check']:
if not all(key in bot for key in ['username', 'command', 'expected_response']):
print(f'Skipping {bot["username"] if "id" in bot else "a bot without a specified username c:"}')
Expand All @@ -58,7 +60,7 @@ async def main() -> None:
# To prevent circular imports
# TODO: in a future refactor we could split the main code in another file only for webpages,
# would improve modularity and reuse of code with an helper file
from src.main import make_request_to_telegram
from .main import make_request_to_telegram
for bot in config_map['bots_to_check']:
if bot['username'] not in received_answer:
for user_to_notify in config_map['chat_ids']:
Expand Down
2 changes: 1 addition & 1 deletion tests/main_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@
'expected_res': None,
'arg': tuple(),
'mock_obj': [main, main],
'mock_func': ['handle_urls', 'bot_checker'],
'mock_func': ['handle_urls', 'run'],
'mock_ret': [None, None]
},
{
Expand Down
22 changes: 6 additions & 16 deletions tests/telegram_checker_test.py
Original file line number Diff line number Diff line change
@@ -1,37 +1,27 @@
import pytest
from pytest_mock import MockerFixture
from unittest.mock import AsyncMock
from unittest.mock import AsyncMock, patch
import src.telegram_checker as tg
import src.main as main
from pyrogram.client import Client
import asyncio

tests = [
{
'func': tg.bot_checker,
'expected_res': None,
'arg': ({'bots_to_check': [{'username':'WebpageBot', 'command':'/start', 'expected_response':'Hello, I\'m the Webpage Bot!\nPlease send me up to 10 links and I will update previews for them.'}]},),
'is_async': False
'arg': ({'bots_to_check': [{'username':'WebpageBot', 'command':'/start', 'expected_response':'Hello'}]},),
'is_async': True
},
{
'func': tg.bot_checker,
'expected_res': None,
'arg': ({},),
'is_async': False
},
{
'func': tg.bot_checker,
'expected_res': None,
'arg': ({'api_id':'12345', 'api_hash':'0123456789abcdef0123456789abcdef','bots_to_check': [{'username':'WebpageBot', 'command':'/start', 'expected_response':'Hello, I\'m the Webpage Bot!\nPlease send me up to 10 links and I will update previews for them.'}]},),
'mock_obj': [Client],
'mock_func': ['run'],
'mock_ret': [None],
'is_async': False
'is_async': True
},
{
'func': tg.main,
'expected_res': None,
'arg': tuple(),
'arg': (Client('healthcheck_user_client'),),
'mock_obj': [main, Client],
'mock_func': ['make_request_to_telegram', 'send_message'],
'mock_ret': [None, None],
Expand All @@ -41,7 +31,7 @@
{
'func': tg.main,
'expected_res': None,
'arg': tuple(),
'arg': (Client('healthcheck_user_client'),),
'mock_obj': [main, Client],
'mock_func': ['make_request_to_telegram', 'send_message'],
'mock_ret': [None, None],
Expand Down

0 comments on commit 0122a39

Please sign in to comment.