aprsd 1.0.0__py3-none-any.whl → 3.4.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/__init__.py +6 -4
- aprsd/cli_helper.py +151 -0
- aprsd/client/__init__.py +13 -0
- aprsd/client/aprsis.py +132 -0
- aprsd/client/base.py +105 -0
- aprsd/client/drivers/__init__.py +0 -0
- aprsd/client/drivers/aprsis.py +224 -0
- aprsd/client/drivers/fake.py +73 -0
- aprsd/client/drivers/kiss.py +119 -0
- aprsd/client/factory.py +88 -0
- aprsd/client/fake.py +48 -0
- aprsd/client/kiss.py +103 -0
- aprsd/client/stats.py +38 -0
- aprsd/cmds/__init__.py +0 -0
- aprsd/cmds/completion.py +22 -0
- aprsd/cmds/dev.py +162 -0
- aprsd/cmds/fetch_stats.py +156 -0
- aprsd/cmds/healthcheck.py +86 -0
- aprsd/cmds/list_plugins.py +319 -0
- aprsd/cmds/listen.py +230 -0
- aprsd/cmds/send_message.py +174 -0
- aprsd/cmds/server.py +142 -0
- aprsd/cmds/webchat.py +681 -0
- aprsd/conf/__init__.py +56 -0
- aprsd/conf/client.py +131 -0
- aprsd/conf/common.py +302 -0
- aprsd/conf/log.py +65 -0
- aprsd/conf/opts.py +80 -0
- aprsd/conf/plugin_common.py +191 -0
- aprsd/conf/plugin_email.py +105 -0
- aprsd/exception.py +13 -0
- aprsd/log/__init__.py +0 -0
- aprsd/log/log.py +138 -0
- aprsd/main.py +104 -867
- aprsd/messaging.py +4 -0
- aprsd/packets/__init__.py +12 -0
- aprsd/packets/collector.py +56 -0
- aprsd/packets/core.py +823 -0
- aprsd/packets/log.py +143 -0
- aprsd/packets/packet_list.py +116 -0
- aprsd/packets/seen_list.py +54 -0
- aprsd/packets/tracker.py +109 -0
- aprsd/packets/watch_list.py +122 -0
- aprsd/plugin.py +475 -284
- aprsd/plugin_utils.py +86 -0
- aprsd/plugins/__init__.py +0 -0
- aprsd/plugins/email.py +709 -0
- aprsd/plugins/fortune.py +61 -0
- aprsd/plugins/location.py +179 -0
- aprsd/plugins/notify.py +61 -0
- aprsd/plugins/ping.py +31 -0
- aprsd/plugins/time.py +115 -0
- aprsd/plugins/version.py +31 -0
- aprsd/plugins/weather.py +405 -0
- aprsd/stats/__init__.py +20 -0
- aprsd/stats/app.py +49 -0
- aprsd/stats/collector.py +38 -0
- aprsd/threads/__init__.py +11 -0
- aprsd/threads/aprsd.py +119 -0
- aprsd/threads/keep_alive.py +124 -0
- aprsd/threads/log_monitor.py +121 -0
- aprsd/threads/registry.py +56 -0
- aprsd/threads/rx.py +354 -0
- aprsd/threads/stats.py +44 -0
- aprsd/threads/tx.py +255 -0
- aprsd/utils/__init__.py +163 -0
- aprsd/utils/counter.py +51 -0
- aprsd/utils/json.py +80 -0
- aprsd/utils/objectstore.py +123 -0
- aprsd/utils/ring_buffer.py +40 -0
- aprsd/utils/trace.py +180 -0
- aprsd/web/__init__.py +0 -0
- aprsd/web/admin/__init__.py +0 -0
- aprsd/web/admin/static/css/index.css +84 -0
- aprsd/web/admin/static/css/prism.css +4 -0
- aprsd/web/admin/static/css/tabs.css +35 -0
- 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 +235 -0
- aprsd/web/admin/static/js/echarts.js +465 -0
- aprsd/web/admin/static/js/logs.js +26 -0
- aprsd/web/admin/static/js/main.js +231 -0
- aprsd/web/admin/static/js/prism.js +12 -0
- aprsd/web/admin/static/js/send-message.js +114 -0
- aprsd/web/admin/static/js/tabs.js +28 -0
- aprsd/web/admin/templates/index.html +196 -0
- aprsd/web/chat/static/css/chat.css +115 -0
- aprsd/web/chat/static/css/index.css +66 -0
- aprsd/web/chat/static/css/style.css.map +1 -0
- aprsd/web/chat/static/css/tabs.css +41 -0
- aprsd/web/chat/static/css/upstream/bootstrap.min.css +6 -0
- aprsd/web/chat/static/css/upstream/font.woff2 +0 -0
- aprsd/web/chat/static/css/upstream/google-fonts.css +23 -0
- aprsd/web/chat/static/css/upstream/jquery-ui.css +1311 -0
- aprsd/web/chat/static/css/upstream/jquery.toast.css +28 -0
- 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 +3 -0
- aprsd/web/chat/static/js/gps.js +84 -0
- aprsd/web/chat/static/js/main.js +45 -0
- aprsd/web/chat/static/js/send-message.js +585 -0
- aprsd/web/chat/static/js/tabs.js +28 -0
- aprsd/web/chat/static/js/upstream/bootstrap.bundle.min.js +7 -0
- aprsd/web/chat/static/js/upstream/jquery-3.7.1.min.js +2 -0
- aprsd/web/chat/static/js/upstream/jquery-ui.min.js +13 -0
- aprsd/web/chat/static/js/upstream/jquery.toast.js +374 -0
- aprsd/web/chat/static/js/upstream/semantic.min.js +11 -0
- aprsd/web/chat/static/js/upstream/socket.io.min.js +7 -0
- aprsd/web/chat/templates/index.html +139 -0
- aprsd/wsgi.py +315 -0
- aprsd-3.4.1.dist-info/AUTHORS +13 -0
- aprsd-3.4.1.dist-info/LICENSE +175 -0
- aprsd-3.4.1.dist-info/METADATA +799 -0
- aprsd-3.4.1.dist-info/RECORD +134 -0
- {aprsd-1.0.0.dist-info → aprsd-3.4.1.dist-info}/WHEEL +1 -1
- aprsd-3.4.1.dist-info/entry_points.txt +8 -0
- aprsd/fake_aprs.py +0 -83
- aprsd/utils.py +0 -166
- aprsd-1.0.0.dist-info/AUTHORS +0 -6
- aprsd-1.0.0.dist-info/METADATA +0 -181
- aprsd-1.0.0.dist-info/RECORD +0 -13
- aprsd-1.0.0.dist-info/entry_points.txt +0 -4
- aprsd-1.0.0.dist-info/pbr.json +0 -1
- /aprsd/{fuzzyclock.py → utils/fuzzyclock.py} +0 -0
- {aprsd-1.0.0.dist-info → aprsd-3.4.1.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,40 @@
|
|
1
|
+
class RingBuffer:
|
2
|
+
"""class that implements a not-yet-full buffer"""
|
3
|
+
|
4
|
+
max: int = 100
|
5
|
+
data: list = []
|
6
|
+
|
7
|
+
def __init__(self, size_max):
|
8
|
+
self.max = size_max
|
9
|
+
self.data = []
|
10
|
+
|
11
|
+
class __Full:
|
12
|
+
"""class that implements a full buffer"""
|
13
|
+
|
14
|
+
def append(self, x):
|
15
|
+
"""Append an element overwriting the oldest one."""
|
16
|
+
self.data[self.cur] = x
|
17
|
+
self.cur = (self.cur + 1) % self.max
|
18
|
+
|
19
|
+
def get(self):
|
20
|
+
"""return list of elements in correct order"""
|
21
|
+
return self.data[self.cur :] + self.data[: self.cur]
|
22
|
+
|
23
|
+
def __len__(self):
|
24
|
+
return len(self.data)
|
25
|
+
|
26
|
+
def append(self, x):
|
27
|
+
"""append an element at the end of the buffer"""
|
28
|
+
|
29
|
+
self.data.append(x)
|
30
|
+
if len(self.data) == self.max:
|
31
|
+
self.cur = 0
|
32
|
+
# Permanently change self's class from non-full to full
|
33
|
+
self.__class__ = self.__Full
|
34
|
+
|
35
|
+
def get(self):
|
36
|
+
"""Return a list of elements from the oldest to the newest."""
|
37
|
+
return self.data
|
38
|
+
|
39
|
+
def __len__(self):
|
40
|
+
return len(self.data)
|
aprsd/utils/trace.py
ADDED
@@ -0,0 +1,180 @@
|
|
1
|
+
import abc
|
2
|
+
import functools
|
3
|
+
import inspect
|
4
|
+
import logging
|
5
|
+
import time
|
6
|
+
import types
|
7
|
+
|
8
|
+
|
9
|
+
VALID_TRACE_FLAGS = {"method", "api"}
|
10
|
+
TRACE_API = False
|
11
|
+
TRACE_METHOD = False
|
12
|
+
TRACE_ENABLED = False
|
13
|
+
LOG = logging.getLogger("APRSD")
|
14
|
+
|
15
|
+
|
16
|
+
def trace(*dec_args, **dec_kwargs):
|
17
|
+
"""Trace calls to the decorated function.
|
18
|
+
|
19
|
+
This decorator should always be defined as the outermost decorator so it
|
20
|
+
is defined last. This is important so it does not interfere
|
21
|
+
with other decorators.
|
22
|
+
|
23
|
+
Using this decorator on a function will cause its execution to be logged at
|
24
|
+
`DEBUG` level with arguments, return values, and exceptions.
|
25
|
+
|
26
|
+
:returns: a function decorator
|
27
|
+
"""
|
28
|
+
|
29
|
+
def _decorator(f):
|
30
|
+
|
31
|
+
func_name = f.__name__
|
32
|
+
|
33
|
+
@functools.wraps(f)
|
34
|
+
def trace_logging_wrapper(*args, **kwargs):
|
35
|
+
filter_function = dec_kwargs.get("filter_function")
|
36
|
+
logger = LOG
|
37
|
+
|
38
|
+
# NOTE(ameade): Don't bother going any further if DEBUG log level
|
39
|
+
# is not enabled for the logger.
|
40
|
+
if not logger.isEnabledFor(logging.DEBUG) or not TRACE_ENABLED:
|
41
|
+
return f(*args, **kwargs)
|
42
|
+
|
43
|
+
all_args = inspect.getcallargs(f, *args, **kwargs)
|
44
|
+
|
45
|
+
pass_filter = filter_function is None or filter_function(all_args)
|
46
|
+
|
47
|
+
if pass_filter:
|
48
|
+
logger.debug(
|
49
|
+
"==> %(func)s: call %(all_args)r",
|
50
|
+
{
|
51
|
+
"func": func_name,
|
52
|
+
"all_args": str(all_args),
|
53
|
+
},
|
54
|
+
)
|
55
|
+
|
56
|
+
start_time = time.time() * 1000
|
57
|
+
try:
|
58
|
+
result = f(*args, **kwargs)
|
59
|
+
except Exception as exc:
|
60
|
+
total_time = int(round(time.time() * 1000)) - start_time
|
61
|
+
logger.debug(
|
62
|
+
"<== %(func)s: exception (%(time)dms) %(exc)r",
|
63
|
+
{
|
64
|
+
"func": func_name,
|
65
|
+
"time": total_time,
|
66
|
+
"exc": exc,
|
67
|
+
},
|
68
|
+
)
|
69
|
+
raise
|
70
|
+
total_time = int(round(time.time() * 1000)) - start_time
|
71
|
+
|
72
|
+
if isinstance(result, dict):
|
73
|
+
mask_result = result
|
74
|
+
elif isinstance(result, str):
|
75
|
+
mask_result = result
|
76
|
+
else:
|
77
|
+
mask_result = result
|
78
|
+
|
79
|
+
if pass_filter:
|
80
|
+
logger.debug(
|
81
|
+
"<== %(func)s: return (%(time)dms) %(result)r",
|
82
|
+
{
|
83
|
+
"func": func_name,
|
84
|
+
"time": total_time,
|
85
|
+
"result": mask_result,
|
86
|
+
},
|
87
|
+
)
|
88
|
+
return result
|
89
|
+
|
90
|
+
return trace_logging_wrapper
|
91
|
+
|
92
|
+
if len(dec_args) == 0:
|
93
|
+
# filter_function is passed and args does not contain f
|
94
|
+
return _decorator
|
95
|
+
else:
|
96
|
+
# filter_function is not passed
|
97
|
+
return _decorator(dec_args[0])
|
98
|
+
|
99
|
+
|
100
|
+
def trace_api(*dec_args, **dec_kwargs):
|
101
|
+
"""Decorates a function if TRACE_API is true."""
|
102
|
+
|
103
|
+
def _decorator(f):
|
104
|
+
@functools.wraps(f)
|
105
|
+
def trace_api_logging_wrapper(*args, **kwargs):
|
106
|
+
if TRACE_API:
|
107
|
+
return trace(f, *dec_args, **dec_kwargs)(*args, **kwargs)
|
108
|
+
return f(*args, **kwargs)
|
109
|
+
|
110
|
+
return trace_api_logging_wrapper
|
111
|
+
|
112
|
+
if len(dec_args) == 0:
|
113
|
+
# filter_function is passed and args does not contain f
|
114
|
+
return _decorator
|
115
|
+
else:
|
116
|
+
# filter_function is not passed
|
117
|
+
return _decorator(dec_args[0])
|
118
|
+
|
119
|
+
|
120
|
+
def trace_method(f):
|
121
|
+
"""Decorates a function if TRACE_METHOD is true."""
|
122
|
+
|
123
|
+
@functools.wraps(f)
|
124
|
+
def trace_method_logging_wrapper(*args, **kwargs):
|
125
|
+
if TRACE_METHOD:
|
126
|
+
return trace(f)(*args, **kwargs)
|
127
|
+
return f(*args, **kwargs)
|
128
|
+
|
129
|
+
return trace_method_logging_wrapper
|
130
|
+
|
131
|
+
|
132
|
+
class TraceWrapperMetaclass(type):
|
133
|
+
"""Metaclass that wraps all methods of a class with trace_method.
|
134
|
+
|
135
|
+
This metaclass will cause every function inside of the class to be
|
136
|
+
decorated with the trace_method decorator.
|
137
|
+
|
138
|
+
To use the metaclass you define a class like so:
|
139
|
+
class MyClass(object, metaclass=utils.TraceWrapperMetaclass):
|
140
|
+
"""
|
141
|
+
|
142
|
+
def __new__(cls, classname, bases, class_dict):
|
143
|
+
new_class_dict = {}
|
144
|
+
for attribute_name, attribute in class_dict.items():
|
145
|
+
if isinstance(attribute, types.FunctionType):
|
146
|
+
# replace it with a wrapped version
|
147
|
+
attribute = functools.update_wrapper(
|
148
|
+
trace_method(attribute),
|
149
|
+
attribute,
|
150
|
+
)
|
151
|
+
new_class_dict[attribute_name] = attribute
|
152
|
+
|
153
|
+
return type.__new__(cls, classname, bases, new_class_dict)
|
154
|
+
|
155
|
+
|
156
|
+
class TraceWrapperWithABCMetaclass(abc.ABCMeta, TraceWrapperMetaclass):
|
157
|
+
"""Metaclass that wraps all methods of a class with trace."""
|
158
|
+
|
159
|
+
|
160
|
+
def setup_tracing(trace_flags):
|
161
|
+
"""Set global variables for each trace flag.
|
162
|
+
|
163
|
+
Sets variables TRACE_METHOD and TRACE_API, which represent
|
164
|
+
whether to log methods or api traces.
|
165
|
+
|
166
|
+
:param trace_flags: a list of strings
|
167
|
+
"""
|
168
|
+
global TRACE_METHOD
|
169
|
+
global TRACE_API
|
170
|
+
global TRACE_ENABLED
|
171
|
+
|
172
|
+
try:
|
173
|
+
trace_flags = [flag.strip() for flag in trace_flags]
|
174
|
+
except TypeError: # Handle when trace_flags is None or a test mock
|
175
|
+
trace_flags = []
|
176
|
+
for invalid_flag in set(trace_flags) - VALID_TRACE_FLAGS:
|
177
|
+
LOG.warning("Invalid trace flag: %s", invalid_flag)
|
178
|
+
TRACE_METHOD = "method" in trace_flags
|
179
|
+
TRACE_API = "api" in trace_flags
|
180
|
+
TRACE_ENABLED = True
|
aprsd/web/__init__.py
ADDED
File without changes
|
File without changes
|
@@ -0,0 +1,84 @@
|
|
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
|
+
}
|
@@ -0,0 +1,4 @@
|
|
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}
|
@@ -0,0 +1,35 @@
|
|
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
|
@@ -0,0 +1,235 @@
|
|
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
|
+
}
|