aprsd 3.4.4__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 (115) hide show
  1. aprsd/cli_helper.py +12 -5
  2. aprsd/client/aprsis.py +31 -9
  3. aprsd/client/base.py +13 -2
  4. aprsd/client/drivers/aprsis.py +6 -3
  5. aprsd/client/drivers/fake.py +15 -20
  6. aprsd/client/factory.py +0 -2
  7. aprsd/client/fake.py +0 -2
  8. aprsd/client/kiss.py +17 -2
  9. aprsd/client/stats.py +1 -3
  10. aprsd/cmds/completion.py +7 -4
  11. aprsd/cmds/dev.py +38 -42
  12. aprsd/cmds/fetch_stats.py +140 -143
  13. aprsd/cmds/healthcheck.py +5 -3
  14. aprsd/cmds/list_plugins.py +140 -134
  15. aprsd/cmds/listen.py +13 -9
  16. aprsd/cmds/server.py +53 -27
  17. aprsd/conf/__init__.py +1 -2
  18. aprsd/conf/client.py +3 -4
  19. aprsd/conf/common.py +19 -93
  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 +10 -4
  26. aprsd/packets/__init__.py +14 -4
  27. aprsd/packets/core.py +57 -67
  28. aprsd/packets/log.py +8 -8
  29. aprsd/packets/packet_list.py +9 -6
  30. aprsd/plugin.py +22 -11
  31. aprsd/plugins/notify.py +1 -4
  32. aprsd/plugins/weather.py +10 -8
  33. aprsd/stats/collector.py +5 -2
  34. aprsd/threads/__init__.py +3 -2
  35. aprsd/threads/aprsd.py +12 -7
  36. aprsd/threads/{keep_alive.py → keepalive.py} +14 -45
  37. aprsd/threads/registry.py +3 -3
  38. aprsd/threads/rx.py +9 -6
  39. aprsd/threads/stats.py +2 -2
  40. aprsd/threads/tx.py +3 -4
  41. aprsd/utils/__init__.py +42 -10
  42. aprsd/utils/json.py +9 -4
  43. aprsd/utils/keepalive_collector.py +55 -0
  44. aprsd/utils/trace.py +0 -2
  45. aprsd-4.0.0.dist-info/AUTHORS +1 -0
  46. aprsd-4.0.0.dist-info/METADATA +293 -0
  47. aprsd-4.0.0.dist-info/RECORD +74 -0
  48. {aprsd-3.4.4.dist-info → aprsd-4.0.0.dist-info}/WHEEL +1 -1
  49. aprsd/cmds/admin.py +0 -57
  50. aprsd/cmds/webchat.py +0 -662
  51. aprsd/conf/plugin_email.py +0 -105
  52. aprsd/plugins/email.py +0 -715
  53. aprsd/plugins/location.py +0 -181
  54. aprsd/threads/log_monitor.py +0 -121
  55. aprsd/web/__init__.py +0 -0
  56. aprsd/web/admin/__init__.py +0 -0
  57. aprsd/web/admin/static/css/index.css +0 -84
  58. aprsd/web/admin/static/css/prism.css +0 -4
  59. aprsd/web/admin/static/css/tabs.css +0 -35
  60. aprsd/web/admin/static/images/Untitled.png +0 -0
  61. aprsd/web/admin/static/images/aprs-symbols-16-0.png +0 -0
  62. aprsd/web/admin/static/images/aprs-symbols-16-1.png +0 -0
  63. aprsd/web/admin/static/images/aprs-symbols-64-0.png +0 -0
  64. aprsd/web/admin/static/images/aprs-symbols-64-1.png +0 -0
  65. aprsd/web/admin/static/images/aprs-symbols-64-2.png +0 -0
  66. aprsd/web/admin/static/js/charts.js +0 -235
  67. aprsd/web/admin/static/js/echarts.js +0 -465
  68. aprsd/web/admin/static/js/logs.js +0 -26
  69. aprsd/web/admin/static/js/main.js +0 -231
  70. aprsd/web/admin/static/js/prism.js +0 -12
  71. aprsd/web/admin/static/js/send-message.js +0 -114
  72. aprsd/web/admin/static/js/tabs.js +0 -28
  73. aprsd/web/admin/templates/index.html +0 -196
  74. aprsd/web/chat/static/css/chat.css +0 -115
  75. aprsd/web/chat/static/css/index.css +0 -66
  76. aprsd/web/chat/static/css/style.css.map +0 -1
  77. aprsd/web/chat/static/css/tabs.css +0 -41
  78. aprsd/web/chat/static/css/upstream/bootstrap.min.css +0 -6
  79. aprsd/web/chat/static/css/upstream/font.woff2 +0 -0
  80. aprsd/web/chat/static/css/upstream/google-fonts.css +0 -23
  81. aprsd/web/chat/static/css/upstream/jquery-ui.css +0 -1311
  82. aprsd/web/chat/static/css/upstream/jquery.toast.css +0 -28
  83. aprsd/web/chat/static/css/upstream/themes/default/assets/fonts/LatoLatin-Bold.woff +0 -0
  84. aprsd/web/chat/static/css/upstream/themes/default/assets/fonts/LatoLatin-Bold.woff2 +0 -0
  85. aprsd/web/chat/static/css/upstream/themes/default/assets/fonts/LatoLatin-Regular.woff +0 -0
  86. aprsd/web/chat/static/css/upstream/themes/default/assets/fonts/LatoLatin-Regular.woff2 +0 -0
  87. aprsd/web/chat/static/css/upstream/themes/default/assets/fonts/icons.woff +0 -0
  88. aprsd/web/chat/static/css/upstream/themes/default/assets/fonts/icons.woff2 +0 -0
  89. aprsd/web/chat/static/css/upstream/themes/default/assets/fonts/outline-icons.woff +0 -0
  90. aprsd/web/chat/static/css/upstream/themes/default/assets/fonts/outline-icons.woff2 +0 -0
  91. aprsd/web/chat/static/images/Untitled.png +0 -0
  92. aprsd/web/chat/static/images/aprs-symbols-16-0.png +0 -0
  93. aprsd/web/chat/static/images/aprs-symbols-16-1.png +0 -0
  94. aprsd/web/chat/static/images/aprs-symbols-64-0.png +0 -0
  95. aprsd/web/chat/static/images/aprs-symbols-64-1.png +0 -0
  96. aprsd/web/chat/static/images/aprs-symbols-64-2.png +0 -0
  97. aprsd/web/chat/static/images/globe.svg +0 -3
  98. aprsd/web/chat/static/js/gps.js +0 -84
  99. aprsd/web/chat/static/js/main.js +0 -45
  100. aprsd/web/chat/static/js/send-message.js +0 -612
  101. aprsd/web/chat/static/js/tabs.js +0 -28
  102. aprsd/web/chat/static/js/upstream/bootstrap.bundle.min.js +0 -7
  103. aprsd/web/chat/static/js/upstream/jquery-3.7.1.min.js +0 -2
  104. aprsd/web/chat/static/js/upstream/jquery-ui.min.js +0 -13
  105. aprsd/web/chat/static/js/upstream/jquery.toast.js +0 -374
  106. aprsd/web/chat/static/js/upstream/semantic.min.js +0 -11
  107. aprsd/web/chat/static/js/upstream/socket.io.min.js +0 -7
  108. aprsd/web/chat/templates/index.html +0 -139
  109. aprsd/wsgi.py +0 -322
  110. aprsd-3.4.4.dist-info/AUTHORS +0 -13
  111. aprsd-3.4.4.dist-info/METADATA +0 -849
  112. aprsd-3.4.4.dist-info/RECORD +0 -134
  113. {aprsd-3.4.4.dist-info → aprsd-4.0.0.dist-info}/LICENSE +0 -0
  114. {aprsd-3.4.4.dist-info → aprsd-4.0.0.dist-info}/entry_points.txt +0 -0
  115. {aprsd-3.4.4.dist-info → aprsd-4.0.0.dist-info}/top_level.txt +0 -0
aprsd/plugins/location.py DELETED
@@ -1,181 +0,0 @@
1
- import logging
2
- import re
3
- import time
4
-
5
- from geopy.geocoders import (
6
- ArcGIS, AzureMaps, Baidu, Bing, GoogleV3, HereV7, Nominatim, OpenCage,
7
- TomTom, What3WordsV3, Woosmap,
8
- )
9
- from oslo_config import cfg
10
-
11
- from aprsd import packets, plugin, plugin_utils
12
- from aprsd.utils import trace
13
-
14
-
15
- CONF = cfg.CONF
16
- LOG = logging.getLogger("APRSD")
17
-
18
-
19
- class UsLocation:
20
- raw = {}
21
-
22
- def __init__(self, info):
23
- self.info = info
24
-
25
- def __str__(self):
26
- return self.info
27
-
28
-
29
- class USGov:
30
- """US Government geocoder that uses the geopy API.
31
-
32
- This is a dummy class the implements the geopy reverse API,
33
- so the factory can return an object that conforms to the API.
34
- """
35
- def reverse(self, coordinates):
36
- """Reverse geocode a coordinate."""
37
- LOG.info(f"USGov reverse geocode {coordinates}")
38
- coords = coordinates.split(",")
39
- lat = float(coords[0])
40
- lon = float(coords[1])
41
- result = plugin_utils.get_weather_gov_for_gps(lat, lon)
42
- # LOG.info(f"WEATHER: {result}")
43
- # LOG.info(f"area description {result['location']['areaDescription']}")
44
- if "location" in result:
45
- loc = UsLocation(result["location"]["areaDescription"])
46
- else:
47
- loc = UsLocation("Unknown Location")
48
-
49
- LOG.info(f"USGov reverse geocode LOC {loc}")
50
- return loc
51
-
52
-
53
- def geopy_factory():
54
- """Factory function for geopy geocoders."""
55
- geocoder = CONF.location_plugin.geopy_geocoder
56
- LOG.info(f"Using geocoder: {geocoder}")
57
- user_agent = CONF.location_plugin.user_agent
58
- LOG.info(f"Using user_agent: {user_agent}")
59
-
60
- if geocoder == "Nominatim":
61
- return Nominatim(user_agent=user_agent)
62
- elif geocoder == "USGov":
63
- return USGov()
64
- elif geocoder == "ArcGIS":
65
- return ArcGIS(
66
- username=CONF.location_plugin.arcgis_username,
67
- password=CONF.location_plugin.arcgis_password,
68
- user_agent=user_agent,
69
- )
70
- elif geocoder == "AzureMaps":
71
- return AzureMaps(
72
- user_agent=user_agent,
73
- subscription_key=CONF.location_plugin.azuremaps_subscription_key,
74
- )
75
- elif geocoder == "Baidu":
76
- return Baidu(user_agent=user_agent, api_key=CONF.location_plugin.baidu_api_key)
77
- elif geocoder == "Bing":
78
- return Bing(user_agent=user_agent, api_key=CONF.location_plugin.bing_api_key)
79
- elif geocoder == "GoogleV3":
80
- return GoogleV3(user_agent=user_agent, api_key=CONF.location_plugin.google_api_key)
81
- elif geocoder == "HERE":
82
- return HereV7(user_agent=user_agent, api_key=CONF.location_plugin.here_api_key)
83
- elif geocoder == "OpenCage":
84
- return OpenCage(user_agent=user_agent, api_key=CONF.location_plugin.opencage_api_key)
85
- elif geocoder == "TomTom":
86
- return TomTom(user_agent=user_agent, api_key=CONF.location_plugin.tomtom_api_key)
87
- elif geocoder == "What3Words":
88
- return What3WordsV3(user_agent=user_agent, api_key=CONF.location_plugin.what3words_api_key)
89
- elif geocoder == "Woosmap":
90
- return Woosmap(user_agent=user_agent, api_key=CONF.location_plugin.woosmap_api_key)
91
- else:
92
- raise ValueError(f"Unknown geocoder: {geocoder}")
93
-
94
-
95
- class LocationPlugin(plugin.APRSDRegexCommandPluginBase, plugin.APRSFIKEYMixin):
96
- """Location!"""
97
-
98
- command_regex = r"^([l]|[l]\s|location)"
99
- command_name = "location"
100
- short_description = "Where in the world is a CALLSIGN's last GPS beacon?"
101
-
102
- def setup(self):
103
- self.ensure_aprs_fi_key()
104
-
105
- @trace.trace
106
- def process(self, packet: packets.MessagePacket):
107
- LOG.info("Location Plugin")
108
- fromcall = packet.from_call
109
- message = packet.get("message_text", None)
110
-
111
- api_key = CONF.aprs_fi.apiKey
112
-
113
- # optional second argument is a callsign to search
114
- a = re.search(r"^.*\s+(.*)", message)
115
- if a is not None:
116
- searchcall = a.group(1)
117
- searchcall = searchcall.upper()
118
- else:
119
- # if no second argument, search for calling station
120
- searchcall = fromcall
121
-
122
- try:
123
- aprs_data = plugin_utils.get_aprs_fi(api_key, searchcall)
124
- except Exception as ex:
125
- LOG.error(f"Failed to fetch aprs.fi '{ex}'")
126
- return "Failed to fetch aprs.fi location"
127
-
128
- LOG.debug(f"LocationPlugin: aprs_data = {aprs_data}")
129
- if not len(aprs_data["entries"]):
130
- LOG.error("Didn't get any entries from aprs.fi")
131
- return "Failed to fetch aprs.fi location"
132
-
133
- lat = float(aprs_data["entries"][0]["lat"])
134
- lon = float(aprs_data["entries"][0]["lng"])
135
-
136
- # Get some information about their location
137
- try:
138
- tic = time.perf_counter()
139
- geolocator = geopy_factory()
140
- LOG.info(f"Using GEOLOCATOR: {geolocator}")
141
- coordinates = f"{lat:0.6f}, {lon:0.6f}"
142
- location = geolocator.reverse(coordinates)
143
- address = location.raw.get("address")
144
- LOG.debug(f"GEOLOCATOR address: {address}")
145
- toc = time.perf_counter()
146
- if address:
147
- LOG.info(f"Geopy address {address} took {toc - tic:0.4f}")
148
- if address.get("country_code") == "us":
149
- area_info = f"{address.get('county')}, {address.get('state')}"
150
- else:
151
- # what to do for address for non US?
152
- area_info = f"{address.get('country'), 'Unknown'}"
153
- else:
154
- area_info = str(location)
155
- except Exception as ex:
156
- LOG.error(ex)
157
- LOG.error(f"Failed to fetch Geopy address {ex}")
158
- area_info = "Unknown Location"
159
-
160
- try: # altitude not always provided
161
- alt = float(aprs_data["entries"][0]["altitude"])
162
- except Exception:
163
- alt = 0
164
- altfeet = int(alt * 3.28084)
165
- aprs_lasttime_seconds = aprs_data["entries"][0]["lasttime"]
166
- # aprs_lasttime_seconds = aprs_lasttime_seconds.encode(
167
- # "ascii", errors="ignore"
168
- # ) # unicode to ascii
169
- delta_seconds = time.time() - int(aprs_lasttime_seconds)
170
- delta_hours = delta_seconds / 60 / 60
171
-
172
- reply = "{}: {} {}' {},{} {}h ago".format(
173
- searchcall,
174
- area_info,
175
- str(altfeet),
176
- f"{lat:0.2f}",
177
- f"{lon:0.2f}",
178
- str("%.1f" % round(delta_hours, 1)),
179
- ).rstrip()
180
-
181
- return reply
@@ -1,121 +0,0 @@
1
- import datetime
2
- import logging
3
- import threading
4
-
5
- from oslo_config import cfg
6
- import requests
7
- import wrapt
8
-
9
- from aprsd import threads
10
- from aprsd.log import log
11
-
12
-
13
- CONF = cfg.CONF
14
- LOG = logging.getLogger("APRSD")
15
-
16
-
17
- def send_log_entries(force=False):
18
- """Send all of the log entries to the web interface."""
19
- if CONF.admin.web_enabled:
20
- if force or LogEntries().is_purge_ready():
21
- entries = LogEntries().get_all_and_purge()
22
- if entries:
23
- try:
24
- requests.post(
25
- f"http://{CONF.admin.web_ip}:{CONF.admin.web_port}/log_entries",
26
- json=entries,
27
- auth=(CONF.admin.user, CONF.admin.password),
28
- )
29
- except Exception:
30
- LOG.warning(f"Failed to send log entries. len={len(entries)}")
31
-
32
-
33
- class LogEntries:
34
- entries = []
35
- lock = threading.Lock()
36
- _instance = None
37
- last_purge = datetime.datetime.now()
38
- max_delta = datetime.timedelta(
39
- hours=0.0, minutes=0, seconds=2,
40
- )
41
-
42
- def __new__(cls, *args, **kwargs):
43
- if cls._instance is None:
44
- cls._instance = super().__new__(cls)
45
- return cls._instance
46
-
47
- def stats(self) -> dict:
48
- return {
49
- "log_entries": self.entries,
50
- }
51
-
52
- @wrapt.synchronized(lock)
53
- def add(self, entry):
54
- self.entries.append(entry)
55
-
56
- @wrapt.synchronized(lock)
57
- def get_all_and_purge(self):
58
- entries = self.entries.copy()
59
- self.entries = []
60
- self.last_purge = datetime.datetime.now()
61
- return entries
62
-
63
- def is_purge_ready(self):
64
- now = datetime.datetime.now()
65
- if (
66
- now - self.last_purge > self.max_delta
67
- and len(self.entries) > 1
68
- ):
69
- return True
70
- return False
71
-
72
- @wrapt.synchronized(lock)
73
- def __len__(self):
74
- return len(self.entries)
75
-
76
-
77
- class LogMonitorThread(threads.APRSDThread):
78
-
79
- def __init__(self):
80
- super().__init__("LogMonitorThread")
81
-
82
- def stop(self):
83
- send_log_entries(force=True)
84
- super().stop()
85
-
86
- def loop(self):
87
- try:
88
- record = log.logging_queue.get(block=True, timeout=2)
89
- if isinstance(record, list):
90
- for item in record:
91
- entry = self.json_record(item)
92
- LogEntries().add(entry)
93
- else:
94
- entry = self.json_record(record)
95
- LogEntries().add(entry)
96
- except Exception:
97
- # Just ignore thi
98
- pass
99
-
100
- send_log_entries()
101
- return True
102
-
103
- def json_record(self, record):
104
- entry = {}
105
- entry["filename"] = record.filename
106
- entry["funcName"] = record.funcName
107
- entry["levelname"] = record.levelname
108
- entry["lineno"] = record.lineno
109
- entry["module"] = record.module
110
- entry["name"] = record.name
111
- entry["pathname"] = record.pathname
112
- entry["process"] = record.process
113
- entry["processName"] = record.processName
114
- if hasattr(record, "stack_info"):
115
- entry["stack_info"] = record.stack_info
116
- else:
117
- entry["stack_info"] = None
118
- entry["thread"] = record.thread
119
- entry["threadName"] = record.threadName
120
- entry["message"] = record.getMessage()
121
- return entry
aprsd/web/__init__.py DELETED
File without changes
File without changes
@@ -1,84 +0,0 @@
1
- body {
2
- background: #eeeeee;
3
- margin: 2em;
4
- text-align: center;
5
- font-family: system-ui, sans-serif;
6
- }
7
-
8
- footer {
9
- padding: 2em;
10
- text-align: center;
11
- height: 10vh;
12
- }
13
-
14
- .ui.segment {
15
- background: #eeeeee;
16
- }
17
-
18
- #graphs {
19
- display: grid;
20
- width: 100%;
21
- height: 300px;
22
- grid-template-columns: 1fr 1fr;
23
- }
24
- #graphs_center {
25
- display: block;
26
- margin-top: 10px;
27
- margin-bottom: 10px;
28
- width: 100%;
29
- height: 300px;
30
- }
31
- #left {
32
- margin-right: 2px;
33
- height: 300px;
34
- }
35
- #right {
36
- height: 300px;
37
- }
38
- #center {
39
- height: 300px;
40
- }
41
- #packetsChart, #messageChart, #emailChart, #memChart {
42
- border: 1px solid #ccc;
43
- background: #ddd;
44
- }
45
- #stats {
46
- margin: auto;
47
- width: 80%;
48
- }
49
- #jsonstats {
50
- display: none;
51
- }
52
- #title {
53
- font-size: 4em;
54
- }
55
- #version{
56
- font-size: .5em;
57
- }
58
- #uptime, #aprsis {
59
- font-size: 1em;
60
- }
61
- #callsign {
62
- font-size: 1.4em;
63
- color: #00F;
64
- padding-top: 8px;
65
- margin:10px;
66
- }
67
-
68
- #title_rx {
69
- background-color: darkseagreen;
70
- text-align: left;
71
- }
72
-
73
- #title_tx {
74
- background-color: lightcoral;
75
- text-align: left;
76
- }
77
-
78
- .aprsd_1 {
79
- background-image: url(/static/images/aprs-symbols-16-0.png);
80
- background-repeat: no-repeat;
81
- background-position: -160px -48px;
82
- width: 16px;
83
- height: 16px;
84
- }
@@ -1,4 +0,0 @@
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}
@@ -1,35 +0,0 @@
1
- /* Style the tab */
2
- .tab {
3
- overflow: hidden;
4
- border: 1px solid #ccc;
5
- background-color: #f1f1f1;
6
- }
7
-
8
- /* Style the buttons that are used to open the tab content */
9
- .tab button {
10
- background-color: inherit;
11
- float: left;
12
- border: none;
13
- outline: none;
14
- cursor: pointer;
15
- padding: 14px 16px;
16
- transition: 0.3s;
17
- }
18
-
19
- /* Change background color of buttons on hover */
20
- .tab button:hover {
21
- background-color: #ddd;
22
- }
23
-
24
- /* Create an active/current tablink class */
25
- .tab button.active {
26
- background-color: #ccc;
27
- }
28
-
29
- /* Style the tab content */
30
- .tabcontent {
31
- display: none;
32
- padding: 6px 12px;
33
- border: 1px solid #ccc;
34
- border-top: none;
35
- }
Binary file
@@ -1,235 +0,0 @@
1
- var packet_list = {};
2
-
3
- window.chartColors = {
4
- red: 'rgb(255, 99, 132)',
5
- orange: 'rgb(255, 159, 64)',
6
- yellow: 'rgb(255, 205, 86)',
7
- green: 'rgb(26, 181, 77)',
8
- blue: 'rgb(54, 162, 235)',
9
- purple: 'rgb(153, 102, 255)',
10
- grey: 'rgb(201, 203, 207)',
11
- black: 'rgb(0, 0, 0)',
12
- lightcoral: 'rgb(240,128,128)',
13
- darkseagreen: 'rgb(143, 188,143)'
14
-
15
- };
16
-
17
- function size_dict(d){c=0; for (i in d) ++c; return c}
18
-
19
- function start_charts() {
20
- Chart.scaleService.updateScaleDefaults('linear', {
21
- ticks: {
22
- min: 0
23
- }
24
- });
25
-
26
- packets_chart = new Chart($("#packetsChart"), {
27
- label: 'APRS Packets',
28
- type: 'line',
29
- data: {
30
- labels: [],
31
- datasets: [{
32
- label: 'Packets Sent',
33
- borderColor: window.chartColors.lightcoral,
34
- data: [],
35
- },
36
- {
37
- label: 'Packets Recieved',
38
- borderColor: window.chartColors.darkseagreen,
39
- data: [],
40
- }]
41
- },
42
- options: {
43
- responsive: true,
44
- maintainAspectRatio: false,
45
- title: {
46
- display: true,
47
- text: 'APRS Packets',
48
- },
49
- scales: {
50
- x: {
51
- type: 'timeseries',
52
- offset: true,
53
- ticks: {
54
- major: { enabled: true },
55
- fontStyle: context => context.tick.major ? 'bold' : undefined,
56
- source: 'data',
57
- maxRotation: 0,
58
- autoSkip: true,
59
- autoSkipPadding: 75,
60
- }
61
- }
62
- }
63
- }
64
- });
65
-
66
- message_chart = new Chart($("#messageChart"), {
67
- label: 'Messages',
68
- type: 'line',
69
- data: {
70
- labels: [],
71
- datasets: [{
72
- label: 'Messages Sent',
73
- borderColor: window.chartColors.lightcoral,
74
- data: [],
75
- },
76
- {
77
- label: 'Messages Recieved',
78
- borderColor: window.chartColors.darkseagreen,
79
- data: [],
80
- },
81
- {
82
- label: 'Ack Sent',
83
- borderColor: window.chartColors.purple,
84
- data: [],
85
- },
86
- {
87
- label: 'Ack Recieved',
88
- borderColor: window.chartColors.black,
89
- data: [],
90
- }],
91
- },
92
- options: {
93
- responsive: true,
94
- maintainAspectRatio: false,
95
- title: {
96
- display: true,
97
- text: 'APRS Messages',
98
- },
99
- scales: {
100
- x: {
101
- type: 'timeseries',
102
- offset: true,
103
- ticks: {
104
- major: { enabled: true },
105
- fontStyle: context => context.tick.major ? 'bold' : undefined,
106
- source: 'data',
107
- maxRotation: 0,
108
- autoSkip: true,
109
- autoSkipPadding: 75,
110
- }
111
- }
112
- }
113
- }
114
- });
115
-
116
- email_chart = new Chart($("#emailChart"), {
117
- label: 'Email Messages',
118
- type: 'line',
119
- data: {
120
- labels: [],
121
- datasets: [{
122
- label: 'Sent',
123
- borderColor: window.chartColors.lightcoral,
124
- data: [],
125
- },
126
- {
127
- label: 'Recieved',
128
- borderColor: window.chartColors.darkseagreen,
129
- data: [],
130
- }],
131
- },
132
- options: {
133
- responsive: true,
134
- maintainAspectRatio: false,
135
- title: {
136
- display: true,
137
- text: 'Email Messages',
138
- },
139
- scales: {
140
- x: {
141
- type: 'timeseries',
142
- offset: true,
143
- ticks: {
144
- major: { enabled: true },
145
- fontStyle: context => context.tick.major ? 'bold' : undefined,
146
- source: 'data',
147
- maxRotation: 0,
148
- autoSkip: true,
149
- autoSkipPadding: 75,
150
- }
151
- }
152
- }
153
- }
154
- });
155
-
156
- memory_chart = new Chart($("#memChart"), {
157
- label: 'Memory Usage',
158
- type: 'line',
159
- data: {
160
- labels: [],
161
- datasets: [{
162
- label: 'Peak Ram usage',
163
- borderColor: window.chartColors.red,
164
- data: [],
165
- },
166
- {
167
- label: 'Current Ram usage',
168
- borderColor: window.chartColors.blue,
169
- data: [],
170
- }],
171
- },
172
- options: {
173
- responsive: true,
174
- maintainAspectRatio: false,
175
- title: {
176
- display: true,
177
- text: 'Memory Usage',
178
- },
179
- scales: {
180
- x: {
181
- type: 'timeseries',
182
- offset: true,
183
- ticks: {
184
- major: { enabled: true },
185
- fontStyle: context => context.tick.major ? 'bold' : undefined,
186
- source: 'data',
187
- maxRotation: 0,
188
- autoSkip: true,
189
- autoSkipPadding: 75,
190
- }
191
- }
192
- }
193
- }
194
- });
195
- }
196
-
197
-
198
- function addData(chart, label, newdata) {
199
- chart.data.labels.push(label);
200
- chart.data.datasets.forEach((dataset) => {
201
- dataset.data.push(newdata);
202
- });
203
- chart.update();
204
- }
205
-
206
- function updateDualData(chart, label, first, second) {
207
- chart.data.labels.push(label);
208
- chart.data.datasets[0].data.push(first);
209
- chart.data.datasets[1].data.push(second);
210
- chart.update();
211
- }
212
- function updateQuadData(chart, label, first, second, third, fourth) {
213
- chart.data.labels.push(label);
214
- chart.data.datasets[0].data.push(first);
215
- chart.data.datasets[1].data.push(second);
216
- chart.data.datasets[2].data.push(third);
217
- chart.data.datasets[3].data.push(fourth);
218
- chart.update();
219
- }
220
-
221
- function update_stats( data ) {
222
- our_callsign = data["APRSDStats"]["callsign"];
223
- $("#version").text( data["APRSDStats"]["version"] );
224
- $("#aprs_connection").html( data["aprs_connection"] );
225
- $("#uptime").text( "uptime: " + data["APRSDStats"]["uptime"] );
226
- const html_pretty = Prism.highlight(JSON.stringify(data, null, '\t'), Prism.languages.json, 'json');
227
- $("#jsonstats").html(html_pretty);
228
- short_time = data["time"].split(/\s(.+)/)[1];
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"]);
235
- }