|
@@ -12,141 +12,160 @@ from ffpb import ffpb_fetch_stats, get_alfred_data, pretty_date
|
|
highscores = None
|
|
highscores = None
|
|
|
|
|
|
def setup(bot):
|
|
def setup(bot):
|
|
- global highscores
|
|
|
|
|
|
+ """Called by willie upon loading this plugin."""
|
|
|
|
|
|
- # load highscores from disk
|
|
|
|
- highscores = shelve.open('highscoredata', writeback=True)
|
|
|
|
- if not 'nodes' in highscores:
|
|
|
|
- highscores['nodes'] = 0
|
|
|
|
- highscores['nodes_ts'] = time.time()
|
|
|
|
- if not 'clients' in highscores:
|
|
|
|
- highscores['clients'] = 0
|
|
|
|
- highscores['clients_ts'] = time.time()
|
|
|
|
|
|
+ global highscores
|
|
|
|
+
|
|
|
|
+ # load highscores from disk
|
|
|
|
+ highscores = shelve.open('highscoredata', writeback=True)
|
|
|
|
+ if not 'nodes' in highscores:
|
|
|
|
+ highscores['nodes'] = 0
|
|
|
|
+ highscores['nodes_ts'] = time.time()
|
|
|
|
+ if not 'clients' in highscores:
|
|
|
|
+ highscores['clients'] = 0
|
|
|
|
+ highscores['clients_ts'] = time.time()
|
|
|
|
|
|
def shutdown(bot):
|
|
def shutdown(bot):
|
|
- global highscores
|
|
|
|
|
|
+ """Called by willie upon loading this plugin."""
|
|
|
|
+
|
|
|
|
+ global highscores
|
|
|
|
|
|
- # store highscores
|
|
|
|
- if not highscores is None:
|
|
|
|
- highscores.sync()
|
|
|
|
- highscores.close()
|
|
|
|
- highscores = None
|
|
|
|
|
|
+ # store highscores
|
|
|
|
+ if not highscores is None:
|
|
|
|
+ highscores.sync()
|
|
|
|
+ highscores.close()
|
|
|
|
+ highscores = None
|
|
|
|
|
|
@willie.module.interval(15)
|
|
@willie.module.interval(15)
|
|
def ffpb_get_stats(bot):
|
|
def ffpb_get_stats(bot):
|
|
- """Fetch current statistics, if the highscore changes signal this."""
|
|
|
|
-
|
|
|
|
- (nodes_active, nodes_total, clients_count) = ffpb_fetch_stats(bot, 'http://map.paderborn.freifunk.net/nodes.json', 'ffpb_stats')
|
|
|
|
-
|
|
|
|
- highscore_changed = False
|
|
|
|
- if nodes_active > highscores['nodes']:
|
|
|
|
- highscores['nodes'] = nodes_active
|
|
|
|
- highscores['nodes_ts'] = time.time()
|
|
|
|
- highscore_changed = True
|
|
|
|
-
|
|
|
|
- if clients_count > highscores['clients']:
|
|
|
|
- highscores['clients'] = clients_count
|
|
|
|
- highscores['clients_ts'] = time.time()
|
|
|
|
- highscore_changed = True
|
|
|
|
-
|
|
|
|
- if highscore_changed:
|
|
|
|
- print('HIGHSCORE changed: {0} nodes ({1}), {2} clients ({3})'.format(highscores['nodes'], highscores['nodes_ts'], highscores['clients'], highscores['clients_ts']))
|
|
|
|
- if not (bot.config.ffpb.msg_target is None):
|
|
|
|
- action_msg = 'notiert sich den neuen Highscore: {0} Knoten ({1}), {2} Clients ({3})'.format(highscores['nodes'], pretty_date(int(highscores['nodes_ts'])), highscores['clients'], pretty_date(int(highscores['clients_ts'])))
|
|
|
|
- action_target = bot.config.ffpb.msg_target
|
|
|
|
- if (not bot.config.ffpb.msg_target_public is None):
|
|
|
|
- action_target = bot.config.ffpb.msg_target_public
|
|
|
|
- bot.msg(action_target, '\x01ACTION %s\x01' % action_msg)
|
|
|
|
|
|
+ """Fetch current statistics, if the highscore changes signal this."""
|
|
|
|
+
|
|
|
|
+ (nodes_active, nodes_total, clients_count) = \
|
|
|
|
+ ffpb_fetch_stats(bot, 'http://map.paderborn.freifunk.net/nodes.json', 'ffpb_stats')
|
|
|
|
+
|
|
|
|
+ highscore_changed = False
|
|
|
|
+ if nodes_active > highscores['nodes']:
|
|
|
|
+ highscores['nodes'] = nodes_active
|
|
|
|
+ highscores['nodes_ts'] = time.time()
|
|
|
|
+ highscore_changed = True
|
|
|
|
+
|
|
|
|
+ if clients_count > highscores['clients']:
|
|
|
|
+ highscores['clients'] = clients_count
|
|
|
|
+ highscores['clients_ts'] = time.time()
|
|
|
|
+ highscore_changed = True
|
|
|
|
+
|
|
|
|
+ if highscore_changed:
|
|
|
|
+ print('HIGHSCORE changed: {0} nodes ({1}), {2} clients ({3})'.format(
|
|
|
|
+ highscores['nodes'],
|
|
|
|
+ highscores['nodes_ts'],
|
|
|
|
+ highscores['clients'],
|
|
|
|
+ highscores['clients_ts'],
|
|
|
|
+ ))
|
|
|
|
+ if not bot.config.ffpb.msg_target is None:
|
|
|
|
+ action_msg = 'notiert sich den neuen Highscore: {0} Knoten ({1}), {2} Clients ({3})'
|
|
|
|
+
|
|
|
|
+ action_target = bot.config.ffpb.msg_target
|
|
|
|
+ if not bot.config.ffpb.msg_target_public is None:
|
|
|
|
+ action_target = bot.config.ffpb.msg_target_public
|
|
|
|
+
|
|
|
|
+ bot.msg(action_target, '\x01ACTION %s\x01' % action_msg.format(
|
|
|
|
+ highscores['nodes'], pretty_date(int(highscores['nodes_ts'])),
|
|
|
|
+ highscores['clients'], pretty_date(int(highscores['clients_ts'])),
|
|
|
|
+ ))
|
|
|
|
|
|
@willie.module.commands('status')
|
|
@willie.module.commands('status')
|
|
def ffpb_status(bot, trigger):
|
|
def ffpb_status(bot, trigger):
|
|
- """State of the network: count of nodes + clients"""
|
|
|
|
|
|
+ """State of the network: count of nodes + clients"""
|
|
|
|
|
|
- stats = bot.memory['ffpb_stats'] if 'ffpb_stats' in bot.memory else None
|
|
|
|
- if stats is None:
|
|
|
|
- bot.say('Uff, kein Plan wo der Zettel ist. Fragst du später nochmal?')
|
|
|
|
- return
|
|
|
|
|
|
+ stats = bot.memory['ffpb_stats'] if 'ffpb_stats' in bot.memory else None
|
|
|
|
+ if stats is None:
|
|
|
|
+ bot.say('Uff, kein Plan wo der Zettel ist. Fragst du später nochmal?')
|
|
|
|
+ return
|
|
|
|
|
|
- bot.say('Es sind {0} Knoten und ca. {1} Clients online.'.format(stats["nodes_active"], stats["clients"]))
|
|
|
|
|
|
+ bot.say('Es sind {0} Knoten und ca. {1} Clients online.'.format(stats["nodes_active"], stats["clients"]))
|
|
|
|
|
|
@willie.module.commands('highscore')
|
|
@willie.module.commands('highscore')
|
|
def ffpb_highscore(bot, trigger):
|
|
def ffpb_highscore(bot, trigger):
|
|
- bot.say('Highscore: {0} Knoten ({1}), {2} Clients ({3})'.format(
|
|
|
|
- highscores['nodes'], pretty_date(int(highscores['nodes_ts'])),
|
|
|
|
- highscores['clients'], pretty_date(int(highscores['clients_ts']))))
|
|
|
|
|
|
+ """Print current highscores (nodes + clients)."""
|
|
|
|
+
|
|
|
|
+ bot.say('Highscore: {0} Knoten ({1}), {2} Clients ({3})'.format(
|
|
|
|
+ highscores['nodes'], pretty_date(int(highscores['nodes_ts'])),
|
|
|
|
+ highscores['clients'], pretty_date(int(highscores['clients_ts']))))
|
|
|
|
|
|
@willie.module.commands('rollout-status')
|
|
@willie.module.commands('rollout-status')
|
|
def ffpb_rolloutstatus(bot, trigger):
|
|
def ffpb_rolloutstatus(bot, trigger):
|
|
- """Display statistic on how many nodes have installed the given firmware version."""
|
|
|
|
-
|
|
|
|
- # initialize results dictionary
|
|
|
|
- result = { }
|
|
|
|
- skipped = 0
|
|
|
|
-
|
|
|
|
- # inform users about changed command parameters
|
|
|
|
- if not trigger.group(2) is None:
|
|
|
|
- bot.reply('Dieses Kommando nimmt keinen Parameter mehr an.')
|
|
|
|
- return
|
|
|
|
-
|
|
|
|
- # get ALFRED data (and ensure it is current)
|
|
|
|
- alfred_data = get_alfred_data(bot, True)
|
|
|
|
- if alfred_data is None:
|
|
|
|
- bot.say('Ich habe irgendein Memo verpasst, sorry - bitte später nochmal fragen.')
|
|
|
|
- return
|
|
|
|
-
|
|
|
|
- # check each node in ALFRED data
|
|
|
|
- for nodeid in alfred_data:
|
|
|
|
- item = alfred_data[nodeid]
|
|
|
|
- if (not 'software' in item) or (not 'firmware' in item['software']) or (not 'autoupdater' in item['software']):
|
|
|
|
- skipped+=1
|
|
|
|
- continue
|
|
|
|
-
|
|
|
|
- release = item['software']['firmware']['release']
|
|
|
|
- branch = item['software']['autoupdater']['branch']
|
|
|
|
- enabled = item['software']['autoupdater']['enabled']
|
|
|
|
- if not release in result or result[release] is None:
|
|
|
|
- result[release] = { 'stable': None, 'testing': None }
|
|
|
|
- if not branch in result[release] or result[release][branch] is None:
|
|
|
|
- result[release][branch] = { 'auto': 0, 'manual': 0, 'total': 0 }
|
|
|
|
-
|
|
|
|
- result[release][branch]['total'] += 1
|
|
|
|
- mode = 'auto' if enabled else 'manual'
|
|
|
|
- result[release][branch][mode] += 1
|
|
|
|
-
|
|
|
|
- # respond to user
|
|
|
|
- releases = sorted([x for x in result])
|
|
|
|
- for release in releases:
|
|
|
|
- output = 'Rollout von \'{0}\':'.format(release)
|
|
|
|
- branches = sorted([x for x in result[release]])
|
|
|
|
- first = True
|
|
|
|
- for branch in branches:
|
|
|
|
- item = result[release][branch]
|
|
|
|
- if item is None: continue
|
|
|
|
-
|
|
|
|
- if not first:
|
|
|
|
- output += ','
|
|
|
|
- first = False
|
|
|
|
-
|
|
|
|
- total = item['total']
|
|
|
|
- auto_count = item['auto']
|
|
|
|
- manual_count = item['manual']
|
|
|
|
-
|
|
|
|
- output += ' {2} {0}'.format(branch, total, auto_count, manual_count)
|
|
|
|
- if manual_count > 0:
|
|
|
|
- output += ' (+{3} manuell)'.format(branch, total, auto_count, manual_count)
|
|
|
|
-
|
|
|
|
- bot.say(output)
|
|
|
|
-
|
|
|
|
- # output count of nodes for which the autoupdater's branch and/or
|
|
|
|
- # firmware version could not be retrieved
|
|
|
|
- if skipped > 0:
|
|
|
|
- bot.say('plus {0} Knoten deren Status gerade nicht abfragbar war'.format(skipped))
|
|
|
|
|
|
+ """Display statistic on how many nodes have installed the given firmware version."""
|
|
|
|
+
|
|
|
|
+ # initialize results dictionary
|
|
|
|
+ result = {}
|
|
|
|
+ skipped = 0
|
|
|
|
+
|
|
|
|
+ # inform users about changed command parameters
|
|
|
|
+ if not trigger.group(2) is None:
|
|
|
|
+ bot.reply('Dieses Kommando nimmt keinen Parameter mehr an.')
|
|
|
|
+ return
|
|
|
|
+
|
|
|
|
+ # get ALFRED data (and ensure it is current)
|
|
|
|
+ alfred_data = get_alfred_data(bot, True)
|
|
|
|
+ if alfred_data is None:
|
|
|
|
+ bot.say('Ich habe irgendein Memo verpasst, sorry - bitte später nochmal fragen.')
|
|
|
|
+ return
|
|
|
|
+
|
|
|
|
+ # check each node in ALFRED data
|
|
|
|
+ for nodeid in alfred_data:
|
|
|
|
+ item = alfred_data[nodeid]
|
|
|
|
+ if (not 'software' in item) or (not 'firmware' in item['software']) or (not 'autoupdater' in item['software']):
|
|
|
|
+ skipped += 1
|
|
|
|
+ continue
|
|
|
|
+
|
|
|
|
+ release = item['software']['firmware']['release']
|
|
|
|
+ branch = item['software']['autoupdater']['branch']
|
|
|
|
+ enabled = item['software']['autoupdater']['enabled']
|
|
|
|
+ if not release in result or result[release] is None:
|
|
|
|
+ result[release] = {'stable': None, 'testing': None,}
|
|
|
|
+ if not branch in result[release] or result[release][branch] is None:
|
|
|
|
+ result[release][branch] = {'auto': 0, 'manual': 0, 'total': 0,}
|
|
|
|
+
|
|
|
|
+ result[release][branch]['total'] += 1
|
|
|
|
+ mode = 'auto' if enabled else 'manual'
|
|
|
|
+ result[release][branch][mode] += 1
|
|
|
|
+
|
|
|
|
+ # respond to user
|
|
|
|
+ releases = sorted([x for x in result])
|
|
|
|
+ for release in releases:
|
|
|
|
+ output = 'Rollout von \'{0}\':'.format(release)
|
|
|
|
+ branches = sorted([x for x in result[release]])
|
|
|
|
+ first = True
|
|
|
|
+ for branch in branches:
|
|
|
|
+ item = result[release][branch]
|
|
|
|
+ if item is None:
|
|
|
|
+ continue
|
|
|
|
+
|
|
|
|
+ if not first:
|
|
|
|
+ output += ','
|
|
|
|
+ first = False
|
|
|
|
+
|
|
|
|
+ total = item['total']
|
|
|
|
+ auto_count = item['auto']
|
|
|
|
+ manual_count = item['manual']
|
|
|
|
+
|
|
|
|
+ output += ' {2} {0}'.format(branch, total, auto_count, manual_count)
|
|
|
|
+ if manual_count > 0:
|
|
|
|
+ output += ' (+{3} manuell)'.format(branch, total, auto_count, manual_count)
|
|
|
|
+
|
|
|
|
+ bot.say(output)
|
|
|
|
+
|
|
|
|
+ # output count of nodes for which the autoupdater's branch and/or
|
|
|
|
+ # firmware version could not be retrieved
|
|
|
|
+ if skipped > 0:
|
|
|
|
+ bot.say('plus {0} Knoten deren Status gerade nicht abfragbar war'.format(skipped))
|
|
|
|
|
|
@willie.module.commands('providers')
|
|
@willie.module.commands('providers')
|
|
def ffpb_providers(bot, trigger):
|
|
def ffpb_providers(bot, trigger):
|
|
- """Fetch the top 5 providers from BATCAVE."""
|
|
|
|
|
|
+ """Fetch the top 5 providers from BATCAVE."""
|
|
|
|
|
|
- providers = json.load(urllib2.urlopen('http://[fdca:ffee:ff12:a255::253]:8888/providers?format=json'))
|
|
|
|
- providers.sort(key=lambda x: x['count'], reverse=True)
|
|
|
|
- bot.say('Unsere Top 5 Provider: ' + ', '.join(['{0} ({1:.0f}%)'.format(x['name'], x['percentage']) for x in providers[:5]]))
|
|
|
|
|
|
+ providers = json.load(urllib2.urlopen('http://[fdca:ffee:ff12:a255::253]:8888/providers?format=json'))
|
|
|
|
+ providers.sort(key=lambda x: x['count'], reverse=True)
|
|
|
|
|
|
|
|
+ top5 = ['{0} ({1:.0f}%)'.format(x['name'], x['percentage']) for x in providers[:5]]
|
|
|
|
+ bot.say('Unsere Top 5 Provider: ' + ', '.join(top5))
|