ffpb_netstatus.py 6.0 KB

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