Fix status query. Closes #36

This commit is contained in:
Ian Renton
2025-10-08 16:26:43 +01:00
parent e01b6d5ea9
commit b45fda2dd2
4 changed files with 54 additions and 39 deletions

View File

@@ -39,21 +39,29 @@ class StatusReporter:
# Write status information and reschedule next timer # Write status information and reschedule next timer
def run(self): def run(self):
self.status_data["uptime"] = str(datetime.now(pytz.UTC) - self.startup_time).split(".")[0] self.status_data["uptime"] = (datetime.now(pytz.UTC) - self.startup_time).total_seconds()
self.status_data["mem_use_mb"] = round(psutil.Process(os.getpid()).memory_info().rss / (1024 * 1024), 3) self.status_data["mem_use_mb"] = round(psutil.Process(os.getpid()).memory_info().rss / (1024 * 1024), 3)
self.status_data["num_spots"] = len(self.spots) self.status_data["num_spots"] = len(self.spots)
self.status_data["num_alerts"] = len(self.alerts) self.status_data["num_alerts"] = len(self.alerts)
self.status_data["spot_providers"] = list( self.status_data["spot_providers"] = list(
map(lambda p: {"name": p.name, "enabled": p.enabled, "status": p.status, "last_updated": p.last_update_time, map(lambda p: {"name": p.name, "enabled": p.enabled, "status": p.status,
"last_spot": p.last_spot_time}, self.spot_providers)) "last_updated": p.last_update_time.replace(
tzinfo=pytz.UTC).timestamp() if p.last_update_time else 0,
"last_spot": p.last_spot_time.replace(
tzinfo=pytz.UTC).timestamp() if p.last_spot_time else 0}, self.spot_providers))
self.status_data["alert_providers"] = list( self.status_data["alert_providers"] = list(
map(lambda p: {"name": p.name, "enabled": p.enabled, "status": p.status, map(lambda p: {"name": p.name, "enabled": p.enabled, "status": p.status,
"last_updated": p.last_update_time}, self.alert_providers)) "last_updated": p.last_update_time.replace(
tzinfo=pytz.UTC).timestamp() if p.last_update_time else 0},
self.alert_providers))
self.status_data["cleanup"] = {"status": self.cleanup_timer.status, self.status_data["cleanup"] = {"status": self.cleanup_timer.status,
"last_ran": self.cleanup_timer.last_cleanup_time} "last_ran": self.cleanup_timer.last_cleanup_time.replace(
tzinfo=pytz.UTC).timestamp() if self.cleanup_timer.last_cleanup_time else 0}
self.status_data["webserver"] = {"status": self.web_server.status, self.status_data["webserver"] = {"status": self.web_server.status,
"last_api_access": self.web_server.last_api_access_time, "last_api_access": self.web_server.last_api_access_time.replace(
"last_page_access": self.web_server.last_page_access_time} tzinfo=pytz.UTC).timestamp() if self.web_server.last_api_access_time else 0,
"last_page_access": self.web_server.last_page_access_time.replace(
tzinfo=pytz.UTC).timestamp() if self.web_server.last_page_access_time else 0}
self.run_timer = Timer(self.run_interval, self.run) self.run_timer = Timer(self.run_interval, self.run)
self.run_timer.start() self.run_timer.start()

View File

@@ -58,6 +58,7 @@ class WebServer:
self.status = "OK" self.status = "OK"
response.content_type = 'application/json' response.content_type = 'application/json'
response.set_header('Cache-Control', 'no-store') response.set_header('Cache-Control', 'no-store')
print(data)
return json.dumps(data, default=serialize_everything) return json.dumps(data, default=serialize_everything)
# Accept a spot # Accept a spot

View File

@@ -33,19 +33,19 @@ paths:
description: Limit the spots to only ones at this time or later. Time in UTC seconds since UNIX epoch. Equivalent to "max_age" but saves the client having to work out how many seconds ago "midnight" was. description: Limit the spots to only ones at this time or later. Time in UTC seconds since UNIX epoch. Equivalent to "max_age" but saves the client having to work out how many seconds ago "midnight" was.
required: false required: false
schema: schema:
type: integer type: number
- name: max_age - name: max_age
in: query in: query
description: Limit the spots to only ones received in the last 'n' seconds. Equivalent to "since" but saves the client having to work out what time was 'n' seconds ago on every call. Refer to the "max_spot_age" in the /options call to figure out what the maximum useful value you can provide is. Larger values will still be accepted, there just won't be any spots in the system older than max_spot_age. description: Limit the spots to only ones received in the last 'n' seconds. Equivalent to "since" but saves the client having to work out what time was 'n' seconds ago on every call. Refer to the "max_spot_age" in the /options call to figure out what the maximum useful value you can provide is. Larger values will still be accepted, there just won't be any spots in the system older than max_spot_age.
required: false required: false
schema: schema:
type: integer type: number
- name: received_since - name: received_since
in: query in: query
description: Limit the spots to only ones that the system found out about at this time or later. Time in UTC seconds since UNIX epoch. If you are using a front-end that tracks the last time it queried the API and requests spots since then, you want *this* version of the query parameter, not "since", because otherwise it may miss things. The logic is "greater than" rather than "greater than or equal to", so you can submit the time of the last received item back to this call and you will get all the more recent spots back, without duplicating the previous latest spot. description: Limit the spots to only ones that the system found out about at this time or later. Time in UTC seconds since UNIX epoch. If you are using a front-end that tracks the last time it queried the API and requests spots since then, you want *this* version of the query parameter, not "since", because otherwise it may miss things. The logic is "greater than" rather than "greater than or equal to", so you can submit the time of the last received item back to this call and you will get all the more recent spots back, without duplicating the previous latest spot.
required: false required: false
schema: schema:
type: integer type: number
- name: source - name: source
in: query in: query
description: "Limit the spots to only ones from one or more sources. To select more than one source, supply a comma-separated list." description: "Limit the spots to only ones from one or more sources. To select more than one source, supply a comma-separated list."
@@ -283,10 +283,10 @@ paths:
type: string type: string
description: The callsign of this server's operator. description: The callsign of this server's operator.
example: "M0TRT" example: "M0TRT"
"uptime": "uptime_sec":
type: string type: integer
description: The amount of time the software has been running for. description: The amount of time the software has been running for, in seconds.
example: "12:34:56" example: 12345
"mem_use_mb": "mem_use_mb":
type: number type: number
description: The amount of memory the software is using, in megabytes. description: The amount of memory the software is using, in megabytes.
@@ -307,9 +307,9 @@ paths:
description: The status of the cleanup thread description: The status of the cleanup thread
example: OK example: OK
last_ran: last_ran:
type: string type: number
description: The last time the cleanup operation ran description: The last time the cleanup operation ran, UTC seconds since UNIX epoch.
example: 2025-09-28T20:31:00+00:00 example: 1759579508
"webserver": "webserver":
type: object type: object
properties: properties:
@@ -318,13 +318,13 @@ paths:
description: The status of the web server description: The status of the web server
example: OK example: OK
last_page_access: last_page_access:
type: string type: number
description: The last time a page was accessed on the web server description: The last time a page was accessed on the web server, UTC seconds since UNIX epoch.
example: 2025-09-28T20:31:00+00:00 example: 1759579508
last_api_access: last_api_access:
type: string type: number
description: The last time an API endpoint was accessed on the web server description: The last time an API endpoint was accessed on the web server, UTC seconds since UNIX epoch.
example: 2025-09-28T20:31:00+00:00 example: 1759579508
spot_providers: spot_providers:
type: array type: array
description: An array of all the spot providers. description: An array of all the spot providers.
@@ -823,13 +823,13 @@ components:
description: The status of the provider. description: The status of the provider.
example: OK example: OK
last_updated: last_updated:
type: string type: number
description: The last time at which this provider received data. description: The last time at which this provider received data, UTC seconds since UNIX epoch.
example: 2025-09-28T20:31:00+00:00 example: 1759579508
last_spot: last_spot:
type: string type: number
description: The time of the latest spot received by this provider. description: The time of the latest spot received by this provider, UTC seconds since UNIX epoch.
example: 2025-09-28T20:31:00+00:00 example: 1759579508
AlertProviderStatus: AlertProviderStatus:
type: object type: object
@@ -847,9 +847,9 @@ components:
description: The status of the provider. description: The status of the provider.
example: OK example: OK
last_updated: last_updated:
type: string type: number
description: The last time at which this provider received data. description: The last time at which this provider received data, UTC seconds since UNIX epoch.
example: 2025-09-28T20:31:00+00:00 example: 1759579508
Band: Band:
type: object type: object

View File

@@ -153,24 +153,30 @@ function loadStatus() {
$("#status-container").append(generateStatusCard("Server Information", [ $("#status-container").append(generateStatusCard("Server Information", [
`Software Version: ${jsonData["software-version"]}`, `Software Version: ${jsonData["software-version"]}`,
`Server Owner Callsign: ${jsonData["server-owner-callsign"]}`, `Server Owner Callsign: ${jsonData["server-owner-callsign"]}`,
`Server Uptime: ${jsonData["uptime"]}`, `Server Uptime: ${moment().subtract(jsonData["uptime"], 'seconds').fromNow()}`,
`Memory Use: ${jsonData["mem_use_mb"]} MB`, `Memory Use: ${jsonData["mem_use_mb"]} MB`,
`Total Spots: ${jsonData["num_spots"]}` `Total Spots: ${jsonData["num_spots"]}`
])); ]));
$("#status-container").append(generateStatusCard("Web Server", [ $("#status-container").append(generateStatusCard("Web Server", [
`Status: ${jsonData["webserver"]["status"]}`, `Status: ${jsonData["webserver"]["status"]}`,
`Last API Access: ${moment.utc(jsonData["webserver"]["last_api_access"], moment.ISO_8601).format("HH:mm")}`, `Last API Access: ${moment.unix(jsonData["webserver"]["last_api_access"]).utc().fromNow()}`,
`Last Page Access: ${moment.utc(jsonData["webserver"]["last_page_access"], moment.ISO_8601).format("HH:mm")}` `Last Page Access: ${moment.unix(jsonData["webserver"]["last_page_access"]).utc().fromNow()}`
])); ]));
$("#status-container").append(generateStatusCard("Cleanup Service", [ $("#status-container").append(generateStatusCard("Cleanup Service", [
`Status: ${jsonData["cleanup"]["status"]}`, `Status: ${jsonData["cleanup"]["status"]}`,
`Last Ran: ${moment.utc(jsonData["cleanup"]["last_ran"], moment.ISO_8601).format("HH:mm")}` `Last Ran: ${moment.unix(jsonData["cleanup"]["last_ran"]).utc().fromNow()}`
])); ]));
jsonData["providers"].forEach(p => { jsonData["spot_providers"].forEach(p => {
$("#status-container").append(generateStatusCard("Provider: " + p["name"], [ $("#status-container").append(generateStatusCard("Provider: " + p["name"], [
`Status: ${p["status"]}`, `Status: ${p["status"]}`,
`Last Updated: ${p["enabled"] ? moment.utc(p["last_updated"], moment.ISO_8601).format("HH:mm") : "N/A"}`, `Last Updated: ${p["enabled"] ? moment.unix(p["last_updated"]).utc().fromNow() : "N/A"}`,
`Latest Spot: ${p["enabled"] ? moment.utc(p["last_spot"], moment.ISO_8601).format("HH:mm YYYY-MM-DD") : "N/A"}` `Latest Spot: ${p["enabled"] ? moment.unix(p["last_spot"]).utc().fromNow() : "N/A"}`
]));
});
jsonData["alert_providers"].forEach(p => {
$("#status-container").append(generateStatusCard("Provider: " + p["name"], [
`Status: ${p["status"]}`,
`Last Updated: ${p["enabled"] ? moment.unix(p["last_updated"]).utc().fromNow() : "N/A"}`
])); ]));
}); });
}); });