aprsd 1.0.0__py3-none-any.whl → 3.4.1__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.
Files changed (141) hide show
  1. aprsd/__init__.py +6 -4
  2. aprsd/cli_helper.py +151 -0
  3. aprsd/client/__init__.py +13 -0
  4. aprsd/client/aprsis.py +132 -0
  5. aprsd/client/base.py +105 -0
  6. aprsd/client/drivers/__init__.py +0 -0
  7. aprsd/client/drivers/aprsis.py +224 -0
  8. aprsd/client/drivers/fake.py +73 -0
  9. aprsd/client/drivers/kiss.py +119 -0
  10. aprsd/client/factory.py +88 -0
  11. aprsd/client/fake.py +48 -0
  12. aprsd/client/kiss.py +103 -0
  13. aprsd/client/stats.py +38 -0
  14. aprsd/cmds/__init__.py +0 -0
  15. aprsd/cmds/completion.py +22 -0
  16. aprsd/cmds/dev.py +162 -0
  17. aprsd/cmds/fetch_stats.py +156 -0
  18. aprsd/cmds/healthcheck.py +86 -0
  19. aprsd/cmds/list_plugins.py +319 -0
  20. aprsd/cmds/listen.py +230 -0
  21. aprsd/cmds/send_message.py +174 -0
  22. aprsd/cmds/server.py +142 -0
  23. aprsd/cmds/webchat.py +681 -0
  24. aprsd/conf/__init__.py +56 -0
  25. aprsd/conf/client.py +131 -0
  26. aprsd/conf/common.py +302 -0
  27. aprsd/conf/log.py +65 -0
  28. aprsd/conf/opts.py +80 -0
  29. aprsd/conf/plugin_common.py +191 -0
  30. aprsd/conf/plugin_email.py +105 -0
  31. aprsd/exception.py +13 -0
  32. aprsd/log/__init__.py +0 -0
  33. aprsd/log/log.py +138 -0
  34. aprsd/main.py +104 -867
  35. aprsd/messaging.py +4 -0
  36. aprsd/packets/__init__.py +12 -0
  37. aprsd/packets/collector.py +56 -0
  38. aprsd/packets/core.py +823 -0
  39. aprsd/packets/log.py +143 -0
  40. aprsd/packets/packet_list.py +116 -0
  41. aprsd/packets/seen_list.py +54 -0
  42. aprsd/packets/tracker.py +109 -0
  43. aprsd/packets/watch_list.py +122 -0
  44. aprsd/plugin.py +475 -284
  45. aprsd/plugin_utils.py +86 -0
  46. aprsd/plugins/__init__.py +0 -0
  47. aprsd/plugins/email.py +709 -0
  48. aprsd/plugins/fortune.py +61 -0
  49. aprsd/plugins/location.py +179 -0
  50. aprsd/plugins/notify.py +61 -0
  51. aprsd/plugins/ping.py +31 -0
  52. aprsd/plugins/time.py +115 -0
  53. aprsd/plugins/version.py +31 -0
  54. aprsd/plugins/weather.py +405 -0
  55. aprsd/stats/__init__.py +20 -0
  56. aprsd/stats/app.py +49 -0
  57. aprsd/stats/collector.py +38 -0
  58. aprsd/threads/__init__.py +11 -0
  59. aprsd/threads/aprsd.py +119 -0
  60. aprsd/threads/keep_alive.py +124 -0
  61. aprsd/threads/log_monitor.py +121 -0
  62. aprsd/threads/registry.py +56 -0
  63. aprsd/threads/rx.py +354 -0
  64. aprsd/threads/stats.py +44 -0
  65. aprsd/threads/tx.py +255 -0
  66. aprsd/utils/__init__.py +163 -0
  67. aprsd/utils/counter.py +51 -0
  68. aprsd/utils/json.py +80 -0
  69. aprsd/utils/objectstore.py +123 -0
  70. aprsd/utils/ring_buffer.py +40 -0
  71. aprsd/utils/trace.py +180 -0
  72. aprsd/web/__init__.py +0 -0
  73. aprsd/web/admin/__init__.py +0 -0
  74. aprsd/web/admin/static/css/index.css +84 -0
  75. aprsd/web/admin/static/css/prism.css +4 -0
  76. aprsd/web/admin/static/css/tabs.css +35 -0
  77. aprsd/web/admin/static/images/Untitled.png +0 -0
  78. aprsd/web/admin/static/images/aprs-symbols-16-0.png +0 -0
  79. aprsd/web/admin/static/images/aprs-symbols-16-1.png +0 -0
  80. aprsd/web/admin/static/images/aprs-symbols-64-0.png +0 -0
  81. aprsd/web/admin/static/images/aprs-symbols-64-1.png +0 -0
  82. aprsd/web/admin/static/images/aprs-symbols-64-2.png +0 -0
  83. aprsd/web/admin/static/js/charts.js +235 -0
  84. aprsd/web/admin/static/js/echarts.js +465 -0
  85. aprsd/web/admin/static/js/logs.js +26 -0
  86. aprsd/web/admin/static/js/main.js +231 -0
  87. aprsd/web/admin/static/js/prism.js +12 -0
  88. aprsd/web/admin/static/js/send-message.js +114 -0
  89. aprsd/web/admin/static/js/tabs.js +28 -0
  90. aprsd/web/admin/templates/index.html +196 -0
  91. aprsd/web/chat/static/css/chat.css +115 -0
  92. aprsd/web/chat/static/css/index.css +66 -0
  93. aprsd/web/chat/static/css/style.css.map +1 -0
  94. aprsd/web/chat/static/css/tabs.css +41 -0
  95. aprsd/web/chat/static/css/upstream/bootstrap.min.css +6 -0
  96. aprsd/web/chat/static/css/upstream/font.woff2 +0 -0
  97. aprsd/web/chat/static/css/upstream/google-fonts.css +23 -0
  98. aprsd/web/chat/static/css/upstream/jquery-ui.css +1311 -0
  99. aprsd/web/chat/static/css/upstream/jquery.toast.css +28 -0
  100. aprsd/web/chat/static/css/upstream/themes/default/assets/fonts/LatoLatin-Bold.woff +0 -0
  101. aprsd/web/chat/static/css/upstream/themes/default/assets/fonts/LatoLatin-Bold.woff2 +0 -0
  102. aprsd/web/chat/static/css/upstream/themes/default/assets/fonts/LatoLatin-Regular.woff +0 -0
  103. aprsd/web/chat/static/css/upstream/themes/default/assets/fonts/LatoLatin-Regular.woff2 +0 -0
  104. aprsd/web/chat/static/css/upstream/themes/default/assets/fonts/icons.woff +0 -0
  105. aprsd/web/chat/static/css/upstream/themes/default/assets/fonts/icons.woff2 +0 -0
  106. aprsd/web/chat/static/css/upstream/themes/default/assets/fonts/outline-icons.woff +0 -0
  107. aprsd/web/chat/static/css/upstream/themes/default/assets/fonts/outline-icons.woff2 +0 -0
  108. aprsd/web/chat/static/images/Untitled.png +0 -0
  109. aprsd/web/chat/static/images/aprs-symbols-16-0.png +0 -0
  110. aprsd/web/chat/static/images/aprs-symbols-16-1.png +0 -0
  111. aprsd/web/chat/static/images/aprs-symbols-64-0.png +0 -0
  112. aprsd/web/chat/static/images/aprs-symbols-64-1.png +0 -0
  113. aprsd/web/chat/static/images/aprs-symbols-64-2.png +0 -0
  114. aprsd/web/chat/static/images/globe.svg +3 -0
  115. aprsd/web/chat/static/js/gps.js +84 -0
  116. aprsd/web/chat/static/js/main.js +45 -0
  117. aprsd/web/chat/static/js/send-message.js +585 -0
  118. aprsd/web/chat/static/js/tabs.js +28 -0
  119. aprsd/web/chat/static/js/upstream/bootstrap.bundle.min.js +7 -0
  120. aprsd/web/chat/static/js/upstream/jquery-3.7.1.min.js +2 -0
  121. aprsd/web/chat/static/js/upstream/jquery-ui.min.js +13 -0
  122. aprsd/web/chat/static/js/upstream/jquery.toast.js +374 -0
  123. aprsd/web/chat/static/js/upstream/semantic.min.js +11 -0
  124. aprsd/web/chat/static/js/upstream/socket.io.min.js +7 -0
  125. aprsd/web/chat/templates/index.html +139 -0
  126. aprsd/wsgi.py +315 -0
  127. aprsd-3.4.1.dist-info/AUTHORS +13 -0
  128. aprsd-3.4.1.dist-info/LICENSE +175 -0
  129. aprsd-3.4.1.dist-info/METADATA +799 -0
  130. aprsd-3.4.1.dist-info/RECORD +134 -0
  131. {aprsd-1.0.0.dist-info → aprsd-3.4.1.dist-info}/WHEEL +1 -1
  132. aprsd-3.4.1.dist-info/entry_points.txt +8 -0
  133. aprsd/fake_aprs.py +0 -83
  134. aprsd/utils.py +0 -166
  135. aprsd-1.0.0.dist-info/AUTHORS +0 -6
  136. aprsd-1.0.0.dist-info/METADATA +0 -181
  137. aprsd-1.0.0.dist-info/RECORD +0 -13
  138. aprsd-1.0.0.dist-info/entry_points.txt +0 -4
  139. aprsd-1.0.0.dist-info/pbr.json +0 -1
  140. /aprsd/{fuzzyclock.py → utils/fuzzyclock.py} +0 -0
  141. {aprsd-1.0.0.dist-info → aprsd-3.4.1.dist-info}/top_level.txt +0 -0
aprsd/cmds/listen.py ADDED
@@ -0,0 +1,230 @@
1
+ #
2
+ # License GPLv2
3
+ #
4
+
5
+ # python included libs
6
+ import datetime
7
+ import logging
8
+ import signal
9
+ import sys
10
+ import time
11
+
12
+ import click
13
+ from oslo_config import cfg
14
+ from rich.console import Console
15
+
16
+ # local imports here
17
+ import aprsd
18
+ from aprsd import cli_helper, packets, plugin, threads
19
+ from aprsd.client import client_factory
20
+ from aprsd.main import cli
21
+ from aprsd.packets import collector as packet_collector
22
+ from aprsd.packets import log as packet_log
23
+ from aprsd.packets import seen_list
24
+ from aprsd.stats import collector
25
+ from aprsd.threads import keep_alive, rx
26
+ from aprsd.threads import stats as stats_thread
27
+
28
+
29
+ # setup the global logger
30
+ # log.basicConfig(level=log.DEBUG) # level=10
31
+ LOG = logging.getLogger("APRSD")
32
+ CONF = cfg.CONF
33
+ console = Console()
34
+
35
+
36
+ def signal_handler(sig, frame):
37
+ threads.APRSDThreadList().stop_all()
38
+ if "subprocess" not in str(frame):
39
+ LOG.info(
40
+ "Ctrl+C, Sending all threads exit! Can take up to 10 seconds {}".format(
41
+ datetime.datetime.now(),
42
+ ),
43
+ )
44
+ time.sleep(5)
45
+ LOG.info(collector.Collector().collect())
46
+
47
+
48
+ class APRSDListenThread(rx.APRSDRXThread):
49
+ def __init__(self, packet_queue, packet_filter=None, plugin_manager=None):
50
+ super().__init__(packet_queue)
51
+ self.packet_filter = packet_filter
52
+ self.plugin_manager = plugin_manager
53
+ if self.plugin_manager:
54
+ LOG.info(f"Plugins {self.plugin_manager.get_message_plugins()}")
55
+
56
+ def process_packet(self, *args, **kwargs):
57
+ packet = self._client.decode_packet(*args, **kwargs)
58
+ filters = {
59
+ packets.Packet.__name__: packets.Packet,
60
+ packets.AckPacket.__name__: packets.AckPacket,
61
+ packets.BeaconPacket.__name__: packets.BeaconPacket,
62
+ packets.GPSPacket.__name__: packets.GPSPacket,
63
+ packets.MessagePacket.__name__: packets.MessagePacket,
64
+ packets.MicEPacket.__name__: packets.MicEPacket,
65
+ packets.ObjectPacket.__name__: packets.ObjectPacket,
66
+ packets.StatusPacket.__name__: packets.StatusPacket,
67
+ packets.ThirdPartyPacket.__name__: packets.ThirdPartyPacket,
68
+ packets.WeatherPacket.__name__: packets.WeatherPacket,
69
+ packets.UnknownPacket.__name__: packets.UnknownPacket,
70
+ }
71
+
72
+ if self.packet_filter:
73
+ filter_class = filters[self.packet_filter]
74
+ if isinstance(packet, filter_class):
75
+ packet_log.log(packet)
76
+ if self.plugin_manager:
77
+ # Don't do anything with the reply
78
+ # This is the listen only command.
79
+ self.plugin_manager.run(packet)
80
+ else:
81
+ packet_log.log(packet)
82
+ if self.plugin_manager:
83
+ # Don't do anything with the reply.
84
+ # This is the listen only command.
85
+ self.plugin_manager.run(packet)
86
+
87
+ packet_collector.PacketCollector().rx(packet)
88
+
89
+
90
+ @cli.command()
91
+ @cli_helper.add_options(cli_helper.common_options)
92
+ @click.option(
93
+ "--aprs-login",
94
+ envvar="APRS_LOGIN",
95
+ show_envvar=True,
96
+ help="What callsign to send the message from.",
97
+ )
98
+ @click.option(
99
+ "--aprs-password",
100
+ envvar="APRS_PASSWORD",
101
+ show_envvar=True,
102
+ help="the APRS-IS password for APRS_LOGIN",
103
+ )
104
+ @click.option(
105
+ "--packet-filter",
106
+ type=click.Choice(
107
+ [
108
+ packets.AckPacket.__name__,
109
+ packets.BeaconPacket.__name__,
110
+ packets.GPSPacket.__name__,
111
+ packets.MicEPacket.__name__,
112
+ packets.MessagePacket.__name__,
113
+ packets.ObjectPacket.__name__,
114
+ packets.RejectPacket.__name__,
115
+ packets.StatusPacket.__name__,
116
+ packets.ThirdPartyPacket.__name__,
117
+ packets.UnknownPacket.__name__,
118
+ packets.WeatherPacket.__name__,
119
+ ],
120
+ case_sensitive=False,
121
+ ),
122
+ help="Filter by packet type",
123
+ )
124
+ @click.option(
125
+ "--load-plugins",
126
+ default=False,
127
+ is_flag=True,
128
+ help="Load plugins as enabled in aprsd.conf ?",
129
+ )
130
+ @click.argument(
131
+ "filter",
132
+ nargs=-1,
133
+ required=True,
134
+ )
135
+ @click.pass_context
136
+ @cli_helper.process_standard_options
137
+ def listen(
138
+ ctx,
139
+ aprs_login,
140
+ aprs_password,
141
+ packet_filter,
142
+ load_plugins,
143
+ filter,
144
+ ):
145
+ """Listen to packets on the APRS-IS Network based on FILTER.
146
+
147
+ FILTER is the APRS Filter to use.\n
148
+ see http://www.aprs-is.net/javAPRSFilter.aspx\n
149
+ r/lat/lon/dist - Range Filter Pass posits and objects within dist km from lat/lon.\n
150
+ p/aa/bb/cc... - Prefix Filter Pass traffic with fromCall that start with aa or bb or cc.\n
151
+ b/call1/call2... - Budlist Filter Pass all traffic from exact call: call1, call2, ... (* wild card allowed) \n
152
+ o/obj1/obj2... - Object Filter Pass all objects with the exact name of obj1, obj2, ... (* wild card allowed)\n
153
+
154
+ """
155
+ signal.signal(signal.SIGINT, signal_handler)
156
+ signal.signal(signal.SIGTERM, signal_handler)
157
+
158
+ if not aprs_login:
159
+ click.echo(ctx.get_help())
160
+ click.echo("")
161
+ ctx.fail("Must set --aprs-login or APRS_LOGIN")
162
+ ctx.exit()
163
+
164
+ if not aprs_password:
165
+ click.echo(ctx.get_help())
166
+ click.echo("")
167
+ ctx.fail("Must set --aprs-password or APRS_PASSWORD")
168
+ ctx.exit()
169
+
170
+ # CONF.aprs_network.login = aprs_login
171
+ # config["aprs"]["password"] = aprs_password
172
+
173
+ LOG.info(f"APRSD Listen Started version: {aprsd.__version__}")
174
+
175
+ CONF.log_opt_values(LOG, logging.DEBUG)
176
+ collector.Collector()
177
+
178
+ # Try and load saved MsgTrack list
179
+ LOG.debug("Loading saved MsgTrack object.")
180
+
181
+ # Initialize the client factory and create
182
+ # The correct client object ready for use
183
+ # Make sure we have 1 client transport enabled
184
+ if not client_factory.is_client_enabled():
185
+ LOG.error("No Clients are enabled in config.")
186
+ sys.exit(-1)
187
+
188
+ # Creates the client object
189
+ LOG.info("Creating client connection")
190
+ aprs_client = client_factory.create()
191
+ LOG.info(aprs_client)
192
+
193
+ LOG.debug(f"Filter by '{filter}'")
194
+ aprs_client.set_filter(filter)
195
+
196
+ keepalive = keep_alive.KeepAliveThread()
197
+ # keepalive.start()
198
+
199
+ if not CONF.enable_seen_list:
200
+ # just deregister the class from the packet collector
201
+ packet_collector.PacketCollector().unregister(seen_list.SeenList)
202
+
203
+ pm = None
204
+ pm = plugin.PluginManager()
205
+ if load_plugins:
206
+ LOG.info("Loading plugins")
207
+ pm.setup_plugins(load_help_plugin=False)
208
+ else:
209
+ LOG.warning(
210
+ "Not Loading any plugins use --load-plugins to load what's "
211
+ "defined in the config file.",
212
+ )
213
+ stats = stats_thread.APRSDStatsStoreThread()
214
+ stats.start()
215
+
216
+ LOG.debug("Create APRSDListenThread")
217
+ listen_thread = APRSDListenThread(
218
+ packet_queue=threads.packet_queue,
219
+ packet_filter=packet_filter,
220
+ plugin_manager=pm,
221
+ )
222
+ LOG.debug("Start APRSDListenThread")
223
+ listen_thread.start()
224
+
225
+ keepalive.start()
226
+ LOG.debug("keepalive Join")
227
+ keepalive.join()
228
+ LOG.debug("listen_thread Join")
229
+ listen_thread.join()
230
+ stats.join()
@@ -0,0 +1,174 @@
1
+ import logging
2
+ import sys
3
+ import time
4
+
5
+ import aprslib
6
+ from aprslib.exceptions import LoginError
7
+ import click
8
+ from oslo_config import cfg
9
+
10
+ import aprsd
11
+ from aprsd import cli_helper, packets
12
+ from aprsd import conf # noqa : F401
13
+ from aprsd.client import client_factory
14
+ from aprsd.main import cli
15
+ from aprsd.packets import collector
16
+ from aprsd.threads import tx
17
+
18
+
19
+ CONF = cfg.CONF
20
+ LOG = logging.getLogger("APRSD")
21
+
22
+
23
+ @cli.command()
24
+ @cli_helper.add_options(cli_helper.common_options)
25
+ @click.option(
26
+ "--aprs-login",
27
+ envvar="APRS_LOGIN",
28
+ show_envvar=True,
29
+ help="What callsign to send the message from. Defaults to config entry.",
30
+ )
31
+ @click.option(
32
+ "--aprs-password",
33
+ envvar="APRS_PASSWORD",
34
+ show_envvar=True,
35
+ help="the APRS-IS password for APRS_LOGIN. Defaults to config entry.",
36
+ )
37
+ @click.option(
38
+ "--no-ack",
39
+ "-n",
40
+ is_flag=True,
41
+ show_default=True,
42
+ default=False,
43
+ help="Don't wait for an ack, just sent it to APRS-IS and bail.",
44
+ )
45
+ @click.option(
46
+ "--wait-response",
47
+ "-w",
48
+ is_flag=True,
49
+ show_default=True,
50
+ default=False,
51
+ help="Wait for a response to the message?",
52
+ )
53
+ @click.option("--raw", default=None, help="Send a raw message. Implies --no-ack")
54
+ @click.argument("tocallsign", required=True)
55
+ @click.argument("command", nargs=-1, required=True)
56
+ @click.pass_context
57
+ @cli_helper.process_standard_options
58
+ def send_message(
59
+ ctx,
60
+ aprs_login,
61
+ aprs_password,
62
+ no_ack,
63
+ wait_response,
64
+ raw,
65
+ tocallsign,
66
+ command,
67
+ ):
68
+ """Send a message to a callsign via APRS_IS."""
69
+ global got_ack, got_response
70
+ quiet = ctx.obj["quiet"]
71
+
72
+ if not aprs_login:
73
+ if CONF.aprs_network.login == conf.client.DEFAULT_LOGIN:
74
+ click.echo("Must set --aprs_login or APRS_LOGIN")
75
+ ctx.exit(-1)
76
+ return
77
+ else:
78
+ aprs_login = CONF.aprs_network.login
79
+
80
+ if not aprs_password:
81
+ if not CONF.aprs_network.password:
82
+ click.echo("Must set --aprs-password or APRS_PASSWORD")
83
+ ctx.exit(-1)
84
+ return
85
+ else:
86
+ aprs_password = CONF.aprs_network.password
87
+
88
+ LOG.info(f"APRSD LISTEN Started version: {aprsd.__version__}")
89
+ if type(command) is tuple:
90
+ command = " ".join(command)
91
+ if not quiet:
92
+ if raw:
93
+ LOG.info(f"L'{aprs_login}' R'{raw}'")
94
+ else:
95
+ LOG.info(f"L'{aprs_login}' To'{tocallsign}' C'{command}'")
96
+
97
+ packets.PacketList()
98
+ packets.WatchList()
99
+ packets.SeenList()
100
+
101
+ got_ack = False
102
+ got_response = False
103
+
104
+ def rx_packet(packet):
105
+ global got_ack, got_response
106
+ cl = client_factory.create()
107
+ packet = cl.decode_packet(packet)
108
+ collector.PacketCollector().rx(packet)
109
+ packet.log("RX")
110
+ # LOG.debug("Got packet back {}".format(packet))
111
+ if isinstance(packet, packets.AckPacket):
112
+ got_ack = True
113
+ else:
114
+ got_response = True
115
+ from_call = packet.from_call
116
+ our_call = CONF.callsign.lower()
117
+ tx.send(
118
+ packets.AckPacket(
119
+ from_call=our_call,
120
+ to_call=from_call,
121
+ msgNo=packet.msgNo,
122
+ ),
123
+ direct=True,
124
+ )
125
+
126
+ if got_ack:
127
+ if wait_response:
128
+ if got_response:
129
+ sys.exit(0)
130
+ else:
131
+ sys.exit(0)
132
+
133
+ try:
134
+ client_factory.create().client
135
+ except LoginError:
136
+ sys.exit(-1)
137
+
138
+ # Send a message
139
+ # then we setup a consumer to rx messages
140
+ # We should get an ack back as well as a new message
141
+ # we should bail after we get the ack and send an ack back for the
142
+ # message
143
+ if raw:
144
+ tx.send(
145
+ packets.Packet(from_call="", to_call="", raw=raw),
146
+ direct=True,
147
+ )
148
+ sys.exit(0)
149
+ else:
150
+ tx.send(
151
+ packets.MessagePacket(
152
+ from_call=aprs_login,
153
+ to_call=tocallsign,
154
+ message_text=command,
155
+ ),
156
+ direct=True,
157
+ )
158
+
159
+ if no_ack:
160
+ sys.exit(0)
161
+
162
+ try:
163
+ # This will register a packet consumer with aprslib
164
+ # When new packets come in the consumer will process
165
+ # the packet
166
+ aprs_client = client_factory.create().client
167
+ aprs_client.consumer(rx_packet, raw=False)
168
+ except aprslib.exceptions.ConnectionDrop:
169
+ LOG.error("Connection dropped, reconnecting")
170
+ time.sleep(5)
171
+ # Force the deletion of the client object connected to aprs
172
+ # This will cause a reconnect, next time client.get_client()
173
+ # is called
174
+ aprs_client.reset()
aprsd/cmds/server.py ADDED
@@ -0,0 +1,142 @@
1
+ import logging
2
+ import signal
3
+ import sys
4
+
5
+ import click
6
+ from oslo_config import cfg
7
+
8
+ import aprsd
9
+ from aprsd import cli_helper
10
+ from aprsd import main as aprsd_main
11
+ from aprsd import packets, plugin, threads, utils
12
+ from aprsd.client import client_factory
13
+ from aprsd.main import cli
14
+ from aprsd.packets import collector as packet_collector
15
+ from aprsd.packets import seen_list
16
+ from aprsd.threads import keep_alive, log_monitor, registry, rx
17
+ from aprsd.threads import stats as stats_thread
18
+ from aprsd.threads import tx
19
+
20
+
21
+ CONF = cfg.CONF
22
+ LOG = logging.getLogger("APRSD")
23
+
24
+
25
+ # main() ###
26
+ @cli.command()
27
+ @cli_helper.add_options(cli_helper.common_options)
28
+ @click.option(
29
+ "-f",
30
+ "--flush",
31
+ "flush",
32
+ is_flag=True,
33
+ show_default=True,
34
+ default=False,
35
+ help="Flush out all old aged messages on disk.",
36
+ )
37
+ @click.pass_context
38
+ @cli_helper.process_standard_options
39
+ def server(ctx, flush):
40
+ """Start the aprsd server gateway process."""
41
+ signal.signal(signal.SIGINT, aprsd_main.signal_handler)
42
+ signal.signal(signal.SIGTERM, aprsd_main.signal_handler)
43
+
44
+ level, msg = utils._check_version()
45
+ if level:
46
+ LOG.warning(msg)
47
+ else:
48
+ LOG.info(msg)
49
+ LOG.info(f"APRSD Started version: {aprsd.__version__}")
50
+
51
+ # Initialize the client factory and create
52
+ # The correct client object ready for use
53
+ if not client_factory.is_client_enabled():
54
+ LOG.error("No Clients are enabled in config.")
55
+ sys.exit(-1)
56
+
57
+ # Creates the client object
58
+ LOG.info("Creating client connection")
59
+ aprs_client = client_factory.create()
60
+ LOG.info(aprs_client)
61
+
62
+ # Create the initial PM singleton and Register plugins
63
+ # We register plugins first here so we can register each
64
+ # plugins config options, so we can dump them all in the
65
+ # log file output.
66
+ LOG.info("Loading Plugin Manager and registering plugins")
67
+ plugin_manager = plugin.PluginManager()
68
+ plugin_manager.setup_plugins()
69
+
70
+ # Dump all the config options now.
71
+ CONF.log_opt_values(LOG, logging.DEBUG)
72
+ message_plugins = plugin_manager.get_message_plugins()
73
+ watchlist_plugins = plugin_manager.get_watchlist_plugins()
74
+ LOG.info("Message Plugins enabled and running:")
75
+ for p in message_plugins:
76
+ LOG.info(p)
77
+ LOG.info("Watchlist Plugins enabled and running:")
78
+ for p in watchlist_plugins:
79
+ LOG.info(p)
80
+
81
+ # Make sure we have 1 client transport enabled
82
+ if not client_factory.is_client_enabled():
83
+ LOG.error("No Clients are enabled in config.")
84
+ sys.exit(-1)
85
+
86
+ if not client_factory.is_client_configured():
87
+ LOG.error("APRS client is not properly configured in config file.")
88
+ sys.exit(-1)
89
+
90
+ # Now load the msgTrack from disk if any
91
+ packets.PacketList()
92
+ if flush:
93
+ LOG.debug("Deleting saved MsgTrack.")
94
+ packets.PacketTrack().flush()
95
+ packets.WatchList().flush()
96
+ packets.SeenList().flush()
97
+ packets.PacketList().flush()
98
+ else:
99
+ # Try and load saved MsgTrack list
100
+ LOG.debug("Loading saved MsgTrack object.")
101
+ packets.PacketTrack().load()
102
+ packets.WatchList().load()
103
+ packets.SeenList().load()
104
+ packets.PacketList().load()
105
+
106
+ keepalive = keep_alive.KeepAliveThread()
107
+ keepalive.start()
108
+
109
+ if not CONF.enable_seen_list:
110
+ # just deregister the class from the packet collector
111
+ packet_collector.PacketCollector().unregister(seen_list.SeenList)
112
+
113
+ stats_store_thread = stats_thread.APRSDStatsStoreThread()
114
+ stats_store_thread.start()
115
+
116
+ rx_thread = rx.APRSDPluginRXThread(
117
+ packet_queue=threads.packet_queue,
118
+ )
119
+ process_thread = rx.APRSDPluginProcessPacketThread(
120
+ packet_queue=threads.packet_queue,
121
+ )
122
+ rx_thread.start()
123
+ process_thread.start()
124
+
125
+ if CONF.enable_beacon:
126
+ LOG.info("Beacon Enabled. Starting Beacon thread.")
127
+ bcn_thread = tx.BeaconSendThread()
128
+ bcn_thread.start()
129
+
130
+ if CONF.aprs_registry.enabled:
131
+ LOG.info("Registry Enabled. Starting Registry thread.")
132
+ registry_thread = registry.APRSRegistryThread()
133
+ registry_thread.start()
134
+
135
+ if CONF.admin.web_enabled:
136
+ log_monitor_thread = log_monitor.LogMonitorThread()
137
+ log_monitor_thread.start()
138
+
139
+ rx_thread.join()
140
+ process_thread.join()
141
+
142
+ return 0