Completed
Push — master ( 2652b1...228f8d )
by Jeffrey
04:14
created

find_config()   B

Complexity

Conditions 7

Size

Total Lines 20

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 7
c 1
b 0
f 0
dl 0
loc 20
rs 7.3333
1
"""
2
Module that contains the command line app.
3
4
Why does this file exist, and why not put this in __main__?
5
6
  You might be tempted to import things from __main__ later, but that will cause
7
  problems: the code will get executed twice:
8
9
  - When you run `python -mapex` python will execute
10
    ``__main__.py`` as a script. That means there won't be any
11
    ``apex.__main__`` in ``sys.modules``.
12
  - When you import __main__ it will get executed again (as a module) because
13
    there's no ``apex.__main__`` in ``sys.modules``.
14
15
  Also see (1) from http://click.pocoo.org/5/setuptools/#setuptools-integration
16
"""
17
18
# These imports are for python3 compatability inside python2
19
from __future__ import absolute_import
20
from __future__ import division
21
from __future__ import print_function
22
from __future__ import unicode_literals
23
24
import os
25
import signal
26
import sys
27
import threading
28
import time
29
import traceback
30
import cachetools
31
import click
32
33
import apex.aprs
34
from apex.kiss import constants as kissConstants
35
from apex.pluginloader import getPlugins
36
from apex.pluginloader import loadPlugin
37
38
if sys.version_info < (3, 0):
39
    import ConfigParser  # noqa: F401
40
elif sys.version_info >= (3, 0):
41
    import configparser
42
43
__author__ = 'Jeffrey Phillips Freeman (WI2ARD)'
44
__maintainer__ = "Jeffrey Phillips Freeman (WI2ARD)"
45
__email__ = "[email protected]"
46
__license__ = 'Apache License, Version 2.0'
47
__copyright__ = 'Copyright 2016, Syncleus, Inc. and contributors'
48
__credits__ = []
49
50
def find_config(config_paths):
51
    config_file = 'apex.conf'
52
    rc_file = '.apexrc'
53
    cur_path = os.path.join(os.curdir, config_file)
54
    home_path = os.path.join(os.path.expanduser("~"), rc_file)
55
    etc_path = os.path.join('etc', config_file)
56
    if config_paths is None:
57
        config_paths = [cur_path, home_path, etc_path]
58
    elif isinstance(config_paths, str):
59
        config_paths = [config_paths]
60
    elif not isinstance(config_paths, list):
61
        raise TypeError('config_paths argument was neither a string nor a list')
62
63
    config = configparser.ConfigParser()
64
    for config_path in config_paths:
65
        try:
66
            if len(config.read(config_path)) > 0:
67
                return config
68
        except IOError:
69
            pass
70
71
@click.command(context_settings=dict(auto_envvar_prefix='APEX'))
72
@click.option('--configfile',
73
              type=click.Path(exists=True, file_okay=True, dir_okay=False, readable=True, resolve_path=True),
74
              help='Configuration file for APEX.')
75
@click.option('-v', '--verbose', is_flag=True, help='Enables verbose mode.')
76
def main(verbose, configfile):
77
    click.echo("verbosity: " + repr(verbose) + " | configfile: " + repr(configfile))
78
79
    port_map = {}
80
    config = find_config(configfile)
81
    for section in config.sections():
82
        if section.startswith("TNC "):
83
            tnc_name = section.split(" ")[1]
84
            if config.has_option(section, 'com_port') and config.has_option(section, 'baud'):
85
                com_port = config.get(section, 'com_port')
86
                baud = config.get(section, 'baud')
87
                kiss_tnc = apex.aprs.AprsKiss(com_port=com_port, baud=baud)
88
            elif config.has_option(section, 'tcp_host') and config.has_option(section, 'tcp_port'):
89
                tcp_host = config.get(section, 'tcp_host')
90
                tcp_port = config.get(section, 'tcp_port')
91
                kiss_tnc = apex.aprs.AprsKiss(host=tcp_host, tcp_port=tcp_port)
92
            else:
93
                raise Exception(
94
                    "Must have either both com_port and baud set or tcp_host and tcp_port set in configuration file")
95
            kiss_init_string = config.get(section, 'kiss_init')
96
            if kiss_init_string == 'MODE_INIT_W8DED':
97
                kiss_tnc.start(kissConstants.MODE_INIT_W8DED)
98
            elif kiss_init_string == 'MODE_INIT_KENWOOD_D710':
99
                kiss_tnc.start(kissConstants.MODE_INIT_KENWOOD_D710)
100
            elif kiss_init_string == 'NONE':
101
                kiss_tnc.start()
102
            else:
103
                raise Exception("KISS init mode not specified")
104
            for port in range(1, 1 + int(config.get(section, 'port_count'))):
105
                port_name = tnc_name + '-' + str(port)
106
                port_section = 'PORT ' + port_name
107
                port_identifier = config.get(port_section, 'identifier')
108
                port_net = config.get(port_section, 'net')
109
                tnc_port = int(config.get(port_section, 'tnc_port'))
110
                port_map[port_name] = {'identifier': port_identifier, 'net': port_net, 'tnc': kiss_tnc,
111
                                       'tnc_port': tnc_port}
112
    if config.has_section('APRS-IS'):
113
        aprsis_callsign = config.get('APRS-IS', 'callsign')
114
        if config.has_option('APRS-IS', 'password'):
115
            aprsis_password = config.get('APRS-IS', 'password')
116
        else:
117
            aprsis_password = -1
118
        aprsis_server = config.get('APRS-IS', 'server')
119
        aprsis_server_port = config.get('APRS-IS', 'server_port')
120
        aprsis = apex.aprs.AprsInternetService(aprsis_callsign, aprsis_password)
121
        aprsis.connect(aprsis_server, int(aprsis_server_port))
122
123
    def sigint_handler(signal, frame):
124
        for port in port_map.values():
125
            port['tnc'].close()
126
        sys.exit(0)
127
128
    signal.signal(signal.SIGINT, sigint_handler)
129
130
    print("Press ctrl + c at any time to exit")
131
132
    packet_cache = cachetools.TTLCache(10000, 5)
133
    # start the plugins
134
    plugins = []
135
    try:
136
        plugin_loaders = getPlugins()
137
        for plugin_loader in plugin_loaders:
138
            loaded_plugin = loadPlugin(plugin_loader)
139
            plugins.append(loaded_plugin)
140
            threading.Thread(target=loaded_plugin.start, args=(config, port_map, packet_cache, aprsis)).start()
141
    except FileNotFoundError:
142
        print("The plugin directory doesnt exist, without plugins this program has nothing to do, so it will exit now.")
143
        return
144
145
    while 1:
146
        something_read = False
147
        try:
148
            for port_name in port_map.keys():
149
                port = port_map[port_name]
150
                frame = port['tnc'].read()
151
                if frame:
152
                    formatted_aprs = apex.aprs.util.format_aprs_frame(frame)
153
                    print(port_name + " << " + formatted_aprs)
154
                    for plugin in plugins:
155
                        something_read = True
156
                        plugin.handle_packet(frame, port, port_name)
157
        except Exception as ex:
158
            # We want to keep this thread alive so long as the application runs.
159
            traceback.print_exc(file=sys.stdout)
160
            print("caught exception while reading packet: " + str(ex))
161
162
        if something_read is False:
163
            time.sleep(1)
164