Browse Source

ffpb: use BATCAVE for data retrieval

Helge Jung 9 years ago
parent
commit
baba15ec87
3 changed files with 41 additions and 119 deletions
  1. 20 101
      modules/ffpb.py
  2. 19 15
      modules/ffpb_netstatus.py
  3. 2 3
      modules/ffpb_nodeinfo.py

+ 20 - 101
modules/ffpb.py

@@ -34,7 +34,7 @@ peers_repo = None
 
 nodeaccess = None
 
-alfred_method = None
+__batcave = None
 
 ffpb_resolver = dns.resolver.Resolver()
 ffpb_resolver.nameservers = ['10.132.254.53']
@@ -88,7 +88,7 @@ class ThreadingTCPServer(SocketServer.ThreadingMixIn, SocketServer.TCPServer):
 def setup(bot):
     """Called by willie upon loading this plugin."""
 
-    global msgserver, peers_repo, alfred_method, nodeaccess
+    global __batcave, msgserver, peers_repo, nodeaccess
 
     # signal begin of setup routine
     bot.memory['ffpb_in_setup'] = True
@@ -128,13 +128,8 @@ def setup(bot):
         msgserver_thread.daemon = True
         msgserver_thread.start()
 
-    # initially fetch ALFRED data
-    alfred_method = bot.config.ffpb.alfred_method
-    if not 'alfred_data' in bot.memory:
-        bot.memory['alfred_data'] = {}
-    if not 'alfred_update' in bot.memory:
-        bot.memory['alfred_update'] = datetime(1970, 1, 1, 23, 42)
-    ffpb_updatealfred(bot)
+    # initialize BATCAVE
+    __batcave = BatcaveClient(bot.config.ffpb.batcave_url)
 
     # signal end of setup routine
     bot.memory['ffpb_in_setup'] = False
@@ -375,7 +370,7 @@ def ffpb_ensurenodeid(nodedata):
     return result
 
 
-def ffpb_findnode(name, alfred_data=None, allow_fuzzymatching=True):
+def ffpb_findnode(name, allow_fuzzymatching=True):
     """helper: try to identify the node the user meant by the given name"""
 
     # no name, no node
@@ -390,27 +385,16 @@ def ffpb_findnode(name, alfred_data=None, allow_fuzzymatching=True):
         name = name[1:-1]
         allow_fuzzymatching = False
 
-    names = {}
-
-    if not alfred_data is None:
-        # try to match MAC
-        m = re.search("^([0-9a-fA-F][0-9a-fA-F]:){5}[0-9a-fA-F][0-9a-fA-F]$", name)
-        if not m is None:
-            mac = m.group(0).lower()
-            if mac in alfred_data:
-                return ffpb_ensurenodeid(alfred_data[mac])
-
-            # try to find alias MAC in ALFRED data
-            for nodeid in alfred_data:
-                node = alfred_data[nodeid]
-                if "network" in node:
-                    if node["network"].get("mac", "").lower() == mac:
-                        return ffpb_ensurenodeid(node)
-                    if "mesh_interfaces" in node["network"]:
-                        for mim in node["network"]["mesh_interfaces"]:
-                            if mim.lower() == mac:
-                                return ffpb_ensurenodeid(node)
+    # try to match MAC
+    m = re.search("^([0-9a-fA-F][0-9a-fA-F]:){5}[0-9a-fA-F][0-9a-fA-F]$", name)
+    if not m is None:
+        mac = m.group(0).lower()
+        node = __batcave.find_node_by_mac(mac)
 
+        if node is not None:
+            return node
+
+        else:
             nodeid = mac.replace(':', '').lower()
             return {
                 'nodeid': nodeid,
@@ -424,15 +408,10 @@ def ffpb_findnode(name, alfred_data=None, allow_fuzzymatching=True):
                 },
             }
 
-        # look through the ALFRED peers
-        for nodeid in alfred_data:
-            node = alfred_data[nodeid]
-            if 'hostname' in node:
-                h = node['hostname']
-                if h.lower() == name.lower():
-                    return node
-                else:
-                    names[h] = nodeid
+    # try to find by NAME
+    node = __batcave.find_node_by_name(name, fuzzymatch=allow_fuzzymatching)
+    if node is not None:
+        return node
 
     # not found in ALFRED data -> try peers_repo
     if not peers_repo is None:
@@ -466,18 +445,6 @@ def ffpb_findnode(name, alfred_data=None, allow_fuzzymatching=True):
                 },
             }
 
-    # do a similar name lookup in the ALFRED data
-    if allow_fuzzymatching and not alfred_data is None:
-        allnames = [x for x in names]
-        possibilities = difflib.get_close_matches(name, allnames, cutoff=0.75)
-        print('findnode: Fuzzy matching \'{0}\' got {1} entries: {2}'.format(
-            name,
-            len(possibilities), ', '.join(possibilities))
-        )
-        if len(possibilities) == 1:
-            # if we got exactly one candidate that might be it
-            return ffpb_ensurenodeid(alfred_data[names[possibilities[0]]])
-
     # none of the above was able to identify the requested node
     return None
 
@@ -490,14 +457,7 @@ def ffpb_findnode_from_botparam(bot, name, ensure_recent_alfreddata=True):
             bot.reply("Grün.")
         return None
 
-    alfred_data = get_alfred_data(bot, ensure_recent_alfreddata)
-    if ensure_recent_alfreddata and alfred_data is None:
-        if not bot is None:
-            bot.say('Informationen sind ausverkauft bzw. veraltet, ' +
-                    'daher sage ich mal lieber nichts zu \'' + name + '\'.')
-        return None
-
-    node = ffpb_findnode(name, alfred_data)
+    node = ffpb_findnode(name)
     if node is None:
         if not bot is None:
             bot.say("Kein Plan wer oder was mit '" + name + "' gemeint ist :(")
@@ -600,47 +560,6 @@ def ffpb_updatealfred(bot):
             bot.msg(action_target, '\x01ACTION %s\x01' % action_msg)
 
 
-def get_alfred_data(bot, ensure_not_outdated=True):
-    """
-    Retrieves the stored alfred_data and optionally checks
-    that it has been updated no more than 5 minutes ago.
-    """
-
-    alfred_data = bot.memory.get('alfred_data', None)
-    alfred_update = bot.memory.get('alfred_update', 0)
-
-    if alfred_data is None:
-        return None
-
-    if ensure_not_outdated:
-        timeout = datetime.now() - timedelta(minutes=5)
-        is_outdated = timeout > alfred_update
-        if is_outdated:
-            return None
-
-    return alfred_data
-
-
-def ffpb_get_batcave_nodefield(nodeid, field):
-    """Query the given field for the given nodeid from the BATCAVE."""
-
-    raw_data = None
-    try:
-        # query BATCAVE for node's field
-        raw_data = urllib2.urlopen('http://[fdca:ffee:ff12:a255::253]:8888/node/{0}/{1}'.format(nodeid, field))
-    except urllib2.URLError as err:
-        print('Failed to contact BATCAVE for \'{0}\'->\'{1}\': {2}'.format(
-              nodeid, field, err))
-        return None
-
-    try:
-        return json.load(raw_data)
-
-    except ValueError as err:
-        print('Could not parse BATCAVE\'s response as JSON for \'{0}\'->\'{1}\':'.format(nodeid, field, err))
-        return None
-
-
 @willie.module.commands('debug-alfred')
 def ffpb_debug_alfred(bot, trigger):
     """Show statistics of available ALFRED data."""
@@ -839,7 +758,7 @@ def ffpb_nodemesh(bot, trigger):
         return
 
     # query BATCAVE for node's neighbours (result is a list of MAC addresses)
-    cave_result = ffpb_get_batcave_nodefield(nodeid, 'neighbours')
+    cave_result = node['neighbours']
     if cave_result is None:
         msg = 'Hm, scheinbar liegen zu \'{0}\' keine Daten vor. ' + \
               'Klingt komisch, ist aber so.'

+ 19 - 15
modules/ffpb_netstatus.py

@@ -7,15 +7,19 @@ import shelve
 import time
 import urllib2
 
-from ffpb import ffpb_fetch_stats, get_alfred_data, pretty_date
+from ffpb import pretty_date
+from batcave import BatcaveClient
 
+__batcave = None
 highscores = None
 
 
 def setup(bot):
     """Called by willie upon loading this plugin."""
 
-    global highscores
+    global __batcave, highscores
+
+    __batcave = BatcaveClient(bot.config.ffpb.batcave_url)
 
     # load highscores from disk
     highscores = shelve.open('highscoredata', writeback=True)
@@ -43,8 +47,13 @@ def shutdown(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')
+    status = __batcave.get_status()
+    if status is None:
+        bot.say('Yikes, offenbar ist das allwissende Auge gerade schlafen.')
+        return
+
+    (nodes_active, clients_count) = \
+        (status['nodes_active'], status['clients_unique'])
 
     highscore_changed = False
     if nodes_active > highscores['nodes']:
@@ -81,20 +90,20 @@ def ffpb_get_stats(bot):
 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
+    stats = __batcave.get_status()
     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"]))
+            stats["nodes_active"], stats["clients_unique"]))
 
 
 @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())
+    status = __batcave.get_status()
     bot.say('Status: ' + str(json.dumps(status))[1:-1])
 
 
@@ -120,15 +129,10 @@ def ffpb_rolloutstatus(bot, trigger):
         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
+    nodes = __batcave.get_nodes()
 
     # check each node in ALFRED data
-    for nodeid in alfred_data:
-        item = alfred_data[nodeid]
+    for item in nodes:
         if (not 'software' in item) or (not 'firmware' in item['software']) or (not 'autoupdater' in item['software']):
             skipped += 1
             continue
@@ -180,7 +184,7 @@ def ffpb_rolloutstatus(bot, trigger):
 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 = __batcave.get_providers()
     providers.sort(key=lambda x: x['count'], reverse=True)
 
     top5 = providers[:5]

+ 2 - 3
modules/ffpb_nodeinfo.py

@@ -5,7 +5,6 @@ import willie
 
 from ffpb import \
     ffpb_findnode_from_botparam, \
-    ffpb_get_batcave_nodefield, \
     mac2ipv6, playitsafe, pretty_date
 
 
@@ -98,7 +97,7 @@ def ffpb_peerinfo(bot, trigger):
             info_uptime = ' up {0}m'.format(minutes)
 
     info_clients = ""
-    clientcount = ffpb_get_batcave_nodefield(info_id, 'clientcount')
+    clientcount = node.get('clientcount')
     if not clientcount is None:
         clientcount = int(clientcount)
         info_clients = ' clients={0}'.format(clientcount)
@@ -118,7 +117,7 @@ def ffpb_lastseen(bot, trigger):
     if node is None:
         return
 
-    last_seen = ffpb_get_batcave_nodefield(node['node_id'], '__UPDATED__')
+    last_seen = node.get('__UPDATED__')
     a_value = int(last_seen['alfred']) if (not last_seen is None) and 'alfred' in last_seen else None
     a_delta = time.time() - a_value if not a_value is None else None
     b_value = int(last_seen['batadv']) if (not last_seen is None) and 'batadv' in last_seen else None