aprsd 3.4.3__py3-none-any.whl → 4.0.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.
Files changed (117) hide show
  1. aprsd/cli_helper.py +12 -5
  2. aprsd/client/aprsis.py +68 -17
  3. aprsd/client/base.py +60 -12
  4. aprsd/client/drivers/aprsis.py +11 -5
  5. aprsd/client/drivers/fake.py +15 -20
  6. aprsd/client/factory.py +6 -3
  7. aprsd/client/fake.py +5 -4
  8. aprsd/client/kiss.py +43 -7
  9. aprsd/client/stats.py +2 -22
  10. aprsd/cmds/completion.py +7 -4
  11. aprsd/cmds/dev.py +39 -43
  12. aprsd/cmds/fetch_stats.py +221 -69
  13. aprsd/cmds/healthcheck.py +7 -5
  14. aprsd/cmds/list_plugins.py +140 -134
  15. aprsd/cmds/listen.py +102 -11
  16. aprsd/cmds/server.py +71 -37
  17. aprsd/conf/__init__.py +1 -2
  18. aprsd/conf/client.py +3 -4
  19. aprsd/conf/common.py +29 -92
  20. aprsd/conf/log.py +2 -4
  21. aprsd/conf/opts.py +5 -4
  22. aprsd/conf/plugin_common.py +11 -121
  23. aprsd/exception.py +2 -0
  24. aprsd/log/log.py +7 -46
  25. aprsd/main.py +19 -9
  26. aprsd/packets/__init__.py +14 -4
  27. aprsd/packets/core.py +82 -91
  28. aprsd/packets/log.py +8 -8
  29. aprsd/packets/packet_list.py +18 -25
  30. aprsd/plugin.py +33 -15
  31. aprsd/plugins/fortune.py +2 -2
  32. aprsd/plugins/notify.py +1 -4
  33. aprsd/plugins/weather.py +10 -8
  34. aprsd/stats/__init__.py +0 -2
  35. aprsd/stats/collector.py +11 -3
  36. aprsd/threads/__init__.py +3 -2
  37. aprsd/threads/aprsd.py +57 -10
  38. aprsd/threads/{keep_alive.py → keepalive.py} +14 -37
  39. aprsd/threads/registry.py +3 -3
  40. aprsd/threads/rx.py +48 -17
  41. aprsd/threads/stats.py +2 -2
  42. aprsd/threads/tx.py +34 -10
  43. aprsd/utils/__init__.py +62 -15
  44. aprsd/utils/counter.py +15 -12
  45. aprsd/utils/json.py +9 -4
  46. aprsd/utils/keepalive_collector.py +55 -0
  47. aprsd/utils/trace.py +4 -4
  48. aprsd-4.0.0.dist-info/AUTHORS +1 -0
  49. aprsd-4.0.0.dist-info/METADATA +293 -0
  50. aprsd-4.0.0.dist-info/RECORD +74 -0
  51. {aprsd-3.4.3.dist-info → aprsd-4.0.0.dist-info}/WHEEL +1 -1
  52. aprsd/cmds/webchat.py +0 -674
  53. aprsd/conf/plugin_email.py +0 -105
  54. aprsd/plugins/email.py +0 -709
  55. aprsd/plugins/location.py +0 -179
  56. aprsd/threads/log_monitor.py +0 -121
  57. aprsd/web/__init__.py +0 -0
  58. aprsd/web/admin/__init__.py +0 -0
  59. aprsd/web/admin/static/css/index.css +0 -84
  60. aprsd/web/admin/static/css/prism.css +0 -4
  61. aprsd/web/admin/static/css/tabs.css +0 -35
  62. aprsd/web/admin/static/images/Untitled.png +0 -0
  63. aprsd/web/admin/static/images/aprs-symbols-16-0.png +0 -0
  64. aprsd/web/admin/static/images/aprs-symbols-16-1.png +0 -0
  65. aprsd/web/admin/static/images/aprs-symbols-64-0.png +0 -0
  66. aprsd/web/admin/static/images/aprs-symbols-64-1.png +0 -0
  67. aprsd/web/admin/static/images/aprs-symbols-64-2.png +0 -0
  68. aprsd/web/admin/static/js/charts.js +0 -235
  69. aprsd/web/admin/static/js/echarts.js +0 -465
  70. aprsd/web/admin/static/js/logs.js +0 -26
  71. aprsd/web/admin/static/js/main.js +0 -231
  72. aprsd/web/admin/static/js/prism.js +0 -12
  73. aprsd/web/admin/static/js/send-message.js +0 -114
  74. aprsd/web/admin/static/js/tabs.js +0 -28
  75. aprsd/web/admin/templates/index.html +0 -196
  76. aprsd/web/chat/static/css/chat.css +0 -115
  77. aprsd/web/chat/static/css/index.css +0 -66
  78. aprsd/web/chat/static/css/style.css.map +0 -1
  79. aprsd/web/chat/static/css/tabs.css +0 -41
  80. aprsd/web/chat/static/css/upstream/bootstrap.min.css +0 -6
  81. aprsd/web/chat/static/css/upstream/font.woff2 +0 -0
  82. aprsd/web/chat/static/css/upstream/google-fonts.css +0 -23
  83. aprsd/web/chat/static/css/upstream/jquery-ui.css +0 -1311
  84. aprsd/web/chat/static/css/upstream/jquery.toast.css +0 -28
  85. aprsd/web/chat/static/css/upstream/themes/default/assets/fonts/LatoLatin-Bold.woff +0 -0
  86. aprsd/web/chat/static/css/upstream/themes/default/assets/fonts/LatoLatin-Bold.woff2 +0 -0
  87. aprsd/web/chat/static/css/upstream/themes/default/assets/fonts/LatoLatin-Regular.woff +0 -0
  88. aprsd/web/chat/static/css/upstream/themes/default/assets/fonts/LatoLatin-Regular.woff2 +0 -0
  89. aprsd/web/chat/static/css/upstream/themes/default/assets/fonts/icons.woff +0 -0
  90. aprsd/web/chat/static/css/upstream/themes/default/assets/fonts/icons.woff2 +0 -0
  91. aprsd/web/chat/static/css/upstream/themes/default/assets/fonts/outline-icons.woff +0 -0
  92. aprsd/web/chat/static/css/upstream/themes/default/assets/fonts/outline-icons.woff2 +0 -0
  93. aprsd/web/chat/static/images/Untitled.png +0 -0
  94. aprsd/web/chat/static/images/aprs-symbols-16-0.png +0 -0
  95. aprsd/web/chat/static/images/aprs-symbols-16-1.png +0 -0
  96. aprsd/web/chat/static/images/aprs-symbols-64-0.png +0 -0
  97. aprsd/web/chat/static/images/aprs-symbols-64-1.png +0 -0
  98. aprsd/web/chat/static/images/aprs-symbols-64-2.png +0 -0
  99. aprsd/web/chat/static/images/globe.svg +0 -3
  100. aprsd/web/chat/static/js/gps.js +0 -84
  101. aprsd/web/chat/static/js/main.js +0 -45
  102. aprsd/web/chat/static/js/send-message.js +0 -585
  103. aprsd/web/chat/static/js/tabs.js +0 -28
  104. aprsd/web/chat/static/js/upstream/bootstrap.bundle.min.js +0 -7
  105. aprsd/web/chat/static/js/upstream/jquery-3.7.1.min.js +0 -2
  106. aprsd/web/chat/static/js/upstream/jquery-ui.min.js +0 -13
  107. aprsd/web/chat/static/js/upstream/jquery.toast.js +0 -374
  108. aprsd/web/chat/static/js/upstream/semantic.min.js +0 -11
  109. aprsd/web/chat/static/js/upstream/socket.io.min.js +0 -7
  110. aprsd/web/chat/templates/index.html +0 -139
  111. aprsd/wsgi.py +0 -315
  112. aprsd-3.4.3.dist-info/AUTHORS +0 -13
  113. aprsd-3.4.3.dist-info/METADATA +0 -793
  114. aprsd-3.4.3.dist-info/RECORD +0 -133
  115. {aprsd-3.4.3.dist-info → aprsd-4.0.0.dist-info}/LICENSE +0 -0
  116. {aprsd-3.4.3.dist-info → aprsd-4.0.0.dist-info}/entry_points.txt +0 -0
  117. {aprsd-3.4.3.dist-info → aprsd-4.0.0.dist-info}/top_level.txt +0 -0
aprsd/cmds/completion.py CHANGED
@@ -3,12 +3,13 @@ import click.shell_completion
3
3
 
4
4
  from aprsd.main import cli
5
5
 
6
-
7
6
  CONTEXT_SETTINGS = dict(help_option_names=["-h", "--help"])
8
7
 
9
8
 
10
9
  @cli.command()
11
- @click.argument("shell", type=click.Choice(list(click.shell_completion._available_shells)))
10
+ @click.argument(
11
+ "shell", type=click.Choice(list(click.shell_completion._available_shells))
12
+ )
12
13
  def completion(shell):
13
14
  """Show the shell completion code"""
14
15
  from click.utils import _detect_program_name
@@ -17,6 +18,8 @@ def completion(shell):
17
18
  prog_name = _detect_program_name()
18
19
  complete_var = f"_{prog_name}_COMPLETE".replace("-", "_").upper()
19
20
  print(cls(cli, {}, prog_name, complete_var).source())
20
- print("# Add the following line to your shell configuration file to have aprsd command line completion")
21
+ print(
22
+ "# Add the following line to your shell configuration file to have aprsd command line completion"
23
+ )
21
24
  print("# but remove the leading '#' character.")
22
- print(f"# eval \"$(aprsd completion {shell})\"")
25
+ print(f'# eval "$(aprsd completion {shell})"')
aprsd/cmds/dev.py CHANGED
@@ -9,18 +9,18 @@ import click
9
9
  from oslo_config import cfg
10
10
 
11
11
  from aprsd import cli_helper, conf, packets, plugin
12
+
12
13
  # local imports here
13
14
  from aprsd.client import base
14
15
  from aprsd.main import cli
15
16
  from aprsd.utils import trace
16
17
 
17
-
18
18
  CONF = cfg.CONF
19
- LOG = logging.getLogger("APRSD")
20
- CONTEXT_SETTINGS = dict(help_option_names=["-h", "--help"])
19
+ LOG = logging.getLogger('APRSD')
20
+ CONTEXT_SETTINGS = dict(help_option_names=['-h', '--help'])
21
21
 
22
22
 
23
- @cli.group(help="Development type subcommands", context_settings=CONTEXT_SETTINGS)
23
+ @cli.group(help='Development type subcommands', context_settings=CONTEXT_SETTINGS)
24
24
  @click.pass_context
25
25
  def dev(ctx):
26
26
  pass
@@ -29,37 +29,37 @@ def dev(ctx):
29
29
  @dev.command()
30
30
  @cli_helper.add_options(cli_helper.common_options)
31
31
  @click.option(
32
- "--aprs-login",
33
- envvar="APRS_LOGIN",
32
+ '--aprs-login',
33
+ envvar='APRS_LOGIN',
34
34
  show_envvar=True,
35
- help="What callsign to send the message from.",
35
+ help='What callsign to send the message from.',
36
36
  )
37
37
  @click.option(
38
- "-p",
39
- "--plugin",
40
- "plugin_path",
38
+ '-p',
39
+ '--plugin',
40
+ 'plugin_path',
41
41
  show_default=True,
42
42
  default=None,
43
- help="The plugin to run. Ex: aprsd.plugins.ping.PingPlugin",
43
+ help='The plugin to run. Ex: aprsd.plugins.ping.PingPlugin',
44
44
  )
45
45
  @click.option(
46
- "-a",
47
- "--all",
48
- "load_all",
46
+ '-a',
47
+ '--all',
48
+ 'load_all',
49
49
  show_default=True,
50
50
  is_flag=True,
51
51
  default=False,
52
- help="Load all the plugins in config?",
52
+ help='Load all the plugins in config?',
53
53
  )
54
54
  @click.option(
55
- "-n",
56
- "--num",
57
- "number",
55
+ '-n',
56
+ '--num',
57
+ 'number',
58
58
  show_default=True,
59
59
  default=1,
60
- help="Number of times to call the plugin",
60
+ help='Number of times to call the plugin',
61
61
  )
62
- @click.argument("message", nargs=-1, required=True)
62
+ @click.argument('message', nargs=-1, required=True)
63
63
  @click.pass_context
64
64
  @cli_helper.process_standard_options
65
65
  def test_plugin(
@@ -76,7 +76,7 @@ def test_plugin(
76
76
 
77
77
  if not aprs_login:
78
78
  if CONF.aprs_network.login == conf.client.DEFAULT_LOGIN:
79
- click.echo("Must set --aprs_login or APRS_LOGIN")
79
+ click.echo('Must set --aprs_login or APRS_LOGIN')
80
80
  ctx.exit(-1)
81
81
  return
82
82
  else:
@@ -86,33 +86,34 @@ def test_plugin(
86
86
 
87
87
  if not plugin_path:
88
88
  click.echo(ctx.get_help())
89
- click.echo("")
90
- click.echo("Failed to provide -p option to test a plugin")
89
+ click.echo('')
90
+ click.echo('Failed to provide -p option to test a plugin')
91
91
  ctx.exit(-1)
92
92
  return
93
93
 
94
94
  if type(message) is tuple:
95
- message = " ".join(message)
95
+ message = ' '.join(message)
96
96
 
97
97
  if CONF.trace_enabled:
98
- trace.setup_tracing(["method", "api"])
98
+ trace.setup_tracing(['method', 'api'])
99
99
 
100
100
  base.APRSClient()
101
101
 
102
102
  pm = plugin.PluginManager()
103
103
  if load_all:
104
- pm.setup_plugins()
104
+ pm.setup_plugins(load_help_plugin=CONF.load_help_plugin)
105
105
  obj = pm._create_class(plugin_path, plugin.APRSDPluginBase)
106
106
  if not obj:
107
107
  click.echo(ctx.get_help())
108
- click.echo("")
108
+ click.echo('')
109
109
  ctx.fail(f"Failed to create object from plugin path '{plugin_path}'")
110
110
  ctx.exit()
111
111
 
112
112
  # Register the plugin they wanted tested.
113
113
  LOG.info(
114
- "Testing plugin {} Version {}".format(
115
- obj.__class__, obj.version,
114
+ 'Testing plugin {} Version {}'.format(
115
+ obj.__class__,
116
+ obj.version,
116
117
  ),
117
118
  )
118
119
  pm.register_msg(obj)
@@ -125,7 +126,7 @@ def test_plugin(
125
126
  )
126
127
  LOG.info(f"P'{plugin_path}' F'{fromcall}' C'{message}'")
127
128
 
128
- for x in range(number):
129
+ for _ in range(number):
129
130
  replies = pm.run(packet)
130
131
  # Plugin might have threads, so lets stop them so we can exit.
131
132
  # obj.stop_threads()
@@ -146,17 +147,12 @@ def test_plugin(
146
147
  elif isinstance(reply, packets.Packet):
147
148
  # We have a message based object.
148
149
  LOG.info(reply)
149
- else:
150
- # A plugin can return a null message flag which signals
151
- # us that they processed the message correctly, but have
152
- # nothing to reply with, so we avoid replying with a
153
- # usage string
154
- if reply is not packets.NULL_MESSAGE:
155
- LOG.info(
156
- packets.MessagePacket(
157
- from_call=CONF.callsign,
158
- to_call=fromcall,
159
- message_text=reply,
160
- ),
161
- )
150
+ elif reply is not packets.NULL_MESSAGE:
151
+ LOG.info(
152
+ packets.MessagePacket(
153
+ from_call=CONF.callsign,
154
+ to_call=fromcall,
155
+ message_text=reply,
156
+ ),
157
+ )
162
158
  pm.stop()
aprsd/cmds/fetch_stats.py CHANGED
@@ -2,8 +2,8 @@
2
2
  import logging
3
3
 
4
4
  import click
5
- from oslo_config import cfg
6
5
  import requests
6
+ from oslo_config import cfg
7
7
  from rich.console import Console
8
8
  from rich.table import Table
9
9
 
@@ -11,32 +11,34 @@ from rich.table import Table
11
11
  import aprsd
12
12
  from aprsd import cli_helper
13
13
  from aprsd.main import cli
14
-
14
+ from aprsd.threads.stats import StatsStore
15
15
 
16
16
  # setup the global logger
17
17
  # log.basicConfig(level=log.DEBUG) # level=10
18
- LOG = logging.getLogger("APRSD")
18
+ LOG = logging.getLogger('APRSD')
19
19
  CONF = cfg.CONF
20
20
 
21
21
 
22
22
  @cli.command()
23
23
  @cli_helper.add_options(cli_helper.common_options)
24
24
  @click.option(
25
- "--host", type=str,
25
+ '--host',
26
+ type=str,
26
27
  default=None,
27
- help="IP address of the remote aprsd admin web ui fetch stats from.",
28
+ help='IP address of the remote aprsd admin web ui fetch stats from.',
28
29
  )
29
30
  @click.option(
30
- "--port", type=int,
31
+ '--port',
32
+ type=int,
31
33
  default=None,
32
- help="Port of the remote aprsd web admin interface to fetch stats from.",
34
+ help='Port of the remote aprsd web admin interface to fetch stats from.',
33
35
  )
34
36
  @click.pass_context
35
37
  @cli_helper.process_standard_options
36
38
  def fetch_stats(ctx, host, port):
37
39
  """Fetch stats from a APRSD admin web interface."""
38
40
  console = Console()
39
- console.print(f"APRSD Fetch-Stats started version: {aprsd.__version__}")
41
+ console.print(f'APRSD Fetch-Stats started version: {aprsd.__version__}')
40
42
 
41
43
  CONF.log_opt_values(LOG, logging.DEBUG)
42
44
  if not host:
@@ -44,113 +46,263 @@ def fetch_stats(ctx, host, port):
44
46
  if not port:
45
47
  port = CONF.admin.web_port
46
48
 
47
- msg = f"Fetching stats from {host}:{port}"
49
+ msg = f'Fetching stats from {host}:{port}'
48
50
  console.print(msg)
49
51
  with console.status(msg):
50
- response = requests.get(f"http://{host}:{port}/stats", timeout=120)
52
+ response = requests.get(f'http://{host}:{port}/stats', timeout=120)
51
53
  if not response:
52
54
  console.print(
53
- f"Failed to fetch stats from {host}:{port}?",
54
- style="bold red",
55
+ f'Failed to fetch stats from {host}:{port}?',
56
+ style='bold red',
55
57
  )
56
58
  return
57
59
 
58
60
  stats = response.json()
59
61
  if not stats:
60
62
  console.print(
61
- f"Failed to fetch stats from aprsd admin ui at {host}:{port}",
62
- style="bold red",
63
+ f'Failed to fetch stats from aprsd admin ui at {host}:{port}',
64
+ style='bold red',
63
65
  )
64
66
  return
65
67
 
66
68
  aprsd_title = (
67
- "APRSD "
68
- f"[bold cyan]v{stats['APRSDStats']['version']}[/] "
69
- f"Callsign [bold green]{stats['APRSDStats']['callsign']}[/] "
70
- f"Uptime [bold yellow]{stats['APRSDStats']['uptime']}[/]"
69
+ 'APRSD '
70
+ f'[bold cyan]v{stats["APRSDStats"]["version"]}[/] '
71
+ f'Callsign [bold green]{stats["APRSDStats"]["callsign"]}[/] '
72
+ f'Uptime [bold yellow]{stats["APRSDStats"]["uptime"]}[/]'
71
73
  )
72
74
 
73
- console.rule(f"Stats from {host}:{port}")
74
- console.print("\n\n")
75
+ console.rule(f'Stats from {host}:{port}')
76
+ console.print('\n\n')
75
77
  console.rule(aprsd_title)
76
78
 
77
79
  # Show the connection to APRS
78
80
  # It can be a connection to an APRS-IS server or a local TNC via KISS or KISSTCP
79
- if "aprs-is" in stats:
80
- title = f"APRS-IS Connection {stats['APRSClientStats']['server_string']}"
81
+ if 'aprs-is' in stats:
82
+ title = f'APRS-IS Connection {stats["APRSClientStats"]["server_string"]}'
81
83
  table = Table(title=title)
82
- table.add_column("Key")
83
- table.add_column("Value")
84
- for key, value in stats["APRSClientStats"].items():
84
+ table.add_column('Key')
85
+ table.add_column('Value')
86
+ for key, value in stats['APRSClientStats'].items():
85
87
  table.add_row(key, value)
86
88
  console.print(table)
87
89
 
88
- threads_table = Table(title="Threads")
89
- threads_table.add_column("Name")
90
- threads_table.add_column("Alive?")
91
- for name, alive in stats["APRSDThreadList"].items():
90
+ threads_table = Table(title='Threads')
91
+ threads_table.add_column('Name')
92
+ threads_table.add_column('Alive?')
93
+ for name, alive in stats['APRSDThreadList'].items():
92
94
  threads_table.add_row(name, str(alive))
93
95
 
94
96
  console.print(threads_table)
95
97
 
96
- packet_totals = Table(title="Packet Totals")
97
- packet_totals.add_column("Key")
98
- packet_totals.add_column("Value")
99
- packet_totals.add_row("Total Received", str(stats["PacketList"]["rx"]))
100
- packet_totals.add_row("Total Sent", str(stats["PacketList"]["tx"]))
98
+ packet_totals = Table(title='Packet Totals')
99
+ packet_totals.add_column('Key')
100
+ packet_totals.add_column('Value')
101
+ packet_totals.add_row('Total Received', str(stats['PacketList']['rx']))
102
+ packet_totals.add_row('Total Sent', str(stats['PacketList']['tx']))
101
103
  console.print(packet_totals)
102
104
 
103
105
  # Show each of the packet types
104
- packets_table = Table(title="Packets By Type")
105
- packets_table.add_column("Packet Type")
106
- packets_table.add_column("TX")
107
- packets_table.add_column("RX")
108
- for key, value in stats["PacketList"]["packets"].items():
109
- packets_table.add_row(key, str(value["tx"]), str(value["rx"]))
106
+ packets_table = Table(title='Packets By Type')
107
+ packets_table.add_column('Packet Type')
108
+ packets_table.add_column('TX')
109
+ packets_table.add_column('RX')
110
+ for key, value in stats['PacketList']['packets'].items():
111
+ packets_table.add_row(key, str(value['tx']), str(value['rx']))
110
112
 
111
113
  console.print(packets_table)
112
114
 
113
- if "plugins" in stats:
114
- count = len(stats["PluginManager"])
115
- plugins_table = Table(title=f"Plugins ({count})")
116
- plugins_table.add_column("Plugin")
117
- plugins_table.add_column("Enabled")
118
- plugins_table.add_column("Version")
119
- plugins_table.add_column("TX")
120
- plugins_table.add_column("RX")
121
- plugins = stats["PluginManager"]
122
- for key, value in plugins.items():
115
+ if 'plugins' in stats:
116
+ count = len(stats['PluginManager'])
117
+ plugins_table = Table(title=f'Plugins ({count})')
118
+ plugins_table.add_column('Plugin')
119
+ plugins_table.add_column('Enabled')
120
+ plugins_table.add_column('Version')
121
+ plugins_table.add_column('TX')
122
+ plugins_table.add_column('RX')
123
+ plugins = stats['PluginManager']
124
+ for key, _ in plugins.items():
123
125
  plugins_table.add_row(
124
126
  key,
125
- str(plugins[key]["enabled"]),
126
- plugins[key]["version"],
127
- str(plugins[key]["tx"]),
128
- str(plugins[key]["rx"]),
127
+ str(plugins[key]['enabled']),
128
+ plugins[key]['version'],
129
+ str(plugins[key]['tx']),
130
+ str(plugins[key]['rx']),
129
131
  )
130
132
 
131
133
  console.print(plugins_table)
132
134
 
133
- seen_list = stats.get("SeenList")
134
-
135
- if seen_list:
135
+ if seen_list := stats.get('SeenList'):
136
136
  count = len(seen_list)
137
- seen_table = Table(title=f"Seen List ({count})")
138
- seen_table.add_column("Callsign")
139
- seen_table.add_column("Message Count")
140
- seen_table.add_column("Last Heard")
137
+ seen_table = Table(title=f'Seen List ({count})')
138
+ seen_table.add_column('Callsign')
139
+ seen_table.add_column('Message Count')
140
+ seen_table.add_column('Last Heard')
141
141
  for key, value in seen_list.items():
142
- seen_table.add_row(key, str(value["count"]), value["last"])
142
+ seen_table.add_row(key, str(value['count']), value['last'])
143
143
 
144
144
  console.print(seen_table)
145
145
 
146
- watch_list = stats.get("WatchList")
147
-
148
- if watch_list:
146
+ if watch_list := stats.get('WatchList'):
149
147
  count = len(watch_list)
150
- watch_table = Table(title=f"Watch List ({count})")
151
- watch_table.add_column("Callsign")
152
- watch_table.add_column("Last Heard")
148
+ watch_table = Table(title=f'Watch List ({count})')
149
+ watch_table.add_column('Callsign')
150
+ watch_table.add_column('Last Heard')
153
151
  for key, value in watch_list.items():
154
- watch_table.add_row(key, value["last"])
152
+ watch_table.add_row(key, value['last'])
155
153
 
156
154
  console.print(watch_table)
155
+
156
+
157
+ @cli.command()
158
+ @cli_helper.add_options(cli_helper.common_options)
159
+ @click.option(
160
+ '--raw',
161
+ is_flag=True,
162
+ default=False,
163
+ help='Dump raw stats instead of formatted output.',
164
+ )
165
+ @click.option(
166
+ '--show-section',
167
+ default=['All'],
168
+ help='Show specific sections of the stats. '
169
+ ' Choices: All, APRSDStats, APRSDThreadList, APRSClientStats,'
170
+ ' PacketList, SeenList, WatchList',
171
+ multiple=True,
172
+ type=click.Choice(
173
+ [
174
+ 'All',
175
+ 'APRSDStats',
176
+ 'APRSDThreadList',
177
+ 'APRSClientStats',
178
+ 'PacketList',
179
+ 'SeenList',
180
+ 'WatchList',
181
+ ],
182
+ case_sensitive=False,
183
+ ),
184
+ )
185
+ @click.pass_context
186
+ @cli_helper.process_standard_options
187
+ def dump_stats(ctx, raw, show_section):
188
+ """Dump the current stats from the running APRSD instance."""
189
+ console = Console()
190
+ console.print(f'APRSD Dump-Stats started version: {aprsd.__version__}')
191
+
192
+ with console.status('Dumping stats'):
193
+ ss = StatsStore()
194
+ ss.load()
195
+ stats = ss.data
196
+ if raw:
197
+ if 'All' in show_section:
198
+ console.print(stats)
199
+ return
200
+ else:
201
+ for section in show_section:
202
+ console.print(f'Dumping {section} section:')
203
+ console.print(stats[section])
204
+ return
205
+
206
+ t = Table(title='APRSD Stats')
207
+ t.add_column('Key')
208
+ t.add_column('Value')
209
+ for key, value in stats['APRSDStats'].items():
210
+ t.add_row(key, str(value))
211
+
212
+ if 'All' in show_section or 'APRSDStats' in show_section:
213
+ console.print(t)
214
+
215
+ # Show the thread list
216
+ t = Table(title='Thread List')
217
+ t.add_column('Name')
218
+ t.add_column('Class')
219
+ t.add_column('Alive?')
220
+ t.add_column('Loop Count')
221
+ t.add_column('Age')
222
+ for name, value in stats['APRSDThreadList'].items():
223
+ t.add_row(
224
+ name,
225
+ value['class'],
226
+ str(value['alive']),
227
+ str(value['loop_count']),
228
+ str(value['age']),
229
+ )
230
+
231
+ if 'All' in show_section or 'APRSDThreadList' in show_section:
232
+ console.print(t)
233
+
234
+ # Show the plugins
235
+ t = Table(title='Plugin List')
236
+ t.add_column('Name')
237
+ t.add_column('Enabled')
238
+ t.add_column('Version')
239
+ t.add_column('TX')
240
+ t.add_column('RX')
241
+ for name, value in stats['PluginManager'].items():
242
+ t.add_row(
243
+ name,
244
+ str(value['enabled']),
245
+ value['version'],
246
+ str(value['tx']),
247
+ str(value['rx']),
248
+ )
249
+
250
+ if 'All' in show_section or 'PluginManager' in show_section:
251
+ console.print(t)
252
+
253
+ # Now show the client stats
254
+ t = Table(title='Client Stats')
255
+ t.add_column('Key')
256
+ t.add_column('Value')
257
+ for key, value in stats['APRSClientStats'].items():
258
+ t.add_row(key, str(value))
259
+
260
+ if 'All' in show_section or 'APRSClientStats' in show_section:
261
+ console.print(t)
262
+
263
+ # now show the packet list
264
+ packet_list = stats.get('PacketList')
265
+ t = Table(title='Packet List')
266
+ t.add_column('Key')
267
+ t.add_column('Value')
268
+ t.add_row('Total Received', str(packet_list['rx']))
269
+ t.add_row('Total Sent', str(packet_list['tx']))
270
+
271
+ if 'All' in show_section or 'PacketList' in show_section:
272
+ console.print(t)
273
+
274
+ # now show the seen list
275
+ seen_list = stats.get('SeenList')
276
+ sorted_seen_list = sorted(
277
+ seen_list.items(),
278
+ )
279
+ t = Table(title='Seen List')
280
+ t.add_column('Callsign')
281
+ t.add_column('Message Count')
282
+ t.add_column('Last Heard')
283
+ for key, value in sorted_seen_list:
284
+ t.add_row(
285
+ key,
286
+ str(value['count']),
287
+ str(value['last']),
288
+ )
289
+
290
+ if 'All' in show_section or 'SeenList' in show_section:
291
+ console.print(t)
292
+
293
+ # now show the watch list
294
+ watch_list = stats.get('WatchList')
295
+ sorted_watch_list = sorted(
296
+ watch_list.items(),
297
+ )
298
+ t = Table(title='Watch List')
299
+ t.add_column('Callsign')
300
+ t.add_column('Last Heard')
301
+ for key, value in sorted_watch_list:
302
+ t.add_row(
303
+ key,
304
+ str(value['last']),
305
+ )
306
+
307
+ if 'All' in show_section or 'WatchList' in show_section:
308
+ console.print(t)
aprsd/cmds/healthcheck.py CHANGED
@@ -13,13 +13,15 @@ from oslo_config import cfg
13
13
  from rich.console import Console
14
14
 
15
15
  import aprsd
16
- from aprsd import cli_helper
17
- from aprsd import conf # noqa
16
+ from aprsd import ( # noqa: F401
17
+ cli_helper,
18
+ conf,
19
+ )
20
+
18
21
  # local imports here
19
22
  from aprsd.main import cli
20
23
  from aprsd.threads import stats as stats_threads
21
24
 
22
-
23
25
  # setup the global logger
24
26
  # log.basicConfig(level=log.DEBUG) # level=10
25
27
  CONF = cfg.CONF
@@ -63,7 +65,7 @@ def healthcheck(ctx, timeout):
63
65
 
64
66
  if email_thread_last_update != "never":
65
67
  d = now - email_thread_last_update
66
- max_timeout = {"hours": 0.0, "minutes": 5, "seconds": 0}
68
+ max_timeout = {"hours": 0.0, "minutes": 5, "seconds": 30}
67
69
  max_delta = datetime.timedelta(**max_timeout)
68
70
  if d > max_delta:
69
71
  console.log(f"Email thread is very old! {d}")
@@ -74,7 +76,7 @@ def healthcheck(ctx, timeout):
74
76
  console.log("No APRSClientStats")
75
77
  sys.exit(-1)
76
78
  else:
77
- aprsis_last_update = client_stats["server_keepalive"]
79
+ aprsis_last_update = client_stats["connection_keepalive"]
78
80
  d = now - aprsis_last_update
79
81
  max_timeout = {"hours": 0.0, "minutes": 5, "seconds": 0}
80
82
  max_delta = datetime.timedelta(**max_timeout)