Syncleus/apex

View on GitHub
src/apex/plugins/apexparadigm/__init__.py

Summary

Maintainability
F
1 wk
Test Coverage
#!/usr/bin/env python
# -*- coding: utf-8 -*-

# These imports are for python3 compatibility inside python2
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

import copy
import re

import apex.routing

__author__ = 'Jeffrey Phillips Freeman (WI2ARD)'
__maintainer__ = 'Jeffrey Phillips Freeman (WI2ARD)'
__email__ = 'jeffrey.freeman@syncleus.com'
__license__ = 'Apache License, Version 2.0'
__copyright__ = 'Copyright 2016, Syncleus, Inc. and contributors'
__credits__ = []
__version__ = '0.0.6'

plugin = None


def start(config, port_map, aprsis):
    global plugin
    plugin = ApexParadigmPlugin(config, port_map, aprsis)
    plugin.run()


def handle_packet(frame, recv_port, recv_port_name):
    plugin.handle_packet(frame, recv_port, recv_port_name)


def stop():
    plugin.stop()


class ApexParadigmPlugin(object):

    BAND_PATH_REGEX = re.compile(r'(\d{1,4})M(\d{0,3})')

    def __init__(self, config, port_map, aprsis):
        self.port_map = port_map
        self.aprsis = aprsis

    def __passive_digipeat(self, frame, recv_port, recv_port_name):
        # can't digipeat packets if we are in the expended path
        if apex.routing.has_seen(self.port_map, frame):
            return

        for hop_index in range(0, len(frame['path'])):
            hop = frame['path'][hop_index]
            if not apex.routing.is_hop_consumed(hop):
                split_hop = hop.split('-')
                node = split_hop[0].upper()
                if len(split_hop) >= 2 and split_hop[1]:
                    ssid = int(split_hop[1])
                else:
                    ssid = 0

                band_path = None
                band_path_net = None
                band_match = self.BAND_PATH_REGEX.match(node)
                if band_match is not None:
                    band_path = band_match.group(1)
                    band_path_net = band_match.group(2)

                for port_name in self.port_map.keys():
                    port = self.port_map[port_name]
                    split_port_identifier = port['identifier'].split('-')
                    port_callsign = split_port_identifier[0].upper()
                    if len(split_port_identifier) >= 2 and split_port_identifier[1]:
                        port_ssid = int(split_port_identifier[1])
                    else:
                        port_ssid = 0

                    if band_path:
                        if band_path_net:
                            if node == port['net']:
                                frame['path'] = frame['path'][:hop_index] + [recv_port['identifier'] + '*'] +\
                                                [hop + '*'] + frame['path'][hop_index+1:]
                                port['tnc'].write(frame, port['tnc_port'])
                                self.aprsis.write(frame)
                                return
                        else:
                            if port['net'].startswith(node):
                                frame['path'] = frame['path'][:hop_index] + [recv_port['identifier'] + '*'] +\
                                                [hop + '*'] + frame['path'][hop_index+1:]
                                port['tnc'].write(frame, port['tnc_port'])
                                self.aprsis.write(frame)
                                return
                    if node == port_callsign and ssid == port_ssid:
                        if ssid is 0:
                            frame['path'][hop_index] = port_callsign + '*'
                        else:
                            frame['path'][hop_index] = port['identifier'] + '*'
                        port['tnc'].write(frame, port['tnc_port'])
                        self.aprsis.write(frame)
                        return
                    elif node == 'GATE' and port['net'].startswith('2M'):
                        frame['path'] = frame['path'][:hop_index] + [recv_port['identifier'] + '*'] + [node + '*'] +\
                                        frame['path'][hop_index+1:]
                        port['tnc'].write(frame, port['tnc_port'])
                        self.aprsis.write(frame)
                        return
                if node.startswith('WIDE') and ssid > 1:
                    frame['path'] = frame['path'][:hop_index] + [recv_port['identifier'] + '*'] +\
                        [node + '-' + str(ssid-1)] + frame['path'][hop_index+1:]
                    port['tnc'].write(frame, port['tnc_port'])
                    self.aprsis.write(frame)
                    return
                elif node.startswith('WIDE') and ssid is 1:
                    frame['path'] = frame['path'][:hop_index] + [recv_port['identifier'] + '*'] + [node + '*'] + frame['path'][hop_index+1:]
                    port['tnc'].write(frame, port['tnc_port'])
                    self.aprsis.write(frame)
                    return
                elif node.startswith('WIDE') and ssid is 0:
                    frame['path'][hop_index] = node + '*'
                    # no return
                else:
                    # If we didnt digipeat it then we didn't modify the frame, send it to aprsis as-is
                    self.aprsis.write(frame)
                    return

    def __preemptive_digipeat(self, frame, recv_port, recv_port_name):
        # can't digipeat packets if we are in the expended path
        if apex.routing.has_seen(self.port_map, frame):
            return

        selected_hop = {}
        node = None
        ssid = 0
        for hop_index in reversed(range(0, len(frame['path']))):
            hop = frame['path'][hop_index]
            # If this is the last node before a spent node, or a spent node itself, we are done
            if apex.routing.is_hop_consumed(hop) or apex.routing.is_hop_consumed(frame['path'][hop_index-1]):
                break
            split_hop = hop.split('-')
            node = split_hop[0].upper()
            if len(split_hop) >= 2 and split_hop[1]:
                ssid = int(split_hop[1])
            else:
                continue

            band_path = None
            band_path_net = None
            band_match = self.BAND_PATH_REGEX.match(node)
            if band_match is not None:
                band_path = band_match.group(1)
                band_path_net = band_match.group(2)

            if not band_path:
                continue

            for port_name in self.port_map.keys():
                port = self.port_map[port_name]
                if band_path_net and node == port['net']:
                    # only when a ssid is present should it be treated preemptively if it is a band path
                    if not selected_hop:
                        selected_hop['index'] = hop_index
                        selected_hop['hop'] = hop
                        selected_hop['node'] = node
                        selected_hop['ssid'] = ssid
                        selected_hop['port_name'] = port_name
                        selected_hop['port'] = port
                        selected_hop['band_path'] = band_path
                        selected_hop['band_path_net'] = band_path_net
                    elif ssid > selected_hop['ssid']:
                        selected_hop['index'] = hop_index
                        selected_hop['hop'] = hop
                        selected_hop['node'] = node
                        selected_hop['ssid'] = ssid
                        selected_hop['port_name'] = port_name
                        selected_hop['port'] = port
                        selected_hop['band_path'] = band_path
                        selected_hop['band_path_net'] = band_path_net
                elif not band_path_net and port['net'].startswith(band_path):
                    # only when a ssid is present should it be treated preemptively if it is a band path
                    if not selected_hop:
                        selected_hop['index'] = hop_index
                        selected_hop['hop'] = hop
                        selected_hop['node'] = node
                        selected_hop['ssid'] = ssid
                        selected_hop['port_name'] = port_name
                        selected_hop['port'] = port
                        selected_hop['band_path'] = band_path
                        selected_hop['band_path_net'] = band_path_net
                    elif ssid > selected_hop['ssid']:
                        selected_hop['index'] = hop_index
                        selected_hop['hop'] = hop
                        selected_hop['node'] = node
                        selected_hop['ssid'] = ssid
                        selected_hop['port_name'] = port_name
                        selected_hop['port'] = port
                        selected_hop['band_path'] = band_path
                        selected_hop['band_path_net'] = band_path_net
        for hop_index in reversed(range(0, len(frame['path']))):
            hop = frame['path'][hop_index]
            # If this is the last node before a spent node, or a spent node itself, we are done
            if apex.routing.is_hop_consumed(hop) or apex.routing.is_hop_consumed(frame['path'][hop_index-1]):
                break
            elif selected_hop and selected_hop['index'] <= hop_index:
                break

            for port_name in self.port_map.keys():
                port = self.port_map[port_name]

                # since the callsign specifically was specified in the path after the band-path the callsign takes
                # precedence
                if port['identifier'] == hop:
                    selected_hop['index'] = hop_index
                    selected_hop['hop'] = hop
                    selected_hop['node'] = node
                    selected_hop['ssid'] = ssid
                    selected_hop['port_name'] = port_name
                    selected_hop['port'] = port
                    selected_hop['band_path'] = None
                    selected_hop['band_path_net'] = None

        if not selected_hop:
            return

        # now lets digipeat this packet
        new_path = []
        for hop_index in range(0, len(frame['path'])):
            hop = frame['path'][hop_index]
            if not apex.routing.is_hop_consumed(hop):
                if hop_index == selected_hop['index']:
                    if selected_hop['band_path'] is None:
                        new_path += [hop + '*']
                    else:
                        new_path += [selected_hop['port']['identifier'] + '*'] + [hop + '*']
                elif hop_index > selected_hop['index']:
                    new_path += [hop]
            else:
                new_path += [hop]
        frame['path'] = new_path
        port['tnc'].write(frame, port['tnc_port'])
        self.aprsis.write(frame)
        return

    def stop(self):
        return

    def run(self):
        return

    def handle_packet(self, frame, recv_port, recv_port_name):
        self.__preemptive_digipeat(copy.deepcopy(frame), recv_port, recv_port_name)
        self.__passive_digipeat(copy.deepcopy(frame), recv_port, recv_port_name)