2023-04-27 08:46:42 +00:00
import asyncio
import logging
2023-05-01 16:26:45 +00:00
from datetime import date , datetime
2023-04-27 08:53:08 +00:00
2023-04-27 08:46:42 +00:00
from telegram import Update
from telegram . ext import ApplicationBuilder , ContextTypes , CommandHandler , MessageHandler , filters
import os
import json
2023-04-28 14:55:31 +00:00
from cowmesh_pi_speedtest import CowmeshPiSpeedtestTester
2023-04-28 12:04:41 +00:00
from cowmesh_router_iperf_test import CowmeshRouterIperfTester
from cowmesh_pi_iperf_test import CowmeshPiIperfTester
2023-04-27 08:46:42 +00:00
PROJECT_PATH = os . path . abspath ( os . path . dirname ( __file__ ) )
SECRETS_PATH = os . path . join ( PROJECT_PATH , " secrets.json " )
2023-05-01 16:26:45 +00:00
LOG_DIR_PATH = " /datadrive/apps/moonlight_analytics/results "
2023-04-27 08:46:42 +00:00
with open ( SECRETS_PATH , ' r ' ) as f :
SECRETS = json . loads ( f . read ( ) )
logging . basicConfig (
format = ' %(asctime)s - %(name)s - %(levelname)s - %(message)s ' ,
level = logging . INFO
)
2023-05-01 16:26:45 +00:00
class MoonlightTester :
2023-04-27 08:46:42 +00:00
2023-05-01 16:26:45 +00:00
async def start ( self , update : Update , context : ContextTypes . DEFAULT_TYPE ) :
await context . bot . send_message ( chat_id = update . effective_chat . id , text = " This is the moonlight analytics bot for mesh network diagnostics. \n \n Type /help to see available commands. " , message_thread_id = update . message . message_thread_id )
2023-04-27 08:46:42 +00:00
2023-05-01 16:26:45 +00:00
async def caps ( self , update : Update , context : ContextTypes . DEFAULT_TYPE ) :
"""
this is just a function to test that the bot is working as expected
"""
text_caps = ' ' . join ( context . args ) . upper ( )
print ( " chat_id: {} " . format ( update . effective_chat . id ) )
print ( " message_thread_id: {} " . format ( update . message . message_thread_id ) )
await context . bot . send_message ( chat_id = update . effective_chat . id , text = text_caps , message_thread_id = update . message . message_thread_id )
2023-04-27 08:46:42 +00:00
2023-05-01 16:26:45 +00:00
async def router_iperf ( self , update : Update , context : ContextTypes . DEFAULT_TYPE ) :
2023-04-28 12:04:41 +00:00
2023-05-01 16:26:45 +00:00
time = context . args [ 0 ] if context . args else None
if not time :
time = 10
2023-04-28 12:04:41 +00:00
2023-05-01 16:26:45 +00:00
log_name = " moonlight- { : % m- %d - % Y}- { : % H- % M}-router-iperf.txt " . format ( date . today ( ) , datetime . now ( ) )
log_location = os . path . join ( LOG_DIR_PATH , log_name )
2023-04-28 12:04:41 +00:00
2023-05-01 16:26:45 +00:00
async def offline_log ( msg ) :
with open ( log_location , ' a ' ) as log_file :
log_file . write ( msg + " \n " )
2023-04-28 12:04:41 +00:00
2023-05-01 16:26:45 +00:00
async def log ( msg ) :
await offline_log ( msg )
await context . bot . send_message ( chat_id = update . effective_chat . id , text = msg ,
message_thread_id = update . message . message_thread_id )
2023-04-28 12:04:41 +00:00
2023-05-01 16:26:45 +00:00
if update . effective_chat . id != int ( SECRETS [ " TELEGRAM_LOG_CHAT_ID " ] ) :
await log ( " ++ can only start iperf test from Moonlight Bot group " )
return
2023-04-28 12:04:41 +00:00
2023-05-01 16:26:45 +00:00
await log ( " ++ starting router iperf test with {} seconds per test " . format ( time ) )
tester = CowmeshRouterIperfTester ( log = log , time = time )
await tester . run_test ( )
await tester . output_results ( )
2023-04-28 12:04:41 +00:00
2023-05-01 16:26:45 +00:00
# send log file
document = open ( log_location , ' rb ' )
await context . bot . send_document ( update . effective_chat . id , document ,
message_thread_id = update . message . message_thread_id )
2023-04-28 12:04:41 +00:00
2023-05-01 16:26:45 +00:00
async def pi_iperf ( self , update : Update , context : ContextTypes . DEFAULT_TYPE ) :
2023-04-27 08:46:42 +00:00
2023-05-01 16:26:45 +00:00
time = context . args [ 0 ] if context . args else None
if not time :
time = 10
2023-04-27 08:46:42 +00:00
2023-05-01 16:26:45 +00:00
log_name = " moonlight- { : % m- %d - % Y}- { : % H- % M}-pi-iperf.txt " . format ( date . today ( ) , datetime . now ( ) )
log_location = os . path . join ( LOG_DIR_PATH , log_name )
2023-04-28 14:55:31 +00:00
2023-05-01 16:26:45 +00:00
async def offline_log ( msg ) :
with open ( log_location , ' a ' ) as log_file :
log_file . write ( msg + " \n " )
async def log ( msg ) :
await offline_log ( msg )
await context . bot . send_message ( chat_id = update . effective_chat . id , text = msg , message_thread_id = update . message . message_thread_id )
2023-04-28 14:55:31 +00:00
2023-05-01 16:26:45 +00:00
if update . effective_chat . id != int ( SECRETS [ " TELEGRAM_LOG_CHAT_ID " ] ) :
await log ( " ++ can only start iperf test from Moonlight Bot group " )
return
2023-04-28 14:55:31 +00:00
2023-05-01 16:26:45 +00:00
await log ( " ++ starting pi iperf test with {} seconds per test " . format ( time ) )
tester = CowmeshPiIperfTester ( log = log , time = time )
await tester . run_test ( )
await tester . output_results ( )
2023-04-28 14:55:31 +00:00
2023-05-01 16:26:45 +00:00
# send log file
document = open ( log_location , ' rb ' )
await context . bot . send_document ( update . effective_chat . id , document , message_thread_id = update . message . message_thread_id )
2023-04-28 14:55:31 +00:00
2023-04-27 08:46:42 +00:00
2023-05-01 16:26:45 +00:00
async def speedtest ( self , update : Update , context : ContextTypes . DEFAULT_TYPE ) :
2023-04-27 08:46:42 +00:00
2023-05-01 16:26:45 +00:00
log_name = " moonlight- { : % m- %d - % Y}- { : % H- % M}-pi-speedtest.txt " . format ( date . today ( ) , datetime . now ( ) )
log_location = os . path . join ( LOG_DIR_PATH , log_name )
2023-04-27 08:46:42 +00:00
2023-05-01 16:26:45 +00:00
async def offline_log ( msg ) :
with open ( log_location , ' a ' ) as log_file :
log_file . write ( msg + " \n " )
2023-04-27 08:46:42 +00:00
2023-05-01 16:26:45 +00:00
async def log ( msg ) :
await offline_log ( msg )
await context . bot . send_message ( chat_id = update . effective_chat . id , text = msg ,
message_thread_id = update . message . message_thread_id )
2023-04-27 08:46:42 +00:00
2023-05-01 16:26:45 +00:00
if update . effective_chat . id != int ( SECRETS [ " TELEGRAM_LOG_CHAT_ID " ] ) :
await log ( " ++ can only start test from Moonlight Bot group " )
return
2023-04-27 08:46:42 +00:00
2023-05-01 16:26:45 +00:00
await log ( " ++ starting pi speedtest-cli speedtest " )
tester = CowmeshPiSpeedtestTester ( log = log )
await tester . run_test ( )
await tester . output_results ( )
2023-04-27 08:46:42 +00:00
2023-05-01 16:26:45 +00:00
# send log file
document = open ( log_location , ' rb ' )
await context . bot . send_document ( update . effective_chat . id , document ,
message_thread_id = update . message . message_thread_id )
2023-04-27 08:46:42 +00:00
2023-05-01 16:26:45 +00:00
async def unknown ( self , update : Update , context : ContextTypes . DEFAULT_TYPE ) :
await context . bot . send_message ( chat_id = update . effective_chat . id , text = " Sorry, I didn ' t understand that, please run /help for a list of available commands. " , message_thread_id = update . message . message_thread_id )
2023-04-27 08:46:42 +00:00
2023-05-01 16:26:45 +00:00
def about_message ( self ) :
msg = " This is a bot designed to help measure the performance of a mesh network through active testing. " \
" Every night the bot runs a network test using iperf to measure the connectivity between all the nodes in the mesh, " \
" and logs the result to this channel. " \
" Members of this channel can also initiate a new network iperf test at any time by sending a message to this channel, " \
" with the command /iperf . " \
" Telegram users outside of this channel cannot initiate a test, to help keep the network secure from being " \
" overrun by malicious users. " \
" The network test runs at night because that is when the fewest people are using the network, and so is more likely to " \
" give consistent results with less random variability. " \
" Please be mindful of initiating too many iperf tests during the day, as it uses a lot of network resources " \
" to run the test and could interfere with the internet connections of people using the network. "
return msg
2023-04-28 12:04:41 +00:00
2023-05-01 16:26:45 +00:00
def help_message ( self ) :
msg = " This bot runs an iperf test every night and logs the results here. You can also initiate a new test using the command /iperf " \
" or read a longer message explaining how this bot works by typing the command /readme. "
return msg
async def about ( self , update : Update , context : ContextTypes . DEFAULT_TYPE ) :
text = self . about_message ( )
await context . bot . send_message ( chat_id = update . effective_chat . id , text = text , message_thread_id = update . message . message_thread_id )
2023-04-28 12:04:41 +00:00
2023-05-01 16:26:45 +00:00
async def help_fun ( self , update : Update , context : ContextTypes . DEFAULT_TYPE ) :
text = self . help_message ( )
await context . bot . send_message ( chat_id = update . effective_chat . id , text = text , message_thread_id = update . message . message_thread_id )
2023-04-28 12:04:41 +00:00
2023-05-01 16:26:45 +00:00
async def send_log ( self , bot , chat_id , message_thread_id , log_location ) :
# send log file
document = open ( log_location , ' rb ' )
2023-05-01 16:38:22 +00:00
await bot . send_document ( chat_id , document , message_thread_id = message_thread_id )
2023-04-27 08:46:42 +00:00
2023-05-01 16:26:45 +00:00
async def nightly_router_iperf ( self , time = 10 ) :
token = SECRETS [ " TELEGRAM_TOKEN " ]
application = ApplicationBuilder ( ) . token ( token ) . build ( )
chat_id = SECRETS [ " TELEGRAM_LOG_CHAT_ID " ]
message_thread_id = SECRETS . get ( " TELEGRAM_LOG_MESSAGE_THREAD_ID " )
bot = application . bot
2023-04-27 08:46:42 +00:00
2023-05-01 16:38:22 +00:00
log_name = " moonlight- { : % m- %d - % Y}- { : % H: % m}-router-iperf.txt " . format ( datetime . today ( ) , datetime . now ( ) )
2023-05-01 16:26:45 +00:00
log_location = os . path . join ( LOG_DIR_PATH , log_name )
2023-04-27 08:46:42 +00:00
2023-05-01 16:26:45 +00:00
async def offline_log ( msg ) :
with open ( log_location , ' a ' ) as log_file :
log_file . write ( msg )
2023-04-27 08:46:42 +00:00
2023-05-01 16:26:45 +00:00
async def log ( msg ) :
await offline_log ( msg )
try :
await bot . send_message ( chat_id = chat_id , text = msg , message_thread_id = message_thread_id )
except :
pass
2023-04-28 14:55:31 +00:00
2023-05-01 16:26:45 +00:00
await log ( " ☾☾ starting nightly router-to-router iperf test with {time} seconds per test " . format ( time = time ) )
tester = CowmeshRouterIperfTester ( log = log , time = time )
await tester . run_test ( )
await tester . output_results ( )
await self . send_log ( bot = bot , log_location = log_location , chat_id = chat_id , message_thread_id = message_thread_id )
2023-04-28 14:55:31 +00:00
2023-05-01 16:26:45 +00:00
async def nightly_pi_iperf ( self , time = 10 ) :
token = SECRETS [ " TELEGRAM_TOKEN " ]
application = ApplicationBuilder ( ) . token ( token ) . build ( )
chat_id = SECRETS [ " TELEGRAM_LOG_CHAT_ID " ]
message_thread_id = SECRETS . get ( " TELEGRAM_LOG_MESSAGE_THREAD_ID " )
bot = application . bot
2023-04-27 08:46:42 +00:00
2023-05-01 16:38:22 +00:00
log_name = " moonlight- { : % m- %d - % Y}- { : % H: % m}-pi-iperf.txt " . format ( datetime . today ( ) , datetime . now ( ) )
2023-05-01 16:26:45 +00:00
log_location = os . path . join ( LOG_DIR_PATH , log_name )
2023-04-27 08:46:42 +00:00
2023-05-01 16:26:45 +00:00
async def offline_log ( msg ) :
with open ( log_location , ' a ' ) as log_file :
log_file . write ( msg )
2023-04-27 08:46:42 +00:00
2023-05-01 16:26:45 +00:00
async def log ( msg ) :
await offline_log ( msg )
try :
await bot . send_message ( chat_id = chat_id , text = msg , message_thread_id = message_thread_id )
except :
pass
2023-04-27 08:46:42 +00:00
2023-05-01 16:26:45 +00:00
await log ( " ☾☾ starting nightly computer-to-computer iperf test with {} seconds per test " . format ( time ) )
tester = CowmeshPiIperfTester ( log = log , time = time )
await tester . run_test ( )
await tester . output_results ( )
await self . send_log ( bot = bot , log_location = log_location , chat_id = chat_id , message_thread_id = message_thread_id )
2023-04-27 08:46:42 +00:00
2023-04-28 12:04:41 +00:00
2023-04-28 14:55:31 +00:00
2023-05-01 16:26:45 +00:00
async def nightly_pi_speedtest ( self ) :
token = SECRETS [ " TELEGRAM_TOKEN " ]
application = ApplicationBuilder ( ) . token ( token ) . build ( )
chat_id = SECRETS [ " TELEGRAM_LOG_CHAT_ID " ]
message_thread_id = SECRETS . get ( " TELEGRAM_LOG_MESSAGE_THREAD_ID " )
bot = application . bot
2023-04-28 14:55:31 +00:00
2023-05-01 16:38:22 +00:00
log_name = " moonlight- { : % m- %d - % Y}- { : % H: % m}-pi-speedtest.txt " . format ( datetime . today ( ) , datetime . now ( ) )
2023-05-01 16:26:45 +00:00
log_location = os . path . join ( LOG_DIR_PATH , log_name )
2023-04-27 08:46:42 +00:00
2023-05-01 16:26:45 +00:00
async def offline_log ( msg ) :
with open ( log_location , ' a ' ) as log_file :
log_file . write ( msg )
async def log ( msg ) :
await offline_log ( msg )
try :
await bot . send_message ( chat_id = chat_id , text = msg , message_thread_id = message_thread_id )
except :
pass
await log ( " ☾☾ starting nightly speedtest-cli speedtest " )
tester = CowmeshPiSpeedtestTester ( log = log )
await tester . run_test ( )
await tester . output_results ( )
await self . send_log ( bot = bot , log_location = log_location , chat_id = chat_id , message_thread_id = message_thread_id )
def init_bot_listener ( self ) :
token = SECRETS [ " TELEGRAM_TOKEN " ]
application = ApplicationBuilder ( ) . token ( token ) . build ( )
start_handler = CommandHandler ( ' start ' , self . start )
application . add_handler ( start_handler )
caps_handler = CommandHandler ( ' caps ' , self . caps )
application . add_handler ( caps_handler )
about_handler = CommandHandler ( ' readme ' , self . about )
application . add_handler ( about_handler )
help_handler = CommandHandler ( ' help ' , self . help_fun )
application . add_handler ( help_handler )
iperf_handler = CommandHandler ( ' iperf ' , self . router_iperf )
application . add_handler ( iperf_handler )
pi_iperf_handler = CommandHandler ( ' pi_iperf ' , self . pi_iperf )
application . add_handler ( pi_iperf_handler )
speedtest_handler = CommandHandler ( ' speedtest ' , self . speedtest )
application . add_handler ( speedtest_handler )
unknown_handler = MessageHandler ( filters . COMMAND , self . unknown )
application . add_handler ( unknown_handler )
application . run_polling ( )
2023-04-27 08:46:42 +00:00
if __name__ == ' __main__ ' :
2023-05-01 16:26:45 +00:00
tester = MoonlightTester ( )
tester . init_bot_listener ( )