#!/usr/bin/python # -*- coding: utf-8 -*- from __future__ import print_function import io import json import string import subprocess import time import ffstatus from .exceptions import SanityCheckError class BatmanParser: batadv_vis = 'batadv-vis' mactranslation = string.maketrans('2367abef', '014589cd') def __str__(self): return 'BatmanParser \'{0}\''.format(self.batadv_vis) def sanitycheck(self): """Checks that batadv-vis is executable and gives sane output.""" testdata = None try: cmd = [self.batadv_vis, '-f', 'jsondoc'] testdata = subprocess.check_output(cmd) except Exception as err: raise SanityCheckError( self, "batadv-vis not found or incompatible", err) try: json.loads(testdata) except Exception as err: raise SanityCheckError( self, "batadv-vis does not return valid JSON data", err) return True def fetch(self, batadv_dump=None): """Fetches the current data from batadv-vis.""" data = {} timestamp = int(time.time()) # call batadv-vis and parse output as JSON rawdata = subprocess.check_output([self.batadv_vis, '-f', 'jsondoc']) batmandata = json.loads(rawdata) # dump raw data into file if requested if batadv_dump is not None: dumpfile = io.open(batadv_dump, 'w') dumpfile.write(rawdata) dumpfile.close() # parse raw data, convert all MAC into nodeid for item in batmandata['vis']: itemid = ffstatus.mac2id(item['primary']) aliases = [] if 'secondary' in item: for mac in item['secondary']: aliases.append(ffstatus.mac2id(mac)) neighbours = {} if 'neighbors' in item: for neighbour in item['neighbors']: #if neighbour['router'] != item['primary']: # print('node {0}\'s neighbor {1} has unexpected router {2}'.format(itemid, neighbour['neighbor'], neighbour['router'])) metric = float(neighbour['metric']) neighbours[neighbour['neighbor']] = metric # construct dict entry as expected by BATCAVE data[itemid] = { 'aliases': aliases, 'neighbours': neighbours, 'clients': [x for x in item.get('clients', [])], '__UPDATED__': {'batadv': timestamp}, '__RAW__': {'batadv': {itemid: item}}, } return data # standalone test mode if __name__ == "__main__": parser = BatmanParser() try: parser.sanitycheck() except SanityCheckError as err: print('SANITY-CHECK failed:', str(err)) import sys sys.exit(1) bdata = parser.fetch() print(json.dumps(bdata))