#!/usr/bin/python from __future__ import print_function from copy import deepcopy import io import json import socket import subprocess import time import string import StringIO 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: testdata = subprocess.check_output([self.batadv_vis, '-f', 'jsondoc']) except Exception as err: raise Exception("batadv-vis not found or incompatible: " + str(err)) try: check = json.loads(testdata) except Exception as err: raise Exception("batadv-vis does not return valid JSON data: " + str(err)) return True def mac2id(self, mac): """Derives a nodeid from the given MAC address.""" temp = str(mac.lower().replace(':', '')) # temp = temp[0] + temp[1].translate(self.mactranslation) + temp[2:] return temp def fetch(self, batadv_dump=None, include_rawdata=False): """Fetches the current data from batadv-vis and returns it.""" data = { } ts = 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 not batadv_dump is None: jsondata = json.dumps(batmandata, ensure_ascii=False) f = io.open(batadv_dump, 'w') f.write(rawdata) f.close() # parse raw data, convert all MAC into nodeid for item in batmandata['vis']: itemid = self.mac2id(item['primary']) aliases = [] if 'secondary' in item: for mac in item['secondary']: aliases.append(self.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'])) neighbours[neighbour['neighbor']] = float(neighbour['metric']) # construct dict entry as expected by BATCAVE data[itemid] = { 'aliases': aliases, 'neighbours': neighbours, 'clients': [ x for x in item['clients'] ] if 'clients' in item else [], '__UPDATED__': { 'batadv': ts, }, '__RAW__': { 'batadv': { itemid: item, } }, } return data # standalone test mode if __name__ == "__main__": b = BatmanParser() try: b.sanitycheck() except Exception as err: print('SANITY-CHECK failed:', str(err)) import sys sys.exit(1) data = b.fetch() print(json.dumps(data))