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/plugins/location.py DELETED
@@ -1,179 +0,0 @@
1
- import logging
2
- import re
3
- import time
4
-
5
- from geopy.geocoders import ArcGIS, AzureMaps, Baidu, Bing, GoogleV3
6
- from geopy.geocoders import HereV7, Nominatim, OpenCage, TomTom, What3WordsV3, Woosmap
7
- from oslo_config import cfg
8
-
9
- from aprsd import packets, plugin, plugin_utils
10
- from aprsd.utils import trace
11
-
12
-
13
- CONF = cfg.CONF
14
- LOG = logging.getLogger("APRSD")
15
-
16
-
17
- class UsLocation:
18
- raw = {}
19
-
20
- def __init__(self, info):
21
- self.info = info
22
-
23
- def __str__(self):
24
- return self.info
25
-
26
-
27
- class USGov:
28
- """US Government geocoder that uses the geopy API.
29
-
30
- This is a dummy class the implements the geopy reverse API,
31
- so the factory can return an object that conforms to the API.
32
- """
33
- def reverse(self, coordinates):
34
- """Reverse geocode a coordinate."""
35
- LOG.info(f"USGov reverse geocode {coordinates}")
36
- coords = coordinates.split(",")
37
- lat = float(coords[0])
38
- lon = float(coords[1])
39
- result = plugin_utils.get_weather_gov_for_gps(lat, lon)
40
- # LOG.info(f"WEATHER: {result}")
41
- # LOG.info(f"area description {result['location']['areaDescription']}")
42
- if 'location' in result:
43
- loc = UsLocation(result['location']['areaDescription'])
44
- else:
45
- loc = UsLocation("Unknown Location")
46
-
47
- LOG.info(f"USGov reverse geocode LOC {loc}")
48
- return loc
49
-
50
-
51
- def geopy_factory():
52
- """Factory function for geopy geocoders."""
53
- geocoder = CONF.location_plugin.geopy_geocoder
54
- LOG.info(f"Using geocoder: {geocoder}")
55
- user_agent = CONF.location_plugin.user_agent
56
- LOG.info(f"Using user_agent: {user_agent}")
57
-
58
- if geocoder == "Nominatim":
59
- return Nominatim(user_agent=user_agent)
60
- elif geocoder == "USGov":
61
- return USGov()
62
- elif geocoder == "ArcGIS":
63
- return ArcGIS(
64
- username=CONF.location_plugin.arcgis_username,
65
- password=CONF.location_plugin.arcgis_password,
66
- user_agent=user_agent,
67
- )
68
- elif geocoder == "AzureMaps":
69
- return AzureMaps(
70
- user_agent=user_agent,
71
- subscription_key=CONF.location_plugin.azuremaps_subscription_key,
72
- )
73
- elif geocoder == "Baidu":
74
- return Baidu(user_agent=user_agent, api_key=CONF.location_plugin.baidu_api_key)
75
- elif geocoder == "Bing":
76
- return Bing(user_agent=user_agent, api_key=CONF.location_plugin.bing_api_key)
77
- elif geocoder == "GoogleV3":
78
- return GoogleV3(user_agent=user_agent, api_key=CONF.location_plugin.google_api_key)
79
- elif geocoder == "HERE":
80
- return HereV7(user_agent=user_agent, api_key=CONF.location_plugin.here_api_key)
81
- elif geocoder == "OpenCage":
82
- return OpenCage(user_agent=user_agent, api_key=CONF.location_plugin.opencage_api_key)
83
- elif geocoder == "TomTom":
84
- return TomTom(user_agent=user_agent, api_key=CONF.location_plugin.tomtom_api_key)
85
- elif geocoder == "What3Words":
86
- return What3WordsV3(user_agent=user_agent, api_key=CONF.location_plugin.what3words_api_key)
87
- elif geocoder == "Woosmap":
88
- return Woosmap(user_agent=user_agent, api_key=CONF.location_plugin.woosmap_api_key)
89
- else:
90
- raise ValueError(f"Unknown geocoder: {geocoder}")
91
-
92
-
93
- class LocationPlugin(plugin.APRSDRegexCommandPluginBase, plugin.APRSFIKEYMixin):
94
- """Location!"""
95
-
96
- command_regex = r"^([l]|[l]\s|location)"
97
- command_name = "location"
98
- short_description = "Where in the world is a CALLSIGN's last GPS beacon?"
99
-
100
- def setup(self):
101
- self.ensure_aprs_fi_key()
102
-
103
- @trace.trace
104
- def process(self, packet: packets.MessagePacket):
105
- LOG.info("Location Plugin")
106
- fromcall = packet.from_call
107
- message = packet.get("message_text", None)
108
-
109
- api_key = CONF.aprs_fi.apiKey
110
-
111
- # optional second argument is a callsign to search
112
- a = re.search(r"^.*\s+(.*)", message)
113
- if a is not None:
114
- searchcall = a.group(1)
115
- searchcall = searchcall.upper()
116
- else:
117
- # if no second argument, search for calling station
118
- searchcall = fromcall
119
-
120
- try:
121
- aprs_data = plugin_utils.get_aprs_fi(api_key, searchcall)
122
- except Exception as ex:
123
- LOG.error(f"Failed to fetch aprs.fi '{ex}'")
124
- return "Failed to fetch aprs.fi location"
125
-
126
- LOG.debug(f"LocationPlugin: aprs_data = {aprs_data}")
127
- if not len(aprs_data["entries"]):
128
- LOG.error("Didn't get any entries from aprs.fi")
129
- return "Failed to fetch aprs.fi location"
130
-
131
- lat = float(aprs_data["entries"][0]["lat"])
132
- lon = float(aprs_data["entries"][0]["lng"])
133
-
134
- # Get some information about their location
135
- try:
136
- tic = time.perf_counter()
137
- geolocator = geopy_factory()
138
- LOG.info(f"Using GEOLOCATOR: {geolocator}")
139
- coordinates = f"{lat:0.6f}, {lon:0.6f}"
140
- location = geolocator.reverse(coordinates)
141
- address = location.raw.get("address")
142
- LOG.debug(f"GEOLOCATOR address: {address}")
143
- toc = time.perf_counter()
144
- if address:
145
- LOG.info(f"Geopy address {address} took {toc - tic:0.4f}")
146
- if address.get("country_code") == "us":
147
- area_info = f"{address.get('county')}, {address.get('state')}"
148
- else:
149
- # what to do for address for non US?
150
- area_info = f"{address.get('country'), 'Unknown'}"
151
- else:
152
- area_info = str(location)
153
- except Exception as ex:
154
- LOG.error(ex)
155
- LOG.error(f"Failed to fetch Geopy address {ex}")
156
- area_info = "Unknown Location"
157
-
158
- try: # altitude not always provided
159
- alt = float(aprs_data["entries"][0]["altitude"])
160
- except Exception:
161
- alt = 0
162
- altfeet = int(alt * 3.28084)
163
- aprs_lasttime_seconds = aprs_data["entries"][0]["lasttime"]
164
- # aprs_lasttime_seconds = aprs_lasttime_seconds.encode(
165
- # "ascii", errors="ignore"
166
- # ) # unicode to ascii
167
- delta_seconds = time.time() - int(aprs_lasttime_seconds)
168
- delta_hours = delta_seconds / 60 / 60
169
-
170
- reply = "{}: {} {}' {},{} {}h ago".format(
171
- searchcall,
172
- area_info,
173
- str(altfeet),
174
- f"{lat:0.2f}",
175
- f"{lon:0.2f}",
176
- str("%.1f" % round(delta_hours, 1)),
177
- ).rstrip()
178
-
179
- 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
- }