Completed
Push — master ( 0367ee...2c22a6 )
by Jeffrey
03:30
created

ApexParadigmPlugin   F

Complexity

Total Complexity 75

Size/Duplication

Total Lines 252
Duplicated Lines 26.98 %

Importance

Changes 4
Bugs 0 Features 0
Metric Value
c 4
b 0
f 0
dl 68
loc 252
rs 2.3076
wmc 75

6 Methods

Rating   Name   Duplication   Size   Complexity  
F __preemptive_digipeat() 38 124 36
F __passive_digipeat() 30 108 35
A stop() 0 2 1
A run() 0 2 1
A __init__() 0 4 1
A handle_packet() 0 3 1

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like ApexParadigmPlugin often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
# These imports are for python3 compatability inside python2
2
from __future__ import absolute_import
3
from __future__ import division
4
from __future__ import print_function
5
6
import copy
7
import re
8
import click
9
10
import apex.aprs.util
11
12
__author__ = 'Jeffrey Phillips Freeman (WI2ARD)'
13
__maintainer__ = 'Jeffrey Phillips Freeman (WI2ARD)'
14
__email__ = '[email protected]'
15
__license__ = 'Apache License, Version 2.0'
16
__copyright__ = 'Copyright 2016, Syncleus, Inc. and contributors'
17
__credits__ = []
18
__version__ = '0.0.2'
19
20
plugin = None
21
22
23
def start(config, port_map, packet_cache, aprsis):
24
    global plugin
25
    plugin = ApexParadigmPlugin(config, port_map, packet_cache, aprsis)
26
    plugin.run()
27
28
29
def handle_packet(frame, recv_port, recv_port_name):
30
    plugin.handle_packet(frame, recv_port, recv_port_name)
31
32
33
def stop():
34
    plugin.stop()
35
36
37
class ApexParadigmPlugin(object):
38
39
    BAND_PATH_REGEX = re.compile(r'(\d{1,4})M(\d{0,3})')
40
41
    def __init__(self, config, port_map, packet_cache, aprsis):
42
        self.port_map = port_map
43
        self.packet_cache = packet_cache
44
        self.aprsis = aprsis
45
46
    def __passive_digipeat(self, frame, recv_port, recv_port_name):
47
        # Can't digipeat anything when you are the source
48
        for port in self.port_map.values():
49
            if frame['source'] == port['identifier']:
50
                return
51
52
        # can't digipeat things we already digipeated.
53
        for hop in frame['path']:
54
            if hop.startswith('WI2ARD') and hop.endswith('*'):
55
                return
56
57
        for hop_index in range(0, len(frame['path'])):
58
            hop = frame['path'][hop_index]
59
            if hop[-1] is not '*':
60
                split_hop = hop.split('-')
61
                node = split_hop[0].upper()
62
                if len(split_hop) >= 2 and split_hop[1]:
63
                    ssid = int(split_hop[1])
64
                else:
65
                    ssid = 0
66
67
                band_path = None
68
                band_path_net = None
69
                band_match = self.BAND_PATH_REGEX.match(node)
70
                if band_match is not None:
71
                    band_path = band_match.group(1)
72
                    band_path_net = band_match.group(2)
73
74
                for port_name in self.port_map.keys():
75
                    port = self.port_map[port_name]
76
                    split_port_identifier = port['identifier'].split('-')
77
                    port_callsign = split_port_identifier[0].upper()
78
                    if len(split_port_identifier) >= 2 and split_port_identifier[1]:
79
                        port_ssid = int(split_port_identifier[1])
80
                    else:
81 View Code Duplication
                        port_ssid = 0
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
82
83
                    if band_path:
84
                        if band_path_net:
85
                            if node == port['net']:
86
                                frame['path'] = frame['path'][:hop_index] + [recv_port['identifier'] + '*'] +\
87
                                                [hop + '*'] + frame['path'][hop_index+1:]
88
                                frame_hash = apex.aprs.util.hash_frame(frame)
89
                                if frame_hash not in self.packet_cache.values():
90
                                    self.packet_cache[str(frame_hash)] = frame_hash
91
                                    port['tnc'].write(frame, port['tnc_port'])
92 View Code Duplication
                                    self.aprsis.send(frame)
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
93
                                    click.echo(port_name + ' >> ' + apex.aprs.util.format_aprs_frame(frame))
94
                                return
95
                        else:
96
                            if port['net'].startswith(node):
97
                                frame['path'] = frame['path'][:hop_index] + [recv_port['identifier'] + '*'] +\
98
                                                [hop + '*'] + frame['path'][hop_index+1:]
99
                                frame_hash = apex.aprs.util.hash_frame(frame)
100
                                if frame_hash not in self.packet_cache.values():
101
                                    self.packet_cache[str(frame_hash)] = frame_hash
102
                                    port['tnc'].write(frame, port['tnc_port'])
103
                                    self.aprsis.send(frame)
104
                                    click.echo(port_name + ' >> ' + apex.aprs.util.format_aprs_frame(frame))
105
                                return
106
                    if node == port_callsign and ssid == port_ssid:
107
                        if ssid is 0:
108
                            frame['path'][hop_index] = port_callsign + '*'
109
                        else:
110
                            frame['path'][hop_index] = port['identifier'] + '*'
111
                        frame_hash = apex.aprs.util.hash_frame(frame)
112
                        if frame_hash not in self.packet_cache.values():
113
                            self.packet_cache[str(frame_hash)] = frame_hash
114 View Code Duplication
                            port['tnc'].write(frame, port['tnc_port'])
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
115
                            self.aprsis.send(frame)
116
                            click.echo(port_name + ' >> ' + apex.aprs.util.format_aprs_frame(frame))
117
                        return
118
                    elif node == 'GATE' and port['net'].startswith('2M'):
119
                        frame['path'] = frame['path'][:hop_index] + [recv_port['identifier'] + '*'] + [node + '*'] +\
120
                                        frame['path'][hop_index+1:]
121
                        frame_hash = apex.aprs.util.hash_frame(frame)
122
                        if frame_hash not in self.packet_cache.values():
123
                            self.packet_cache[str(frame_hash)] = frame_hash
124
                            port['tnc'].write(frame, port['tnc_port'])
125
                            self.aprsis.send(frame)
126
                            click.echo(port_name + ' >> ' + apex.aprs.util.format_aprs_frame(frame))
127
                        return
128
                if node.startswith('WIDE') and ssid > 1:
129
                    frame['path'] = frame['path'][:hop_index] + [recv_port['identifier'] + '*'] +\
130
                        [node + '-' + str(ssid-1)] + frame['path'][hop_index+1:]
131
                    frame_hash = apex.aprs.util.hash_frame(frame)
132
                    if frame_hash not in self.packet_cache.values():
133
                        self.packet_cache[str(frame_hash)] = frame_hash
134
                        recv_port['tnc'].write(frame, recv_port['tnc_port'])
135
                        self.aprsis.send(frame)
136
                        click.echo(recv_port_name + ' >> ' + apex.aprs.util.format_aprs_frame(frame))
137
                    return
138
                elif node.startswith('WIDE') and ssid is 1:
139
                    frame['path'] = frame['path'][:hop_index] + [recv_port['identifier'] + '*'] + [node + '*'] + frame['path'][hop_index+1:]
140
                    frame_hash = apex.aprs.util.hash_frame(frame)
141
                    if frame_hash not in self.packet_cache.values():
142
                        self.packet_cache[str(frame_hash)] = frame_hash
143
                        recv_port['tnc'].write(frame, recv_port['tnc_port'])
144
                        self.aprsis.send(frame)
145
                        click.echo(recv_port_name + ' >> ' + apex.aprs.util.format_aprs_frame(frame))
146
                    return
147
                elif node.startswith('WIDE') and ssid is 0:
148
                    frame['path'][hop_index] = node + '*'
149
                    # no return
150
                else:
151
                    # If we didnt digipeat it then we didn't modify the frame, send it to aprsis as-is
152
                    self.aprsis.send(frame)
153
                    return
154
155
    def __preemptive_digipeat(self, frame, recv_port, recv_port_name):
156
        # Can't digipeat anything when you are the source
157
        for port in self.port_map.values():
158
            if frame['source'] == port['identifier']:
159
                return
160
161
        # can't digipeat things we already digipeated.
162
        for hop in frame['path']:
163
            if hop.startswith('WI2ARD') and hop.endswith('*'):
164
                return
165
166
        selected_hop = {}
167
        for hop_index in reversed(range(0, len(frame['path']))):
168
            hop = frame['path'][hop_index]
169
            # If this is the last node before a spent node, or a spent node itself, we are done
170
            if hop[-1] == '*' or frame['path'][hop_index-1][-1] == '*':
171
                break
172
            split_hop = hop.split('-')
173
            node = split_hop[0].upper()
174
            if len(split_hop) >= 2 and split_hop[1]:
175
                ssid = int(split_hop[1])
176
            else:
177
                continue
178
179
            band_path = None
180
            band_path_net = None
181
            band_match = self.BAND_PATH_REGEX.match(node)
182
            if band_match is not None:
183
                band_path = band_match.group(1)
184
                band_path_net = band_match.group(2)
185
186
            if not band_path:
187
                continue
188 View Code Duplication
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
189
            for port_name in self.port_map.keys():
190
                port = self.port_map[port_name]
191
                if band_path_net and node == port['net']:
192
                    # only when a ssid is present should it be treated preemptively if it is a band path
193
                    if not selected_hop:
194
                        selected_hop['index'] = hop_index
195
                        selected_hop['hop'] = hop
196
                        selected_hop['node'] = node
197
                        selected_hop['ssid'] = ssid
198
                        selected_hop['port_name'] = port_name
199
                        selected_hop['port'] = port
200
                        selected_hop['band_path'] = band_path
201
                        selected_hop['band_path_net'] = band_path_net
202
                    elif ssid > selected_hop['ssid']:
203
                        selected_hop['index'] = hop_index
204
                        selected_hop['hop'] = hop
205
                        selected_hop['node'] = node
206 View Code Duplication
                        selected_hop['ssid'] = ssid
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
207
                        selected_hop['port_name'] = port_name
208
                        selected_hop['port'] = port
209
                        selected_hop['band_path'] = band_path
210
                        selected_hop['band_path_net'] = band_path_net
211
                elif not band_path_net and port['net'].startswith(band_path):
212
                    # only when a ssid is present should it be treated preemptively if it is a band path
213
                    if not selected_hop:
214
                        selected_hop['index'] = hop_index
215
                        selected_hop['hop'] = hop
216
                        selected_hop['node'] = node
217
                        selected_hop['ssid'] = ssid
218
                        selected_hop['port_name'] = port_name
219
                        selected_hop['port'] = port
220
                        selected_hop['band_path'] = band_path
221
                        selected_hop['band_path_net'] = band_path_net
222
                    elif ssid > selected_hop['ssid']:
223
                        selected_hop['index'] = hop_index
224
                        selected_hop['hop'] = hop
225
                        selected_hop['node'] = node
226
                        selected_hop['ssid'] = ssid
227
                        selected_hop['port_name'] = port_name
228
                        selected_hop['port'] = port
229
                        selected_hop['band_path'] = band_path
230
                        selected_hop['band_path_net'] = band_path_net
231
        for hop_index in reversed(range(0, len(frame['path']))):
232
            hop = frame['path'][hop_index]
233
            # If this is the last node before a spent node, or a spent node itself, we are done
234
            if hop[-1] == '*' or frame['path'][hop_index-1][-1] == '*':
235
                break
236
            elif selected_hop and selected_hop['index'] <= hop_index:
237
                break
238
239
            for port_name in self.port_map.keys():
240
                port = self.port_map[port_name]
241
242
                # since the callsign specifically was specified in the path after the band-path the callsign takes
243
                # precedence
244
                if port['identifier'] == hop:
245
                    selected_hop['index'] = hop_index
246
                    selected_hop['hop'] = hop
247
                    selected_hop['node'] = node
248
                    selected_hop['ssid'] = ssid
249
                    selected_hop['port_name'] = port_name
250
                    selected_hop['port'] = port
251
                    selected_hop['band_path'] = None
252
                    selected_hop['band_path_net'] = None
253
254
        if not selected_hop:
255
            return
256
257
        # now lets digipeat this packet
258
        new_path = []
259
        for hop_index in range(0, len(frame['path'])):
260
            hop = frame['path'][hop_index]
261
            if hop[-1] != '*':
262
                if hop_index == selected_hop['index']:
263
                    if selected_hop['band_path'] is None:
264
                        new_path += [hop + '*']
265
                    else:
266
                        new_path += [selected_hop['port']['identifier'] + '*'] + [hop + '*']
267
                elif hop_index > selected_hop['index']:
268
                    new_path += [hop]
269
            else:
270
                new_path += [hop]
271
        frame['path'] = new_path
272
        frame_hash = apex.aprs.util.hash_frame(frame)
273
        if frame_hash not in self.packet_cache.values():
274
            self.packet_cache[str(frame_hash)] = frame_hash
275
            selected_hop['port']['tnc'].write(frame, selected_hop['port']['tnc_port'])
276
            self.aprsis.send(frame)
277
            click.echo(selected_hop['port_name'] + ' >> ' + apex.aprs.util.format_aprs_frame(frame))
278
        return
279
280
    def stop(self):
281
        return
282
283
    def run(self):
284
        return
285
286
    def handle_packet(self, frame, recv_port, recv_port_name):
287
        self.__preemptive_digipeat(copy.deepcopy(frame), recv_port, recv_port_name)
288
        self.__passive_digipeat(copy.deepcopy(frame), recv_port, recv_port_name)
289