# -*- coding: utf-8 -*- from __future__ import print_function import willie import json import shelve import time import urllib2 from ffpb import ffpb_fetch_stats, get_alfred_data, pretty_date highscores = None def setup(bot): """Called by willie upon loading this plugin.""" 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): """Called by willie upon loading this plugin.""" global highscores # store highscores if not highscores is None: highscores.sync() highscores.close() highscores = None @willie.module.interval(15) 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})' 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') def ffpb_status(bot, trigger): """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 bot.say('Es sind {0} Knoten und ca. {1} Clients online.'.format( stats["nodes_active"], stats["clients"])) @willie.module.commands('batcave-status') def ffpb_batcave_status(bot, trigger): """State as given by BATCAVE.""" status = json.loads(urllib2.urlopen('http://[fdca:ffee:ff12:a255::253]:8888/status').read()) bot.say('Status: ' + str(json.dumps(status))[1:-1]) @willie.module.commands('highscore') def ffpb_highscore(bot, trigger): """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') 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)) @willie.module.commands('providers') def ffpb_providers(bot, trigger): """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) top5 = providers[:5] top5 = ['{0} ({1:.0f}%)'.format(x['name'], x['percentage']) for x in top5] bot.say('Unsere Top 5 Provider: ' + ', '.join(top5))