aprsd 3.4.4__py3-none-any.whl → 4.0.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- aprsd/cli_helper.py +12 -5
- aprsd/client/aprsis.py +31 -9
- aprsd/client/base.py +13 -2
- aprsd/client/drivers/aprsis.py +6 -3
- aprsd/client/drivers/fake.py +15 -20
- aprsd/client/factory.py +0 -2
- aprsd/client/fake.py +0 -2
- aprsd/client/kiss.py +17 -2
- aprsd/client/stats.py +1 -3
- aprsd/cmds/completion.py +7 -4
- aprsd/cmds/dev.py +38 -42
- aprsd/cmds/fetch_stats.py +140 -143
- aprsd/cmds/healthcheck.py +5 -3
- aprsd/cmds/list_plugins.py +140 -134
- aprsd/cmds/listen.py +13 -9
- aprsd/cmds/server.py +53 -27
- aprsd/conf/__init__.py +1 -2
- aprsd/conf/client.py +3 -4
- aprsd/conf/common.py +19 -93
- aprsd/conf/log.py +2 -4
- aprsd/conf/opts.py +5 -4
- aprsd/conf/plugin_common.py +11 -121
- aprsd/exception.py +2 -0
- aprsd/log/log.py +7 -46
- aprsd/main.py +10 -4
- aprsd/packets/__init__.py +14 -4
- aprsd/packets/core.py +57 -67
- aprsd/packets/log.py +8 -8
- aprsd/packets/packet_list.py +9 -6
- aprsd/plugin.py +22 -11
- aprsd/plugins/notify.py +1 -4
- aprsd/plugins/weather.py +10 -8
- aprsd/stats/collector.py +5 -2
- aprsd/threads/__init__.py +3 -2
- aprsd/threads/aprsd.py +12 -7
- aprsd/threads/{keep_alive.py → keepalive.py} +14 -45
- aprsd/threads/registry.py +3 -3
- aprsd/threads/rx.py +9 -6
- aprsd/threads/stats.py +2 -2
- aprsd/threads/tx.py +3 -4
- aprsd/utils/__init__.py +42 -10
- aprsd/utils/json.py +9 -4
- aprsd/utils/keepalive_collector.py +55 -0
- aprsd/utils/trace.py +0 -2
- aprsd-4.0.1.dist-info/AUTHORS +1 -0
- {aprsd-3.4.4.dist-info → aprsd-4.0.1.dist-info}/METADATA +307 -408
- aprsd-4.0.1.dist-info/RECORD +74 -0
- {aprsd-3.4.4.dist-info → aprsd-4.0.1.dist-info}/WHEEL +1 -1
- aprsd/cmds/admin.py +0 -57
- aprsd/cmds/webchat.py +0 -662
- aprsd/conf/plugin_email.py +0 -105
- aprsd/plugins/email.py +0 -715
- aprsd/plugins/location.py +0 -181
- aprsd/threads/log_monitor.py +0 -121
- aprsd/web/__init__.py +0 -0
- aprsd/web/admin/__init__.py +0 -0
- aprsd/web/admin/static/css/index.css +0 -84
- aprsd/web/admin/static/css/prism.css +0 -4
- aprsd/web/admin/static/css/tabs.css +0 -35
- aprsd/web/admin/static/images/Untitled.png +0 -0
- aprsd/web/admin/static/images/aprs-symbols-16-0.png +0 -0
- aprsd/web/admin/static/images/aprs-symbols-16-1.png +0 -0
- aprsd/web/admin/static/images/aprs-symbols-64-0.png +0 -0
- aprsd/web/admin/static/images/aprs-symbols-64-1.png +0 -0
- aprsd/web/admin/static/images/aprs-symbols-64-2.png +0 -0
- aprsd/web/admin/static/js/charts.js +0 -235
- aprsd/web/admin/static/js/echarts.js +0 -465
- aprsd/web/admin/static/js/logs.js +0 -26
- aprsd/web/admin/static/js/main.js +0 -231
- aprsd/web/admin/static/js/prism.js +0 -12
- aprsd/web/admin/static/js/send-message.js +0 -114
- aprsd/web/admin/static/js/tabs.js +0 -28
- aprsd/web/admin/templates/index.html +0 -196
- aprsd/web/chat/static/css/chat.css +0 -115
- aprsd/web/chat/static/css/index.css +0 -66
- aprsd/web/chat/static/css/style.css.map +0 -1
- aprsd/web/chat/static/css/tabs.css +0 -41
- aprsd/web/chat/static/css/upstream/bootstrap.min.css +0 -6
- aprsd/web/chat/static/css/upstream/font.woff2 +0 -0
- aprsd/web/chat/static/css/upstream/google-fonts.css +0 -23
- aprsd/web/chat/static/css/upstream/jquery-ui.css +0 -1311
- aprsd/web/chat/static/css/upstream/jquery.toast.css +0 -28
- aprsd/web/chat/static/css/upstream/themes/default/assets/fonts/LatoLatin-Bold.woff +0 -0
- aprsd/web/chat/static/css/upstream/themes/default/assets/fonts/LatoLatin-Bold.woff2 +0 -0
- aprsd/web/chat/static/css/upstream/themes/default/assets/fonts/LatoLatin-Regular.woff +0 -0
- aprsd/web/chat/static/css/upstream/themes/default/assets/fonts/LatoLatin-Regular.woff2 +0 -0
- aprsd/web/chat/static/css/upstream/themes/default/assets/fonts/icons.woff +0 -0
- aprsd/web/chat/static/css/upstream/themes/default/assets/fonts/icons.woff2 +0 -0
- aprsd/web/chat/static/css/upstream/themes/default/assets/fonts/outline-icons.woff +0 -0
- aprsd/web/chat/static/css/upstream/themes/default/assets/fonts/outline-icons.woff2 +0 -0
- aprsd/web/chat/static/images/Untitled.png +0 -0
- aprsd/web/chat/static/images/aprs-symbols-16-0.png +0 -0
- aprsd/web/chat/static/images/aprs-symbols-16-1.png +0 -0
- aprsd/web/chat/static/images/aprs-symbols-64-0.png +0 -0
- aprsd/web/chat/static/images/aprs-symbols-64-1.png +0 -0
- aprsd/web/chat/static/images/aprs-symbols-64-2.png +0 -0
- aprsd/web/chat/static/images/globe.svg +0 -3
- aprsd/web/chat/static/js/gps.js +0 -84
- aprsd/web/chat/static/js/main.js +0 -45
- aprsd/web/chat/static/js/send-message.js +0 -612
- aprsd/web/chat/static/js/tabs.js +0 -28
- aprsd/web/chat/static/js/upstream/bootstrap.bundle.min.js +0 -7
- aprsd/web/chat/static/js/upstream/jquery-3.7.1.min.js +0 -2
- aprsd/web/chat/static/js/upstream/jquery-ui.min.js +0 -13
- aprsd/web/chat/static/js/upstream/jquery.toast.js +0 -374
- aprsd/web/chat/static/js/upstream/semantic.min.js +0 -11
- aprsd/web/chat/static/js/upstream/socket.io.min.js +0 -7
- aprsd/web/chat/templates/index.html +0 -139
- aprsd/wsgi.py +0 -322
- aprsd-3.4.4.dist-info/AUTHORS +0 -13
- aprsd-3.4.4.dist-info/RECORD +0 -134
- {aprsd-3.4.4.dist-info → aprsd-4.0.1.dist-info}/LICENSE +0 -0
- {aprsd-3.4.4.dist-info → aprsd-4.0.1.dist-info}/entry_points.txt +0 -0
- {aprsd-3.4.4.dist-info → aprsd-4.0.1.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
|
aprsd/threads/log_monitor.py
DELETED
@@ -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
|
aprsd/web/admin/__init__.py
DELETED
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
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
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
|
-
}
|