mirror of
https://github.com/craigerl/aprsd.git
synced 2025-02-03 09:44:15 -05:00
commit
b73373db3f
@ -145,6 +145,8 @@ def sample_config(ctx):
|
|||||||
if not sys.argv[1:]:
|
if not sys.argv[1:]:
|
||||||
raise SystemExit
|
raise SystemExit
|
||||||
raise
|
raise
|
||||||
|
LOG.warning(conf.namespace)
|
||||||
|
return
|
||||||
generator.generate(conf)
|
generator.generate(conf)
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import abc
|
import abc
|
||||||
from dataclasses import asdict, dataclass, field
|
from dataclasses import asdict, dataclass, field
|
||||||
import datetime
|
from datetime import datetime
|
||||||
import json
|
|
||||||
import logging
|
import logging
|
||||||
import re
|
import re
|
||||||
import time
|
import time
|
||||||
@ -9,9 +8,9 @@ import time
|
|||||||
from typing import List
|
from typing import List
|
||||||
|
|
||||||
import dacite
|
import dacite
|
||||||
|
from dataclasses_json import dataclass_json
|
||||||
|
|
||||||
from aprsd.utils import counter
|
from aprsd.utils import counter
|
||||||
from aprsd.utils import json as aprsd_json
|
|
||||||
|
|
||||||
|
|
||||||
LOG = logging.getLogger("APRSD")
|
LOG = logging.getLogger("APRSD")
|
||||||
@ -28,12 +27,20 @@ PACKET_TYPE_BEACON = "beacon"
|
|||||||
PACKET_TYPE_THIRDPARTY = "thirdparty"
|
PACKET_TYPE_THIRDPARTY = "thirdparty"
|
||||||
PACKET_TYPE_UNCOMPRESSED = "uncompressed"
|
PACKET_TYPE_UNCOMPRESSED = "uncompressed"
|
||||||
|
|
||||||
|
NO_DATE = datetime(1900, 10, 24)
|
||||||
|
|
||||||
|
|
||||||
def _init_timestamp():
|
def _init_timestamp():
|
||||||
"""Build a unix style timestamp integer"""
|
"""Build a unix style timestamp integer"""
|
||||||
return int(round(time.time()))
|
return int(round(time.time()))
|
||||||
|
|
||||||
|
|
||||||
|
def _init_send_time():
|
||||||
|
# We have to use a datetime here, or the json encoder
|
||||||
|
# Fails on a NoneType.
|
||||||
|
return NO_DATE
|
||||||
|
|
||||||
|
|
||||||
def _init_msgNo(): # noqa: N802
|
def _init_msgNo(): # noqa: N802
|
||||||
"""For some reason __post__init doesn't get called.
|
"""For some reason __post__init doesn't get called.
|
||||||
|
|
||||||
@ -45,6 +52,20 @@ def _init_msgNo(): # noqa: N802
|
|||||||
return c.value
|
return c.value
|
||||||
|
|
||||||
|
|
||||||
|
def factory_from_dict(packet_dict):
|
||||||
|
pkt_type = get_packet_type(packet_dict)
|
||||||
|
if pkt_type:
|
||||||
|
cls = TYPE_LOOKUP[pkt_type]
|
||||||
|
return cls.from_dict(packet_dict)
|
||||||
|
|
||||||
|
|
||||||
|
def factory_from_json(packet_dict):
|
||||||
|
pkt_type = get_packet_type(packet_dict)
|
||||||
|
if pkt_type:
|
||||||
|
return TYPE_LOOKUP[pkt_type].from_json(packet_dict)
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass_json
|
||||||
@dataclass(unsafe_hash=True)
|
@dataclass(unsafe_hash=True)
|
||||||
class Packet(metaclass=abc.ABCMeta):
|
class Packet(metaclass=abc.ABCMeta):
|
||||||
from_call: str = field(default=None)
|
from_call: str = field(default=None)
|
||||||
@ -64,7 +85,19 @@ class Packet(metaclass=abc.ABCMeta):
|
|||||||
# Fields related to sending packets out
|
# Fields related to sending packets out
|
||||||
send_count: int = field(repr=False, default=0, compare=False, hash=False)
|
send_count: int = field(repr=False, default=0, compare=False, hash=False)
|
||||||
retry_count: int = field(repr=False, default=3, compare=False, hash=False)
|
retry_count: int = field(repr=False, default=3, compare=False, hash=False)
|
||||||
last_send_time: datetime.timedelta = field(repr=False, default=None, compare=False, hash=False)
|
# last_send_time: datetime = field(
|
||||||
|
# metadata=dc_json_config(
|
||||||
|
# encoder=datetime.isoformat,
|
||||||
|
# decoder=datetime.fromisoformat,
|
||||||
|
# ),
|
||||||
|
# repr=True,
|
||||||
|
# default_factory=_init_send_time,
|
||||||
|
# compare=False,
|
||||||
|
# hash=False
|
||||||
|
# )
|
||||||
|
last_send_time: float = field(repr=False, default=0, compare=False, hash=False)
|
||||||
|
last_send_attempt: int = field(repr=False, default=0, compare=False, hash=False)
|
||||||
|
|
||||||
# Do we allow this packet to be saved to send later?
|
# Do we allow this packet to be saved to send later?
|
||||||
allow_delay: bool = field(repr=False, default=True, compare=False, hash=False)
|
allow_delay: bool = field(repr=False, default=True, compare=False, hash=False)
|
||||||
path: List[str] = field(default_factory=list, compare=False, hash=False)
|
path: List[str] = field(default_factory=list, compare=False, hash=False)
|
||||||
@ -73,16 +106,12 @@ class Packet(metaclass=abc.ABCMeta):
|
|||||||
def __post__init__(self):
|
def __post__init__(self):
|
||||||
LOG.warning(f"POST INIT {self}")
|
LOG.warning(f"POST INIT {self}")
|
||||||
|
|
||||||
@property
|
|
||||||
def __dict__(self):
|
|
||||||
return asdict(self)
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def json(self):
|
def json(self):
|
||||||
"""
|
"""
|
||||||
get the json formated string
|
get the json formated string
|
||||||
"""
|
"""
|
||||||
return json.dumps(self.__dict__, cls=aprsd_json.EnhancedJSONEncoder)
|
return self.to_json()
|
||||||
|
|
||||||
def get(self, key, default=None):
|
def get(self, key, default=None):
|
||||||
"""Emulate a getter on a dict."""
|
"""Emulate a getter on a dict."""
|
||||||
@ -289,6 +318,7 @@ class RejectPacket(Packet):
|
|||||||
self.payload = f":{self.to_call.ljust(9)} :rej{self.msgNo}"
|
self.payload = f":{self.to_call.ljust(9)} :rej{self.msgNo}"
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass_json
|
||||||
@dataclass(unsafe_hash=True)
|
@dataclass(unsafe_hash=True)
|
||||||
class MessagePacket(Packet):
|
class MessagePacket(Packet):
|
||||||
message_text: str = field(default=None)
|
message_text: str = field(default=None)
|
||||||
@ -406,12 +436,12 @@ class GPSPacket(Packet):
|
|||||||
def _build_time_zulu(self):
|
def _build_time_zulu(self):
|
||||||
"""Build the timestamp in UTC/zulu."""
|
"""Build the timestamp in UTC/zulu."""
|
||||||
if self.timestamp:
|
if self.timestamp:
|
||||||
local_dt = datetime.datetime.fromtimestamp(self.timestamp)
|
local_dt = datetime.fromtimestamp(self.timestamp)
|
||||||
else:
|
else:
|
||||||
local_dt = datetime.datetime.now()
|
local_dt = datetime.now()
|
||||||
self.timestamp = datetime.datetime.timestamp(local_dt)
|
self.timestamp = datetime.timestamp(local_dt)
|
||||||
|
|
||||||
utc_offset_timedelta = datetime.datetime.utcnow() - local_dt
|
utc_offset_timedelta = datetime.utcnow() - local_dt
|
||||||
result_utc_datetime = local_dt + utc_offset_timedelta
|
result_utc_datetime = local_dt + utc_offset_timedelta
|
||||||
time_zulu = result_utc_datetime.strftime("%d%H%M")
|
time_zulu = result_utc_datetime.strftime("%d%H%M")
|
||||||
return time_zulu
|
return time_zulu
|
||||||
@ -567,7 +597,7 @@ class WeatherPacket(GPSPacket):
|
|||||||
|
|
||||||
class ThirdParty(Packet):
|
class ThirdParty(Packet):
|
||||||
# Holds the encapsulated packet
|
# Holds the encapsulated packet
|
||||||
subpacket: Packet = None
|
subpacket: Packet = field(default=None, compare=True, hash=False)
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
"""Build the repr version of the packet."""
|
"""Build the repr version of the packet."""
|
||||||
@ -600,7 +630,7 @@ def get_packet_type(packet: dict):
|
|||||||
|
|
||||||
pkt_format = packet.get("format", None)
|
pkt_format = packet.get("format", None)
|
||||||
msg_response = packet.get("response", None)
|
msg_response = packet.get("response", None)
|
||||||
packet_type = "unknown"
|
packet_type = PACKET_TYPE_UNKNOWN
|
||||||
if pkt_format == "message" and msg_response == "ack":
|
if pkt_format == "message" and msg_response == "ack":
|
||||||
packet_type = PACKET_TYPE_ACK
|
packet_type = PACKET_TYPE_ACK
|
||||||
elif pkt_format == "message" and msg_response == "rej":
|
elif pkt_format == "message" and msg_response == "rej":
|
||||||
@ -620,6 +650,10 @@ def get_packet_type(packet: dict):
|
|||||||
packet_type = PACKET_TYPE_WX
|
packet_type = PACKET_TYPE_WX
|
||||||
elif pkt_format == PACKET_TYPE_THIRDPARTY:
|
elif pkt_format == PACKET_TYPE_THIRDPARTY:
|
||||||
packet_type = PACKET_TYPE_THIRDPARTY
|
packet_type = PACKET_TYPE_THIRDPARTY
|
||||||
|
|
||||||
|
if packet_type == PACKET_TYPE_UNKNOWN:
|
||||||
|
if "latitude" in packet:
|
||||||
|
packet_type = PACKET_TYPE_BEACON
|
||||||
return packet_type
|
return packet_type
|
||||||
|
|
||||||
|
|
||||||
|
@ -19,11 +19,12 @@ class PacketList(MutableMapping):
|
|||||||
lock = threading.Lock()
|
lock = threading.Lock()
|
||||||
_total_rx: int = 0
|
_total_rx: int = 0
|
||||||
_total_tx: int = 0
|
_total_tx: int = 0
|
||||||
|
types = {}
|
||||||
|
|
||||||
def __new__(cls, *args, **kwargs):
|
def __new__(cls, *args, **kwargs):
|
||||||
if cls._instance is None:
|
if cls._instance is None:
|
||||||
cls._instance = super().__new__(cls)
|
cls._instance = super().__new__(cls)
|
||||||
cls._maxlen = 1000
|
cls._maxlen = 100
|
||||||
cls.d = OrderedDict()
|
cls.d = OrderedDict()
|
||||||
return cls._instance
|
return cls._instance
|
||||||
|
|
||||||
@ -32,6 +33,10 @@ class PacketList(MutableMapping):
|
|||||||
"""Add a packet that was received."""
|
"""Add a packet that was received."""
|
||||||
self._total_rx += 1
|
self._total_rx += 1
|
||||||
self._add(packet)
|
self._add(packet)
|
||||||
|
ptype = packet.__class__.__name__
|
||||||
|
if not ptype in self.types:
|
||||||
|
self.types[ptype] = {"tx": 0, "rx": 0}
|
||||||
|
self.types[ptype]["rx"] += 1
|
||||||
seen_list.SeenList().update_seen(packet)
|
seen_list.SeenList().update_seen(packet)
|
||||||
stats.APRSDStats().rx(packet)
|
stats.APRSDStats().rx(packet)
|
||||||
|
|
||||||
@ -40,6 +45,10 @@ class PacketList(MutableMapping):
|
|||||||
"""Add a packet that was received."""
|
"""Add a packet that was received."""
|
||||||
self._total_tx += 1
|
self._total_tx += 1
|
||||||
self._add(packet)
|
self._add(packet)
|
||||||
|
ptype = packet.__class__.__name__
|
||||||
|
if not ptype in self.types:
|
||||||
|
self.types[ptype] = {"tx": 0, "rx": 0}
|
||||||
|
self.types[ptype]["tx"] += 1
|
||||||
seen_list.SeenList().update_seen(packet)
|
seen_list.SeenList().update_seen(packet)
|
||||||
stats.APRSDStats().tx(packet)
|
stats.APRSDStats().tx(packet)
|
||||||
|
|
||||||
@ -50,6 +59,9 @@ class PacketList(MutableMapping):
|
|||||||
def _add(self, packet):
|
def _add(self, packet):
|
||||||
self[packet.key] = packet
|
self[packet.key] = packet
|
||||||
|
|
||||||
|
def copy(self):
|
||||||
|
return self.d.copy()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def maxlen(self):
|
def maxlen(self):
|
||||||
return self._maxlen
|
return self._maxlen
|
||||||
|
@ -65,6 +65,7 @@ class PacketTrack(objectstore.ObjectStoreMixin):
|
|||||||
@wrapt.synchronized(lock)
|
@wrapt.synchronized(lock)
|
||||||
def add(self, packet):
|
def add(self, packet):
|
||||||
key = packet.msgNo
|
key = packet.msgNo
|
||||||
|
packet._last_send_attempt = 0
|
||||||
self.data[key] = packet
|
self.data[key] = packet
|
||||||
self.total_tracked += 1
|
self.total_tracked += 1
|
||||||
|
|
||||||
@ -83,7 +84,7 @@ class PacketTrack(objectstore.ObjectStoreMixin):
|
|||||||
"""Walk the list of messages and restart them if any."""
|
"""Walk the list of messages and restart them if any."""
|
||||||
for key in self.data.keys():
|
for key in self.data.keys():
|
||||||
pkt = self.data[key]
|
pkt = self.data[key]
|
||||||
if pkt.last_send_attempt < pkt.retry_count:
|
if pkt._last_send_attempt < pkt.retry_count:
|
||||||
tx.send(pkt)
|
tx.send(pkt)
|
||||||
|
|
||||||
def _resend(self, packet):
|
def _resend(self, packet):
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
import datetime
|
|
||||||
import logging
|
import logging
|
||||||
import time
|
import time
|
||||||
|
|
||||||
@ -128,10 +127,10 @@ class SendPacketThread(aprsd_threads.APRSDThread):
|
|||||||
# Message is still outstanding and needs to be acked.
|
# Message is still outstanding and needs to be acked.
|
||||||
if packet.last_send_time:
|
if packet.last_send_time:
|
||||||
# Message has a last send time tracking
|
# Message has a last send time tracking
|
||||||
now = datetime.datetime.now()
|
now = int(round(time.time()))
|
||||||
sleeptime = (packet.send_count + 1) * 31
|
sleeptime = (packet.send_count + 1) * 31
|
||||||
delta = now - packet.last_send_time
|
delta = now - packet.last_send_time
|
||||||
if delta > datetime.timedelta(seconds=sleeptime):
|
if delta > sleeptime:
|
||||||
# It's time to try to send it again
|
# It's time to try to send it again
|
||||||
send_now = True
|
send_now = True
|
||||||
else:
|
else:
|
||||||
@ -140,7 +139,7 @@ class SendPacketThread(aprsd_threads.APRSDThread):
|
|||||||
if send_now:
|
if send_now:
|
||||||
# no attempt time, so lets send it, and start
|
# no attempt time, so lets send it, and start
|
||||||
# tracking the time.
|
# tracking the time.
|
||||||
packet.last_send_time = datetime.datetime.now()
|
packet.last_send_time = int(round(time.time()))
|
||||||
send(packet, direct=True)
|
send(packet, direct=True)
|
||||||
packet.send_count += 1
|
packet.send_count += 1
|
||||||
|
|
||||||
@ -173,13 +172,13 @@ class SendAckThread(aprsd_threads.APRSDThread):
|
|||||||
|
|
||||||
if self.packet.last_send_time:
|
if self.packet.last_send_time:
|
||||||
# Message has a last send time tracking
|
# Message has a last send time tracking
|
||||||
now = datetime.datetime.now()
|
now = int(round(time.time()))
|
||||||
|
|
||||||
# aprs duplicate detection is 30 secs?
|
# aprs duplicate detection is 30 secs?
|
||||||
# (21 only sends first, 28 skips middle)
|
# (21 only sends first, 28 skips middle)
|
||||||
sleep_time = 31
|
sleep_time = 31
|
||||||
delta = now - self.packet.last_send_time
|
delta = now - self.packet.last_send_time
|
||||||
if delta > datetime.timedelta(seconds=sleep_time):
|
if delta > sleep_time:
|
||||||
# It's time to try to send it again
|
# It's time to try to send it again
|
||||||
send_now = True
|
send_now = True
|
||||||
elif self.loop_count % 10 == 0:
|
elif self.loop_count % 10 == 0:
|
||||||
@ -190,7 +189,7 @@ class SendAckThread(aprsd_threads.APRSDThread):
|
|||||||
if send_now:
|
if send_now:
|
||||||
send(self.packet, direct=True)
|
send(self.packet, direct=True)
|
||||||
self.packet.send_count += 1
|
self.packet.send_count += 1
|
||||||
self.packet.last_send_time = datetime.datetime.now()
|
self.packet.last_send_time = int(round(time.time()))
|
||||||
|
|
||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
self.loop_count += 1
|
self.loop_count += 1
|
||||||
|
403
aprsd/web/admin/static/js/echarts.js
Normal file
403
aprsd/web/admin/static/js/echarts.js
Normal file
@ -0,0 +1,403 @@
|
|||||||
|
var packet_list = {};
|
||||||
|
|
||||||
|
var tx_data = [];
|
||||||
|
var rx_data = [];
|
||||||
|
|
||||||
|
var packet_types_data = {};
|
||||||
|
|
||||||
|
var mem_current = []
|
||||||
|
var mem_peak = []
|
||||||
|
|
||||||
|
|
||||||
|
function start_charts() {
|
||||||
|
console.log("start_charts() called");
|
||||||
|
// Initialize the echarts instance based on the prepared dom
|
||||||
|
create_packets_chart();
|
||||||
|
create_packets_types_chart();
|
||||||
|
create_messages_chart();
|
||||||
|
create_ack_chart();
|
||||||
|
create_memory_chart();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function create_packets_chart() {
|
||||||
|
// The packets totals TX/RX chart.
|
||||||
|
pkt_c_canvas = document.getElementById('packetsChart');
|
||||||
|
packets_chart = echarts.init(pkt_c_canvas);
|
||||||
|
|
||||||
|
// Specify the configuration items and data for the chart
|
||||||
|
var option = {
|
||||||
|
title: {
|
||||||
|
text: 'APRS Packet totals'
|
||||||
|
},
|
||||||
|
legend: {},
|
||||||
|
tooltip : {
|
||||||
|
trigger: 'axis'
|
||||||
|
},
|
||||||
|
toolbox: {
|
||||||
|
show : true,
|
||||||
|
feature : {
|
||||||
|
mark : {show: true},
|
||||||
|
dataView : {show: true, readOnly: true},
|
||||||
|
magicType : {show: true, type: ['line', 'bar']},
|
||||||
|
restore : {show: true},
|
||||||
|
saveAsImage : {show: true}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
calculable : true,
|
||||||
|
xAxis: { type: 'time' },
|
||||||
|
yAxis: { },
|
||||||
|
series: [
|
||||||
|
{
|
||||||
|
name: 'tx',
|
||||||
|
type: 'line',
|
||||||
|
smooth: true,
|
||||||
|
color: 'red',
|
||||||
|
encode: {
|
||||||
|
x: 'timestamp',
|
||||||
|
y: 'tx' // refer sensor 1 value
|
||||||
|
}
|
||||||
|
},{
|
||||||
|
name: 'rx',
|
||||||
|
type: 'line',
|
||||||
|
smooth: true,
|
||||||
|
encode: {
|
||||||
|
x: 'timestamp',
|
||||||
|
y: 'rx'
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
};
|
||||||
|
|
||||||
|
// Display the chart using the configuration items and data just specified.
|
||||||
|
packets_chart.setOption(option);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function create_packets_types_chart() {
|
||||||
|
// The packets types chart
|
||||||
|
pkt_types_canvas = document.getElementById('packetTypesChart');
|
||||||
|
packet_types_chart = echarts.init(pkt_types_canvas);
|
||||||
|
|
||||||
|
// The series and data are built and updated on the fly
|
||||||
|
// as packets come in.
|
||||||
|
var option = {
|
||||||
|
title: {
|
||||||
|
text: 'Packet Types'
|
||||||
|
},
|
||||||
|
legend: {},
|
||||||
|
tooltip : {
|
||||||
|
trigger: 'axis'
|
||||||
|
},
|
||||||
|
toolbox: {
|
||||||
|
show : true,
|
||||||
|
feature : {
|
||||||
|
mark : {show: true},
|
||||||
|
dataView : {show: true, readOnly: true},
|
||||||
|
magicType : {show: true, type: ['line', 'bar']},
|
||||||
|
restore : {show: true},
|
||||||
|
saveAsImage : {show: true}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
calculable : true,
|
||||||
|
xAxis: { type: 'time' },
|
||||||
|
yAxis: { },
|
||||||
|
}
|
||||||
|
|
||||||
|
packet_types_chart.setOption(option);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function create_messages_chart() {
|
||||||
|
msg_c_canvas = document.getElementById('messagesChart');
|
||||||
|
message_chart = echarts.init(msg_c_canvas);
|
||||||
|
|
||||||
|
// Specify the configuration items and data for the chart
|
||||||
|
var option = {
|
||||||
|
title: {
|
||||||
|
text: 'Message Packets'
|
||||||
|
},
|
||||||
|
legend: {},
|
||||||
|
tooltip: {
|
||||||
|
trigger: 'axis'
|
||||||
|
},
|
||||||
|
toolbox: {
|
||||||
|
show: true,
|
||||||
|
feature: {
|
||||||
|
mark : {show: true},
|
||||||
|
dataView : {show: true, readOnly: true},
|
||||||
|
magicType : {show: true, type: ['line', 'bar']},
|
||||||
|
restore : {show: true},
|
||||||
|
saveAsImage : {show: true}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
calculable: true,
|
||||||
|
xAxis: { type: 'time' },
|
||||||
|
yAxis: { },
|
||||||
|
series: [
|
||||||
|
{
|
||||||
|
name: 'tx',
|
||||||
|
type: 'line',
|
||||||
|
smooth: true,
|
||||||
|
color: 'red',
|
||||||
|
encode: {
|
||||||
|
x: 'timestamp',
|
||||||
|
y: 'tx' // refer sensor 1 value
|
||||||
|
}
|
||||||
|
},{
|
||||||
|
name: 'rx',
|
||||||
|
type: 'line',
|
||||||
|
smooth: true,
|
||||||
|
encode: {
|
||||||
|
x: 'timestamp',
|
||||||
|
y: 'rx'
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
};
|
||||||
|
|
||||||
|
// Display the chart using the configuration items and data just specified.
|
||||||
|
message_chart.setOption(option);
|
||||||
|
}
|
||||||
|
|
||||||
|
function create_ack_chart() {
|
||||||
|
ack_canvas = document.getElementById('acksChart');
|
||||||
|
ack_chart = echarts.init(ack_canvas);
|
||||||
|
|
||||||
|
// Specify the configuration items and data for the chart
|
||||||
|
var option = {
|
||||||
|
title: {
|
||||||
|
text: 'Ack Packets'
|
||||||
|
},
|
||||||
|
legend: {},
|
||||||
|
tooltip: {
|
||||||
|
trigger: 'axis'
|
||||||
|
},
|
||||||
|
toolbox: {
|
||||||
|
show: true,
|
||||||
|
feature: {
|
||||||
|
mark : {show: true},
|
||||||
|
dataView : {show: true, readOnly: false},
|
||||||
|
magicType : {show: true, type: ['line', 'bar']},
|
||||||
|
restore : {show: true},
|
||||||
|
saveAsImage : {show: true}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
calculable: true,
|
||||||
|
xAxis: { type: 'time' },
|
||||||
|
yAxis: { },
|
||||||
|
series: [
|
||||||
|
{
|
||||||
|
name: 'tx',
|
||||||
|
type: 'line',
|
||||||
|
smooth: true,
|
||||||
|
color: 'red',
|
||||||
|
encode: {
|
||||||
|
x: 'timestamp',
|
||||||
|
y: 'tx' // refer sensor 1 value
|
||||||
|
}
|
||||||
|
},{
|
||||||
|
name: 'rx',
|
||||||
|
type: 'line',
|
||||||
|
smooth: true,
|
||||||
|
encode: {
|
||||||
|
x: 'timestamp',
|
||||||
|
y: 'rx'
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
};
|
||||||
|
|
||||||
|
ack_chart.setOption(option);
|
||||||
|
}
|
||||||
|
|
||||||
|
function create_memory_chart() {
|
||||||
|
ack_canvas = document.getElementById('memChart');
|
||||||
|
memory_chart = echarts.init(ack_canvas);
|
||||||
|
|
||||||
|
// Specify the configuration items and data for the chart
|
||||||
|
var option = {
|
||||||
|
title: {
|
||||||
|
text: 'Memory Usage'
|
||||||
|
},
|
||||||
|
legend: {},
|
||||||
|
tooltip: {
|
||||||
|
trigger: 'axis'
|
||||||
|
},
|
||||||
|
toolbox: {
|
||||||
|
show: true,
|
||||||
|
feature: {
|
||||||
|
mark : {show: true},
|
||||||
|
dataView : {show: true, readOnly: false},
|
||||||
|
magicType : {show: true, type: ['line', 'bar']},
|
||||||
|
restore : {show: true},
|
||||||
|
saveAsImage : {show: true}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
calculable: true,
|
||||||
|
xAxis: { type: 'time' },
|
||||||
|
yAxis: { },
|
||||||
|
series: [
|
||||||
|
{
|
||||||
|
name: 'current',
|
||||||
|
type: 'line',
|
||||||
|
smooth: true,
|
||||||
|
color: 'red',
|
||||||
|
encode: {
|
||||||
|
x: 'timestamp',
|
||||||
|
y: 'current' // refer sensor 1 value
|
||||||
|
}
|
||||||
|
},{
|
||||||
|
name: 'peak',
|
||||||
|
type: 'line',
|
||||||
|
smooth: true,
|
||||||
|
encode: {
|
||||||
|
x: 'timestamp',
|
||||||
|
y: 'peak'
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
};
|
||||||
|
|
||||||
|
memory_chart.setOption(option);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
function updatePacketData(chart, time, first, second) {
|
||||||
|
tx_data.push([time, first]);
|
||||||
|
rx_data.push([time, second]);
|
||||||
|
option = {
|
||||||
|
series: [
|
||||||
|
{
|
||||||
|
name: 'tx',
|
||||||
|
data: tx_data,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'rx',
|
||||||
|
data: rx_data,
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
chart.setOption(option);
|
||||||
|
}
|
||||||
|
|
||||||
|
function updatePacketTypesData(time, typesdata) {
|
||||||
|
//The options series is created on the fly each time based on
|
||||||
|
//the packet types we have in the data
|
||||||
|
var series = []
|
||||||
|
|
||||||
|
for (const k in typesdata) {
|
||||||
|
tx = [time, typesdata[k]["tx"]]
|
||||||
|
rx = [time, typesdata[k]["rx"]]
|
||||||
|
|
||||||
|
if (packet_types_data.hasOwnProperty(k)) {
|
||||||
|
packet_types_data[k]["tx"].push(tx)
|
||||||
|
packet_types_data[k]["rx"].push(rx)
|
||||||
|
} else {
|
||||||
|
packet_types_data[k] = {'tx': [tx], 'rx': [rx]}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function updatePacketTypesChart() {
|
||||||
|
series = []
|
||||||
|
for (const k in packet_types_data) {
|
||||||
|
entry = {
|
||||||
|
name: k+"tx",
|
||||||
|
data: packet_types_data[k]["tx"],
|
||||||
|
type: 'line',
|
||||||
|
smooth: true,
|
||||||
|
encode: {
|
||||||
|
x: 'timestamp',
|
||||||
|
y: k+'tx' // refer sensor 1 value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
series.push(entry)
|
||||||
|
entry = {
|
||||||
|
name: k+"rx",
|
||||||
|
data: packet_types_data[k]["rx"],
|
||||||
|
type: 'line',
|
||||||
|
smooth: true,
|
||||||
|
encode: {
|
||||||
|
x: 'timestamp',
|
||||||
|
y: k+'rx' // refer sensor 1 value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
series.push(entry)
|
||||||
|
}
|
||||||
|
|
||||||
|
option = {
|
||||||
|
series: series
|
||||||
|
}
|
||||||
|
console.log(option)
|
||||||
|
packet_types_chart.setOption(option);
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateTypeChart(chart, key) {
|
||||||
|
//Generic function to update a packet type chart
|
||||||
|
if (! packet_types_data.hasOwnProperty(key)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! packet_types_data[key].hasOwnProperty('tx')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var option = {
|
||||||
|
series: [{
|
||||||
|
name: "tx",
|
||||||
|
data: packet_types_data[key]["tx"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "rx",
|
||||||
|
data: packet_types_data[key]["rx"]
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
|
||||||
|
chart.setOption(option);
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateMemChart(time, current, peak) {
|
||||||
|
mem_current.push([time, current]);
|
||||||
|
mem_peak.push([time, peak]);
|
||||||
|
option = {
|
||||||
|
series: [
|
||||||
|
{
|
||||||
|
name: 'current',
|
||||||
|
data: mem_current,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'peak',
|
||||||
|
data: mem_peak,
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
memory_chart.setOption(option);
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateMessagesChart() {
|
||||||
|
updateTypeChart(message_chart, "MessagePacket")
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateAcksChart() {
|
||||||
|
updateTypeChart(ack_chart, "AckPacket")
|
||||||
|
}
|
||||||
|
|
||||||
|
function update_stats( data ) {
|
||||||
|
console.log(data);
|
||||||
|
our_callsign = data["stats"]["aprsd"]["callsign"];
|
||||||
|
$("#version").text( data["stats"]["aprsd"]["version"] );
|
||||||
|
$("#aprs_connection").html( data["aprs_connection"] );
|
||||||
|
$("#uptime").text( "uptime: " + data["stats"]["aprsd"]["uptime"] );
|
||||||
|
const html_pretty = Prism.highlight(JSON.stringify(data, null, '\t'), Prism.languages.json, 'json');
|
||||||
|
$("#jsonstats").html(html_pretty);
|
||||||
|
|
||||||
|
t = Date.parse(data["time"]);
|
||||||
|
ts = new Date(t);
|
||||||
|
updatePacketData(packets_chart, ts, data["stats"]["packets"]["sent"], data["stats"]["packets"]["received"]);
|
||||||
|
updatePacketTypesData(ts, data["stats"]["packets"]["types"]);
|
||||||
|
updatePacketTypesChart();
|
||||||
|
updateMessagesChart();
|
||||||
|
updateAcksChart();
|
||||||
|
updateMemChart(ts, data["stats"]["aprsd"]["memory_current"], data["stats"]["aprsd"]["memory_peak"]);
|
||||||
|
//updateQuadData(message_chart, short_time, data["stats"]["messages"]["sent"], data["stats"]["messages"]["received"], data["stats"]["messages"]["ack_sent"], data["stats"]["messages"]["ack_recieved"]);
|
||||||
|
//updateDualData(email_chart, short_time, data["stats"]["email"]["sent"], data["stats"]["email"]["recieved"]);
|
||||||
|
//updateDualData(memory_chart, short_time, data["stats"]["aprsd"]["memory_peak"], data["stats"]["aprsd"]["memory_current"]);
|
||||||
|
}
|
@ -6,6 +6,7 @@
|
|||||||
<script src="https://cdn.socket.io/4.7.1/socket.io.min.js" integrity="sha512-+NaO7d6gQ1YPxvc/qHIqZEchjGm207SszoNeMgppoqD/67fEqmc1edS8zrbxPD+4RQI3gDgT/83ihpFW61TG/Q==" crossorigin="anonymous"></script>
|
<script src="https://cdn.socket.io/4.7.1/socket.io.min.js" integrity="sha512-+NaO7d6gQ1YPxvc/qHIqZEchjGm207SszoNeMgppoqD/67fEqmc1edS8zrbxPD+4RQI3gDgT/83ihpFW61TG/Q==" crossorigin="anonymous"></script>
|
||||||
|
|
||||||
<script src="https://cdn.jsdelivr.net/npm/chart.js@2.9.4/dist/Chart.bundle.js"></script>
|
<script src="https://cdn.jsdelivr.net/npm/chart.js@2.9.4/dist/Chart.bundle.js"></script>
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/echarts@5.4.3/dist/echarts.min.js"></script>
|
||||||
|
|
||||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/semantic-ui@2.4.2/dist/semantic.min.css">
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/semantic-ui@2.4.2/dist/semantic.min.css">
|
||||||
<script src="https://cdn.jsdelivr.net/npm/semantic-ui@2.4.2/dist/semantic.min.js"></script>
|
<script src="https://cdn.jsdelivr.net/npm/semantic-ui@2.4.2/dist/semantic.min.js"></script>
|
||||||
@ -15,7 +16,7 @@
|
|||||||
<link rel="stylesheet" href="/static/css/prism.css">
|
<link rel="stylesheet" href="/static/css/prism.css">
|
||||||
<script src="/static/js/prism.js"></script>
|
<script src="/static/js/prism.js"></script>
|
||||||
<script src="/static/js/main.js"></script>
|
<script src="/static/js/main.js"></script>
|
||||||
<script src="/static/js/charts.js"></script>
|
<script src="/static/js/echarts.js"></script>
|
||||||
<script src="/static/js/tabs.js"></script>
|
<script src="/static/js/tabs.js"></script>
|
||||||
<script src="/static/js/send-message.js"></script>
|
<script src="/static/js/send-message.js"></script>
|
||||||
<script src="/static/js/logs.js"></script>
|
<script src="/static/js/logs.js"></script>
|
||||||
@ -83,6 +84,7 @@
|
|||||||
<div class="item" data-tab="plugin-tab">Plugins</div>
|
<div class="item" data-tab="plugin-tab">Plugins</div>
|
||||||
<div class="item" data-tab="config-tab">Config</div>
|
<div class="item" data-tab="config-tab">Config</div>
|
||||||
<div class="item" data-tab="log-tab">LogFile</div>
|
<div class="item" data-tab="log-tab">LogFile</div>
|
||||||
|
<!-- <div class="item" data-tab="oslo-tab">OSLO CONFIG</div> //-->
|
||||||
<div class="item" data-tab="raw-tab">Raw JSON</div>
|
<div class="item" data-tab="raw-tab">Raw JSON</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -92,25 +94,25 @@
|
|||||||
<div class="ui equal width relaxed grid">
|
<div class="ui equal width relaxed grid">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="column">
|
<div class="column">
|
||||||
<div class="ui segment" style="height: 300px">
|
<div class="ui segment" style="height: 300px" id="packetsChart"></div>
|
||||||
<canvas id="packetsChart"></canvas>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="column">
|
|
||||||
<div class="ui segment" style="height: 300px">
|
|
||||||
<canvas id="messageChart"></canvas>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="column">
|
<div class="column">
|
||||||
<div class="ui segment" style="height: 300px">
|
<div class="ui segment" style="height: 300px" id="packetTypesChart"></div>
|
||||||
<canvas id="emailChart"></canvas>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="column">
|
||||||
|
<div class="ui segment" style="height: 300px" id="messagesChart"></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="column">
|
<div class="column">
|
||||||
<div class="ui segment" style="height: 300px">
|
<div class="ui segment" style="height: 300px" id="acksChart"></div>
|
||||||
<canvas id="memChart"></canvas>
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="column">
|
||||||
|
<div class="ui segment" style="height: 300px" id="memChart">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -118,7 +120,7 @@
|
|||||||
<div id="stats" class="two column">
|
<div id="stats" class="two column">
|
||||||
<button class="ui button" id="toggleStats">Toggle raw json</button>
|
<button class="ui button" id="toggleStats">Toggle raw json</button>
|
||||||
<pre id="jsonstats" class="language-json">{{ stats }}</pre>
|
<pre id="jsonstats" class="language-json">{{ stats }}</pre>
|
||||||
</div> --!>
|
</div> //-->
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -164,9 +166,15 @@
|
|||||||
<pre id="logContainer" style="height: 600px;overflow-y:auto;overflow-x:auto;"><code id="logtext" class="language-log" ></code></pre>
|
<pre id="logContainer" style="height: 600px;overflow-y:auto;overflow-x:auto;"><code id="logtext" class="language-log" ></code></pre>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
<div class="ui bottom attached tab segment" data-tab="oslo-tab">
|
||||||
|
<h3 class="ui dividing header">OSLO</h3>
|
||||||
|
<pre id="osloContainer" style="height:600px;overflow-y:auto;" class="language-json">{{ oslo_out|safe }}</pre>
|
||||||
|
</div> //-->
|
||||||
|
|
||||||
<div class="ui bottom attached tab segment" data-tab="raw-tab">
|
<div class="ui bottom attached tab segment" data-tab="raw-tab">
|
||||||
<h3 class="ui dividing header">Raw JSON</h3>
|
<h3 class="ui dividing header">Raw JSON</h3>
|
||||||
<pre id="jsonstats" class="language-json">{{ stats|safe }}</pre>
|
<pre id="jsonstats" class="language-yaml" style="height:600px;overflow-y:auto;">{{ stats|safe }}</pre>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="ui text container">
|
<div class="ui text container">
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
import datetime
|
import datetime
|
||||||
|
import importlib.metadata as imp
|
||||||
|
import io
|
||||||
import json
|
import json
|
||||||
import logging
|
import logging
|
||||||
from logging.handlers import RotatingFileHandler
|
from logging.handlers import RotatingFileHandler
|
||||||
@ -8,7 +10,7 @@ import flask
|
|||||||
from flask import Flask
|
from flask import Flask
|
||||||
from flask.logging import default_handler
|
from flask.logging import default_handler
|
||||||
from flask_httpauth import HTTPBasicAuth
|
from flask_httpauth import HTTPBasicAuth
|
||||||
from oslo_config import cfg
|
from oslo_config import cfg, generator
|
||||||
import socketio
|
import socketio
|
||||||
from werkzeug.security import check_password_hash
|
from werkzeug.security import check_password_hash
|
||||||
|
|
||||||
@ -96,9 +98,17 @@ def _stats():
|
|||||||
if packet_list:
|
if packet_list:
|
||||||
rx = packet_list.total_rx()
|
rx = packet_list.total_rx()
|
||||||
tx = packet_list.total_tx()
|
tx = packet_list.total_tx()
|
||||||
|
types = {}
|
||||||
|
|
||||||
|
types_copy = packet_list.types.copy()
|
||||||
|
|
||||||
|
for key in types_copy:
|
||||||
|
types[str(key)] = dict(types_copy[key])
|
||||||
|
|
||||||
stats_dict["packets"] = {
|
stats_dict["packets"] = {
|
||||||
"sent": tx,
|
"sent": tx,
|
||||||
"received": rx,
|
"received": rx,
|
||||||
|
"types": types,
|
||||||
}
|
}
|
||||||
if track:
|
if track:
|
||||||
size_tracker = len(track)
|
size_tracker = len(track)
|
||||||
@ -123,7 +133,6 @@ def stats():
|
|||||||
@app.route("/")
|
@app.route("/")
|
||||||
def index():
|
def index():
|
||||||
stats = _stats()
|
stats = _stats()
|
||||||
LOG.debug(stats)
|
|
||||||
wl = aprsd_rpc_client.RPCClient().get_watch_list()
|
wl = aprsd_rpc_client.RPCClient().get_watch_list()
|
||||||
if wl and wl.is_enabled():
|
if wl and wl.is_enabled():
|
||||||
watch_count = len(wl)
|
watch_count = len(wl)
|
||||||
@ -185,6 +194,7 @@ def index():
|
|||||||
watch_age=watch_age,
|
watch_age=watch_age,
|
||||||
seen_count=seen_count,
|
seen_count=seen_count,
|
||||||
plugin_count=plugin_count,
|
plugin_count=plugin_count,
|
||||||
|
# oslo_out=generate_oslo()
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -205,10 +215,12 @@ def get_packets():
|
|||||||
LOG.debug("/packets called")
|
LOG.debug("/packets called")
|
||||||
packet_list = aprsd_rpc_client.RPCClient().get_packet_list()
|
packet_list = aprsd_rpc_client.RPCClient().get_packet_list()
|
||||||
if packet_list:
|
if packet_list:
|
||||||
packets = packet_list.get()
|
|
||||||
tmp_list = []
|
tmp_list = []
|
||||||
for pkt in packets:
|
pkts = packet_list.copy()
|
||||||
tmp_list.append(pkt.json)
|
for key in pkts:
|
||||||
|
pkt = packet_list.get(key)
|
||||||
|
if pkt:
|
||||||
|
tmp_list.append(pkt.json)
|
||||||
|
|
||||||
return json.dumps(tmp_list)
|
return json.dumps(tmp_list)
|
||||||
else:
|
else:
|
||||||
@ -225,6 +237,36 @@ def plugins():
|
|||||||
return "reloaded"
|
return "reloaded"
|
||||||
|
|
||||||
|
|
||||||
|
def _get_namespaces():
|
||||||
|
args = []
|
||||||
|
|
||||||
|
all = imp.entry_points()
|
||||||
|
selected = []
|
||||||
|
if "oslo.config.opts" in all:
|
||||||
|
for x in all["oslo.config.opts"]:
|
||||||
|
if x.group == "oslo.config.opts":
|
||||||
|
selected.append(x)
|
||||||
|
for entry in selected:
|
||||||
|
if "aprsd" in entry.name:
|
||||||
|
args.append("--namespace")
|
||||||
|
args.append(entry.name)
|
||||||
|
|
||||||
|
return args
|
||||||
|
|
||||||
|
|
||||||
|
def generate_oslo():
|
||||||
|
CONF.namespace = _get_namespaces()
|
||||||
|
string_out = io.StringIO()
|
||||||
|
generator.generate(CONF, string_out)
|
||||||
|
return string_out.getvalue()
|
||||||
|
|
||||||
|
|
||||||
|
@auth.login_required
|
||||||
|
@app.route("/oslo")
|
||||||
|
def oslo():
|
||||||
|
return generate_oslo()
|
||||||
|
|
||||||
|
|
||||||
@auth.login_required
|
@auth.login_required
|
||||||
@app.route("/save")
|
@app.route("/save")
|
||||||
def save():
|
def save():
|
||||||
@ -348,6 +390,8 @@ if __name__ == "uwsgi_file_aprsd_wsgi":
|
|||||||
log_level = init_app(
|
log_level = init_app(
|
||||||
log_level="DEBUG",
|
log_level="DEBUG",
|
||||||
config_file="/config/aprsd.conf",
|
config_file="/config/aprsd.conf",
|
||||||
|
# Commented out for local development.
|
||||||
|
# config_file=cli_helper.DEFAULT_CONFIG_FILE
|
||||||
)
|
)
|
||||||
setup_logging(app, log_level)
|
setup_logging(app, log_level)
|
||||||
sio.register_namespace(LoggingNamespace("/logs"))
|
sio.register_namespace(LoggingNamespace("/logs"))
|
||||||
@ -362,7 +406,11 @@ if __name__ == "aprsd.wsgi":
|
|||||||
sio = socketio.Server(logger=True, async_mode=async_mode)
|
sio = socketio.Server(logger=True, async_mode=async_mode)
|
||||||
app.wsgi_app = socketio.WSGIApp(sio, app.wsgi_app)
|
app.wsgi_app = socketio.WSGIApp(sio, app.wsgi_app)
|
||||||
|
|
||||||
log_level = init_app(config_file="/config/aprsd.conf", log_level="DEBUG")
|
log_level = init_app(
|
||||||
|
log_level="DEBUG",
|
||||||
|
# config_file="/config/aprsd.conf",
|
||||||
|
config_file=cli_helper.DEFAULT_CONFIG_FILE,
|
||||||
|
)
|
||||||
setup_logging(app, log_level)
|
setup_logging(app, log_level)
|
||||||
sio.register_namespace(LoggingNamespace("/logs"))
|
sio.register_namespace(LoggingNamespace("/logs"))
|
||||||
CONF.log_opt_values(LOG, logging.DEBUG)
|
CONF.log_opt_values(LOG, logging.DEBUG)
|
||||||
|
@ -1,212 +1,87 @@
|
|||||||
#
|
#
|
||||||
# This file is autogenerated by pip-compile with Python 3.11
|
# This file is autogenerated by pip-compile with Python 3.10
|
||||||
# by the following command:
|
# by the following command:
|
||||||
#
|
#
|
||||||
# pip-compile --annotation-style=line dev-requirements.in
|
# pip-compile --annotation-style=line dev-requirements.in
|
||||||
#
|
#
|
||||||
add-trailing-comma==3.1.0
|
add-trailing-comma==3.1.0 # via gray
|
||||||
# via gray
|
alabaster==0.7.13 # via sphinx
|
||||||
alabaster==0.7.13
|
attrs==23.1.0 # via jsonschema, referencing
|
||||||
# via sphinx
|
autoflake==1.5.3 # via gray
|
||||||
attrs==23.1.0
|
babel==2.13.1 # via sphinx
|
||||||
# via
|
black==23.11.0 # via gray
|
||||||
# jsonschema
|
build==1.0.3 # via pip-tools
|
||||||
# referencing
|
cachetools==5.3.2 # via tox
|
||||||
autoflake==1.5.3
|
certifi==2023.7.22 # via requests
|
||||||
# via gray
|
cfgv==3.4.0 # via pre-commit
|
||||||
babel==2.12.1
|
chardet==5.2.0 # via tox
|
||||||
# via sphinx
|
charset-normalizer==3.3.2 # via requests
|
||||||
black==23.7.0
|
click==8.1.7 # via black, pip-tools
|
||||||
# via gray
|
colorama==0.4.6 # via tox
|
||||||
build==1.0.3
|
commonmark==0.9.1 # via rich
|
||||||
# via pip-tools
|
configargparse==1.7 # via gray
|
||||||
cachetools==5.3.1
|
coverage[toml]==7.3.2 # via coverage, pytest-cov
|
||||||
# via tox
|
distlib==0.3.7 # via virtualenv
|
||||||
certifi==2023.7.22
|
docutils==0.20.1 # via sphinx
|
||||||
# via requests
|
exceptiongroup==1.1.3 # via pytest
|
||||||
cfgv==3.4.0
|
filelock==3.13.1 # via tox, virtualenv
|
||||||
# via pre-commit
|
fixit==0.1.4 # via gray
|
||||||
chardet==5.2.0
|
flake8==6.1.0 # via -r dev-requirements.in, fixit, pep8-naming
|
||||||
# via tox
|
gray==0.13.0 # via -r dev-requirements.in
|
||||||
charset-normalizer==3.2.0
|
identify==2.5.31 # via pre-commit
|
||||||
# via requests
|
idna==3.4 # via requests
|
||||||
click==8.1.7
|
imagesize==1.4.1 # via sphinx
|
||||||
# via
|
importlib-resources==6.1.1 # via fixit
|
||||||
# black
|
iniconfig==2.0.0 # via pytest
|
||||||
# pip-tools
|
isort==5.12.0 # via -r dev-requirements.in, gray
|
||||||
colorama==0.4.6
|
jinja2==3.1.2 # via sphinx
|
||||||
# via tox
|
jsonschema==4.20.0 # via fixit
|
||||||
commonmark==0.9.1
|
jsonschema-specifications==2023.11.1 # via jsonschema
|
||||||
# via rich
|
libcst==1.1.0 # via fixit
|
||||||
configargparse==1.7
|
markupsafe==2.1.3 # via jinja2
|
||||||
# via gray
|
mccabe==0.7.0 # via flake8
|
||||||
coverage[toml]==7.3.1
|
mypy==1.7.0 # via -r dev-requirements.in
|
||||||
# via pytest-cov
|
mypy-extensions==1.0.0 # via black, mypy, typing-inspect
|
||||||
distlib==0.3.7
|
nodeenv==1.8.0 # via pre-commit
|
||||||
# via virtualenv
|
packaging==23.2 # via black, build, pyproject-api, pytest, sphinx, tox
|
||||||
docutils==0.20.1
|
pathspec==0.11.2 # via black
|
||||||
# via sphinx
|
pep8-naming==0.13.3 # via -r dev-requirements.in
|
||||||
filelock==3.12.3
|
pip-tools==7.3.0 # via -r dev-requirements.in
|
||||||
# via
|
platformdirs==3.11.0 # via black, tox, virtualenv
|
||||||
# tox
|
pluggy==1.3.0 # via pytest, tox
|
||||||
# virtualenv
|
pre-commit==3.5.0 # via -r dev-requirements.in
|
||||||
fixit==0.1.4
|
pycodestyle==2.11.1 # via flake8
|
||||||
# via gray
|
pyflakes==3.1.0 # via autoflake, flake8
|
||||||
flake8==6.1.0
|
pygments==2.16.1 # via rich, sphinx
|
||||||
# via
|
pyproject-api==1.6.1 # via tox
|
||||||
# -r dev-requirements.in
|
pyproject-hooks==1.0.0 # via build
|
||||||
# fixit
|
pytest==7.4.3 # via -r dev-requirements.in, pytest-cov
|
||||||
# pep8-naming
|
pytest-cov==4.1.0 # via -r dev-requirements.in
|
||||||
gray==0.13.0
|
pyupgrade==3.15.0 # via gray
|
||||||
# via -r dev-requirements.in
|
pyyaml==6.0.1 # via fixit, libcst, pre-commit
|
||||||
identify==2.5.27
|
referencing==0.31.0 # via jsonschema, jsonschema-specifications
|
||||||
# via pre-commit
|
requests==2.31.0 # via sphinx
|
||||||
idna==3.4
|
rich==12.6.0 # via gray
|
||||||
# via requests
|
rpds-py==0.13.0 # via jsonschema, referencing
|
||||||
imagesize==1.4.1
|
snowballstemmer==2.2.0 # via sphinx
|
||||||
# via sphinx
|
sphinx==7.2.6 # via -r dev-requirements.in, sphinxcontrib-applehelp, sphinxcontrib-devhelp, sphinxcontrib-htmlhelp, sphinxcontrib-qthelp, sphinxcontrib-serializinghtml
|
||||||
importlib-resources==6.0.1
|
sphinxcontrib-applehelp==1.0.7 # via sphinx
|
||||||
# via fixit
|
sphinxcontrib-devhelp==1.0.5 # via sphinx
|
||||||
iniconfig==2.0.0
|
sphinxcontrib-htmlhelp==2.0.4 # via sphinx
|
||||||
# via pytest
|
sphinxcontrib-jsmath==1.0.1 # via sphinx
|
||||||
isort==5.12.0
|
sphinxcontrib-qthelp==1.0.6 # via sphinx
|
||||||
# via
|
sphinxcontrib-serializinghtml==1.1.9 # via sphinx
|
||||||
# -r dev-requirements.in
|
tokenize-rt==5.2.0 # via add-trailing-comma, pyupgrade
|
||||||
# gray
|
toml==0.10.2 # via autoflake
|
||||||
jinja2==3.1.2
|
tomli==2.0.1 # via black, build, coverage, mypy, pip-tools, pyproject-api, pyproject-hooks, pytest, tox
|
||||||
# via sphinx
|
tox==4.11.3 # via -r dev-requirements.in
|
||||||
jsonschema==4.19.0
|
typing-extensions==4.8.0 # via black, libcst, mypy, typing-inspect
|
||||||
# via fixit
|
typing-inspect==0.9.0 # via libcst
|
||||||
jsonschema-specifications==2023.7.1
|
unify==0.5 # via gray
|
||||||
# via jsonschema
|
untokenize==0.1.1 # via unify
|
||||||
libcst==1.0.1
|
urllib3==2.1.0 # via requests
|
||||||
# via fixit
|
virtualenv==20.24.6 # via pre-commit, tox
|
||||||
markupsafe==2.1.3
|
wheel==0.41.3 # via pip-tools
|
||||||
# via jinja2
|
|
||||||
mccabe==0.7.0
|
|
||||||
# via flake8
|
|
||||||
mypy==1.5.1
|
|
||||||
# via -r dev-requirements.in
|
|
||||||
mypy-extensions==1.0.0
|
|
||||||
# via
|
|
||||||
# black
|
|
||||||
# mypy
|
|
||||||
# typing-inspect
|
|
||||||
nodeenv==1.8.0
|
|
||||||
# via pre-commit
|
|
||||||
packaging==23.1
|
|
||||||
# via
|
|
||||||
# black
|
|
||||||
# build
|
|
||||||
# pyproject-api
|
|
||||||
# pytest
|
|
||||||
# sphinx
|
|
||||||
# tox
|
|
||||||
pathspec==0.11.2
|
|
||||||
# via black
|
|
||||||
pep8-naming==0.13.3
|
|
||||||
# via -r dev-requirements.in
|
|
||||||
pip-tools==7.3.0
|
|
||||||
# via -r dev-requirements.in
|
|
||||||
platformdirs==3.10.0
|
|
||||||
# via
|
|
||||||
# black
|
|
||||||
# tox
|
|
||||||
# virtualenv
|
|
||||||
pluggy==1.3.0
|
|
||||||
# via
|
|
||||||
# pytest
|
|
||||||
# tox
|
|
||||||
pre-commit==3.4.0
|
|
||||||
# via -r dev-requirements.in
|
|
||||||
pycodestyle==2.11.0
|
|
||||||
# via flake8
|
|
||||||
pyflakes==3.1.0
|
|
||||||
# via
|
|
||||||
# autoflake
|
|
||||||
# flake8
|
|
||||||
pygments==2.16.1
|
|
||||||
# via
|
|
||||||
# rich
|
|
||||||
# sphinx
|
|
||||||
pyproject-api==1.6.1
|
|
||||||
# via tox
|
|
||||||
pyproject-hooks==1.0.0
|
|
||||||
# via build
|
|
||||||
pytest==7.4.2
|
|
||||||
# via
|
|
||||||
# -r dev-requirements.in
|
|
||||||
# pytest-cov
|
|
||||||
pytest-cov==4.1.0
|
|
||||||
# via -r dev-requirements.in
|
|
||||||
pyupgrade==3.10.1
|
|
||||||
# via gray
|
|
||||||
pyyaml==6.0.1
|
|
||||||
# via
|
|
||||||
# fixit
|
|
||||||
# libcst
|
|
||||||
# pre-commit
|
|
||||||
referencing==0.30.2
|
|
||||||
# via
|
|
||||||
# jsonschema
|
|
||||||
# jsonschema-specifications
|
|
||||||
requests==2.31.0
|
|
||||||
# via sphinx
|
|
||||||
rich==12.6.0
|
|
||||||
# via gray
|
|
||||||
rpds-py==0.10.2
|
|
||||||
# via
|
|
||||||
# jsonschema
|
|
||||||
# referencing
|
|
||||||
snowballstemmer==2.2.0
|
|
||||||
# via sphinx
|
|
||||||
sphinx==7.2.5
|
|
||||||
# via
|
|
||||||
# -r dev-requirements.in
|
|
||||||
# sphinxcontrib-applehelp
|
|
||||||
# sphinxcontrib-devhelp
|
|
||||||
# sphinxcontrib-htmlhelp
|
|
||||||
# sphinxcontrib-qthelp
|
|
||||||
# sphinxcontrib-serializinghtml
|
|
||||||
sphinxcontrib-applehelp==1.0.7
|
|
||||||
# via sphinx
|
|
||||||
sphinxcontrib-devhelp==1.0.5
|
|
||||||
# via sphinx
|
|
||||||
sphinxcontrib-htmlhelp==2.0.4
|
|
||||||
# via sphinx
|
|
||||||
sphinxcontrib-jsmath==1.0.1
|
|
||||||
# via sphinx
|
|
||||||
sphinxcontrib-qthelp==1.0.6
|
|
||||||
# via sphinx
|
|
||||||
sphinxcontrib-serializinghtml==1.1.9
|
|
||||||
# via sphinx
|
|
||||||
tokenize-rt==5.2.0
|
|
||||||
# via
|
|
||||||
# add-trailing-comma
|
|
||||||
# pyupgrade
|
|
||||||
toml==0.10.2
|
|
||||||
# via autoflake
|
|
||||||
tox==4.11.2
|
|
||||||
# via -r dev-requirements.in
|
|
||||||
typing-extensions==4.7.1
|
|
||||||
# via
|
|
||||||
# libcst
|
|
||||||
# mypy
|
|
||||||
# typing-inspect
|
|
||||||
typing-inspect==0.9.0
|
|
||||||
# via libcst
|
|
||||||
unify==0.5
|
|
||||||
# via gray
|
|
||||||
untokenize==0.1.1
|
|
||||||
# via unify
|
|
||||||
urllib3==2.0.7
|
|
||||||
# via requests
|
|
||||||
virtualenv==20.24.5
|
|
||||||
# via
|
|
||||||
# pre-commit
|
|
||||||
# tox
|
|
||||||
wheel==0.41.2
|
|
||||||
# via pip-tools
|
|
||||||
|
|
||||||
# The following packages are considered to be unsafe in a requirements file:
|
# The following packages are considered to be unsafe in a requirements file:
|
||||||
# pip
|
# pip
|
||||||
|
@ -36,3 +36,4 @@ rpyc
|
|||||||
shellingham
|
shellingham
|
||||||
geopy
|
geopy
|
||||||
rush
|
rush
|
||||||
|
dataclasses-json
|
||||||
|
247
requirements.txt
247
requirements.txt
@ -1,180 +1,83 @@
|
|||||||
#
|
#
|
||||||
# This file is autogenerated by pip-compile with Python 3.11
|
# This file is autogenerated by pip-compile with Python 3.10
|
||||||
# by the following command:
|
# by the following command:
|
||||||
#
|
#
|
||||||
# pip-compile --annotation-style=line requirements.in
|
# pip-compile --annotation-style=line requirements.in
|
||||||
#
|
#
|
||||||
aprslib==0.7.2
|
aprslib==0.7.2 # via -r requirements.in
|
||||||
# via -r requirements.in
|
attrs==23.1.0 # via -r requirements.in, ax253, kiss3, rush
|
||||||
attrs==23.1.0
|
ax253==0.1.5.post1 # via kiss3
|
||||||
# via
|
beautifulsoup4==4.12.2 # via -r requirements.in
|
||||||
# -r requirements.in
|
bidict==0.22.1 # via python-socketio
|
||||||
# ax253
|
bitarray==2.8.3 # via ax253, kiss3
|
||||||
# kiss3
|
blinker==1.7.0 # via flask
|
||||||
# rush
|
certifi==2023.7.22 # via requests
|
||||||
ax253==0.1.5.post1
|
charset-normalizer==3.3.2 # via requests
|
||||||
# via kiss3
|
click==8.1.7 # via -r requirements.in, click-completion, click-params, flask
|
||||||
beautifulsoup4==4.12.2
|
click-completion==0.5.2 # via -r requirements.in
|
||||||
# via -r requirements.in
|
click-params==0.4.1 # via -r requirements.in
|
||||||
bidict==0.22.1
|
commonmark==0.9.1 # via rich
|
||||||
# via python-socketio
|
dacite2==2.0.0 # via -r requirements.in
|
||||||
bitarray==2.8.1
|
dataclasses==0.6 # via -r requirements.in
|
||||||
# via
|
dataclasses-json==0.6.2 # via -r requirements.in
|
||||||
# ax253
|
debtcollector==2.5.0 # via oslo-config
|
||||||
# kiss3
|
decorator==5.1.1 # via validators
|
||||||
blinker==1.6.2
|
dnspython==2.4.2 # via eventlet
|
||||||
# via flask
|
eventlet==0.33.3 # via -r requirements.in
|
||||||
certifi==2023.7.22
|
flask==3.0.0 # via -r requirements.in, flask-httpauth, flask-socketio
|
||||||
# via requests
|
flask-httpauth==4.8.0 # via -r requirements.in
|
||||||
charset-normalizer==3.2.0
|
flask-socketio==5.3.6 # via -r requirements.in
|
||||||
# via requests
|
geographiclib==2.0 # via geopy
|
||||||
click==8.1.7
|
geopy==2.4.0 # via -r requirements.in
|
||||||
# via
|
gevent==23.9.1 # via -r requirements.in
|
||||||
# -r requirements.in
|
greenlet==3.0.1 # via eventlet, gevent
|
||||||
# click-completion
|
h11==0.14.0 # via wsproto
|
||||||
# click-params
|
idna==3.4 # via requests
|
||||||
# flask
|
imapclient==3.0.0 # via -r requirements.in
|
||||||
click-completion==0.5.2
|
importlib-metadata==6.8.0 # via ax253, kiss3
|
||||||
# via -r requirements.in
|
itsdangerous==2.1.2 # via flask
|
||||||
click-params==0.4.1
|
jinja2==3.1.2 # via click-completion, flask
|
||||||
# via -r requirements.in
|
kiss3==8.0.0 # via -r requirements.in
|
||||||
commonmark==0.9.1
|
markupsafe==2.1.3 # via jinja2, werkzeug
|
||||||
# via rich
|
marshmallow==3.20.1 # via dataclasses-json
|
||||||
dacite2==2.0.0
|
mypy-extensions==1.0.0 # via typing-inspect
|
||||||
# via -r requirements.in
|
netaddr==0.9.0 # via oslo-config
|
||||||
dataclasses==0.6
|
oslo-config==9.2.0 # via -r requirements.in
|
||||||
# via -r requirements.in
|
oslo-i18n==6.2.0 # via oslo-config
|
||||||
debtcollector==2.5.0
|
packaging==23.2 # via marshmallow
|
||||||
# via oslo-config
|
pbr==6.0.0 # via -r requirements.in, oslo-i18n, stevedore
|
||||||
decorator==5.1.1
|
pluggy==1.3.0 # via -r requirements.in
|
||||||
# via validators
|
plumbum==1.8.2 # via rpyc
|
||||||
dnspython==2.4.2
|
pygments==2.16.1 # via rich
|
||||||
# via eventlet
|
pyserial==3.5 # via pyserial-asyncio
|
||||||
eventlet==0.33.3
|
pyserial-asyncio==0.6 # via kiss3
|
||||||
# via -r requirements.in
|
python-engineio==4.8.0 # via python-socketio
|
||||||
flask==2.3.3
|
python-socketio==5.10.0 # via -r requirements.in, flask-socketio
|
||||||
# via
|
pytz==2023.3.post1 # via -r requirements.in
|
||||||
# -r requirements.in
|
pyyaml==6.0.1 # via -r requirements.in, oslo-config
|
||||||
# flask-httpauth
|
requests==2.31.0 # via -r requirements.in, oslo-config, update-checker
|
||||||
# flask-socketio
|
rfc3986==2.0.0 # via oslo-config
|
||||||
flask-httpauth==4.8.0
|
rich==12.6.0 # via -r requirements.in
|
||||||
# via -r requirements.in
|
rpyc==5.3.1 # via -r requirements.in
|
||||||
flask-socketio==5.3.6
|
rush==2021.4.0 # via -r requirements.in
|
||||||
# via -r requirements.in
|
shellingham==1.5.4 # via -r requirements.in, click-completion
|
||||||
geographiclib==2.0
|
simple-websocket==1.0.0 # via python-engineio
|
||||||
# via geopy
|
six==1.16.0 # via -r requirements.in, click-completion, eventlet
|
||||||
geopy==2.4.0
|
soupsieve==2.5 # via beautifulsoup4
|
||||||
# via -r requirements.in
|
stevedore==5.1.0 # via oslo-config
|
||||||
gevent==23.9.1
|
tabulate==0.9.0 # via -r requirements.in
|
||||||
# via -r requirements.in
|
thesmuggler==1.0.1 # via -r requirements.in
|
||||||
greenlet==3.0.0rc3
|
typing-extensions==4.8.0 # via typing-inspect
|
||||||
# via
|
typing-inspect==0.9.0 # via dataclasses-json
|
||||||
# eventlet
|
update-checker==0.18.0 # via -r requirements.in
|
||||||
# gevent
|
urllib3==2.1.0 # via requests
|
||||||
idna==3.4
|
validators==0.20.0 # via click-params
|
||||||
# via requests
|
werkzeug==3.0.1 # via -r requirements.in, flask
|
||||||
imapclient==2.3.1
|
wrapt==1.16.0 # via -r requirements.in, debtcollector
|
||||||
# via -r requirements.in
|
wsproto==1.2.0 # via simple-websocket
|
||||||
importlib-metadata==6.8.0
|
zipp==3.17.0 # via importlib-metadata
|
||||||
# via
|
zope-event==5.0 # via gevent
|
||||||
# ax253
|
zope-interface==6.1 # via gevent
|
||||||
# kiss3
|
|
||||||
itsdangerous==2.1.2
|
|
||||||
# via flask
|
|
||||||
jinja2==3.1.2
|
|
||||||
# via
|
|
||||||
# click-completion
|
|
||||||
# flask
|
|
||||||
kiss3==8.0.0
|
|
||||||
# via -r requirements.in
|
|
||||||
markupsafe==2.1.3
|
|
||||||
# via
|
|
||||||
# jinja2
|
|
||||||
# werkzeug
|
|
||||||
netaddr==0.8.0
|
|
||||||
# via oslo-config
|
|
||||||
oslo-config==9.2.0
|
|
||||||
# via -r requirements.in
|
|
||||||
oslo-i18n==6.1.0
|
|
||||||
# via oslo-config
|
|
||||||
pbr==5.11.1
|
|
||||||
# via
|
|
||||||
# -r requirements.in
|
|
||||||
# oslo-i18n
|
|
||||||
# stevedore
|
|
||||||
pluggy==1.3.0
|
|
||||||
# via -r requirements.in
|
|
||||||
plumbum==1.8.2
|
|
||||||
# via rpyc
|
|
||||||
pygments==2.16.1
|
|
||||||
# via rich
|
|
||||||
pyserial==3.5
|
|
||||||
# via pyserial-asyncio
|
|
||||||
pyserial-asyncio==0.6
|
|
||||||
# via kiss3
|
|
||||||
python-engineio==4.7.0
|
|
||||||
# via python-socketio
|
|
||||||
python-socketio==5.9.0
|
|
||||||
# via
|
|
||||||
# -r requirements.in
|
|
||||||
# flask-socketio
|
|
||||||
pytz==2023.3.post1
|
|
||||||
# via -r requirements.in
|
|
||||||
pyyaml==6.0.1
|
|
||||||
# via
|
|
||||||
# -r requirements.in
|
|
||||||
# oslo-config
|
|
||||||
requests==2.31.0
|
|
||||||
# via
|
|
||||||
# -r requirements.in
|
|
||||||
# oslo-config
|
|
||||||
# update-checker
|
|
||||||
rfc3986==2.0.0
|
|
||||||
# via oslo-config
|
|
||||||
rich==12.6.0
|
|
||||||
# via -r requirements.in
|
|
||||||
rpyc==5.3.1
|
|
||||||
# via -r requirements.in
|
|
||||||
rush==2021.4.0
|
|
||||||
# via -r requirements.in
|
|
||||||
shellingham==1.5.3
|
|
||||||
# via
|
|
||||||
# -r requirements.in
|
|
||||||
# click-completion
|
|
||||||
six==1.16.0
|
|
||||||
# via
|
|
||||||
# -r requirements.in
|
|
||||||
# click-completion
|
|
||||||
# eventlet
|
|
||||||
# imapclient
|
|
||||||
soupsieve==2.5
|
|
||||||
# via beautifulsoup4
|
|
||||||
stevedore==5.1.0
|
|
||||||
# via oslo-config
|
|
||||||
tabulate==0.9.0
|
|
||||||
# via -r requirements.in
|
|
||||||
thesmuggler==1.0.1
|
|
||||||
# via -r requirements.in
|
|
||||||
update-checker==0.18.0
|
|
||||||
# via -r requirements.in
|
|
||||||
urllib3==2.0.7
|
|
||||||
# via requests
|
|
||||||
validators==0.20.0
|
|
||||||
# via click-params
|
|
||||||
werkzeug==3.0.1
|
|
||||||
# via
|
|
||||||
# -r requirements.in
|
|
||||||
# flask
|
|
||||||
wrapt==1.15.0
|
|
||||||
# via
|
|
||||||
# -r requirements.in
|
|
||||||
# debtcollector
|
|
||||||
zipp==3.16.2
|
|
||||||
# via importlib-metadata
|
|
||||||
zope-event==5.0
|
|
||||||
# via gevent
|
|
||||||
zope-interface==6.0
|
|
||||||
# via gevent
|
|
||||||
|
|
||||||
# The following packages are considered to be unsafe in a requirements file:
|
# The following packages are considered to be unsafe in a requirements file:
|
||||||
# setuptools
|
# setuptools
|
||||||
|
2
tox.ini
2
tox.ini
@ -2,7 +2,7 @@
|
|||||||
minversion = 2.9.0
|
minversion = 2.9.0
|
||||||
skipdist = True
|
skipdist = True
|
||||||
skip_missing_interpreters = true
|
skip_missing_interpreters = true
|
||||||
envlist = pep8,py{39,310}
|
envlist = pep8,py{39,310,311}
|
||||||
#requires = tox-pipenv
|
#requires = tox-pipenv
|
||||||
# pip==22.0.4
|
# pip==22.0.4
|
||||||
# pip-tools==5.4.0
|
# pip-tools==5.4.0
|
||||||
|
Loading…
Reference in New Issue
Block a user