aprsd 3.3.4__py2.py3-none-any.whl → 3.4.0__py2.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 (70) hide show
  1. aprsd/client.py +133 -20
  2. aprsd/clients/aprsis.py +6 -3
  3. aprsd/clients/fake.py +1 -1
  4. aprsd/clients/kiss.py +1 -1
  5. aprsd/cmds/completion.py +13 -27
  6. aprsd/cmds/fetch_stats.py +53 -57
  7. aprsd/cmds/healthcheck.py +32 -30
  8. aprsd/cmds/list_plugins.py +2 -2
  9. aprsd/cmds/listen.py +33 -17
  10. aprsd/cmds/send_message.py +2 -2
  11. aprsd/cmds/server.py +26 -9
  12. aprsd/cmds/webchat.py +34 -29
  13. aprsd/conf/common.py +46 -31
  14. aprsd/log/log.py +28 -6
  15. aprsd/main.py +4 -17
  16. aprsd/packets/__init__.py +3 -2
  17. aprsd/packets/collector.py +56 -0
  18. aprsd/packets/core.py +456 -321
  19. aprsd/packets/log.py +143 -0
  20. aprsd/packets/packet_list.py +83 -66
  21. aprsd/packets/seen_list.py +30 -19
  22. aprsd/packets/tracker.py +60 -62
  23. aprsd/packets/watch_list.py +64 -38
  24. aprsd/plugin.py +41 -16
  25. aprsd/plugins/email.py +35 -7
  26. aprsd/plugins/time.py +3 -2
  27. aprsd/plugins/version.py +4 -5
  28. aprsd/plugins/weather.py +0 -1
  29. aprsd/stats/__init__.py +20 -0
  30. aprsd/stats/app.py +46 -0
  31. aprsd/stats/collector.py +38 -0
  32. aprsd/threads/__init__.py +3 -2
  33. aprsd/threads/aprsd.py +67 -36
  34. aprsd/threads/keep_alive.py +55 -49
  35. aprsd/threads/log_monitor.py +46 -0
  36. aprsd/threads/rx.py +43 -24
  37. aprsd/threads/stats.py +44 -0
  38. aprsd/threads/tx.py +36 -17
  39. aprsd/utils/__init__.py +12 -0
  40. aprsd/utils/counter.py +6 -3
  41. aprsd/utils/json.py +20 -0
  42. aprsd/utils/objectstore.py +22 -17
  43. aprsd/web/admin/static/css/prism.css +4 -189
  44. aprsd/web/admin/static/js/charts.js +9 -7
  45. aprsd/web/admin/static/js/echarts.js +71 -9
  46. aprsd/web/admin/static/js/main.js +47 -6
  47. aprsd/web/admin/static/js/prism.js +11 -2246
  48. aprsd/web/admin/templates/index.html +18 -7
  49. aprsd/web/chat/static/js/gps.js +3 -1
  50. aprsd/web/chat/static/js/main.js +4 -3
  51. aprsd/web/chat/static/js/send-message.js +5 -2
  52. aprsd/web/chat/templates/index.html +1 -0
  53. aprsd/wsgi.py +62 -127
  54. {aprsd-3.3.4.dist-info → aprsd-3.4.0.dist-info}/METADATA +14 -16
  55. {aprsd-3.3.4.dist-info → aprsd-3.4.0.dist-info}/RECORD +60 -63
  56. {aprsd-3.3.4.dist-info → aprsd-3.4.0.dist-info}/WHEEL +1 -1
  57. aprsd-3.4.0.dist-info/pbr.json +1 -0
  58. aprsd/plugins/query.py +0 -81
  59. aprsd/rpc/__init__.py +0 -14
  60. aprsd/rpc/client.py +0 -165
  61. aprsd/rpc/server.py +0 -99
  62. aprsd/stats.py +0 -266
  63. aprsd/web/admin/static/json-viewer/jquery.json-viewer.css +0 -57
  64. aprsd/web/admin/static/json-viewer/jquery.json-viewer.js +0 -158
  65. aprsd/web/chat/static/json-viewer/jquery.json-viewer.css +0 -57
  66. aprsd/web/chat/static/json-viewer/jquery.json-viewer.js +0 -158
  67. aprsd-3.3.4.dist-info/pbr.json +0 -1
  68. {aprsd-3.3.4.dist-info → aprsd-3.4.0.dist-info}/LICENSE +0 -0
  69. {aprsd-3.3.4.dist-info → aprsd-3.4.0.dist-info}/entry_points.txt +0 -0
  70. {aprsd-3.3.4.dist-info → aprsd-3.4.0.dist-info}/top_level.txt +0 -0
aprsd/utils/json.py CHANGED
@@ -3,6 +3,8 @@ import decimal
3
3
  import json
4
4
  import sys
5
5
 
6
+ from aprsd.packets import core
7
+
6
8
 
7
9
  class EnhancedJSONEncoder(json.JSONEncoder):
8
10
  def default(self, obj):
@@ -42,6 +44,24 @@ class EnhancedJSONEncoder(json.JSONEncoder):
42
44
  return super().default(obj)
43
45
 
44
46
 
47
+ class SimpleJSONEncoder(json.JSONEncoder):
48
+ def default(self, obj):
49
+ if isinstance(obj, datetime.datetime):
50
+ return obj.isoformat()
51
+ elif isinstance(obj, datetime.date):
52
+ return str(obj)
53
+ elif isinstance(obj, datetime.time):
54
+ return str(obj)
55
+ elif isinstance(obj, datetime.timedelta):
56
+ return str(obj)
57
+ elif isinstance(obj, decimal.Decimal):
58
+ return str(obj)
59
+ elif isinstance(obj, core.Packet):
60
+ return obj.to_dict()
61
+ else:
62
+ return super().default(obj)
63
+
64
+
45
65
  class EnhancedJSONDecoder(json.JSONDecoder):
46
66
 
47
67
  def __init__(self, *args, **kwargs):
@@ -2,6 +2,7 @@ import logging
2
2
  import os
3
3
  import pathlib
4
4
  import pickle
5
+ import threading
5
6
 
6
7
  from oslo_config import cfg
7
8
 
@@ -25,19 +26,28 @@ class ObjectStoreMixin:
25
26
  aprsd server -f (flush) will wipe all saved objects.
26
27
  """
27
28
 
29
+ def __init__(self):
30
+ self.lock = threading.RLock()
31
+
28
32
  def __len__(self):
29
- return len(self.data)
33
+ with self.lock:
34
+ return len(self.data)
30
35
 
31
36
  def __iter__(self):
32
- return iter(self.data)
37
+ with self.lock:
38
+ return iter(self.data)
33
39
 
34
40
  def get_all(self):
35
41
  with self.lock:
36
42
  return self.data
37
43
 
38
- def get(self, id):
44
+ def get(self, key):
45
+ with self.lock:
46
+ return self.data.get(key)
47
+
48
+ def copy(self):
39
49
  with self.lock:
40
- return self.data[id]
50
+ return self.data.copy()
41
51
 
42
52
  def _init_store(self):
43
53
  if not CONF.enable_save:
@@ -58,31 +68,26 @@ class ObjectStoreMixin:
58
68
  self.__class__.__name__.lower(),
59
69
  )
60
70
 
61
- def _dump(self):
62
- dump = {}
63
- with self.lock:
64
- for key in self.data.keys():
65
- dump[key] = self.data[key]
66
-
67
- return dump
68
-
69
71
  def save(self):
70
72
  """Save any queued to disk?"""
71
73
  if not CONF.enable_save:
72
74
  return
75
+ self._init_store()
76
+ save_filename = self._save_filename()
73
77
  if len(self) > 0:
74
78
  LOG.info(
75
79
  f"{self.__class__.__name__}::Saving"
76
- f" {len(self)} entries to disk at"
77
- f"{CONF.save_location}",
80
+ f" {len(self)} entries to disk at "
81
+ f"{save_filename}",
78
82
  )
79
- with open(self._save_filename(), "wb+") as fp:
80
- pickle.dump(self._dump(), fp)
83
+ with self.lock:
84
+ with open(save_filename, "wb+") as fp:
85
+ pickle.dump(self.data, fp)
81
86
  else:
82
87
  LOG.debug(
83
88
  "{} Nothing to save, flushing old save file '{}'".format(
84
89
  self.__class__.__name__,
85
- self._save_filename(),
90
+ save_filename,
86
91
  ),
87
92
  )
88
93
  self.flush()
@@ -1,189 +1,4 @@
1
- /* PrismJS 1.24.1
2
- https://prismjs.com/download.html#themes=prism-tomorrow&languages=markup+css+clike+javascript+log&plugins=show-language+toolbar */
3
- /**
4
- * prism.js tomorrow night eighties for JavaScript, CoffeeScript, CSS and HTML
5
- * Based on https://github.com/chriskempson/tomorrow-theme
6
- * @author Rose Pritchard
7
- */
8
-
9
- code[class*="language-"],
10
- pre[class*="language-"] {
11
- color: #ccc;
12
- background: none;
13
- font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
14
- font-size: 1em;
15
- text-align: left;
16
- white-space: pre;
17
- word-spacing: normal;
18
- word-break: normal;
19
- word-wrap: normal;
20
- line-height: 1.5;
21
-
22
- -moz-tab-size: 4;
23
- -o-tab-size: 4;
24
- tab-size: 4;
25
-
26
- -webkit-hyphens: none;
27
- -moz-hyphens: none;
28
- -ms-hyphens: none;
29
- hyphens: none;
30
-
31
- }
32
-
33
- /* Code blocks */
34
- pre[class*="language-"] {
35
- padding: 1em;
36
- margin: .5em 0;
37
- overflow: auto;
38
- }
39
-
40
- :not(pre) > code[class*="language-"],
41
- pre[class*="language-"] {
42
- background: #2d2d2d;
43
- }
44
-
45
- /* Inline code */
46
- :not(pre) > code[class*="language-"] {
47
- padding: .1em;
48
- border-radius: .3em;
49
- white-space: normal;
50
- }
51
-
52
- .token.comment,
53
- .token.block-comment,
54
- .token.prolog,
55
- .token.doctype,
56
- .token.cdata {
57
- color: #999;
58
- }
59
-
60
- .token.punctuation {
61
- color: #ccc;
62
- }
63
-
64
- .token.tag,
65
- .token.attr-name,
66
- .token.namespace,
67
- .token.deleted {
68
- color: #e2777a;
69
- }
70
-
71
- .token.function-name {
72
- color: #6196cc;
73
- }
74
-
75
- .token.boolean,
76
- .token.number,
77
- .token.function {
78
- color: #f08d49;
79
- }
80
-
81
- .token.property,
82
- .token.class-name,
83
- .token.constant,
84
- .token.symbol {
85
- color: #f8c555;
86
- }
87
-
88
- .token.selector,
89
- .token.important,
90
- .token.atrule,
91
- .token.keyword,
92
- .token.builtin {
93
- color: #cc99cd;
94
- }
95
-
96
- .token.string,
97
- .token.char,
98
- .token.attr-value,
99
- .token.regex,
100
- .token.variable {
101
- color: #7ec699;
102
- }
103
-
104
- .token.operator,
105
- .token.entity,
106
- .token.url {
107
- color: #67cdcc;
108
- }
109
-
110
- .token.important,
111
- .token.bold {
112
- font-weight: bold;
113
- }
114
- .token.italic {
115
- font-style: italic;
116
- }
117
-
118
- .token.entity {
119
- cursor: help;
120
- }
121
-
122
- .token.inserted {
123
- color: green;
124
- }
125
-
126
- div.code-toolbar {
127
- position: relative;
128
- }
129
-
130
- div.code-toolbar > .toolbar {
131
- position: absolute;
132
- top: .3em;
133
- right: .2em;
134
- transition: opacity 0.3s ease-in-out;
135
- opacity: 0;
136
- }
137
-
138
- div.code-toolbar:hover > .toolbar {
139
- opacity: 1;
140
- }
141
-
142
- /* Separate line b/c rules are thrown out if selector is invalid.
143
- IE11 and old Edge versions don't support :focus-within. */
144
- div.code-toolbar:focus-within > .toolbar {
145
- opacity: 1;
146
- }
147
-
148
- div.code-toolbar > .toolbar > .toolbar-item {
149
- display: inline-block;
150
- }
151
-
152
- div.code-toolbar > .toolbar > .toolbar-item > a {
153
- cursor: pointer;
154
- }
155
-
156
- div.code-toolbar > .toolbar > .toolbar-item > button {
157
- background: none;
158
- border: 0;
159
- color: inherit;
160
- font: inherit;
161
- line-height: normal;
162
- overflow: visible;
163
- padding: 0;
164
- -webkit-user-select: none; /* for button */
165
- -moz-user-select: none;
166
- -ms-user-select: none;
167
- }
168
-
169
- div.code-toolbar > .toolbar > .toolbar-item > a,
170
- div.code-toolbar > .toolbar > .toolbar-item > button,
171
- div.code-toolbar > .toolbar > .toolbar-item > span {
172
- color: #bbb;
173
- font-size: .8em;
174
- padding: 0 .5em;
175
- background: #f5f2f0;
176
- background: rgba(224, 224, 224, 0.2);
177
- box-shadow: 0 2px 0 0 rgba(0,0,0,0.2);
178
- border-radius: .5em;
179
- }
180
-
181
- div.code-toolbar > .toolbar > .toolbar-item > a:hover,
182
- div.code-toolbar > .toolbar > .toolbar-item > a:focus,
183
- div.code-toolbar > .toolbar > .toolbar-item > button:hover,
184
- div.code-toolbar > .toolbar > .toolbar-item > button:focus,
185
- div.code-toolbar > .toolbar > .toolbar-item > span:hover,
186
- div.code-toolbar > .toolbar > .toolbar-item > span:focus {
187
- color: inherit;
188
- text-decoration: none;
189
- }
1
+ /* PrismJS 1.29.0
2
+ https://prismjs.com/download.html#themes=prism-tomorrow&languages=markup+css+clike+javascript+json+json5+log&plugins=show-language+toolbar */
3
+ code[class*=language-],pre[class*=language-]{color:#ccc;background:0 0;font-family:Consolas,Monaco,'Andale Mono','Ubuntu Mono',monospace;font-size:1em;text-align:left;white-space:pre;word-spacing:normal;word-break:normal;word-wrap:normal;line-height:1.5;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-hyphens:none;-moz-hyphens:none;-ms-hyphens:none;hyphens:none}pre[class*=language-]{padding:1em;margin:.5em 0;overflow:auto}:not(pre)>code[class*=language-],pre[class*=language-]{background:#2d2d2d}:not(pre)>code[class*=language-]{padding:.1em;border-radius:.3em;white-space:normal}.token.block-comment,.token.cdata,.token.comment,.token.doctype,.token.prolog{color:#999}.token.punctuation{color:#ccc}.token.attr-name,.token.deleted,.token.namespace,.token.tag{color:#e2777a}.token.function-name{color:#6196cc}.token.boolean,.token.function,.token.number{color:#f08d49}.token.class-name,.token.constant,.token.property,.token.symbol{color:#f8c555}.token.atrule,.token.builtin,.token.important,.token.keyword,.token.selector{color:#cc99cd}.token.attr-value,.token.char,.token.regex,.token.string,.token.variable{color:#7ec699}.token.entity,.token.operator,.token.url{color:#67cdcc}.token.bold,.token.important{font-weight:700}.token.italic{font-style:italic}.token.entity{cursor:help}.token.inserted{color:green}
4
+ div.code-toolbar{position:relative}div.code-toolbar>.toolbar{position:absolute;z-index:10;top:.3em;right:.2em;transition:opacity .3s ease-in-out;opacity:0}div.code-toolbar:hover>.toolbar{opacity:1}div.code-toolbar:focus-within>.toolbar{opacity:1}div.code-toolbar>.toolbar>.toolbar-item{display:inline-block}div.code-toolbar>.toolbar>.toolbar-item>a{cursor:pointer}div.code-toolbar>.toolbar>.toolbar-item>button{background:0 0;border:0;color:inherit;font:inherit;line-height:normal;overflow:visible;padding:0;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none}div.code-toolbar>.toolbar>.toolbar-item>a,div.code-toolbar>.toolbar>.toolbar-item>button,div.code-toolbar>.toolbar>.toolbar-item>span{color:#bbb;font-size:.8em;padding:0 .5em;background:#f5f2f0;background:rgba(224,224,224,.2);box-shadow:0 2px 0 0 rgba(0,0,0,.2);border-radius:.5em}div.code-toolbar>.toolbar>.toolbar-item>a:focus,div.code-toolbar>.toolbar>.toolbar-item>a:hover,div.code-toolbar>.toolbar>.toolbar-item>button:focus,div.code-toolbar>.toolbar>.toolbar-item>button:hover,div.code-toolbar>.toolbar>.toolbar-item>span:focus,div.code-toolbar>.toolbar>.toolbar-item>span:hover{color:inherit;text-decoration:none}
@@ -219,15 +219,17 @@ function updateQuadData(chart, label, first, second, third, fourth) {
219
219
  }
220
220
 
221
221
  function update_stats( data ) {
222
- our_callsign = data["stats"]["aprsd"]["callsign"];
223
- $("#version").text( data["stats"]["aprsd"]["version"] );
222
+ our_callsign = data["APRSDStats"]["callsign"];
223
+ $("#version").text( data["APRSDStats"]["version"] );
224
224
  $("#aprs_connection").html( data["aprs_connection"] );
225
- $("#uptime").text( "uptime: " + data["stats"]["aprsd"]["uptime"] );
225
+ $("#uptime").text( "uptime: " + data["APRSDStats"]["uptime"] );
226
226
  const html_pretty = Prism.highlight(JSON.stringify(data, null, '\t'), Prism.languages.json, 'json');
227
227
  $("#jsonstats").html(html_pretty);
228
228
  short_time = data["time"].split(/\s(.+)/)[1];
229
- updateDualData(packets_chart, short_time, data["stats"]["packets"]["sent"], data["stats"]["packets"]["received"]);
230
- updateQuadData(message_chart, short_time, data["stats"]["messages"]["sent"], data["stats"]["messages"]["received"], data["stats"]["messages"]["ack_sent"], data["stats"]["messages"]["ack_recieved"]);
231
- updateDualData(email_chart, short_time, data["stats"]["email"]["sent"], data["stats"]["email"]["recieved"]);
232
- updateDualData(memory_chart, short_time, data["stats"]["aprsd"]["memory_peak"], data["stats"]["aprsd"]["memory_current"]);
229
+ packet_list = data["PacketList"]["packets"];
230
+ updateDualData(packets_chart, short_time, data["PacketList"]["sent"], data["PacketList"]["received"]);
231
+ updateQuadData(message_chart, short_time, packet_list["MessagePacket"]["tx"], packet_list["MessagePacket"]["rx"],
232
+ packet_list["AckPacket"]["tx"], packet_list["AckPacket"]["rx"]);
233
+ updateDualData(email_chart, short_time, data["EmailStats"]["sent"], data["EmailStats"]["recieved"]);
234
+ updateDualData(memory_chart, short_time, data["APRSDStats"]["memory_peak"], data["APRSDStats"]["memory_current"]);
233
235
  }
@@ -8,6 +8,8 @@ var packet_types_data = {};
8
8
  var mem_current = []
9
9
  var mem_peak = []
10
10
 
11
+ var thread_current = []
12
+
11
13
 
12
14
  function start_charts() {
13
15
  console.log("start_charts() called");
@@ -17,6 +19,7 @@ function start_charts() {
17
19
  create_messages_chart();
18
20
  create_ack_chart();
19
21
  create_memory_chart();
22
+ create_thread_chart();
20
23
  }
21
24
 
22
25
 
@@ -258,6 +261,49 @@ function create_memory_chart() {
258
261
  memory_chart.setOption(option);
259
262
  }
260
263
 
264
+ function create_thread_chart() {
265
+ thread_canvas = document.getElementById('threadChart');
266
+ thread_chart = echarts.init(thread_canvas);
267
+
268
+ // Specify the configuration items and data for the chart
269
+ var option = {
270
+ title: {
271
+ text: 'Active Threads'
272
+ },
273
+ legend: {},
274
+ tooltip: {
275
+ trigger: 'axis'
276
+ },
277
+ toolbox: {
278
+ show: true,
279
+ feature: {
280
+ mark : {show: true},
281
+ dataView : {show: true, readOnly: false},
282
+ magicType : {show: true, type: ['line', 'bar']},
283
+ restore : {show: true},
284
+ saveAsImage : {show: true}
285
+ }
286
+ },
287
+ calculable: true,
288
+ xAxis: { type: 'time' },
289
+ yAxis: { },
290
+ series: [
291
+ {
292
+ name: 'current',
293
+ type: 'line',
294
+ smooth: true,
295
+ color: 'red',
296
+ encode: {
297
+ x: 'timestamp',
298
+ y: 'current' // refer sensor 1 value
299
+ }
300
+ }
301
+ ]
302
+ };
303
+
304
+ thread_chart.setOption(option);
305
+ }
306
+
261
307
 
262
308
 
263
309
 
@@ -327,7 +373,6 @@ function updatePacketTypesChart() {
327
373
  option = {
328
374
  series: series
329
375
  }
330
- console.log(option)
331
376
  packet_types_chart.setOption(option);
332
377
  }
333
378
 
@@ -372,6 +417,21 @@ function updateMemChart(time, current, peak) {
372
417
  memory_chart.setOption(option);
373
418
  }
374
419
 
420
+ function updateThreadChart(time, threads) {
421
+ keys = Object.keys(threads);
422
+ thread_count = keys.length;
423
+ thread_current.push([time, thread_count]);
424
+ option = {
425
+ series: [
426
+ {
427
+ name: 'current',
428
+ data: thread_current,
429
+ }
430
+ ]
431
+ }
432
+ thread_chart.setOption(option);
433
+ }
434
+
375
435
  function updateMessagesChart() {
376
436
  updateTypeChart(message_chart, "MessagePacket")
377
437
  }
@@ -381,22 +441,24 @@ function updateAcksChart() {
381
441
  }
382
442
 
383
443
  function update_stats( data ) {
384
- console.log(data);
385
- our_callsign = data["stats"]["aprsd"]["callsign"];
386
- $("#version").text( data["stats"]["aprsd"]["version"] );
387
- $("#aprs_connection").html( data["aprs_connection"] );
388
- $("#uptime").text( "uptime: " + data["stats"]["aprsd"]["uptime"] );
444
+ console.log("update_stats() echarts.js called")
445
+ stats = data["stats"];
446
+ our_callsign = stats["APRSDStats"]["callsign"];
447
+ $("#version").text( stats["APRSDStats"]["version"] );
448
+ $("#aprs_connection").html( stats["aprs_connection"] );
449
+ $("#uptime").text( "uptime: " + stats["APRSDStats"]["uptime"] );
389
450
  const html_pretty = Prism.highlight(JSON.stringify(data, null, '\t'), Prism.languages.json, 'json');
390
451
  $("#jsonstats").html(html_pretty);
391
452
 
392
453
  t = Date.parse(data["time"]);
393
454
  ts = new Date(t);
394
- updatePacketData(packets_chart, ts, data["stats"]["packets"]["sent"], data["stats"]["packets"]["received"]);
395
- updatePacketTypesData(ts, data["stats"]["packets"]["types"]);
455
+ updatePacketData(packets_chart, ts, stats["PacketList"]["tx"], stats["PacketList"]["rx"]);
456
+ updatePacketTypesData(ts, stats["PacketList"]["types"]);
396
457
  updatePacketTypesChart();
397
458
  updateMessagesChart();
398
459
  updateAcksChart();
399
- updateMemChart(ts, data["stats"]["aprsd"]["memory_current"], data["stats"]["aprsd"]["memory_peak"]);
460
+ updateMemChart(ts, stats["APRSDStats"]["memory_current"], stats["APRSDStats"]["memory_peak"]);
461
+ updateThreadChart(ts, stats["APRSDThreadList"]);
400
462
  //updateQuadData(message_chart, short_time, data["stats"]["messages"]["sent"], data["stats"]["messages"]["received"], data["stats"]["messages"]["ack_sent"], data["stats"]["messages"]["ack_recieved"]);
401
463
  //updateDualData(email_chart, short_time, data["stats"]["email"]["sent"], data["stats"]["email"]["recieved"]);
402
464
  //updateDualData(memory_chart, short_time, data["stats"]["aprsd"]["memory_peak"], data["stats"]["aprsd"]["memory_current"]);
@@ -24,11 +24,15 @@ function ord(str){return str.charCodeAt(0);}
24
24
 
25
25
 
26
26
  function update_watchlist( data ) {
27
- // Update the watch list
27
+ // Update the watch list
28
+ stats = data["stats"];
29
+ if (stats.hasOwnProperty("WatchList") == false) {
30
+ return
31
+ }
28
32
  var watchdiv = $("#watchDiv");
29
33
  var html_str = '<table class="ui celled striped table"><thead><tr><th>HAM Callsign</th><th>Age since last seen by APRSD</th></tr></thead><tbody>'
30
34
  watchdiv.html('')
31
- jQuery.each(data["stats"]["aprsd"]["watch_list"], function(i, val) {
35
+ jQuery.each(stats["WatchList"], function(i, val) {
32
36
  html_str += '<tr><td class="collapsing"><img id="callsign_'+i+'" class="aprsd_1"></img>' + i + '</td><td>' + val["last"] + '</td></tr>'
33
37
  });
34
38
  html_str += "</tbody></table>";
@@ -60,12 +64,16 @@ function update_watchlist_from_packet(callsign, val) {
60
64
  }
61
65
 
62
66
  function update_seenlist( data ) {
67
+ stats = data["stats"];
68
+ if (stats.hasOwnProperty("SeenList") == false) {
69
+ return
70
+ }
63
71
  var seendiv = $("#seenDiv");
64
72
  var html_str = '<table class="ui celled striped table">'
65
73
  html_str += '<thead><tr><th>HAM Callsign</th><th>Age since last seen by APRSD</th>'
66
74
  html_str += '<th>Number of packets RX</th></tr></thead><tbody>'
67
75
  seendiv.html('')
68
- var seen_list = data["stats"]["aprsd"]["seen_list"]
76
+ var seen_list = stats["SeenList"]
69
77
  var len = Object.keys(seen_list).length
70
78
  $('#seen_count').html(len)
71
79
  jQuery.each(seen_list, function(i, val) {
@@ -79,6 +87,10 @@ function update_seenlist( data ) {
79
87
  }
80
88
 
81
89
  function update_plugins( data ) {
90
+ stats = data["stats"];
91
+ if (stats.hasOwnProperty("PluginManager") == false) {
92
+ return
93
+ }
82
94
  var plugindiv = $("#pluginDiv");
83
95
  var html_str = '<table class="ui celled striped table"><thead><tr>'
84
96
  html_str += '<th>Plugin Name</th><th>Plugin Enabled?</th>'
@@ -87,7 +99,7 @@ function update_plugins( data ) {
87
99
  html_str += '</tr></thead><tbody>'
88
100
  plugindiv.html('')
89
101
 
90
- var plugins = data["stats"]["plugins"];
102
+ var plugins = stats["PluginManager"];
91
103
  var keys = Object.keys(plugins);
92
104
  keys.sort();
93
105
  for (var i=0; i<keys.length; i++) { // now lets iterate in sort order
@@ -101,14 +113,42 @@ function update_plugins( data ) {
101
113
  plugindiv.append(html_str);
102
114
  }
103
115
 
116
+ function update_threads( data ) {
117
+ stats = data["stats"];
118
+ if (stats.hasOwnProperty("APRSDThreadList") == false) {
119
+ return
120
+ }
121
+ var threadsdiv = $("#threadsDiv");
122
+ var countdiv = $("#thread_count");
123
+ var html_str = '<table class="ui celled striped table"><thead><tr>'
124
+ html_str += '<th>Thread Name</th><th>Alive?</th>'
125
+ html_str += '<th>Age</th><th>Loop Count</th>'
126
+ html_str += '</tr></thead><tbody>'
127
+ threadsdiv.html('')
128
+
129
+ var threads = stats["APRSDThreadList"];
130
+ var keys = Object.keys(threads);
131
+ countdiv.html(keys.length);
132
+ keys.sort();
133
+ for (var i=0; i<keys.length; i++) { // now lets iterate in sort order
134
+ var key = keys[i];
135
+ var val = threads[key];
136
+ html_str += '<tr><td class="collapsing">' + key + '</td>';
137
+ html_str += '<td>' + val["alive"] + '</td><td>' + val["age"] + '</td>';
138
+ html_str += '<td>' + val["loop_count"] + '</td></tr>';
139
+ }
140
+ html_str += "</tbody></table>";
141
+ threadsdiv.append(html_str);
142
+ }
143
+
104
144
  function update_packets( data ) {
105
145
  var packetsdiv = $("#packetsDiv");
106
146
  //nuke the contents first, then add to it.
107
147
  if (size_dict(packet_list) == 0 && size_dict(data) > 0) {
108
148
  packetsdiv.html('')
109
149
  }
110
- jQuery.each(data, function(i, val) {
111
- pkt = JSON.parse(val);
150
+ jQuery.each(data.packets, function(i, val) {
151
+ pkt = val;
112
152
 
113
153
  update_watchlist_from_packet(pkt['from_call'], pkt);
114
154
  if ( packet_list.hasOwnProperty(pkt['timestamp']) == false ) {
@@ -167,6 +207,7 @@ function start_update() {
167
207
  update_watchlist(data);
168
208
  update_seenlist(data);
169
209
  update_plugins(data);
210
+ update_threads(data);
170
211
  },
171
212
  complete: function() {
172
213
  setTimeout(statsworker, 10000);