ffpb_netstatus.py 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. # -*- coding: utf-8 -*-
  2. from __future__ import print_function
  3. import willie
  4. import json
  5. import shelve
  6. import time
  7. import urllib2
  8. from ffpb import ffpb_fetch_stats, get_alfred_data, pretty_date
  9. highscores = None
  10. def setup(bot):
  11. """Called by willie upon loading this plugin."""
  12. global highscores
  13. # load highscores from disk
  14. highscores = shelve.open('highscoredata', writeback=True)
  15. if not 'nodes' in highscores:
  16. highscores['nodes'] = 0
  17. highscores['nodes_ts'] = time.time()
  18. if not 'clients' in highscores:
  19. highscores['clients'] = 0
  20. highscores['clients_ts'] = time.time()
  21. def shutdown(bot):
  22. """Called by willie upon loading this plugin."""
  23. global highscores
  24. # store highscores
  25. if not highscores is None:
  26. highscores.sync()
  27. highscores.close()
  28. highscores = None
  29. @willie.module.interval(15)
  30. def ffpb_get_stats(bot):
  31. """Fetch current statistics, if the highscore changes signal this."""
  32. (nodes_active, nodes_total, clients_count) = \
  33. ffpb_fetch_stats(bot, 'http://map.paderborn.freifunk.net/nodes.json', 'ffpb_stats')
  34. highscore_changed = False
  35. if nodes_active > highscores['nodes']:
  36. highscores['nodes'] = nodes_active
  37. highscores['nodes_ts'] = time.time()
  38. highscore_changed = True
  39. if clients_count > highscores['clients']:
  40. highscores['clients'] = clients_count
  41. highscores['clients_ts'] = time.time()
  42. highscore_changed = True
  43. if highscore_changed:
  44. print('HIGHSCORE changed: {0} nodes ({1}), {2} clients ({3})'.format(
  45. highscores['nodes'],
  46. highscores['nodes_ts'],
  47. highscores['clients'],
  48. highscores['clients_ts'],
  49. ))
  50. if not bot.config.ffpb.msg_target is None:
  51. action_msg = 'notiert sich den neuen Highscore: {0} Knoten ({1}), {2} Clients ({3})'
  52. action_target = bot.config.ffpb.msg_target
  53. if not bot.config.ffpb.msg_target_public is None:
  54. action_target = bot.config.ffpb.msg_target_public
  55. bot.msg(action_target, '\x01ACTION %s\x01' % action_msg.format(
  56. highscores['nodes'], pretty_date(int(highscores['nodes_ts'])),
  57. highscores['clients'], pretty_date(int(highscores['clients_ts'])),
  58. ))
  59. @willie.module.commands('status')
  60. def ffpb_status(bot, trigger):
  61. """State of the network: count of nodes + clients"""
  62. stats = bot.memory['ffpb_stats'] if 'ffpb_stats' in bot.memory else None
  63. if stats is None:
  64. bot.say('Uff, kein Plan wo der Zettel ist. Fragst du später nochmal?')
  65. return
  66. bot.say('Es sind {0} Knoten und ca. {1} Clients online.'.format(stats["nodes_active"], stats["clients"]))
  67. @willie.module.commands('highscore')
  68. def ffpb_highscore(bot, trigger):
  69. """Print current highscores (nodes + clients)."""
  70. bot.say('Highscore: {0} Knoten ({1}), {2} Clients ({3})'.format(
  71. highscores['nodes'], pretty_date(int(highscores['nodes_ts'])),
  72. highscores['clients'], pretty_date(int(highscores['clients_ts']))))
  73. @willie.module.commands('rollout-status')
  74. def ffpb_rolloutstatus(bot, trigger):
  75. """Display statistic on how many nodes have installed the given firmware version."""
  76. # initialize results dictionary
  77. result = {}
  78. skipped = 0
  79. # inform users about changed command parameters
  80. if not trigger.group(2) is None:
  81. bot.reply('Dieses Kommando nimmt keinen Parameter mehr an.')
  82. return
  83. # get ALFRED data (and ensure it is current)
  84. alfred_data = get_alfred_data(bot, True)
  85. if alfred_data is None:
  86. bot.say('Ich habe irgendein Memo verpasst, sorry - bitte später nochmal fragen.')
  87. return
  88. # check each node in ALFRED data
  89. for nodeid in alfred_data:
  90. item = alfred_data[nodeid]
  91. if (not 'software' in item) or (not 'firmware' in item['software']) or (not 'autoupdater' in item['software']):
  92. skipped += 1
  93. continue
  94. release = item['software']['firmware']['release']
  95. branch = item['software']['autoupdater']['branch']
  96. enabled = item['software']['autoupdater']['enabled']
  97. if not release in result or result[release] is None:
  98. result[release] = {'stable': None, 'testing': None,}
  99. if not branch in result[release] or result[release][branch] is None:
  100. result[release][branch] = {'auto': 0, 'manual': 0, 'total': 0,}
  101. result[release][branch]['total'] += 1
  102. mode = 'auto' if enabled else 'manual'
  103. result[release][branch][mode] += 1
  104. # respond to user
  105. releases = sorted([x for x in result])
  106. for release in releases:
  107. output = 'Rollout von \'{0}\':'.format(release)
  108. branches = sorted([x for x in result[release]])
  109. first = True
  110. for branch in branches:
  111. item = result[release][branch]
  112. if item is None:
  113. continue
  114. if not first:
  115. output += ','
  116. first = False
  117. total = item['total']
  118. auto_count = item['auto']
  119. manual_count = item['manual']
  120. output += ' {2} {0}'.format(branch, total, auto_count, manual_count)
  121. if manual_count > 0:
  122. output += ' (+{3} manuell)'.format(branch, total, auto_count, manual_count)
  123. bot.say(output)
  124. # output count of nodes for which the autoupdater's branch and/or
  125. # firmware version could not be retrieved
  126. if skipped > 0:
  127. bot.say('plus {0} Knoten deren Status gerade nicht abfragbar war'.format(skipped))
  128. @willie.module.commands('providers')
  129. def ffpb_providers(bot, trigger):
  130. """Fetch the top 5 providers from BATCAVE."""
  131. providers = json.load(urllib2.urlopen('http://[fdca:ffee:ff12:a255::253]:8888/providers?format=json'))
  132. providers.sort(key=lambda x: x['count'], reverse=True)
  133. top5 = ['{0} ({1:.0f}%)'.format(x['name'], x['percentage']) for x in providers[:5]]
  134. bot.say('Unsere Top 5 Provider: ' + ', '.join(top5))