2015-11-29 20:59:34 +00:00
|
|
|
import socket
|
2015-11-30 14:03:38 +00:00
|
|
|
import logging
|
2015-11-29 20:59:34 +00:00
|
|
|
from time import time
|
|
|
|
|
|
|
|
from ogn.gateway import settings
|
|
|
|
from ogn.aprs_parser import parse_aprs
|
|
|
|
from ogn.aprs_utils import create_aprs_login
|
2015-12-10 16:28:29 +00:00
|
|
|
from ogn.exceptions import AprsParseError, OgnParseError, AmbigousTimeError
|
2015-11-29 20:59:34 +00:00
|
|
|
|
|
|
|
|
|
|
|
class ognGateway:
|
2015-11-30 14:11:10 +00:00
|
|
|
def __init__(self, aprs_user, aprs_filter=''):
|
2015-11-30 14:03:38 +00:00
|
|
|
self.logger = logging.getLogger(__name__)
|
2015-11-30 14:11:10 +00:00
|
|
|
self.logger.info("Connect to OGN as {} with filter '{}'".format(aprs_user, (aprs_filter if aprs_filter else 'full-feed')))
|
|
|
|
self.aprs_user = aprs_user
|
|
|
|
self.aprs_filter = aprs_filter
|
2015-11-29 20:59:34 +00:00
|
|
|
|
2015-11-30 14:11:10 +00:00
|
|
|
def connect(self):
|
2015-11-29 20:59:34 +00:00
|
|
|
# create socket, connect to server, login and make a file object associated with the socket
|
|
|
|
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
|
|
|
self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
|
2015-11-30 14:20:00 +00:00
|
|
|
|
|
|
|
if self.aprs_filter:
|
|
|
|
port = settings.APRS_SERVER_PORT_CLIENT_DEFINED_FILTERS
|
|
|
|
else:
|
|
|
|
port = settings.APRS_SERVER_PORT_FULL_FEED
|
|
|
|
|
|
|
|
self.sock.connect((settings.APRS_SERVER_HOST, port))
|
|
|
|
self.logger.debug('Server port {}'.format(port))
|
2015-11-29 20:59:34 +00:00
|
|
|
|
2015-11-30 14:11:10 +00:00
|
|
|
login = create_aprs_login(self.aprs_user, -1, settings.APRS_APP_NAME, settings.APRS_APP_VER, self.aprs_filter)
|
2015-11-29 20:59:34 +00:00
|
|
|
self.sock.send(login.encode())
|
|
|
|
self.sock_file = self.sock.makefile('rw')
|
|
|
|
|
|
|
|
def disconnect(self):
|
2015-11-30 14:11:10 +00:00
|
|
|
self.logger.info('Disconnect')
|
|
|
|
try:
|
|
|
|
# close everything
|
|
|
|
self.sock.shutdown(0)
|
|
|
|
self.sock.close()
|
2016-01-05 23:23:45 +00:00
|
|
|
except OSError:
|
2015-11-30 14:11:10 +00:00
|
|
|
self.logger.error('Socket close error', exc_info=True)
|
|
|
|
|
|
|
|
def run(self, callback, autoreconnect=False):
|
|
|
|
self.process_beacon = callback
|
2015-11-29 20:59:34 +00:00
|
|
|
|
|
|
|
while True:
|
2015-11-30 14:11:10 +00:00
|
|
|
try:
|
2015-11-29 20:59:34 +00:00
|
|
|
keepalive_time = time()
|
2015-11-30 14:11:10 +00:00
|
|
|
while True:
|
|
|
|
if time() - keepalive_time > settings.APRS_KEEPALIVE_TIME:
|
|
|
|
self.logger.info('Send keepalive')
|
|
|
|
self.sock.send('#keepalive'.encode())
|
|
|
|
keepalive_time = time()
|
|
|
|
|
|
|
|
# Read packet string from socket
|
|
|
|
packet_str = self.sock_file.readline().strip()
|
2015-11-29 20:59:34 +00:00
|
|
|
|
2015-11-30 14:11:10 +00:00
|
|
|
# A zero length line should not be return if keepalives are being sent
|
|
|
|
# A zero length line will only be returned after ~30m if keepalives are not sent
|
|
|
|
if len(packet_str) == 0:
|
|
|
|
self.logger.warning('Read returns zero length string. Failure. Orderly closeout')
|
|
|
|
break
|
2015-11-29 20:59:34 +00:00
|
|
|
|
2015-11-30 14:11:10 +00:00
|
|
|
self.proceed_line(packet_str)
|
|
|
|
except BrokenPipeError:
|
|
|
|
self.logger.error('BrokenPipeError', exc_info=True)
|
|
|
|
except socket.error:
|
|
|
|
self.logger.error('socket.error', exc_info=True)
|
2015-11-29 20:59:34 +00:00
|
|
|
|
2015-11-30 14:11:10 +00:00
|
|
|
if autoreconnect:
|
|
|
|
self.connect()
|
|
|
|
else:
|
|
|
|
return
|
2015-11-29 20:59:34 +00:00
|
|
|
|
|
|
|
def proceed_line(self, line):
|
|
|
|
try:
|
|
|
|
beacon = parse_aprs(line)
|
2015-11-30 14:03:38 +00:00
|
|
|
self.logger.debug('Received beacon: {}'.format(beacon))
|
2015-11-29 20:59:34 +00:00
|
|
|
except AprsParseError:
|
2015-11-30 14:03:38 +00:00
|
|
|
self.logger.error('AprsParseError while parsing line: {}'.format(line), exc_info=True)
|
2015-11-29 20:59:34 +00:00
|
|
|
return
|
|
|
|
except OgnParseError:
|
2015-11-30 14:03:38 +00:00
|
|
|
self.logger.error('OgnParseError while parsing line: {}'.format(line), exc_info=True)
|
2015-11-29 20:59:34 +00:00
|
|
|
return
|
2015-12-10 16:28:29 +00:00
|
|
|
except AmbigousTimeError as e:
|
2016-01-29 01:49:58 +00:00
|
|
|
self.logger.error('Drop packet, {:.0f}s from past: {}'.format(e.timedelta.total_seconds(), line))
|
2015-12-10 16:28:29 +00:00
|
|
|
return
|
2015-11-29 20:59:34 +00:00
|
|
|
|
|
|
|
if beacon is not None:
|
2015-11-30 14:11:10 +00:00
|
|
|
self.process_beacon(beacon)
|