aprsd 4.1.2__py3-none-any.whl → 4.2.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,144 +0,0 @@
1
- import datetime
2
- import logging
3
-
4
- import kiss
5
- from ax253 import Frame
6
- from oslo_config import cfg
7
-
8
- from aprsd import conf # noqa
9
- from aprsd.packets import core
10
- from aprsd.utils import trace
11
-
12
- CONF = cfg.CONF
13
- LOG = logging.getLogger('APRSD')
14
-
15
-
16
- class KISS3Client:
17
- path = []
18
-
19
- # date for last time we heard from the server
20
- aprsd_keepalive = datetime.datetime.now()
21
- _connected = False
22
-
23
- def __init__(self):
24
- self.setup()
25
-
26
- def is_alive(self):
27
- return self._connected
28
-
29
- def setup(self):
30
- # we can be TCP kiss or Serial kiss
31
- if CONF.kiss_serial.enabled:
32
- LOG.debug(
33
- 'KISS({}) Serial connection to {}'.format(
34
- kiss.__version__,
35
- CONF.kiss_serial.device,
36
- ),
37
- )
38
- self.kiss = kiss.SerialKISS(
39
- port=CONF.kiss_serial.device,
40
- speed=CONF.kiss_serial.baudrate,
41
- strip_df_start=True,
42
- )
43
- self.path = CONF.kiss_serial.path
44
- elif CONF.kiss_tcp.enabled:
45
- LOG.debug(
46
- 'KISS({}) TCP Connection to {}:{}'.format(
47
- kiss.__version__,
48
- CONF.kiss_tcp.host,
49
- CONF.kiss_tcp.port,
50
- ),
51
- )
52
- self.kiss = kiss.TCPKISS(
53
- host=CONF.kiss_tcp.host,
54
- port=CONF.kiss_tcp.port,
55
- strip_df_start=True,
56
- )
57
- self.path = CONF.kiss_tcp.path
58
-
59
- LOG.debug('Starting KISS interface connection')
60
- try:
61
- self.kiss.start()
62
- if self.kiss.protocol.transport.is_closing():
63
- LOG.warning('KISS transport is closing, not setting consumer callback')
64
- self._connected = False
65
- else:
66
- self._connected = True
67
- except Exception:
68
- LOG.error('Failed to start KISS interface.')
69
- self._connected = False
70
-
71
- @trace.trace
72
- def stop(self):
73
- if not self._connected:
74
- # do nothing since we aren't connected
75
- return
76
-
77
- try:
78
- self.kiss.stop()
79
- self.kiss.loop.call_soon_threadsafe(
80
- self.kiss.protocol.transport.close,
81
- )
82
- except Exception:
83
- LOG.error('Failed to stop KISS interface.')
84
-
85
- def close(self):
86
- self.stop()
87
-
88
- def set_filter(self, filter):
89
- # This does nothing right now.
90
- pass
91
-
92
- def parse_frame(self, frame_bytes):
93
- try:
94
- frame = Frame.from_bytes(frame_bytes)
95
- # Now parse it with aprslib
96
- kwargs = {
97
- 'frame': frame,
98
- }
99
- self._parse_callback(**kwargs)
100
- self.aprsd_keepalive = datetime.datetime.now()
101
- except Exception as ex:
102
- LOG.error('Failed to parse bytes received from KISS interface.')
103
- LOG.exception(ex)
104
-
105
- def consumer(self, callback):
106
- if not self._connected:
107
- raise Exception('KISS transport is not connected')
108
-
109
- self._parse_callback = callback
110
- if not self.kiss.protocol.transport.is_closing():
111
- self.kiss.read(callback=self.parse_frame, min_frames=1)
112
- else:
113
- self._connected = False
114
-
115
- def send(self, packet):
116
- """Send an APRS Message object."""
117
-
118
- payload = None
119
- path = self.path
120
- if isinstance(packet, core.Packet):
121
- packet.prepare()
122
- payload = packet.payload.encode('US-ASCII')
123
- if packet.path:
124
- path = packet.path
125
- else:
126
- msg_payload = f'{packet.raw}{{{str(packet.msgNo)}'
127
- payload = (
128
- ':{:<9}:{}'.format(
129
- packet.to_call,
130
- msg_payload,
131
- )
132
- ).encode('US-ASCII')
133
-
134
- LOG.debug(
135
- f"KISS Send '{payload}' TO '{packet.to_call}' From "
136
- f"'{packet.from_call}' with PATH '{path}'",
137
- )
138
- frame = Frame.ui(
139
- destination='APZ100',
140
- source=packet.from_call,
141
- path=path,
142
- info=payload,
143
- )
144
- self.kiss.write(frame)
aprsd/client/factory.py DELETED
@@ -1,91 +0,0 @@
1
- import logging
2
- from typing import Callable, Protocol, runtime_checkable
3
-
4
- from aprsd import exception
5
- from aprsd.packets import core
6
-
7
- LOG = logging.getLogger("APRSD")
8
-
9
-
10
- @runtime_checkable
11
- class Client(Protocol):
12
- def __init__(self):
13
- pass
14
-
15
- def connect(self) -> bool:
16
- pass
17
-
18
- def disconnect(self) -> bool:
19
- pass
20
-
21
- def decode_packet(self, *args, **kwargs) -> type[core.Packet]:
22
- pass
23
-
24
- def is_enabled(self) -> bool:
25
- pass
26
-
27
- def is_configured(self) -> bool:
28
- pass
29
-
30
- def transport(self) -> str:
31
- pass
32
-
33
- def send(self, message: str) -> bool:
34
- pass
35
-
36
- def setup_connection(self) -> None:
37
- pass
38
-
39
-
40
- class ClientFactory:
41
- _instance = None
42
- clients = []
43
- client = None
44
-
45
- def __new__(cls, *args, **kwargs):
46
- """This magic turns this into a singleton."""
47
- if cls._instance is None:
48
- cls._instance = super().__new__(cls)
49
- # Put any initialization here.
50
- return cls._instance
51
-
52
- def __init__(self):
53
- self.clients: list[Callable] = []
54
-
55
- def register(self, aprsd_client: Callable):
56
- if isinstance(aprsd_client, Client):
57
- raise ValueError("Client must be a subclass of Client protocol")
58
-
59
- self.clients.append(aprsd_client)
60
-
61
- def create(self, key=None):
62
- for client in self.clients:
63
- if client.is_enabled():
64
- self.client = client()
65
- return self.client
66
- raise Exception("No client is configured!!")
67
-
68
- def client_exists(self):
69
- return bool(self.client)
70
-
71
- def is_client_enabled(self):
72
- """Make sure at least one client is enabled."""
73
- enabled = False
74
- for client in self.clients:
75
- if client.is_enabled():
76
- enabled = True
77
- return enabled
78
-
79
- def is_client_configured(self):
80
- enabled = False
81
- for client in self.clients:
82
- try:
83
- if client.is_configured():
84
- enabled = True
85
- except exception.MissingConfigOptionException as ex:
86
- LOG.error(ex.message)
87
- return False
88
- except exception.ConfigOptionBogusDefaultException as ex:
89
- LOG.error(ex.message)
90
- return False
91
- return enabled
aprsd/client/fake.py DELETED
@@ -1,49 +0,0 @@
1
- import logging
2
-
3
- from oslo_config import cfg
4
-
5
- from aprsd import client
6
- from aprsd.client import base
7
- from aprsd.client.drivers import fake as fake_driver
8
- from aprsd.utils import trace
9
-
10
- CONF = cfg.CONF
11
- LOG = logging.getLogger("APRSD")
12
-
13
-
14
- class APRSDFakeClient(base.APRSClient, metaclass=trace.TraceWrapperMetaclass):
15
- def stats(self, serializable=False) -> dict:
16
- return {
17
- "transport": "Fake",
18
- "connected": True,
19
- }
20
-
21
- @staticmethod
22
- def is_enabled():
23
- if CONF.fake_client.enabled:
24
- return True
25
- return False
26
-
27
- @staticmethod
28
- def is_configured():
29
- return APRSDFakeClient.is_enabled()
30
-
31
- def is_alive(self):
32
- return True
33
-
34
- def close(self):
35
- pass
36
-
37
- def setup_connection(self):
38
- self.connected = True
39
- return fake_driver.APRSDFakeClient()
40
-
41
- @staticmethod
42
- def transport():
43
- return client.TRANSPORT_FAKE
44
-
45
- def decode_packet(self, *args, **kwargs):
46
- LOG.debug(f"kwargs {kwargs}")
47
- pkt = kwargs["packet"]
48
- LOG.debug(f"Got an APRS Fake Packet '{pkt}'")
49
- return pkt
aprsd/client/kiss.py DELETED
@@ -1,143 +0,0 @@
1
- import datetime
2
- import logging
3
-
4
- import aprslib
5
- import timeago
6
- from loguru import logger
7
- from oslo_config import cfg
8
-
9
- from aprsd import client, exception
10
- from aprsd.client import base
11
- from aprsd.client.drivers import kiss
12
- from aprsd.packets import core
13
-
14
- CONF = cfg.CONF
15
- LOG = logging.getLogger('APRSD')
16
- LOGU = logger
17
-
18
-
19
- class KISSClient(base.APRSClient):
20
- _client = None
21
- keepalive = datetime.datetime.now()
22
-
23
- def stats(self, serializable=False) -> dict:
24
- stats = {}
25
- if self.is_configured():
26
- keepalive = self.keepalive
27
- if serializable:
28
- keepalive = keepalive.isoformat()
29
- stats = {
30
- 'connected': self.is_connected,
31
- 'connection_keepalive': keepalive,
32
- 'transport': self.transport(),
33
- }
34
- if self.transport() == client.TRANSPORT_TCPKISS:
35
- stats['host'] = CONF.kiss_tcp.host
36
- stats['port'] = CONF.kiss_tcp.port
37
- elif self.transport() == client.TRANSPORT_SERIALKISS:
38
- stats['device'] = CONF.kiss_serial.device
39
- return stats
40
-
41
- @staticmethod
42
- def is_enabled():
43
- """Return if tcp or serial KISS is enabled."""
44
- if CONF.kiss_serial.enabled:
45
- return True
46
-
47
- if CONF.kiss_tcp.enabled:
48
- return True
49
-
50
- return False
51
-
52
- @staticmethod
53
- def is_configured():
54
- # Ensure that the config vars are correctly set
55
- if KISSClient.is_enabled():
56
- transport = KISSClient.transport()
57
- if transport == client.TRANSPORT_SERIALKISS:
58
- if not CONF.kiss_serial.device:
59
- LOG.error('KISS serial enabled, but no device is set.')
60
- raise exception.MissingConfigOptionException(
61
- 'kiss_serial.device is not set.',
62
- )
63
- elif transport == client.TRANSPORT_TCPKISS:
64
- if not CONF.kiss_tcp.host:
65
- LOG.error('KISS TCP enabled, but no host is set.')
66
- raise exception.MissingConfigOptionException(
67
- 'kiss_tcp.host is not set.',
68
- )
69
-
70
- return True
71
- return False
72
-
73
- def is_alive(self):
74
- if self._client:
75
- return self._client.is_alive()
76
- else:
77
- return False
78
-
79
- def close(self):
80
- if self._client:
81
- self._client.stop()
82
-
83
- def keepalive_check(self):
84
- # Don't check the first time through.
85
- if not self.is_alive() and self._checks:
86
- LOG.warning("Resetting client. It's not alive.")
87
- self.reset()
88
- self._checks = True
89
-
90
- def keepalive_log(self):
91
- if ka := self._client.aprsd_keepalive:
92
- keepalive = timeago.format(ka)
93
- else:
94
- keepalive = 'N/A'
95
- LOGU.opt(colors=True).info(f'<green>Client keepalive {keepalive}</green>')
96
-
97
- @staticmethod
98
- def transport():
99
- if CONF.kiss_serial.enabled:
100
- return client.TRANSPORT_SERIALKISS
101
-
102
- if CONF.kiss_tcp.enabled:
103
- return client.TRANSPORT_TCPKISS
104
-
105
- def decode_packet(self, *args, **kwargs):
106
- """We get a frame, which has to be decoded."""
107
- LOG.debug(f'kwargs {kwargs}')
108
- frame = kwargs['frame']
109
- LOG.debug(f"Got an APRS Frame '{frame}'")
110
- # try and nuke the * from the fromcall sign.
111
- # frame.header._source._ch = False
112
- # payload = str(frame.payload.decode())
113
- # msg = f"{str(frame.header)}:{payload}"
114
- # msg = frame.tnc2
115
- # LOG.debug(f"Decoding {msg}")
116
-
117
- try:
118
- raw = aprslib.parse(str(frame))
119
- packet = core.factory(raw)
120
- if isinstance(packet, core.ThirdPartyPacket):
121
- return packet.subpacket
122
- else:
123
- return packet
124
- except Exception as ex:
125
- LOG.error(f'Error decoding packet: {ex}')
126
-
127
- def setup_connection(self):
128
- try:
129
- self._client = kiss.KISS3Client()
130
- self.connected = self.login_status['success'] = True
131
- except Exception as ex:
132
- self.connected = self.login_status['success'] = False
133
- self.login_status['message'] = str(ex)
134
- return self._client
135
-
136
- def consumer(self, callback, blocking=False, immortal=False, raw=False):
137
- try:
138
- self._client.consumer(callback)
139
- self.keepalive = datetime.datetime.now()
140
- except Exception as ex:
141
- LOG.error(f'Consumer failed {ex}')
142
- LOG.error(ex)
143
- raise ex