Skip to content

Instantly share code, notes, and snippets.

/statbot.py Secret

Created January 4, 2018 08:22
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save anonymous/129d926d08380fceebe35ee24182ee40 to your computer and use it in GitHub Desktop.
Save anonymous/129d926d08380fceebe35ee24182ee40 to your computer and use it in GitHub Desktop.
#!/usr/bin/env python2
# -*- coding: utf-8 -*-
'''
o x e x o r h a s h e x o (bitmessage) BM-NBfVnT48vSeyjQ9bceneRuW76NypwRsx
r r (email) xor@danwin1210.me
h ┏┓┏┓┏━━┓┏━┓ h
a ┗╋╋┛┃┏┓┃┃┏┛ a Copyright (c) 2017 by Exor Hash Comsec Trust.
s ┏╋╋┓┃┗┛┃┃┃ s All rights reserved.
h ┗┛┗┛┗━━┛┗┛ h
s s This software and accompaniments are subject to the
a exor hash a terms of the SSS License v0.0, included herewith.
h comsec h
r r
o x e x o r h a s h e x o
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
See:Sue:Sell (SSS) license version 0.0
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
You may see this code. There is no warranty. You agree you shall not sue me. You
agree that no claim of damages may arise from use of this software. You may not
sell this software. You agree you have no rights incidental to use of this code.
Rights not granted by this license are reserved to the author.
'''
# STATBOT v0.0 : pings other STATBOTS to measure bitmessage transit times
''' HELLO! READ THESE COMMENTS ON HOW TO INSTALL! '''
# First shut down bitmessage. Don't try to install with bitmessage running.
# Copy the file 'statbot.py' to the same directory as bitmessagemain.py
# Navigate to the same directory with a terminal.
# In terminal type 'python2 statbot.py setup'. (without the quotes)
# The statbot installation wizard will guide the installation.
# After that, start up bitmessage, then run the script from the command line:
# $ python2 statbot.py run
# End of comments and header.
# ------------------------------------------------------------------------------
import sys
if len(sys.argv) > 2:
print "bad command line argument. try 'statbot.py help'."
sys.exit()
if len(sys.argv) < 2:
print "( statbot ) ( error ) You must specify a statbot switch after the command."
print "( statbot ) switches: 'help', 'run', 'ping', 'bonk', 'logo', 'info', 'setup'."
print "( statbot ) examples: 'statbot.py run', 'statbot.py logo', 'statbot.py bonk'."
sys.exit()
if len(sys.argv) == 2 and sys.argv[1] == "help":
print "( statbot ) ( help ) valid switches: 'help', 'run', 'ping', 'bonk', 'logo', 'info', 'setup'."
print "( statbot ) ( help ) example: 'statbot.py run', 'statbot.py logo', 'statbot.py bonk'."
sys.exit()
if len(sys.argv) == 2 and sys.argv[1] == "logo":
logo = '''
o x e x o r h a s h e x o (bitmessage) BM-NBfVnT48vSeyjQ9bceneRuW76NypwRsx
r r (email) xor@danwin1210.me
h ┏┓┏┓┏━━┓┏━┓ h
a ┗╋╋┛┃┏┓┃┃┏┛ a Copyright (c) 2017 by Exor Hash Comsec Trust.
s ┏╋╋┓┃┗┛┃┃┃ s All rights reserved.
h ┗┛┗┛┗━━┛┗┛ h
s s This software and accompaniments are subject to the
a exor hash a terms of the SSS License v0.0, included herewith.
h comsec h
r r
o x e x o r h a s h e x o
'''
print logo
sys.exit()
if len(sys.argv) == 2 and sys.argv[1] == "info":
info = '''
STATBOT : pings other STATBOTS to measure bitmessage transit times.
The statbot periodically sends a bitmessage to a chan that is monitored by all
other statbots. They gather and share timestamp data to estimate metrics on how
long it takes a bitmessage to traverse the network in usage (not just transit),
including PoW time. Since PoW time is neglibible for short messages this is a
good estimation of either traversal from send or transit between sockets.
Follow the setup instructions, then once set up with bitmessage running, open a
terminal and type the command 'statbot.py run' to start the pinger. Over a
period of many hours (or days) the timestamps will be analyzed and a periodic
report will be sent by every statbot at random intervals. You must run the
pinger for statbot to gather proper statistics.
Every ping that is sent is automatically handled by the bitmessage api as soon
as each ping message arrives. Once running zero interaction is required.
The extra commands 'ping' and 'bonk' are included for troubleshooting and should
not be invoked in normal usage.
'''
print info
sys.exit()
from bmconfigparser import BMConfigParser
import ConfigParser
import subprocess
import xmlrpclib
import ntpath
import socket
import base64
import random
import json
import time
import api
import sys
import os
app_dir = os.path.dirname(os.path.abspath(__file__))
os.chdir(app_dir)
print "( statbot ) ( app dir ) ", app_dir
print "( statbot ) ( file ) ", __file__
if not os.path.isfile("bitmessagemain.py"):
print "( statbot ) [ ERROR 02 ] could not find 'bitmessagemain.py.'"
print "( statbot ) statbot.py must be placed in bitmessage /src/ directory to run."
print "( statbot ) [ ERROR 02 ] cannot proceed. exiting."
sys.exit
statbotpath = os.path.abspath(__file__)
if not os.path.exists("statbot"):
os.makedirs("statbot")
def wait(secs):
time.sleep(secs)
def loput(iput, match):
if iput.lower() == match.lower():
return True
else:
return False
def getApiPort():
tcp = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
tcp.bind(('', 0))
addr, port = tcp.getsockname()
tcp.close()
return port
def getApiAddress():
tcp = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
tcp.bind(('', 0))
host, port = tcp.getsockname()
tcp.close()
#return 'tcp://{host}:{port}'.format(**locals())
return host
def drawHeader():
try:
os.system('cls' if os.name == 'nt' else 'clear')
except:
print ''
try:
os.system('cls' if os.name == 'nt' else 'tput reset')
except:
print ''
print ''
print ' STATBOT v0.0'
print '________________________________________________________________________________'
print ''
def findKeysFolder(): # Ref. { PyBitmessage/bminterface.py }
import sys
APPNAME = "PyBitmessage"
from os import path, environ
if sys.platform == 'darwin':
if "HOME" in environ:
dataFolder = path.join(os.environ["HOME"], "Library/Application support/", APPNAME) + '/'
else:
drawHeader()
print '( statbot ) [ ERROR ] ( install ) OS X: Unable to find keys directory.'
print '( statbot ) [ ERROR ] ( install ) Try to configure keys.dat manually.'
print '( statbot ) [ ERROR ] ( install ) STATBOT may not run on your system. exiting.'
sys.exit()
elif 'win32' in sys.platform or 'win64' in sys.platform:
dataFolder = path.join(environ['APPDATA'], APPNAME) + '\\'
else:
dataFolder = path.expanduser(path.join("~", "." + "config", APPNAME + "/"))
return dataFolder
def getApiString():
global keysPath
config = ConfigParser.SafeConfigParser()
keysPath = 'keys.dat'
config.read(keysPath) # first try to load keys.dat from source directory.
try:
config.get('bitmessagesettings','settingsversion')
keysFolder = ''
except:
# keys.dat not found in source directory. Try appdata directory.
keysFolder = findKeysFolder()
keysPath = keysFolder + 'keys.dat'
config = ConfigParser.SafeConfigParser()
config.read(keysPath)
try:
config.get('bitmessagesettings','settingsversion')
except:
# keys.dat not there either. something is wrong.
drawHeader()
print ' '
print '+--------------------------------------------------------------------+'
print '| STATBOT is unable to access the Bitmessage keys.dat file. |'
print '| Check to ensure statbot is in the same directory as Bitmessage. |'
print '+--------------------------------------------------------------------+'
print ' '
print config
print ' '
try:
apiPort = config.getint('bitmessagesettings', 'apiport')
except:
print '( statbot ) ( error ) unable to access keys.dat'
try:
apiInterface = config.get('bitmessagesettings', 'apiinterface')
except:
print '( statbot ) ( error ) unable to access keys.dat'
try:
apiUsername = config.get('bitmessagesettings', 'apiusername')
except:
print '( statbot ) ( error ) unable to access keys.dat'
try:
apiPassword = config.get('bitmessagesettings', 'apipassword')
except:
print '( statbot ) ( error ) unable to access keys.dat'
apiString = "http://" + apiUsername + ":" + apiPassword + "@" + apiInterface+ ":" + str(apiPort) + "/"
return apiString
api_string = getApiString()
# being install wizard
def apiData():
global keysPath
config = ConfigParser.SafeConfigParser()
keysPath = 'keys.dat'
config.read(keysPath) # first try to load keys.dat from source directory.
try:
config.get('bitmessagesettings','settingsversion')
keysFolder = ''
except:
# keys.dat not found in source directory. Try appdata directory.
keysFolder = findKeysFolder()
keysPath = keysFolder + 'keys.dat'
config = ConfigParser.SafeConfigParser()
config.read(keysPath)
try:
config.get('bitmessagesettings','settingsversion')
except:
# keys.dat not there either. something is wrong.
drawHeader()
print ' '
print '+--------------------------------------------------------------------+'
print '| STATBOT is unable to access the Bitmessage keys.dat file. |'
print '| Check to ensure statbot is in the same directory as Bitmessage. |'
print '+--------------------------------------------------------------------+'
print ' '
print config
print ' '
try:
apiConfigured = config.getboolean('bitmessagesettings','apienabled')
apiEnabled = apiConfigured
except:
apiConfigured = False # if not found set to false to force configuration.
print "API is disabled. STATBOT must enable and configure the Bitmessage API."
print "Use the 'setup' command to do this automatically."
raise
try:
notifypathtrue = config.has_option('bitmessagesettings', 'apinotifypath')
notifypath = config.get('bitmessagesettings', 'apinotifypath')
except:
notifypath = " (!) apinotifypath not configured for statbot."
# keys.dat found. retrieve data.
# if any setting is null, false, or incorrect, increment a boolean match, to ensure setup runs.
misconfigured = False
try:
apiEnabled = config.getboolean('bitmessagesettings','apienabled')
except:
apiEnabled = False
if apiEnabled != True:
misconfigured = True
apiEnabled = str(apiEnabled) + " (!)"
try:
apiPort = config.getint('bitmessagesettings', 'apiport')
except:
misconfigured = True
apiPort = " (!)"
try:
apiInterface = config.get('bitmessagesettings', 'apiinterface')
except:
misconfigured = True
apiInterface += " (!)"
if "." not in apiInterface:
misconfigured = True
apiInterface += " (!)"
try:
apiUsername = config.get('bitmessagesettings', 'apiusername')
except:
misconfigured = True
apiUsername += " (!)"
try:
apiPassword = config.get('bitmessagesettings', 'apipassword')
except:
misconfigured = True
apiPassword += " (!)"
try:
apinotifypath = config.get('bitmessagesettings', 'apinotifypath')
except:
misconfigured = True
apinotifypath = " (!)"
if apinotifypath != statbotpath and apinotifypath != "":
apinotifypath += " (!)"
misconfigured = True
if apinotifypath == "":
apinotifypath += " (!)"
misconfigured = True
drawHeader()
print ' +---------------------------------+'
print ' | Current STATBOT API Settings | (!) Indicates a bad setting.'
print ' +---------------------------------+'
print ''
print ' statbotpath = ' + str(statbotpath)
print ' apinotifypath = ' + str(apinotifypath)
print ' apiEnabled = ' + str(apiEnabled)
print ' apiPort = ' + str(apiPort)
print ' apiInterface = ' + str(apiInterface)
print ' apiUsername = ' + str(apiUsername)
print ' apiPassword = ' + str(apiPassword)
print ''
print ''
if notifypath != statbotpath or misconfigured == True:
print ' STATBOT must permanently change these settings to install and run.'
print ' Would you like STATBOT to do this automatically (Y)es / (N)o ?'
print ''
valid = False
userInput = raw_input(' [$] ')
print '\n ( statbot ) ( setup ) ' + str(userInput)
if userInput.lower() == "yes":
setupWizard(statbotpath, apinotifypath, apiEnabled, apiPort, apiInterface, apiUsername, apiPassword)
valid = True
elif userInput.lower() == "y":
setupWizard(statbotpath, apinotifypath, apiEnabled, apiPort, apiInterface, apiUsername, apiPassword)
valid = True
elif userInput.lower() == "no" or userInput.lower() == "n":
print " (!) returning to command help menu."
wait(1.5)
installMenu()
valid = True
elif valid == False and "yes" not in userInput.lower() and "no" not in userInput.lower():
print "( " + userInput + " ) is an invalid command."
print " (!) returning to command help menu."
wait(1.5)
installMenu()
if notifypath == statbotpath and misconfigured == False:
print ' STATBOT and bitmessage settings appear correct.'
print ' Would you like STATBOT to reconfigure anyway? (Y)es / (N)o ?'
print ''
valid = False
userInput = raw_input(' [$] ')
print '\n ( statbot ) ( setup ) ' + str(userInput)
if userInput.lower() == "yes":
setupWizard(statbotpath, apinotifypath, apiEnabled, apiPort, apiInterface, apiUsername, apiPassword)
valid = True
elif userInput.lower() == "y":
setupWizard(statbotpath, apinotifypath, apiEnabled, apiPort, apiInterface, apiUsername, apiPassword)
valid = True
elif userInput.lower() == "no" or userInput.lower() == "n":
print " (!) returning to command help menu."
wait(1.5)
installMenu()
valid = True
elif valid == False and "yes" not in userInput.lower() and "no" not in userInput.lower():
print "( " + userInput + " ) is an invalid command."
print " (!) returning to command help menu."
wait(1.5)
installMenu()
def show_api():
drawHeader()
print '\n\n\n current Bitmessage API connection string:\n\n ' + api_string + "\n\n\n"
userInput = raw_input(' [$] press <enter> to go back to menu. [$]')
installMenu()
def installMenu():
drawHeader()
print ' +----------------------------------------------------------+'
print ' | Available Commands |'
print ' +----------------------------------------------------------+'
print ' | |'
print ' | help : show this help guide. |'
print ' | quit : quit the program. |'
print ' | test : test the bitmessage / statbot API link. |'
print ' | show : show the API connection string. |'
print ' | setup : setup bitmessage to run statbot. |'
print ' | |'
print ' +----------------------------------------------------------+'
print ''
userInput = raw_input(' [$] ')
userInput = userInput.lower()
if userInput == "help" or userInput == "h" or userInput == "?":
installMenu()
elif userInput == "setup":
apiData()
elif userInput == "test":
apiData()
elif userInput == "show":
show_api()
elif userInput == "quit" or userInput == "exit":
print ' ( statbot ) ( exit )'
sys.exit()
else:
print " not a valid command. try again."
wait(2)
installMenu()
def changeSettings(apinotifypath, apiEnabled, apiPort, apiInterface, apiUsername, apiPassword):
global keysPath
# avoid using BMConfigParser, as it requires redrawing every entry in the file.
'''
BMConfigParser().add_section('bitmessagesettings')
BMConfigParser().set('bitmessagesettings', 'statbot', 'true')
BMConfigParser().set('bitmessagesettings', 'statbotversion', '0.0')
BMConfigParser().set('bitmessagesettings', 'apienabled','true')
BMConfigParser().set('bitmessagesettings', 'apinotifypath', str(apinotifypath))
BMConfigParser().set('bitmessagesettings', 'apienabled', str(apiEnabled))
BMConfigParser().set('bitmessagesettings', 'apiport', str(apiPort))
BMConfigParser().set('bitmessagesettings', 'apiinterface', str(apiInterface))
BMConfigParser().set('bitmessagesettings', 'apiusername', str(apiUsername))
BMConfigParser().set('bitmessagesettings', 'apipassword', str(apiPassword))
'''
try:
with open(keysPath, 'a') as configfile:
configfile.write("\n\n\n")
configfile.write("\n[bitmessagesettings]")
configfile.write("\nstatbot = True")
configfile.write("\nstatbotversion = 0.0")
configfile.write("\napienabled = True")
configfile.write("\napinotifypath = " + str(apinotifypath))
configfile.write("\napiport = " + str(apiPort))
configfile.write("\napiinterface = " + str(apiInterface))
configfile.write("\napiusername = " + apiUsername)
configfile.write("\napipassword = " + apiPassword)
configfile.write("\n\n\n")
#BMConfigParser().write(configfile)
configfile.close()
except:
print " (!) Unknown error. terminating program."
wait(1.5)
raise
sys.exit()
print ''
print " success! changes written to keys.dat."
print " shut down and restart bitmessage for changes to take effect."
print ""
print " (!) all done. exiting."
wait(1.5)
sys.exit()
def randomToken():
from base64 import b64encode
from os import urandom
random_bytes = urandom(64)
token = b64encode(random_bytes).decode('utf-8')
token = token.replace("/", "")
token = token.replace("+", "")
token = token[19:39]
return token
def setupWizard(statbotpath, apinotifypath, apiEnabled, apiPort, apiInterface, apiUsername, apiPassword):
# generate new settings values
apinotifypath = statbotpath
apiEnabled = True
apiPort = getApiPort()
apiInterface = getApiAddress()
apiUsername = randomToken()
apiPassword = randomToken()
valid = False
while valid == False:
sys.stdout.write("\r")
sys.stdout.flush()
drawHeader()
print ' +---------------------------------+'
print ' | Automatic Setup Wizard |'
print ' +---------------------------------+'
print ''
print ' Review of proposed settings:'
print ''
print ' apinotifypath = ' + str(statbotpath)
print ' apiEnabled = True'
print ' apiPort = ' + str(apiPort)
print ' apiInterface = ' + str(apiInterface)
print ' apiUsername = ' + str(apiUsername)
print ' apiPassword = ' + str(apiPassword)
print ''
print " To apply changes, type 'yes' and press 'enter'."
print " To cancel type 'no' and press 'enter'. (yes), (no) ?"
userInput = raw_input(' [$] ')
userInput = userInput.lower()
if userInput == "no":
installMenu()
valid == True
yes = loput(userInput, "yes")
if yes:
changeSettings(apinotifypath, apiEnabled, apiPort, apiInterface, apiUsername, apiPassword)
valid == True
if userInput != "yes" and userInput != "no":
print " (!) Invalid command. ( ", str(userInput), " ) Try again."
valid == False
wait(1.5)
if len(sys.argv) == 2 and sys.argv[1] == "setup":
installMenu() # show the setup commands menu
sys.exit()
# end install wizard
# begin the statbot
print "( statbot ) ( app dir ) ", app_dir
print "( statbot ) ( file ) ", __file__
api = xmlrpclib.ServerProxy(api_string)
print "( statbot ) ( api_string ) ", api_string
#command = sys.argv[0] #will use later, for now __file__
def apiTest():
try:
result = api.add(4,5)
if result == 9:
print "( statbot ) bitmessage API is enabled and responding. proceeding."
elif result != 9:
print "( statbot ) bitmessage API error. check keys.dat configuration."
print "( statbot ) bitmessage API error. is bitmessage running?. exiting."
sys.exit()
except:
print "( statbot ) bitmessage API error. check keys.dat configuration. is API enabled?"
print "( statbot ) bitmessage API error. is bitmessage running?. exiting."
sys.exit()
# create the statbot chan for message pool (all STATBOTS use same chan)
def checkChan(chanName):
try:
passphrase = chanName.encode('base64')
checkphrase = api.createChan(passphrase)
api.statusBar("( statbot ) checking chan.")
except ValueError:
print "( statbot ) [ ERROR 00 ] unable to create channel."
print "( statbot ) [ ERROR 00 ] if channel exists this is not an error. continuing."
api.statusBar("( statbot ) checking chan.")
return checkphrase
chanName = "stat_bonk"
checkphrase = checkChan(chanName)
api.statusBar("( statbot ) checking chan.")
if "Chan address is already present" in checkphrase:
print "( statbot ) success. [chan] " + chanName + " exists. proceeding."
elif checkphrase[:3] == "BM-":
print "( statbot ) success. [chan] " + chanName + " created. proceeding."
elif checkphrase != "":
print "( statbot ) [ ERROR 01 ] [ BM-API ] error creating [chan] ", checkphrase, "exiting."
api.statusBar("( statbot ) [ ERROR 01 ] exiting.")
sys.exit()
chanName = "stat_ping"
checkphrase = checkChan(chanName)
api.statusBar("( statbot ) checking chan.")
if "Chan address is already present" in checkphrase:
print "( statbot ) success. [chan] " + chanName + " exists. proceeding."
elif checkphrase[:3] == "BM-":
print "( statbot ) success. [chan] " + chanName + " created. proceeding."
elif checkphrase != "":
print "( statbot ) [ ERROR 01 ] [ BM-API ] error creating [chan] ", checkphrase, "exiting."
api.statusBar("( statbot ) [ ERROR 01 ] exiting.")
sys.exit()
def getAddress(passphrase,vNumber,sNumber):
passphrase = passphrase.encode('base64')
return api.getDeterministicAddress(passphrase,vNumber,sNumber)
api.statusBar("( statbot ) getting chan address.")
# check for statbot ID file. if non-existent, generate a new botID and add to file.
# if it exists, read the botID to variable
def getBotID():
if not os.path.isfile("statbot/bmstatbotID.dat"):
try:
lo = 100000000000000000000000
hi = 999999999999999999999999
botNum = random.randrange(lo, hi)
botID = str(hex(botNum)).strip("L")[2:18]
print "( statbot ) [ BOTID ] generated new botID: ", botID
readID = open("statbot/bmstatbotID.dat", "w")
botID = readID.write(botID)
readID.close()
return botID
except:
print "( statbot ) [ ERROR 03 ] [ BOTID] can't create bmstatbotID file."
print "( statbot ) [ ERROR 03 ] check your filesystem policy. exiting."
sys.exit()
if os.path.isfile("statbot/bmstatbotID.dat"):
try:
readID = open("statbot/bmstatbotID.dat", "r")
botID = readID.read()
readID.close()
print "( statbot ) ( BOTID ) retrieved botID: ", botID
#return botID
except:
print "( statbot ) [ ERROR 04 ] can't access bmstatbotID file."
return botID
# this botID will be for reports and will be important in later versions.
getBotID()
# check ticket counter file; create file if necessary
def pingPongCount(type):
if type == "ping":
filename = "statbot/statbot_PING_counter.dat"
if type == "pong":
filename = "statbot/statbot_PONG_counter.dat"
if type == "bonk":
filename = "statbot/statbot_BONK_counter.dat"
print "( statbot ) checking ( ", type, " ) counter."
if not os.path.isfile(filename):
try:
makeCounter = open(filename, "w")
makeCounter.write("0")
makeCounter.close()
print "( statbot ) created new ( ", type, " ) counter file."
except:
print "( statbot ) [ ERROR 05 ] ( ", type, " ) can't create counter file."
if os.path.isfile(filename):
try:
readCounter = open(filename, "r")
totalServed = readCounter.read()
readCounter.close()
except:
print "( statbot ) [ ERROR 06 ] ( counter ) ( ", type, " ) can't access file."
try:
numberServed = int(totalServed) # if can't convert to int() must be corrupted.
except ValueError:
print "( statbot ) [ ERROR 07 ] ( counter ) file was corrupted, replacing it."
numberServed = 0
numberServed += 1
newCount = str(numberServed)
try:
writeCounter = open(filename, "w")
writeCounter.write(newCount)
writeCounter.close()
print "( statbot ) ( counter ) ( ", type, " ) ( # ", newCount, " )"
#return newCount
except:
print "( statbot ) [ ERROR 08 ] ( counter ) ( ", type, " ) can't write to file."
return newCount
def sendPong(timeString, sub, msg):
print "( statbot ) ( pong ) composing message."
address = getAddress("stat_ping", 4, 1)
print "( statbot ) ( pong ) ( address ) ", address
plainSubject = "PONG " + timeString
print "( statbot ) ( pong ) ( subject ) ", plainSubject
plainMessage = sub + " " + msg
message = plainMessage.encode('base64')
subject = plainSubject.encode('base64')
ttl = 3600
try:
ackData = api.sendMessage(address, address, subject, message, 2, ttl)
print "( statbot ) ( pong ) ( status ) ", api.getStatus(ackData)
print "( statbot ) ( pong ) ( # ", newCount, " ) sent."
except:
print "( statbot ) [ ERROR 09] ( pong ) ( api error ) could not send pong."
newCount = pingPongCount("pong")
# I did not code exceptions for following file access, since if the first round
# did not halt the program, everything should be ok - will update it eventually.
def dumpMsg(timeString, sub, msg):
print " ( statbot ) ( dump ) ( ", sub[:4], " ) get data from inbound message."
if sub[:4] == "PING":
filename = "statbot/statbot_PING_dump.dat"
elif sub[:4] == "PONG":
filename = "statbot/statbot_PONG_dump.dat"
elif sub[:4] == "BONK":
filename = "statbot/statbot_BONK_dump.dat"
elif sub[:4] != "PING":
print "( statbot ) [ ERROR 10 ] ( dump ) ( garbage ) looks like we got garbage!"
print "( statbot ) [ ERROR 10 ] ( dump ) ( garbage ) ( ", sub[:40], " )"
print "( statbot ) [ ERROR 10 ] ( dump ) ( garbage ) logged to statbottrash.dat"
filename = "statbot/statbottrash.dat"
if not os.path.isfile(filename):
try:
g = open(filename, "w")
g.write("")
g.close()
except:
print "( statbot ) [ ERROR 11 ] ( dump ) ( ", sub[:4], " ) can't create file"
print "( statbot ) [ ERROR 11 ] ( dump ) exiting."
sys.exit()
if os.path.isfile(filename):
try:
lineString = timeString + " " + sub + " " + msg + "\n"
h = open(filename, "a")
h.write(lineString)
h.close()
except:
print "( statbot ) [ ERROR 12 ] ( dump ) ( ", sub[:4], " ) can't write to file"
print "( statbot ) [ ERROR 12 ] ( dump ) exiting."
sys.exit()
botID = getBotID()
if sub[:4] == "PING" and str(getBotID()) not in msg:
sendPong(timeString, sub, msg)
# Delete the first message from the JSON object, index[0].
def delMsg0():
global api
address = getAddress("stat_ping", 4, 1)
inboxMessages = json.loads(api.getInboxMessagesByReceiver(address))
numMessages = len(inboxMessages['inboxMessages'])
if (numMessages > 0):
# Get the msgid of the first message, which is a hex number.
msgID = inboxMessages['inboxMessages'][0]['msgid']
print "( statbot ) ( delete ) ", str(msgID)[:55]
api.trashMessage(msgID)
return "Deleted first message."
# Get the first message from the JSON object, index[0]
def getMsg0():
global api
numMessages = 1
while numMessages > 0:
# removed api connection string from here and made it a global so it can
# be in top of file for easy install reference
address = getAddress("stat_ping", 4, 1)
inboxMessages = json.loads(api.getInboxMessagesByReceiver(address))
numMessages = len(inboxMessages['inboxMessages'])
print "( statbot ) ( get msg ) ( total ) " + str(numMessages)
if (numMessages < 1):
print "( statbot ) ( get msg ) ( total ) [0] zero messages to review."
if (numMessages > 0):
timeString = str(time.time())[:10]
msgID = inboxMessages['inboxMessages'][0]['msgid']
print "( statbot ) ( get msg ) ( msgid ) ", msgID[:45]
frm = inboxMessages['inboxMessages'][0]['fromAddress']
print "( statbot ) ( get msg ) ( from )", frm[:55]
sub = inboxMessages['inboxMessages'][0]['subject'].decode('base64')
print "( statbot ) ( get msg ) ( subject ) ", sub[:45]
msg = inboxMessages['inboxMessages'][0]['message'].decode('base64')
print "( statbot ) ( get msg ) ( message ) ", msg[:45]
command = inboxMessages['inboxMessages'][0]['subject'].decode('base64')[:4]
print "( statbot ) ( get msg ) ( message ) ( type ) ( ", command, " )"
dumpMsg(timeString, sub, msg)
delMsg0()
def sendPing():
print "( statbot ) ( ping ) generating message."
address = getAddress("stat_ping", 4, 1)
print "( statbot ) ( ping ) ( address ) ", address
timeStamp=time.time()
timeString = str(timeStamp)
timeSecs = timeString[:10]
print "( statbot ) ( ping ) ( time ) ", timeSecs
botID = getBotID()
lo = 100000000000000000000000
hi = 999999999999999999999999
msgNum = random.randrange(lo, hi)
msgNum = str(hex(msgNum)).strip("L")[2:18]
print "( statbot ) ( ping ) ( identifier ) ", msgNum
plainSubject = "PING " + timeSecs
print "( statbot ) ( ping ) ( subject ) ", plainSubject
plainMessage = msgNum + " " + str(getBotID())
message = plainMessage.encode('base64')
subject = plainSubject.encode('base64')
ttl = 3600
try:
ackData = api.sendMessage(address, address, subject, message, 2, ttl)
print "( statbot ) ( ping ) ( status ) ", api.getStatus(ackData)
except:
print "( statbot ) [ ERROR ] ( ping ) ( api ) API Error."
newCount = pingPongCount("ping")
print "( statbot ) ( ping ) ( counter ) ( # ", newCount, " )"
def garbageCleanup():
for gc in range (0, 3):
getMsg0()
print "( statbot ) ( cleanup ) garbage cleanup complete."
# generate and send statistical report every 100-300 cycles.
def sendBonk():
print "( statbot ) ( bonk ) generating statistical report."
botID = str(getBotID())
botID = botID.strip("\n")
print "( statbot ) ( bonk ) ( bot ID ) ", botID
file = "statbot/statbot_PONG_dump.dat"
if not os.path.isfile(file):
print "( statbot ) ( bonk ) ( file ) ( ", file, " ) not found."
if os.path.isfile(file):
fastestPing = 999999
fastestPong = 999999
fastestTrip = 999999
longestPing = 0
longestPong = 0
longestTrip = 0
avgPing = 0
avgPong = 0
avgTrip = 0
totalTransitTime = 0
totalPingPongs = 0
with open(file) as fileobject:
for line in fileobject:
line = line.strip("\n")
columns = line.split(" ")
entries = len(columns)
#print "# of columns in bonk: " + str(entries)
if entries == 7 and str(botID) == str(columns[6]):
print "( statbot ) ( bonk ) ( entry ) ( ", botID, " ) ( ", columns[6], " )"
try:
iPinged = int(columns[4])
theyPonged = int(columns[2])
iBonked = int(columns[0])
except ValueError:
print "( statbot ) [ ERROR ] ( bonk ) ( not integer ) corrupt dump data."
#print iPinged, theyPonged, iBonked
outTime = theyPonged - iPinged
backTime = iBonked - theyPonged
roundTime = iBonked - iPinged
avgPing += outTime
avgPong += backTime
avgTrip += roundTime # figure this with totalTransitTime / totalPingPongs
totalTransitTime += roundTime
totalPingPongs += 1
if outTime < fastestPing:
fastestPing = outTime
if backTime < fastestPong:
fastestPong = backTime
if roundTime < fastestTrip:
fastestTrip = roundTime
if outTime > longestPing:
longestPing = outTime
if backTime > longestPong:
longestPong = backTime
if roundTime > longestTrip:
longestTrip = roundTime
fileobject.close()
if totalPingPongs > 0: # prevent division by zero error
avgTrip = avgTrip / totalPingPongs
avgPing = avgPing / totalPingPongs
avgPong = avgPong / totalPingPongs
print "( statbot ) ( bonk ) ( report ) ( fastestPing ) ", str(fastestPing)
print "( statbot ) ( bonk ) ( report ) ( fastestPong ) ", str(fastestPong)
print "( statbot ) ( bonk ) ( report ) ( fastestTrip ) ", str(fastestTrip)
print "( statbot ) ( bonk ) ( report ) ( longestPing ) ", str(longestPing)
print "( statbot ) ( bonk ) ( report ) ( longestPong ) ", str(longestPong)
print "( statbot ) ( bonk ) ( report ) ( longestTrip ) ", str(longestTrip)
print "( statbot ) ( bonk ) ( report ) ( avgPing ) ", str(avgPing)
print "( statbot ) ( bonk ) ( report ) ( avgPong ) ", str(avgPong)
print "( statbot ) ( bonk ) ( report ) ( avgTrip ) ", str(avgTrip)
print "( statbot ) ( bonk ) ( report ) ( totalTransitTime ) ", str(totalTransitTime)
print "( statbot ) ( bonk ) ( report ) ( totalPingPongs ) ", str(totalPingPongs)
sub = "BONK " + str(botID)
msg = "fastestPing " + str(fastestPing) + "\n"
msg += "fastestPong " + str(fastestPong) + "\n"
msg += "fastestTrip " + str(fastestTrip) + "\n"
msg += "longestPing " + str(longestPing) + "\n"
msg += "longestPong " + str(longestPong) + "\n"
msg += "longestTrip " + str(longestTrip) + "\n"
msg += "avgPing " + str(avgPing) + "\n"
msg += "avgPong " + str(avgPong) + "\n"
msg += "avgTrip " + str(avgTrip) + "\n"
msg += "totalTransitTime " + str(totalTransitTime) + "\n"
msg += "totalPingPongs " + str(totalPingPongs) + "\n"
print "( statbot ) ( bonk ) ( report ) generating message."
address = getAddress("stat_bonk", 4, 1)
print "( statbot ) ( bonk ) ( report ) ( address ) ", address
message = msg.encode('base64')
subject = sub.encode('base64')
ttl = 3600
try:
ackData = api.sendMessage(address, address, subject, message, 2, ttl)
print "( statbot ) ( bonk ) ( report ) ( message ) ( status ) ", api.getStatus(ackData)
except:
print "( statbot ) ( bonk ) ( report ) ( message ) ( api ) API Error."
newCount = pingPongCount("bonk")
print "( statbot ) ( bonk ) ( report ) ( message ) ( # ", newCount, " )"
def run_statbot():
try:
apiTest()
print "( statbot ) ( run bot ) ( api test ) ( success ) API responds. continuing."
except:
print "( statbot ) ( run bot ) ( api test ) ( failure ) API unresponsive. exiting."
sys.exit()
if len(sys.argv) == 2 and "newMessage" == sys.argv[1]:
getMsg0()
bonk = random.randrange(0, 334)
if bonk == 333:
print "( statbot ) ( bonk ) ( random ) initiated."
sendBonk()
print "( statbot ) ( single ) ( done ) single linear run complete."
if len(sys.argv) == 2:
while "run" in sys.argv[1]:
try:
os.system('cls' if os.name == 'nt' else 'clear')
except:
print "( statbot ) ( run ) ( reset ) command not available."
pause = random.randrange(900, 1800)
print "( statbot ) ( run ) ( random ) ping in ( ", str(pause), " ) seconds."
for seconds in range (0, pause):
wait(1)
sys.stdout.write("\r( statbot ) ( run ) ( wait ) ==> " + str(seconds) + " ")
sys.stdout.flush()
print ""
sendPing()
if len(sys.argv) == 2:
if sys.argv[1] == "ping":
sendPing()
if sys.argv[1] == "bonk":
sendBonk()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment