mirror of
https://git.ianrenton.com/ian/spothole.git
synced 2025-10-27 00:39:26 +00:00
Fix some bugginess with how expired alerts and alert max_duration were handled. Closes #34
This commit is contained in:
@@ -35,11 +35,8 @@ class AlertProvider:
|
||||
for alert in alerts:
|
||||
# Fill in any blanks
|
||||
alert.infer_missing()
|
||||
# Add to the list, provided it meets the semsible date test. If alerts have an end time, it must be in the
|
||||
# future, or if not, then the start date must be at least in the last 24 hours.
|
||||
if (alert.end_time and alert.end_time > datetime.now(pytz.UTC).timestamp()) or (
|
||||
not alert.end_time and alert.start_time > (datetime.now(
|
||||
pytz.UTC) - timedelta(days=1)).timestamp()):
|
||||
# Add to the list, provided it heas not already expired.
|
||||
if not alert.expired():
|
||||
self.alerts.add(alert.id, alert, expire=MAX_ALERT_AGE)
|
||||
|
||||
# Stop any threads and prepare for application shutdown
|
||||
|
||||
@@ -34,13 +34,10 @@ class CleanupTimer:
|
||||
self.alerts.expire()
|
||||
|
||||
# Alerts can persist in the system for a while, so we want to explicitly clean up any alerts that have
|
||||
# definitively ended, or if they have no definite end time, then if the start time was more than 24 hours
|
||||
# ago.
|
||||
# expired
|
||||
for id in list(self.alerts.iterkeys()):
|
||||
alert = self.alerts[id]
|
||||
if (alert.end_time and alert.end_time < datetime.now(pytz.UTC).timestamp()) or (
|
||||
not alert.end_time and alert.start_time < (datetime.now(
|
||||
pytz.UTC) - timedelta(days=1)).timestamp()):
|
||||
if alert.expired():
|
||||
self.alerts.evict(id)
|
||||
|
||||
self.status = "OK"
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import copy
|
||||
import hashlib
|
||||
import json
|
||||
from dataclasses import dataclass
|
||||
from datetime import datetime
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
import copy
|
||||
import pytz
|
||||
|
||||
from core.constants import DXCC_FLAGS
|
||||
@@ -117,4 +117,12 @@ class Alert:
|
||||
|
||||
# JSON serialise
|
||||
def to_json(self):
|
||||
return json.dumps(self, default=lambda o: o.__dict__, sort_keys=True)
|
||||
return json.dumps(self, default=lambda o: o.__dict__, sort_keys=True)
|
||||
|
||||
# Decide if this alert has expired (in which case it should not be added to the system in the first place, and not
|
||||
# returned by the web server if later requested, and removed by the cleanup functions. "Expired" is defined as
|
||||
# either having an end_time in the past, or if it only has a start_time, then that start time was more than 3 hours
|
||||
# ago. If it somehow doesn't have a start_time either, it is considered to be expired.
|
||||
def expired(self):
|
||||
return not self.start_time or (self.end_time and self.end_time < datetime.now(pytz.UTC).timestamp()) or (
|
||||
not self.end_time and self.start_time < (datetime.now(pytz.UTC) - timedelta(hours=3)).timestamp())
|
||||
|
||||
@@ -187,6 +187,8 @@ class WebServer:
|
||||
alerts = []
|
||||
for k in alert_ids:
|
||||
alerts.append(self.alerts.get(k))
|
||||
# We never want alerts that seem to be in the past
|
||||
alerts = list(filter(lambda alert: not alert.expired(), alerts))
|
||||
alerts = sorted(alerts, key=lambda alert: (alert.start_time if alert and alert.start_time else 0))
|
||||
for k in query.keys():
|
||||
match k:
|
||||
@@ -195,8 +197,10 @@ class WebServer:
|
||||
alerts = [a for a in alerts if a.received_time > since]
|
||||
case "max_duration":
|
||||
max_duration = int(query.get(k))
|
||||
alerts = [a for a in alerts if (a.end_time and a.end_time - a.start_time <= max_duration) or (
|
||||
not a.end_time and datetime.now(pytz.UTC).timestamp() - a.start_time <= max_duration)]
|
||||
# Check the duration if end_time is provided. If end_time is not provided, assume the activation is
|
||||
# "short", i.e. it always passes this check.
|
||||
alerts = [a for a in alerts if (a.end_time and a.end_time - a.start_time <= max_duration) or
|
||||
not a.end_time]
|
||||
case "source":
|
||||
sources = query.get(k).split(",")
|
||||
alerts = [a for a in alerts if a.source in sources]
|
||||
|
||||
@@ -37,9 +37,9 @@ class GMA(HTTPSpotProvider):
|
||||
sig_refs_names=[source_spot["NAME"]],
|
||||
time=datetime.strptime(source_spot["DATE"] + source_spot["TIME"], "%Y%m%d%H%M").replace(
|
||||
tzinfo=pytz.UTC).timestamp(),
|
||||
latitude=float(source_spot["LAT"]) if (source_spot["LAT"] != "") else None,
|
||||
# Seen GMA spots with no lat/lon
|
||||
longitude=float(source_spot["LON"]) if (source_spot["LON"] != "") else None)
|
||||
latitude=float(source_spot["LAT"]) if (source_spot["LAT"] and source_spot["LAT"] != "") else None,
|
||||
# Seen GMA spots with no (or empty) lat/lon
|
||||
longitude=float(source_spot["LON"]) if (source_spot["LON"] and source_spot["LON"] != "") else None)
|
||||
|
||||
# GMA doesn't give what programme (SIG) the reference is for until we separately look it up.
|
||||
ref_response = self.REF_INFO_CACHE.get(self.REF_INFO_URL_ROOT + source_spot["REF"],
|
||||
|
||||
@@ -48,11 +48,17 @@ function updateTable() {
|
||||
// Split alerts into three types, each of which will get its own table header: On now, next 24h, and later. "On now"
|
||||
// is considered to be events with an end_time where start<now<end, or events with no end time that started in the
|
||||
// last hour.
|
||||
onNow = alerts.filter(a => (a["end_time"] != null && moment.unix(a["end_time"]).utc().isSameOrAfter() && moment.unix(a["start_time"]).utc().isBefore())
|
||||
|| (a["end_time"] == null && moment.unix(a["start_time"]).utc().add(1, 'hours').isSameOrAfter() && moment.unix(a["start_time"]).utc().isBefore()));
|
||||
onNow = alerts.filter(a => (a["end_time"] != null && a["end_time"] != 0 && moment.unix(a["end_time"]).utc().isSameOrAfter() && moment.unix(a["start_time"]).utc().isBefore())
|
||||
|| ((a["end_time"] == null || a["end_time"] == 0) && moment.unix(a["start_time"]).utc().add(1, 'hours').isSameOrAfter() && moment.unix(a["start_time"]).utc().isBefore()));
|
||||
next24h = alerts.filter(a => moment.unix(a["start_time"]).utc().isSameOrAfter() && moment.unix(a["start_time"]).utc().subtract(24, 'hours').isBefore());
|
||||
later = alerts.filter(a => moment.unix(a["start_time"]).utc().subtract(24, 'hours').isSameOrAfter());
|
||||
|
||||
alerts.forEach(a => {
|
||||
if (!(a in onNow) && !(a in next24h) && !(a in later)) {
|
||||
console.log(moment.unix(a["start_time"]).format('YYYY-MM-DD hh:mm') + " " + moment.unix(a["end_time"]).format('YYYY-MM-DD hh:mm'));
|
||||
}
|
||||
});
|
||||
|
||||
if (onNow.length > 0) {
|
||||
table.find('tbody').append('<tr class="table-primary"><td colspan="100" style="text-align:center;">On Now</td></tr>');
|
||||
addAlertRowsToTable(table.find('tbody'), onNow);
|
||||
|
||||
@@ -66,13 +66,13 @@ function updateRefreshDisplay() {
|
||||
count = REFRESH_INTERVAL_SEC - secSinceUpdate;
|
||||
if (count <= 60) {
|
||||
var number = count.toFixed(0);
|
||||
updatingString = "Updating in " + number + " second" + (number != "1" ? "s" : "") + ". ";
|
||||
updatingString = "Updating in <span class='nowrap'>" + number + " second" + (number != "1" ? "s" : "") + ".</span>";
|
||||
} else {
|
||||
var number = Math.round(count / 60.0).toFixed(0);
|
||||
updatingString = "Updating in " + number + " minute" + (number != "1" ? "s" : "") + ". ";
|
||||
updatingString = "Updating in <span class='nowrap'>" + number + " minute" + (number != "1" ? "s" : "") + ".</span>";
|
||||
}
|
||||
}
|
||||
$("#timing-container").text("Last updated at " + lastUpdateTime.format('HH:mm') + " UTC. " + updatingString);
|
||||
$("#timing-container").html("Last updated at " + lastUpdateTime.format('HH:mm') + " UTC. " + updatingString);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user