This commit is contained in:
notplants 2023-05-01 21:56:45 +05:30
parent 1fb2a1d1c7
commit a138b92f3a
7 changed files with 398 additions and 249 deletions

22
cowmesh_constants.py Normal file
View File

@ -0,0 +1,22 @@
NODES = [
"jaaga",
"redcottage",
"new-gazebo2",
"kotemanetp",
"guard",
"ddhills",
"bambino",
"thimmanayaka"
]
HOST_TO_IP = {
"jaaga": "10.56.121.19",
"redcottage": "10.56.58.194",
"redcottage2": "10.56.114.42",
"new-gazebo2": "10.56.114.42",
"new-gazebo": "10.56.113.2",
"guard": "10.56.121.73",
"kotemanetp": "10.56.40.113",
"thimmanayaka": "10.56.39.34",
"bambino": "10.56.0.102"
}

View File

@ -73,21 +73,27 @@ class CowmeshPiIperfTester:
async def start_iperf_servers(self): async def start_iperf_servers(self):
for node in nodes: for node in nodes:
print("++ starting iperf server on {}".format(node)) try:
user = SECRETS["HOST_INFO"][node]["user"] print("++ starting iperf server on {}".format(node))
password = SECRETS["HOST_INFO"][node]["password"] user = SECRETS["HOST_INFO"][node]["user"]
password = SECRETS["HOST_INFO"][node]["password"]
myconn = paramiko.SSHClient() myconn = paramiko.SSHClient()
myconn.set_missing_host_key_policy(paramiko.AutoAddPolicy()) myconn.set_missing_host_key_policy(paramiko.AutoAddPolicy())
myconn.connect(node, username=user, password=password) myconn.connect(node, username=user, password=password)
remote_cmd = 'iperf -s &' remote_cmd = 'iperf -s &'
(stdin, stdout, stderr) = myconn.exec_command(remote_cmd) (stdin, stdout, stderr) = myconn.exec_command(remote_cmd)
await self.debug_log("{}".format(stdout.read())) await self.debug_log("{}".format(stdout.read()))
await self.debug_log("{}".format(type(myconn))) await self.debug_log("{}".format(type(myconn)))
await self.debug_log("Options available to deal with the connections are many like\n{}".format(dir(myconn))) await self.debug_log("Options available to deal with the connections are many like\n{}".format(dir(myconn)))
myconn.close() myconn.close()
except:
try:
self.log("++ error starting iperf server on {}".format(node))
except:
continue
async def cleanup_iperf_servers(self): async def cleanup_iperf_servers(self):
await self.log("++ shutting down iperf servers") await self.log("++ shutting down iperf servers")
@ -107,9 +113,12 @@ class CowmeshPiIperfTester:
await self.debug_log("skip self") await self.debug_log("skip self")
continue continue
r = await self.test_between_two_nodes(node_a, node_b)
result_key = "{} -> {}".format(node_a, node_b) result_key = "{} -> {}".format(node_a, node_b)
self.results[result_key] = r try:
r = await self.test_between_two_nodes(node_a, node_b)
self.results[result_key] = r
except Exception as e:
self.results[result_key] = "error: {}".format(e)
# try: # try:
# await self.cleanup_iperf_servers() # await self.cleanup_iperf_servers()

View File

@ -11,6 +11,7 @@ import asyncio, asyncssh, sys
import paramiko import paramiko
import subprocess import subprocess
import json import json
from cowmesh_constants import NODES, HOST_TO_IP
from cowmesh_helpers import cleanup_iperf_server from cowmesh_helpers import cleanup_iperf_server
@ -19,32 +20,14 @@ SECRETS_PATH = os.path.join(PROJECT_PATH, "secrets.json")
with open(SECRETS_PATH, 'r') as f: with open(SECRETS_PATH, 'r') as f:
SECRETS = json.loads(f.read()) SECRETS = json.loads(f.read())
nodes = [
"jaaga",
"redcottage",
"new-gazebo2",
"kotemanetp",
"guard"
]
host_to_ip = {
"jaaga": "10.56.121.19",
"redcottage": "10.56.58.194",
"redcottage2": "10.56.114.42",
"new-gazebo2": "10.56.114.42",
"new-gazebo": "10.56.113.2",
"guard": "10.56.121.73",
"kotemanetp": "10.56.40.113"
}
class CowmeshRouterIperfTester: class CowmeshRouterIperfTester:
def __init__(self, log=None, debug=False, seconds=10): def __init__(self, log=None, debug=False, time=10):
if log: if log:
self.log = log self.log = log
self.debug = debug self.debug = debug
self.time = seconds self.time = time
self.results = {} self.results = {}
async def log(self, msg): async def log(self, msg):
@ -64,7 +47,7 @@ class CowmeshRouterIperfTester:
myconn.connect(node_a, username =u_name, password=pswd) myconn.connect(node_a, username =u_name, password=pswd)
ip = host_to_ip[node_b] ip = HOST_TO_IP[node_b]
remote_cmd = 'iperf -c {ip} -p 5001 -t {seconds}'.format(ip=ip, seconds=self.time) remote_cmd = 'iperf -c {ip} -p 5001 -t {seconds}'.format(ip=ip, seconds=self.time)
(stdin, stdout, stderr) = myconn.exec_command(remote_cmd) (stdin, stdout, stderr) = myconn.exec_command(remote_cmd)
@ -77,50 +60,69 @@ class CowmeshRouterIperfTester:
if match: if match:
to_return = match.group(1) to_return = match.group(1)
else: else:
to_return = None match = re.search("(\S+) Kbits", output)
if match:
to_return = match.group(1)
to_return = float(to_return) / 1000.0
else:
to_return = None
return to_return return to_return
async def start_iperf_servers(self): async def start_iperf_servers(self):
for node in nodes: for node in NODES:
print("++ starting iperf server on {}".format(node)) try:
u_name = 'root' print("++ starting iperf server on {}".format(node))
pswd = SECRETS["ROUTER_PASSWORD"] u_name = 'root'
pswd = SECRETS["ROUTER_PASSWORD"]
myconn = paramiko.SSHClient() myconn = paramiko.SSHClient()
myconn.set_missing_host_key_policy(paramiko.AutoAddPolicy()) myconn.set_missing_host_key_policy(paramiko.AutoAddPolicy())
myconn.connect(node, username=u_name, password=pswd) myconn.connect(node, username=u_name, password=pswd)
remote_cmd = 'iperf -s &' remote_cmd = 'iperf -s &'
(stdin, stdout, stderr) = myconn.exec_command(remote_cmd) (stdin, stdout, stderr) = myconn.exec_command(remote_cmd)
await self.debug_log("{}".format(stdout.read())) await self.debug_log("{}".format(stdout.read()))
await self.debug_log("{}".format(type(myconn))) await self.debug_log("{}".format(type(myconn)))
await self.debug_log("Options available to deal with the connections are many like\n{}".format(dir(myconn))) await self.debug_log("Options available to deal with the connections are many like\n{}".format(dir(myconn)))
myconn.close() myconn.close()
except:
try:
await self.log("++ error starting iperf server on {}".format(node))
except:
continue
async def cleanup_iperf_servers(self): async def cleanup_iperf_servers(self):
await self.log("shutting down iperf servers") await self.log("shutting down iperf servers")
for node in nodes: for node in NODES:
user = "root" user = "root"
password = SECRETS["ROUTER_PASSWORD"] password = SECRETS["ROUTER_PASSWORD"]
ip = host_to_ip[node] ip = HOST_TO_IP[node]
await cleanup_iperf_server(node=node, ip=ip, username=user, password=password, log=self.log) await cleanup_iperf_server(node=node, ip=ip, username=user, password=password, log=self.log)
async def run_test(self): async def run_test(self):
await self.start_iperf_servers() try:
await self.start_iperf_servers()
except:
pass
for node_a in nodes: for node_a in NODES:
for node_b in nodes: for node_b in NODES:
if node_a == node_b: if node_a == node_b:
await self.debug_log("skip self") await self.debug_log("skip self")
continue continue
r = await self.test_between_two_nodes(node_a, node_b) try:
result_key = "{} -> {}".format(node_a, node_b) r = await self.test_between_two_nodes(node_a, node_b)
self.results[result_key] = r result_key = "{} -> {}".format(node_a, node_b)
self.results[result_key] = r
except Exception as e:
try:
await self.log("++ error running test between {} and {}: {}".format(node_a, node_b, e))
except:
continue
# try: # try:
# await self.cleanup_iperf_servers() # await self.cleanup_iperf_servers()
# except: # except:

View File

@ -7,29 +7,24 @@ import os
import time import time
import asyncio, asyncssh, sys import asyncio, asyncssh, sys
import subprocess import subprocess
import json
import paramiko
PROJECT_PATH = os.path.abspath(os.path.dirname(__file__)) PROJECT_PATH = os.path.abspath(os.path.dirname(__file__))
test_img_path = os.path.join(PROJECT_PATH, "test.png") test_img_path = os.path.join(PROJECT_PATH, "test.png")
SECRETS_PATH = os.path.join(PROJECT_PATH, "secrets.json")
with open(SECRETS_PATH, 'r') as f:
SECRETS = json.loads(f.read())
base_node = "janastunuc" # nuc in jaaga
nodes = [
"janastunuc", # nuc in jaaga
"solipi", # pi in guard
"writer", # pi in new-gazebo
]
node_dict = {
"jagga-nuc": {
"ip": "10.56.10.247",
"user": "cow",
"node_path": "/datadrive/data/cowmesh-network-test"
},
"redcottage-pi": {
"ip": "10.56.148.122",
"user": "admin",
"node_path": "/home/admin/cowmesh-network-test"
},
"newgazebo-pi": {
"ip": "10.56.11.111",
"user": "pi",
"node_path": "/home/pi/cowmesh-network-test"
},
}
# url for downloading test.png from the internet # url for downloading test.png from the internet
internet_url = "https://canalswans.commoninternet.net/test.png" internet_url = "https://canalswans.commoninternet.net/test.png"
@ -44,12 +39,13 @@ if PREPARE_TEST:
os.system(internet_scp_cmd) os.system(internet_scp_cmd)
# first put the image on every node without testing the time (so that the test is prepared to run) # first put the image on every node without testing the time (so that the test is prepared to run)
for name, from_node_vals in node_dict.items(): for name, from_node_vals in SECRETS["HOST_INFO"].items():
print("PREPARING NODE {}".format(name)) print("PREPARING NODE {}".format(name))
ip = from_node_vals["ip"] ip = from_node_vals["ip"]
dir_path = from_node_vals["node_path"] dir_path = from_node_vals["node_path"]
file_path = os.path.join(dir_path, "test.png") file_path = os.path.join(dir_path, "test.png")
user = from_node_vals["user"] user = from_node_vals["user"]
password = from_node_vals["password"]
mkdir_cmd = "ssh {user}@{ip} 'mkdir -p {dir_path}'".format(user=user, ip=ip, dir_path=dir_path) mkdir_cmd = "ssh {user}@{ip} 'mkdir -p {dir_path}'".format(user=user, ip=ip, dir_path=dir_path)
os.system(mkdir_cmd) os.system(mkdir_cmd)
scp_cmd = "scp {test_img_path} {user}@{ip}:{file_path}".format( scp_cmd = "scp {test_img_path} {user}@{ip}:{file_path}".format(
@ -60,16 +56,43 @@ if PREPARE_TEST:
) )
os.system(scp_cmd) os.system(scp_cmd)
myconn = paramiko.SSHClient()
myconn.set_missing_host_key_policy(paramiko.AutoAddPolicy())
myconn.connect(ip, username=user, password=password)
remote_cmd = 'mkdir -p {dir_path}'.format(dir_path=dir_path)
(stdin, stdout, stderr) = myconn.exec_command(remote_cmd)
output = str(stdout.read())
print("output: {}".format(output))
print(("errors: {}".format(stderr.read())))
scp_cmd = "scp {test_img_path} {user}@{ip}:{file_path}".format(
test_img_path=test_img_path,
ip=ip,
user=user,
file_path=file_path
)
(stdin, stdout, stderr) = myconn.exec_command(scp_cmd)
output = str(stdout.read())
print("output: {}".format(output))
print(("errors: {}".format(stderr.read())))
myconn.close()
results = {} results = {}
async def run_test(): async def run_test():
# run the test on each node # run the test on each node
for from_name, from_node_vals in node_dict.items(): node_dict = SECRETS["HOST_INFO"]
for node in nodes:
from_name = node
from_node_vals = node_dict[node]
from_ip = from_node_vals["ip"] from_ip = from_node_vals["ip"]
from_dir_path = from_node_vals["node_path"] from_dir_path = from_node_vals["node_path"]
from_file_path = os.path.join(from_dir_path, "test.png") from_file_path = os.path.join(from_dir_path, "test.png")
from_user = from_node_vals["user"] from_user = from_node_vals["user"]
for to_name, to_node_vals in node_dict.items(): from_password = from_node_vals["password"]
for to_name in nodes:
to_node_vals = node_dict[to_name]
if from_name == to_name: if from_name == to_name:
print("skip self") print("skip self")
continue continue
@ -80,35 +103,40 @@ async def run_test():
to_ip = to_node_vals["ip"] to_ip = to_node_vals["ip"]
to_dir_path = to_node_vals["node_path"] to_dir_path = to_node_vals["node_path"]
to_file_path = os.path.join(to_dir_path, "download.png") to_file_path = os.path.join(to_dir_path, "download.png")
to_password = to_node_vals["password"]
async with asyncssh.connect(from_ip, username=from_user) as conn: scp_cmd = "scp -i {key_path} {from_file_path} {to_user}@{to_ip}:{to_file_path}".format(
key_path="$HOME/.ssh/janastu",
to_user=to_user,
to_ip=to_ip,
to_file_path=to_file_path,
from_file_path=from_file_path
)
scp_cmd = "scp -i {key_path} {from_file_path} {to_user}@{to_ip}:{to_file_path}".format( start = time.time()
key_path="$HOME/.ssh/janastu",
to_user=to_user,
to_ip=to_ip,
to_file_path=to_file_path,
from_file_path=from_file_path
)
print(scp_cmd) myconn = paramiko.SSHClient()
myconn.set_missing_host_key_policy(paramiko.AutoAddPolicy())
myconn.connect(from_ip, username=from_user, password=from_password)
print(scp_cmd)
(stdin, stdout, stderr) = myconn.exec_command(scp_cmd)
exit_status = stdout.channel.recv_exit_status()
output = str(stdout.read())
error = str(stderr.read())
print("output: {}".format(output))
print(("errors: {}".format(stderr.read())))
start = time.time() result_key = "{} -> {}".format(from_name, to_name)
result = await conn.run(scp_cmd) if exit_status == 0:
print("success: {}".format(output))
if result.exit_status == 0: end = time.time()
print(result.stdout, end='') elapsed = (end - start)
end = time.time() print("{}: {} seconds".format(result_key, elapsed))
elapsed = (end - start) results[result_key] = elapsed
result_key = "{}->{}".format(from_name, to_name) else:
print("{}: {} seconds".format(result_key, elapsed)) print("error: {}".format(error))
results[result_key] = elapsed results[result_key] = "error: {}".format(error)
else: return
print(result.stderr, end='', file=sys.stderr)
print('Program exited with status %d' % result.exit_status,
file=sys.stderr)
results[result_key] = "error: {}".format(result.stderr)
return
# scp_with_time_cmd = "set -e; /usr/bin/time -f '%e' {}".format(scp_cmd) # scp_with_time_cmd = "set -e; /usr/bin/time -f '%e' {}".format(scp_cmd)
# print("running: {}".format(scp_with_time_cmd)) # print("running: {}".format(scp_with_time_cmd))
@ -117,6 +145,7 @@ async def run_test():
def run_laptop_test(): def run_laptop_test():
from_name = "laptop" from_name = "laptop"
# also measure transfers from laptop # also measure transfers from laptop
node_dict = SECRETS["HOST_INFO"]
for to_name, to_node_vals in node_dict.items(): for to_name, to_node_vals in node_dict.items():
print("** running test.png transfer test from laptop to {}".format(to_name)) print("** running test.png transfer test from laptop to {}".format(to_name))
@ -154,8 +183,8 @@ def run_laptop_test():
try: try:
asyncio.get_event_loop().run_until_complete(run_test()) # asyncio.get_event_loop().run_until_complete(run_test())
# run_laptop_test() run_laptop_test()
print("** final results **") print("** final results **")
file_size = 13476 file_size = 13476

0
get_device_info.y.py Normal file
View File

View File

@ -1,5 +1,6 @@
import asyncio import asyncio
import logging import logging
from datetime import date, datetime
from telegram import Update from telegram import Update
from telegram.ext import ApplicationBuilder, ContextTypes, CommandHandler, MessageHandler, filters from telegram.ext import ApplicationBuilder, ContextTypes, CommandHandler, MessageHandler, filters
@ -12,6 +13,7 @@ from cowmesh_pi_iperf_test import CowmeshPiIperfTester
PROJECT_PATH = os.path.abspath(os.path.dirname(__file__)) PROJECT_PATH = os.path.abspath(os.path.dirname(__file__))
SECRETS_PATH = os.path.join(PROJECT_PATH, "secrets.json") SECRETS_PATH = os.path.join(PROJECT_PATH, "secrets.json")
LOG_DIR_PATH = "/datadrive/apps/moonlight_analytics/results"
with open(SECRETS_PATH, 'r') as f: with open(SECRETS_PATH, 'r') as f:
SECRETS = json.loads(f.read()) SECRETS = json.loads(f.read())
@ -20,186 +22,270 @@ logging.basicConfig(
level=logging.INFO level=logging.INFO
) )
class MoonlightTester:
async def start(update: Update, context: ContextTypes.DEFAULT_TYPE): 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\nType /help to see available commands.", message_thread_id=update.message.message_thread_id) await context.bot.send_message(chat_id=update.effective_chat.id, text="This is the moonlight analytics bot for mesh network diagnostics.\n\nType /help to see available commands.", message_thread_id=update.message.message_thread_id)
async def caps(update: Update, context: ContextTypes.DEFAULT_TYPE): async def caps(self, update: Update, context: ContextTypes.DEFAULT_TYPE):
""" """
this is just a function to test that the bot is working as expected this is just a function to test that the bot is working as expected
""" """
text_caps = ' '.join(context.args).upper() text_caps = ' '.join(context.args).upper()
print("chat_id: {}".format(update.effective_chat.id)) print("chat_id: {}".format(update.effective_chat.id))
print("message_thread_id: {}".format(update.message.message_thread_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) await context.bot.send_message(chat_id=update.effective_chat.id, text=text_caps, message_thread_id=update.message.message_thread_id)
async def router_iperf(update: Update, context: ContextTypes.DEFAULT_TYPE): async def router_iperf(self, update: Update, context: ContextTypes.DEFAULT_TYPE):
time = context.args[0] if context.args else None time = context.args[0] if context.args else None
if not time: if not time:
time = 10 time = 10
async def log(msg):
await context.bot.send_message(chat_id=update.effective_chat.id, text=msg, message_thread_id=update.message.message_thread_id)
if update.effective_chat.id != int(SECRETS["TELEGRAM_LOG_CHAT_ID"]): log_name = "moonlight-{:%m-%d-%Y}-{:%H-%M}-router-iperf.txt".format(date.today(), datetime.now())
await log("++ can only start iperf test from Moonlight Bot group") log_location = os.path.join(LOG_DIR_PATH, log_name)
return
await log("++ starting router iperf test with {} seconds per test".format(time)) async def offline_log(msg):
tester = CowmeshRouterIperfTester(log=log, seconds=time) with open(log_location, 'a') as log_file:
await tester.run_test() log_file.write(msg + "\n")
await tester.output_results()
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)
if update.effective_chat.id != int(SECRETS["TELEGRAM_LOG_CHAT_ID"]):
await log("++ can only start iperf test from Moonlight Bot group")
return
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()
# 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)
async def pi_iperf(self, update: Update, context: ContextTypes.DEFAULT_TYPE):
time = context.args[0] if context.args else None
if not time:
time = 10
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)
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)
if update.effective_chat.id != int(SECRETS["TELEGRAM_LOG_CHAT_ID"]):
await log("++ can only start iperf test from Moonlight Bot group")
return
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()
# 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)
async def pi_iperf(update: Update, context: ContextTypes.DEFAULT_TYPE): async def speedtest(self, update: Update, context: ContextTypes.DEFAULT_TYPE):
time = context.args[0] if context.args else None log_name = "moonlight-{:%m-%d-%Y}-{:%H-%M}-pi-speedtest.txt".format(date.today(), datetime.now())
if not time: log_location = os.path.join(LOG_DIR_PATH, log_name)
time = 10
async def log(msg):
await context.bot.send_message(chat_id=update.effective_chat.id, text=msg, message_thread_id=update.message.message_thread_id)
if update.effective_chat.id != int(SECRETS["TELEGRAM_LOG_CHAT_ID"]): async def offline_log(msg):
await log("++ can only start iperf test from Moonlight Bot group") with open(log_location, 'a') as log_file:
return log_file.write(msg + "\n")
await log("++ starting pi iperf test with {} seconds per test".format(time)) async def log(msg):
tester = CowmeshPiIperfTester(log=log, time=time) await offline_log(msg)
await tester.run_test() await context.bot.send_message(chat_id=update.effective_chat.id, text=msg,
await tester.output_results() message_thread_id=update.message.message_thread_id)
if update.effective_chat.id != int(SECRETS["TELEGRAM_LOG_CHAT_ID"]):
await log("++ can only start test from Moonlight Bot group")
return
await log("++ starting pi speedtest-cli speedtest")
tester = CowmeshPiSpeedtestTester(log=log)
await tester.run_test()
await tester.output_results()
# 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)
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)
async def speedtest(update: Update, context: ContextTypes.DEFAULT_TYPE): def about_message(self):
msg = "This is a bot designed to help measure the performance of a mesh network through active testing. " \
async def log(msg): "Every night the bot runs a network test using iperf to measure the connectivity between all the nodes in the mesh, " \
await context.bot.send_message(chat_id=update.effective_chat.id, text=msg, message_thread_id=update.message.message_thread_id) "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, " \
if update.effective_chat.id != int(SECRETS["TELEGRAM_LOG_CHAT_ID"]): "with the command /iperf . " \
await log("++ can only start test from Moonlight Bot group") "Telegram users outside of this channel cannot initiate a test, to help keep the network secure from being " \
return "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 " \
await log("++ starting pi speedtest-cli speedtest") "give consistent results with less random variability. " \
tester = CowmeshPiSpeedtestTester(log=log) "Please be mindful of initiating too many iperf tests during the day, as it uses a lot of network resources " \
await tester.run_test() "to run the test and could interfere with the internet connections of people using the network. "
await tester.output_results() return msg
async def unknown(update: Update, context: ContextTypes.DEFAULT_TYPE): def help_message(self):
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) 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
def about_message(): async def about(self, update: Update, context: ContextTypes.DEFAULT_TYPE):
msg = "This is a bot designed to help measure the performance of a mesh network through active testing. " \ text = self.about_message()
"Every night the bot runs a network test using iperf to measure the connectivity between all the nodes in the mesh, " \ await context.bot.send_message(chat_id=update.effective_chat.id, text=text, message_thread_id=update.message.message_thread_id)
"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
def help_message(): async def help_fun(self, update: Update, context: ContextTypes.DEFAULT_TYPE):
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 " \ text = self.help_message()
"or read a longer message explaining how this bot works by typing the command /readme." await context.bot.send_message(chat_id=update.effective_chat.id, text=text, message_thread_id=update.message.message_thread_id)
return msg
async def send_log(self, bot, chat_id, message_thread_id, log_location):
# send log file
document = open(log_location, 'rb')
bot.send_document(chat_id, document, message_thread_id=message_thread_id)
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
log_name = "moonlight-{:%M-%d-%Y}-{:%H:%m}-router-iperf.txt".format(datetime.today(), datetime.now())
log_location = os.path.join(LOG_DIR_PATH, log_name)
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 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)
async def about(update: Update, context: ContextTypes.DEFAULT_TYPE):
text = about_message() async def nightly_pi_iperf(self, time=10):
await context.bot.send_message(chat_id=update.effective_chat.id, text=text, message_thread_id=update.message.message_thread_id) 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
async def help_fun(update: Update, context: ContextTypes.DEFAULT_TYPE): log_name = "moonlight-{:%M-%d-%Y}-{:%H:%m}-pi-iperf.txt".format(datetime.today(), datetime.now())
text = help_message() log_location = os.path.join(LOG_DIR_PATH, log_name)
await context.bot.send_message(chat_id=update.effective_chat.id, text=text, message_thread_id=update.message.message_thread_id)
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 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)
async def nightly_router_iperf(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
async def log(msg): async def nightly_pi_speedtest(self):
await bot.send_message(chat_id=chat_id, text=msg, message_thread_id=message_thread_id) 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
await log("☾☾ starting nightly router-to-router iperf test with {} seconds per test") log_name = "moonlight-{:%M-%d-%Y}-{:%H:%m}-pi-iperf.txt".format(datetime.today(), datetime.now())
tester = CowmeshRouterIperfTester(log=log, time=time) log_location = os.path.join(LOG_DIR_PATH, log_name)
await tester.run_test()
await tester.output_results() 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)
async def nightly_pi_iperf(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
async def log(msg): def init_bot_listener(self):
await bot.send_message(chat_id=chat_id, text=msg, message_thread_id=message_thread_id) token = SECRETS["TELEGRAM_TOKEN"]
application = ApplicationBuilder().token(token).build()
await log("☾☾ starting nightly computer-to-computer iperf test with {} seconds per test".format(time)) start_handler = CommandHandler('start', self.start)
tester = CowmeshPiIperfTester(log=log, time=time) application.add_handler(start_handler)
await tester.run_test()
await tester.output_results()
caps_handler = CommandHandler('caps', self.caps)
application.add_handler(caps_handler)
async def nightly_pi_speedtest(): about_handler = CommandHandler('readme', self.about)
token = SECRETS["TELEGRAM_TOKEN"] application.add_handler(about_handler)
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
async def log(msg): help_handler = CommandHandler('help', self.help_fun)
await bot.send_message(chat_id=chat_id, text=msg, message_thread_id=message_thread_id) application.add_handler(help_handler)
await log("☾☾ starting nightly speedtest-cli speedtest") iperf_handler = CommandHandler('iperf', self.router_iperf)
tester = CowmeshPiSpeedtestTester(log=log) application.add_handler(iperf_handler)
await tester.run_test()
await tester.output_results()
pi_iperf_handler = CommandHandler('pi_iperf', self.pi_iperf)
application.add_handler(pi_iperf_handler)
def init_bot_listener(): speedtest_handler = CommandHandler('speedtest', self.speedtest)
token = SECRETS["TELEGRAM_TOKEN"] application.add_handler(speedtest_handler)
application = ApplicationBuilder().token(token).build()
start_handler = CommandHandler('start', start) unknown_handler = MessageHandler(filters.COMMAND, self.unknown)
application.add_handler(start_handler) application.add_handler(unknown_handler)
caps_handler = CommandHandler('caps', caps) application.run_polling()
application.add_handler(caps_handler)
about_handler = CommandHandler('readme', about)
application.add_handler(about_handler)
help_handler = CommandHandler('help', help_fun)
application.add_handler(help_handler)
iperf_handler = CommandHandler('iperf', router_iperf)
application.add_handler(iperf_handler)
pi_iperf_handler = CommandHandler('pi_iperf', pi_iperf)
application.add_handler(pi_iperf_handler)
speedtest_handler = CommandHandler('speedtest', speedtest)
application.add_handler(speedtest_handler)
unknown_handler = MessageHandler(filters.COMMAND, unknown)
application.add_handler(unknown_handler)
application.run_polling()
if __name__ == '__main__': if __name__ == '__main__':
init_bot_listener() tester = MoonlightTester()
tester.init_bot_listener()

View File

@ -1,14 +1,15 @@
import argparse import argparse
from moonlight_analytics import nightly_router_iperf, nightly_pi_iperf, nightly_pi_speedtest from moonlight_analytics import MoonlightTester
import asyncio import asyncio
import sys import sys
if __name__ == '__main__': if __name__ == '__main__':
tester = MoonlightTester()
time = sys.argv[2] if len(sys.argv) > 2 else 10 time = sys.argv[2] if len(sys.argv) > 2 else 10
if sys.argv[1] == "router": if sys.argv[1] == "router":
asyncio.get_event_loop().run_until_complete(nightly_router_iperf(time=time)) asyncio.get_event_loop().run_until_complete(tester.nightly_router_iperf(time=time))
elif sys.argv[1] == "pi": elif sys.argv[1] == "pi":
asyncio.get_event_loop().run_until_complete(nightly_pi_iperf(time=time)) asyncio.get_event_loop().run_until_complete(tester.nightly_pi_iperf(time=time))
elif sys.argv[1] == "speedtest": elif sys.argv[1] == "speedtest":
asyncio.get_event_loop().run_until_complete(nightly_pi_speedtest()) asyncio.get_event_loop().run_until_complete(tester.nightly_pi_speedtest())