mirror of
https://git.ianrenton.com/ian/spothole.git
synced 2026-08-05 18:11:41 +00:00
Fix a bug where some NaN values could leak into the JSON output, causing it to be invalid. Created a new safe_json_dumps method since we would otherwise now be providing multiple parameters all over the code
This commit is contained in:
+8
-5
@@ -1,8 +1,11 @@
|
|||||||
def serialize_everything(obj):
|
import simplejson
|
||||||
"""Convert objects to serialisable things. Used by JSON serialiser as a default when it encounters unserializable things.
|
|
||||||
Just converts objects to dict. Try to avoid doing anything clever here when serialising spots, because we also need
|
|
||||||
to receive spots without complex handling."""
|
def safe_json_dumps(obj):
|
||||||
return obj.__dict__
|
"""Safe version of json.dumps that also converts objects to dicts so they can be output, and ignores NaN floats
|
||||||
|
which are invalid in JSON."""
|
||||||
|
|
||||||
|
return simplejson.dumps(obj, ensure_ascii=False, ignore_nan=True, default=lambda o: o.__dict__)
|
||||||
|
|
||||||
|
|
||||||
def empty_queue(q):
|
def empty_queue(q):
|
||||||
|
|||||||
@@ -17,3 +17,4 @@ websocket-client~=1.8.0
|
|||||||
tornado~=6.4.2
|
tornado~=6.4.2
|
||||||
tornado_eventsource~=3.0.0
|
tornado_eventsource~=3.0.0
|
||||||
geopandas~=0.13.2
|
geopandas~=0.13.2
|
||||||
|
simplejson~=4.1.1
|
||||||
@@ -14,7 +14,7 @@ from core.constants import UNKNOWN_BAND
|
|||||||
from core.lookup_helper import infer_band_from_freq
|
from core.lookup_helper import infer_band_from_freq
|
||||||
from core.prometheus_metrics_handler import api_requests_counter
|
from core.prometheus_metrics_handler import api_requests_counter
|
||||||
from core.sig_utils import get_ref_regex_for_sig
|
from core.sig_utils import get_ref_regex_for_sig
|
||||||
from core.utils import serialize_everything
|
from core.utils import safe_json_dumps
|
||||||
from data.sig_ref import SIGRef
|
from data.sig_ref import SIGRef
|
||||||
from data.spot import Spot
|
from data.spot import Spot
|
||||||
|
|
||||||
@@ -42,8 +42,7 @@ class APISpotHandler(tornado.web.RequestHandler):
|
|||||||
# Reject if not allowed
|
# Reject if not allowed
|
||||||
if not ALLOW_SPOTTING:
|
if not ALLOW_SPOTTING:
|
||||||
self.set_status(401)
|
self.set_status(401)
|
||||||
self.write(json.dumps("Error - this server does not allow new spots to be added via the API.",
|
self.write(safe_json_dumps("Error - this server does not allow new spots to be added via the API."))
|
||||||
default=serialize_everything))
|
|
||||||
self.set_header("Cache-Control", "no-store")
|
self.set_header("Cache-Control", "no-store")
|
||||||
self.set_header("Content-Type", "application/json")
|
self.set_header("Content-Type", "application/json")
|
||||||
return
|
return
|
||||||
@@ -51,8 +50,7 @@ class APISpotHandler(tornado.web.RequestHandler):
|
|||||||
# Reject if format not json
|
# Reject if format not json
|
||||||
if not self.request.headers.get('Content-Type', '').startswith("application/json"):
|
if not self.request.headers.get('Content-Type', '').startswith("application/json"):
|
||||||
self.set_status(415)
|
self.set_status(415)
|
||||||
self.write(
|
self.write(safe_json_dumps("Error - request Content-Type must be application/json"))
|
||||||
json.dumps("Error - request Content-Type must be application/json", default=serialize_everything))
|
|
||||||
self.set_header("Cache-Control", "no-store")
|
self.set_header("Cache-Control", "no-store")
|
||||||
self.set_header("Content-Type", "application/json")
|
self.set_header("Content-Type", "application/json")
|
||||||
return
|
return
|
||||||
@@ -61,7 +59,7 @@ class APISpotHandler(tornado.web.RequestHandler):
|
|||||||
post_data = self.request.body
|
post_data = self.request.body
|
||||||
if not post_data:
|
if not post_data:
|
||||||
self.set_status(422)
|
self.set_status(422)
|
||||||
self.write(json.dumps("Error - request body is empty", default=serialize_everything))
|
self.write(safe_json_dumps("Error - request body is empty"))
|
||||||
self.set_header("Cache-Control", "no-store")
|
self.set_header("Cache-Control", "no-store")
|
||||||
self.set_header("Content-Type", "application/json")
|
self.set_header("Content-Type", "application/json")
|
||||||
return
|
return
|
||||||
@@ -81,8 +79,7 @@ class APISpotHandler(tornado.web.RequestHandler):
|
|||||||
# Reject if no timestamp, frequency, dx_call or de_call
|
# Reject if no timestamp, frequency, dx_call or de_call
|
||||||
if not spot.time or not spot.dx_call or not spot.freq or not spot.de_call:
|
if not spot.time or not spot.dx_call or not spot.freq or not spot.de_call:
|
||||||
self.set_status(422)
|
self.set_status(422)
|
||||||
self.write(json.dumps("Error - 'time', 'dx_call', 'freq' and 'de_call' must be provided as a minimum.",
|
self.write(safe_json_dumps("Error - 'time', 'dx_call', 'freq' and 'de_call' must be provided as a minimum."))
|
||||||
default=serialize_everything))
|
|
||||||
self.set_header("Cache-Control", "no-store")
|
self.set_header("Cache-Control", "no-store")
|
||||||
self.set_header("Content-Type", "application/json")
|
self.set_header("Content-Type", "application/json")
|
||||||
return
|
return
|
||||||
@@ -90,15 +87,13 @@ class APISpotHandler(tornado.web.RequestHandler):
|
|||||||
# Reject invalid-looking callsigns
|
# Reject invalid-looking callsigns
|
||||||
if not re.match(r"^[A-Za-z0-9/\-]*$", spot.dx_call):
|
if not re.match(r"^[A-Za-z0-9/\-]*$", spot.dx_call):
|
||||||
self.set_status(422)
|
self.set_status(422)
|
||||||
self.write(json.dumps("Error - '" + spot.dx_call + "' does not look like a valid callsign.",
|
self.write(safe_json_dumps("Error - '" + spot.dx_call + "' does not look like a valid callsign."))
|
||||||
default=serialize_everything))
|
|
||||||
self.set_header("Cache-Control", "no-store")
|
self.set_header("Cache-Control", "no-store")
|
||||||
self.set_header("Content-Type", "application/json")
|
self.set_header("Content-Type", "application/json")
|
||||||
return
|
return
|
||||||
if not re.match(r"^[A-Za-z0-9/\-]*$", spot.de_call):
|
if not re.match(r"^[A-Za-z0-9/\-]*$", spot.de_call):
|
||||||
self.set_status(422)
|
self.set_status(422)
|
||||||
self.write(json.dumps("Error - '" + spot.de_call + "' does not look like a valid callsign.",
|
self.write(safe_json_dumps("Error - '" + spot.de_call + "' does not look like a valid callsign."))
|
||||||
default=serialize_everything))
|
|
||||||
self.set_header("Cache-Control", "no-store")
|
self.set_header("Cache-Control", "no-store")
|
||||||
self.set_header("Content-Type", "application/json")
|
self.set_header("Content-Type", "application/json")
|
||||||
return
|
return
|
||||||
@@ -106,8 +101,7 @@ class APISpotHandler(tornado.web.RequestHandler):
|
|||||||
# Reject if frequency not in a known band
|
# Reject if frequency not in a known band
|
||||||
if infer_band_from_freq(spot.freq) == UNKNOWN_BAND:
|
if infer_band_from_freq(spot.freq) == UNKNOWN_BAND:
|
||||||
self.set_status(422)
|
self.set_status(422)
|
||||||
self.write(json.dumps("Error - Frequency of " + str(spot.freq / 1000.0) + "kHz is not in a known band.",
|
self.write(safe_json_dumps("Error - Frequency of " + str(spot.freq / 1000.0) + "kHz is not in a known band."))
|
||||||
default=serialize_everything))
|
|
||||||
self.set_header("Cache-Control", "no-store")
|
self.set_header("Cache-Control", "no-store")
|
||||||
self.set_header("Content-Type", "application/json")
|
self.set_header("Content-Type", "application/json")
|
||||||
return
|
return
|
||||||
@@ -117,8 +111,7 @@ class APISpotHandler(tornado.web.RequestHandler):
|
|||||||
r"^([A-R]{2}[0-9]{2}[A-X]{2}[0-9]{2}[A-X]{2}|[A-R]{2}[0-9]{2}[A-X]{2}[0-9]{2}|[A-R]{2}[0-9]{2}[A-X]{2}|[A-R]{2}[0-9]{2})$",
|
r"^([A-R]{2}[0-9]{2}[A-X]{2}[0-9]{2}[A-X]{2}|[A-R]{2}[0-9]{2}[A-X]{2}[0-9]{2}|[A-R]{2}[0-9]{2}[A-X]{2}|[A-R]{2}[0-9]{2})$",
|
||||||
spot.dx_grid.upper()):
|
spot.dx_grid.upper()):
|
||||||
self.set_status(422)
|
self.set_status(422)
|
||||||
self.write(json.dumps("Error - '" + spot.dx_grid + "' does not look like a valid Maidenhead grid.",
|
self.write(safe_json_dumps("Error - '" + spot.dx_grid + "' does not look like a valid Maidenhead grid."))
|
||||||
default=serialize_everything))
|
|
||||||
self.set_header("Cache-Control", "no-store")
|
self.set_header("Cache-Control", "no-store")
|
||||||
self.set_header("Content-Type", "application/json")
|
self.set_header("Content-Type", "application/json")
|
||||||
return
|
return
|
||||||
@@ -127,9 +120,8 @@ class APISpotHandler(tornado.web.RequestHandler):
|
|||||||
if spot.sig and spot.sig_refs and len(spot.sig_refs) > 0 and spot.sig_refs[0].id and get_ref_regex_for_sig(
|
if spot.sig and spot.sig_refs and len(spot.sig_refs) > 0 and spot.sig_refs[0].id and get_ref_regex_for_sig(
|
||||||
spot.sig) and not re.match(get_ref_regex_for_sig(spot.sig), spot.sig_refs[0].id):
|
spot.sig) and not re.match(get_ref_regex_for_sig(spot.sig), spot.sig_refs[0].id):
|
||||||
self.set_status(422)
|
self.set_status(422)
|
||||||
self.write(json.dumps(
|
self.write(safe_json_dumps(
|
||||||
"Error - '" + spot.sig_refs[0].id + "' does not look like a valid reference for " + spot.sig + ".",
|
"Error - '" + spot.sig_refs[0].id + "' does not look like a valid reference for " + spot.sig + "."))
|
||||||
default=serialize_everything))
|
|
||||||
self.set_header("Cache-Control", "no-store")
|
self.set_header("Cache-Control", "no-store")
|
||||||
self.set_header("Content-Type", "application/json")
|
self.set_header("Content-Type", "application/json")
|
||||||
return
|
return
|
||||||
@@ -139,14 +131,14 @@ class APISpotHandler(tornado.web.RequestHandler):
|
|||||||
spot.infer_missing()
|
spot.infer_missing()
|
||||||
self._spots.add(spot.id, spot, expire=MAX_SPOT_AGE)
|
self._spots.add(spot.id, spot, expire=MAX_SPOT_AGE)
|
||||||
|
|
||||||
self.write(json.dumps("OK", default=serialize_everything))
|
self.write(safe_json_dumps("OK"))
|
||||||
self.set_status(201)
|
self.set_status(201)
|
||||||
self.set_header("Cache-Control", "no-store")
|
self.set_header("Cache-Control", "no-store")
|
||||||
self.set_header("Content-Type", "application/json")
|
self.set_header("Content-Type", "application/json")
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logging.error(e)
|
logging.error(e)
|
||||||
self.write(json.dumps("Error - an internal server error occurred.", default=serialize_everything))
|
self.write(safe_json_dumps("Error - an internal server error occurred."))
|
||||||
self.set_status(500)
|
self.set_status(500)
|
||||||
self.set_header("Cache-Control", "no-store")
|
self.set_header("Cache-Control", "no-store")
|
||||||
self.set_header("Content-Type", "application/json")
|
self.set_header("Content-Type", "application/json")
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import copy
|
import copy
|
||||||
import json
|
|
||||||
import logging
|
import logging
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from queue import Queue
|
from queue import Queue
|
||||||
@@ -12,7 +11,7 @@ from tornado import httputil
|
|||||||
from tornado.web import Application
|
from tornado.web import Application
|
||||||
|
|
||||||
from core.prometheus_metrics_handler import api_requests_counter
|
from core.prometheus_metrics_handler import api_requests_counter
|
||||||
from core.utils import serialize_everything, empty_queue
|
from core.utils import safe_json_dumps, empty_queue
|
||||||
from data.lookup_credentials import extract_credentials
|
from data.lookup_credentials import extract_credentials
|
||||||
|
|
||||||
SSE_HANDLER_MAX_QUEUE_SIZE = 100
|
SSE_HANDLER_MAX_QUEUE_SIZE = 100
|
||||||
@@ -57,15 +56,15 @@ class APIAlertsHandler(tornado.web.RequestHandler):
|
|||||||
data = get_alert_list_with_filters(self._alerts, query_params)
|
data = get_alert_list_with_filters(self._alerts, query_params)
|
||||||
if credentials:
|
if credentials:
|
||||||
data = self._enrich(data, credentials)
|
data = self._enrich(data, credentials)
|
||||||
self.write(json.dumps(data, default=serialize_everything))
|
self.write(safe_json_dumps(data))
|
||||||
self.set_status(200)
|
self.set_status(200)
|
||||||
except ValueError as e:
|
except ValueError as e:
|
||||||
logging.error(e)
|
logging.error(e)
|
||||||
self.write(json.dumps("Bad request - " + str(e), default=serialize_everything))
|
self.write(safe_json_dumps("Bad request - " + str(e)))
|
||||||
self.set_status(400)
|
self.set_status(400)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logging.error(e)
|
logging.error(e)
|
||||||
self.write(json.dumps("Error - an internal server error occurred.", default=serialize_everything))
|
self.write(safe_json_dumps("Error - an internal server error occurred."))
|
||||||
self.set_status(500)
|
self.set_status(500)
|
||||||
self.set_header("Cache-Control", "no-store")
|
self.set_header("Cache-Control", "no-store")
|
||||||
self.set_header("Content-Type", "application/json")
|
self.set_header("Content-Type", "application/json")
|
||||||
@@ -150,7 +149,7 @@ class APIAlertsStreamHandler(tornado_eventsource.handler.EventSourceHandler):
|
|||||||
if self._credentials:
|
if self._credentials:
|
||||||
alert = copy.deepcopy(alert)
|
alert = copy.deepcopy(alert)
|
||||||
alert.infer_missing(self._credentials)
|
alert.infer_missing(self._credentials)
|
||||||
self.write_message(msg=json.dumps(alert, default=serialize_everything))
|
self.write_message(msg=safe_json_dumps(alert))
|
||||||
|
|
||||||
else:
|
else:
|
||||||
# Send a keepalive comment if the queue was empty
|
# Send a keepalive comment if the queue was empty
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import json
|
|
||||||
import logging
|
import logging
|
||||||
import re
|
import re
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
@@ -13,7 +12,7 @@ from core.constants import SIGS
|
|||||||
from core.geo_utils import lat_lon_for_grid_sw_corner_plus_size, lat_lon_to_cq_zone, lat_lon_to_itu_zone
|
from core.geo_utils import lat_lon_for_grid_sw_corner_plus_size, lat_lon_to_cq_zone, lat_lon_to_itu_zone
|
||||||
from core.prometheus_metrics_handler import api_requests_counter
|
from core.prometheus_metrics_handler import api_requests_counter
|
||||||
from core.sig_utils import get_ref_regex_for_sig, populate_sig_ref_info
|
from core.sig_utils import get_ref_regex_for_sig, populate_sig_ref_info
|
||||||
from core.utils import serialize_everything
|
from core.utils import safe_json_dumps
|
||||||
from data.lookup_credentials import extract_credentials
|
from data.lookup_credentials import extract_credentials
|
||||||
from data.sig_ref import SIGRef
|
from data.sig_ref import SIGRef
|
||||||
from data.spot import Spot
|
from data.spot import Spot
|
||||||
@@ -65,19 +64,18 @@ class APILookupCallHandler(tornado.web.RequestHandler):
|
|||||||
"longitude": fake_spot.dx_longitude,
|
"longitude": fake_spot.dx_longitude,
|
||||||
"location_source": fake_spot.dx_location_source
|
"location_source": fake_spot.dx_location_source
|
||||||
}
|
}
|
||||||
self.write(json.dumps(data, default=serialize_everything))
|
self.write(safe_json_dumps(data))
|
||||||
|
|
||||||
else:
|
else:
|
||||||
self.write(json.dumps("Error - '" + call + "' does not look like a valid callsign.",
|
self.write(safe_json_dumps("Error - '" + call + "' does not look like a valid callsign."))
|
||||||
default=serialize_everything))
|
|
||||||
self.set_status(422)
|
self.set_status(422)
|
||||||
else:
|
else:
|
||||||
self.write(json.dumps("Error - call must be provided", default=serialize_everything))
|
self.write(safe_json_dumps("Error - call must be provided"))
|
||||||
self.set_status(422)
|
self.set_status(422)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logging.error(e)
|
logging.error(e)
|
||||||
self.write(json.dumps("Error - an internal server error occurred.", default=serialize_everything))
|
self.write(safe_json_dumps("Error - an internal server error occurred."))
|
||||||
self.set_status(500)
|
self.set_status(500)
|
||||||
|
|
||||||
self.set_header("Cache-Control", "no-store")
|
self.set_header("Cache-Control", "no-store")
|
||||||
@@ -114,24 +112,22 @@ class APILookupSIGRefHandler(tornado.web.RequestHandler):
|
|||||||
if sig in list(map(lambda p: p.name.upper(), SIGS)):
|
if sig in list(map(lambda p: p.name.upper(), SIGS)):
|
||||||
if not get_ref_regex_for_sig(sig) or re.match(get_ref_regex_for_sig(sig), ref_id):
|
if not get_ref_regex_for_sig(sig) or re.match(get_ref_regex_for_sig(sig), ref_id):
|
||||||
data = populate_sig_ref_info(SIGRef(id=ref_id, sig=sig))
|
data = populate_sig_ref_info(SIGRef(id=ref_id, sig=sig))
|
||||||
self.write(json.dumps(data, default=serialize_everything))
|
self.write(safe_json_dumps(data))
|
||||||
|
|
||||||
else:
|
else:
|
||||||
self.write(
|
self.write(safe_json_dumps(
|
||||||
json.dumps(
|
"Error - '" + ref_id + "' does not look like a valid reference ID for " + sig + "."))
|
||||||
"Error - '" + ref_id + "' does not look like a valid reference ID for " + sig + ".",
|
|
||||||
default=serialize_everything))
|
|
||||||
self.set_status(422)
|
self.set_status(422)
|
||||||
else:
|
else:
|
||||||
self.write(json.dumps("Error - sig '" + sig + "' is not known.", default=serialize_everything))
|
self.write(safe_json_dumps("Error - sig '" + sig + "' is not known."))
|
||||||
self.set_status(422)
|
self.set_status(422)
|
||||||
else:
|
else:
|
||||||
self.write(json.dumps("Error - sig and id must be provided", default=serialize_everything))
|
self.write(safe_json_dumps("Error - sig and id must be provided"))
|
||||||
self.set_status(422)
|
self.set_status(422)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logging.error(e)
|
logging.error(e)
|
||||||
self.write(json.dumps("Error - an internal server error occurred.", default=serialize_everything))
|
self.write(safe_json_dumps("Error - an internal server error occurred."))
|
||||||
self.set_status(500)
|
self.set_status(500)
|
||||||
|
|
||||||
self.set_header("Cache-Control", "no-store")
|
self.set_header("Cache-Control", "no-store")
|
||||||
@@ -185,15 +181,15 @@ class APILookupGridHandler(tornado.web.RequestHandler):
|
|||||||
"latitude": lat + lat_cell_size,
|
"latitude": lat + lat_cell_size,
|
||||||
"longitude": lon + lon_cell_size,
|
"longitude": lon + lon_cell_size,
|
||||||
}}
|
}}
|
||||||
self.write(json.dumps(response, default=serialize_everything))
|
self.write(safe_json_dumps(response))
|
||||||
|
|
||||||
else:
|
else:
|
||||||
self.write(json.dumps("Error - grid must be provided", default=serialize_everything))
|
self.write(safe_json_dumps("Error - grid must be provided"))
|
||||||
self.set_status(422)
|
self.set_status(422)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logging.error(e)
|
logging.error(e)
|
||||||
self.write(json.dumps("Error - an internal server error occurred.", default=serialize_everything))
|
self.write(safe_json_dumps("Error - an internal server error occurred."))
|
||||||
self.set_status(500)
|
self.set_status(500)
|
||||||
|
|
||||||
self.set_header("Cache-Control", "no-store")
|
self.set_header("Cache-Control", "no-store")
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import json
|
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
@@ -10,7 +9,7 @@ from tornado.web import Application
|
|||||||
from core.config import MAX_SPOT_AGE, ALLOW_SPOTTING
|
from core.config import MAX_SPOT_AGE, ALLOW_SPOTTING
|
||||||
from core.constants import BANDS, ALL_MODES, MODE_TYPES, SIGS, CONTINENTS, PROPAGATION_MODES
|
from core.constants import BANDS, ALL_MODES, MODE_TYPES, SIGS, CONTINENTS, PROPAGATION_MODES
|
||||||
from core.prometheus_metrics_handler import api_requests_counter
|
from core.prometheus_metrics_handler import api_requests_counter
|
||||||
from core.utils import serialize_everything
|
from core.utils import safe_json_dumps
|
||||||
|
|
||||||
|
|
||||||
class APIOptionsHandler(tornado.web.RequestHandler):
|
class APIOptionsHandler(tornado.web.RequestHandler):
|
||||||
@@ -50,7 +49,7 @@ class APIOptionsHandler(tornado.web.RequestHandler):
|
|||||||
if ALLOW_SPOTTING:
|
if ALLOW_SPOTTING:
|
||||||
options["spot_sources"].append("API")
|
options["spot_sources"].append("API")
|
||||||
|
|
||||||
self.write(json.dumps(options, default=serialize_everything))
|
self.write(safe_json_dumps(options))
|
||||||
self.set_status(200)
|
self.set_status(200)
|
||||||
self.set_header("Cache-Control", "no-store")
|
self.set_header("Cache-Control", "no-store")
|
||||||
self.set_header("Content-Type", "application/json")
|
self.set_header("Content-Type", "application/json")
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import copy
|
import copy
|
||||||
import json
|
|
||||||
import logging
|
import logging
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
from queue import Queue
|
from queue import Queue
|
||||||
@@ -12,7 +11,7 @@ from tornado import httputil
|
|||||||
from tornado.web import Application
|
from tornado.web import Application
|
||||||
|
|
||||||
from core.prometheus_metrics_handler import api_requests_counter
|
from core.prometheus_metrics_handler import api_requests_counter
|
||||||
from core.utils import serialize_everything, empty_queue
|
from core.utils import safe_json_dumps, empty_queue
|
||||||
from data.lookup_credentials import extract_credentials
|
from data.lookup_credentials import extract_credentials
|
||||||
|
|
||||||
SSE_HANDLER_MAX_QUEUE_SIZE = 1000
|
SSE_HANDLER_MAX_QUEUE_SIZE = 1000
|
||||||
@@ -57,15 +56,15 @@ class APISpotsHandler(tornado.web.RequestHandler):
|
|||||||
data = get_spot_list_with_filters(self._spots, query_params)
|
data = get_spot_list_with_filters(self._spots, query_params)
|
||||||
if credentials:
|
if credentials:
|
||||||
data = self._enrich(data, credentials)
|
data = self._enrich(data, credentials)
|
||||||
self.write(json.dumps(data, default=serialize_everything))
|
self.write(safe_json_dumps(data))
|
||||||
self.set_status(200)
|
self.set_status(200)
|
||||||
except ValueError as e:
|
except ValueError as e:
|
||||||
logging.error(e)
|
logging.error(e)
|
||||||
self.write(json.dumps("Bad request - " + str(e), default=serialize_everything))
|
self.write(safe_json_dumps("Bad request - " + str(e)))
|
||||||
self.set_status(400)
|
self.set_status(400)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logging.error(e)
|
logging.error(e)
|
||||||
self.write(json.dumps("Error - an internal server error occurred.", default=serialize_everything))
|
self.write(safe_json_dumps("Error - an internal server error occurred."))
|
||||||
self.set_status(500)
|
self.set_status(500)
|
||||||
self.set_header("Cache-Control", "no-store")
|
self.set_header("Cache-Control", "no-store")
|
||||||
self.set_header("Content-Type", "application/json")
|
self.set_header("Content-Type", "application/json")
|
||||||
@@ -152,7 +151,7 @@ class APISpotsStreamHandler(tornado_eventsource.handler.EventSourceHandler):
|
|||||||
if self._credentials:
|
if self._credentials:
|
||||||
spot = copy.deepcopy(spot)
|
spot = copy.deepcopy(spot)
|
||||||
spot.infer_missing(self._credentials)
|
spot.infer_missing(self._credentials)
|
||||||
self.write_message(msg=json.dumps(spot, default=serialize_everything))
|
self.write_message(msg=safe_json_dumps(spot))
|
||||||
|
|
||||||
else:
|
else:
|
||||||
# Send a keepalive comment if the queue was empty
|
# Send a keepalive comment if the queue was empty
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import json
|
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
@@ -8,7 +7,7 @@ from tornado import httputil
|
|||||||
from tornado.web import Application
|
from tornado.web import Application
|
||||||
|
|
||||||
from core.prometheus_metrics_handler import api_requests_counter
|
from core.prometheus_metrics_handler import api_requests_counter
|
||||||
from core.utils import serialize_everything
|
from core.utils import safe_json_dumps
|
||||||
|
|
||||||
|
|
||||||
class APIStatusHandler(tornado.web.RequestHandler):
|
class APIStatusHandler(tornado.web.RequestHandler):
|
||||||
@@ -30,7 +29,7 @@ class APIStatusHandler(tornado.web.RequestHandler):
|
|||||||
self._web_server_metrics["status"] = "OK"
|
self._web_server_metrics["status"] = "OK"
|
||||||
api_requests_counter.inc()
|
api_requests_counter.inc()
|
||||||
|
|
||||||
self.write(json.dumps(self._status_data, default=serialize_everything))
|
self.write(safe_json_dumps(self._status_data))
|
||||||
self.set_status(200)
|
self.set_status(200)
|
||||||
self.set_header("Cache-Control", "no-store")
|
self.set_header("Cache-Control", "no-store")
|
||||||
self.set_header("Content-Type", "application/json")
|
self.set_header("Content-Type", "application/json")
|
||||||
|
|||||||
@@ -76,7 +76,7 @@
|
|||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script src="/js/add-spot.js?v=1782461355"></script>
|
<script src="/js/add-spot.js?v=1782666584"></script>
|
||||||
<script>$(document).ready(function () {
|
<script>$(document).ready(function () {
|
||||||
$("#nav-link-add-spot").addClass("active");
|
$("#nav-link-add-spot").addClass("active");
|
||||||
}); <!-- highlight active page in nav --></script>
|
}); <!-- highlight active page in nav --></script>
|
||||||
|
|||||||
@@ -75,7 +75,7 @@
|
|||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script src="/js/alerts.js?v=1782461355"></script>
|
<script src="/js/alerts.js?v=1782666584"></script>
|
||||||
<script>$(document).ready(function () {
|
<script>$(document).ready(function () {
|
||||||
$("#nav-link-alerts").addClass("active");
|
$("#nav-link-alerts").addClass("active");
|
||||||
}); <!-- highlight active page in nav --></script>
|
}); <!-- highlight active page in nav --></script>
|
||||||
|
|||||||
@@ -75,8 +75,8 @@
|
|||||||
<script>
|
<script>
|
||||||
let spotProvidersEnabledByDefault = {% raw json_encode(web_ui_options["spot-providers-enabled-by-default"]) %};
|
let spotProvidersEnabledByDefault = {% raw json_encode(web_ui_options["spot-providers-enabled-by-default"]) %};
|
||||||
</script>
|
</script>
|
||||||
<script src="/js/spotsbandsandmap.js?v=1782461355"></script>
|
<script src="/js/spotsbandsandmap.js?v=1782666584"></script>
|
||||||
<script src="/js/bands.js?v=1782461355"></script>
|
<script src="/js/bands.js?v=1782666584"></script>
|
||||||
<script>$(document).ready(function () {
|
<script>$(document).ready(function () {
|
||||||
$("#nav-link-bands").addClass("active");
|
$("#nav-link-bands").addClass("active");
|
||||||
}); <!-- highlight active page in nav --></script>
|
}); <!-- highlight active page in nav --></script>
|
||||||
|
|||||||
+5
-5
@@ -1,6 +1,6 @@
|
|||||||
{% extends "skeleton.html" %}
|
{% extends "skeleton.html" %}
|
||||||
{% block head_extra %}
|
{% block head_extra %}
|
||||||
<link rel="stylesheet" href="/css/style.css?v=1782461355" type="text/css">
|
<link rel="stylesheet" href="/css/style.css?v=1782666584" type="text/css">
|
||||||
<link href="/vendor/css/bootstrap-5.3.8.min.css" rel="stylesheet">
|
<link href="/vendor/css/bootstrap-5.3.8.min.css" rel="stylesheet">
|
||||||
<link href="/vendor/css/fontawesome-6.7.2.min.css" rel="stylesheet">
|
<link href="/vendor/css/fontawesome-6.7.2.min.css" rel="stylesheet">
|
||||||
<link href="/vendor/css/solid-6.7.2.min.css" rel="stylesheet">
|
<link href="/vendor/css/solid-6.7.2.min.css" rel="stylesheet">
|
||||||
@@ -10,10 +10,10 @@
|
|||||||
<script src="/vendor/js/bootstrap-5.3.8.bundle.min.js"></script>
|
<script src="/vendor/js/bootstrap-5.3.8.bundle.min.js"></script>
|
||||||
<script src="/vendor/js/tinycolor2-1.6.0.min.js"></script>
|
<script src="/vendor/js/tinycolor2-1.6.0.min.js"></script>
|
||||||
|
|
||||||
<script src="/js/utils.js?v=1782461355"></script>
|
<script src="/js/utils.js?v=1782666584"></script>
|
||||||
<script src="/js/ui-ham.js?v=1782461355"></script>
|
<script src="/js/ui-ham.js?v=1782666584"></script>
|
||||||
<script src="/js/geo.js?v=1782461355"></script>
|
<script src="/js/geo.js?v=1782666584"></script>
|
||||||
<script src="/js/common.js?v=1782461355"></script>
|
<script src="/js/common.js?v=1782666584"></script>
|
||||||
{% end %}
|
{% end %}
|
||||||
{% block body %}
|
{% block body %}
|
||||||
<div class="container">
|
<div class="container">
|
||||||
|
|||||||
@@ -284,7 +284,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script src="/vendor/js/chart-4.4.9.umd.min.js"></script>
|
<script src="/vendor/js/chart-4.4.9.umd.min.js"></script>
|
||||||
<script src="/js/conditions.js?v=1782461355"></script>
|
<script src="/js/conditions.js?v=1782666584"></script>
|
||||||
<script>$(document).ready(function () {
|
<script>$(document).ready(function () {
|
||||||
$("#nav-link-conditions").addClass("active");
|
$("#nav-link-conditions").addClass("active");
|
||||||
}); <!-- highlight active page in nav --></script>
|
}); <!-- highlight active page in nav --></script>
|
||||||
|
|||||||
+2
-2
@@ -95,8 +95,8 @@
|
|||||||
<script>
|
<script>
|
||||||
let spotProvidersEnabledByDefault = {% raw json_encode(web_ui_options["spot-providers-enabled-by-default"]) %};
|
let spotProvidersEnabledByDefault = {% raw json_encode(web_ui_options["spot-providers-enabled-by-default"]) %};
|
||||||
</script>
|
</script>
|
||||||
<script src="/js/spotsbandsandmap.js?v=1782461355"></script>
|
<script src="/js/spotsbandsandmap.js?v=1782666584"></script>
|
||||||
<script src="/js/map.js?v=1782461355"></script>
|
<script src="/js/map.js?v=1782666584"></script>
|
||||||
<script>$(document).ready(function () {
|
<script>$(document).ready(function () {
|
||||||
$("#nav-link-map").addClass("active");
|
$("#nav-link-map").addClass("active");
|
||||||
}); <!-- highlight active page in nav --></script>
|
}); <!-- highlight active page in nav --></script>
|
||||||
|
|||||||
@@ -116,8 +116,8 @@
|
|||||||
<script>
|
<script>
|
||||||
let spotProvidersEnabledByDefault = {% raw json_encode(web_ui_options["spot-providers-enabled-by-default"]) %};
|
let spotProvidersEnabledByDefault = {% raw json_encode(web_ui_options["spot-providers-enabled-by-default"]) %};
|
||||||
</script>
|
</script>
|
||||||
<script src="/js/spotsbandsandmap.js?v=1782461355"></script>
|
<script src="/js/spotsbandsandmap.js?v=1782666584"></script>
|
||||||
<script src="/js/spots.js?v=1782461355"></script>
|
<script src="/js/spots.js?v=1782666584"></script>
|
||||||
<script>$(document).ready(function () {
|
<script>$(document).ready(function () {
|
||||||
$("#nav-link-spots").addClass("active");
|
$("#nav-link-spots").addClass("active");
|
||||||
}); <!-- highlight active page in nav --></script>
|
}); <!-- highlight active page in nav --></script>
|
||||||
|
|||||||
@@ -59,7 +59,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script src="/js/status.js?v=1782461355"></script>
|
<script src="/js/status.js?v=1782666584"></script>
|
||||||
<script>
|
<script>
|
||||||
$(document).ready(function () {
|
$(document).ready(function () {
|
||||||
$("#nav-link-status").addClass("active");
|
$("#nav-link-status").addClass("active");
|
||||||
|
|||||||
Reference in New Issue
Block a user