mirror of
https://github.com/smittix/intercept.git
synced 2026-07-20 07:18:11 -07:00
Fix GPS globe startup and satellite polling errors
This commit is contained in:
+16
-15
@@ -207,21 +207,22 @@ def get_position():
|
|||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
@gps_bp.route('/satellites')
|
@gps_bp.route('/satellites')
|
||||||
def get_satellites():
|
def get_satellites():
|
||||||
"""Get current satellite sky view data."""
|
"""Get current satellite sky view data."""
|
||||||
reader = get_gps_reader()
|
reader = get_gps_reader()
|
||||||
|
|
||||||
if not reader or not reader.is_running:
|
if not reader or not reader.is_running:
|
||||||
return jsonify({
|
return jsonify({
|
||||||
'status': 'error',
|
'status': 'waiting',
|
||||||
'message': 'GPS client not running'
|
'running': False,
|
||||||
}), 400
|
'message': 'GPS client not running'
|
||||||
|
})
|
||||||
sky = reader.sky
|
|
||||||
if sky:
|
sky = reader.sky
|
||||||
return jsonify({
|
if sky:
|
||||||
'status': 'ok',
|
return jsonify({
|
||||||
|
'status': 'ok',
|
||||||
'sky': sky.to_dict()
|
'sky': sky.to_dict()
|
||||||
})
|
})
|
||||||
else:
|
else:
|
||||||
|
|||||||
+67
-16
@@ -74,12 +74,32 @@ const GPS = (function() {
|
|||||||
if (skyRendererInitPromise) return skyRendererInitPromise;
|
if (skyRendererInitPromise) return skyRendererInitPromise;
|
||||||
skyRendererInitAttempted = true;
|
skyRendererInitAttempted = true;
|
||||||
|
|
||||||
|
let fallbackRenderer = null;
|
||||||
|
const fallbackCanvas = document.getElementById('gpsSkyCanvas');
|
||||||
|
const fallbackOverlay = document.getElementById('gpsSkyOverlay');
|
||||||
|
|
||||||
|
// Show an immediate fallback while the globe library loads.
|
||||||
|
setSkyCanvasFallbackMode(true);
|
||||||
|
if (fallbackCanvas) {
|
||||||
|
try {
|
||||||
|
fallbackRenderer = createWebGlSkyRenderer(fallbackCanvas, fallbackOverlay);
|
||||||
|
skyRenderer = fallbackRenderer;
|
||||||
|
} catch (err) {
|
||||||
|
fallbackRenderer = null;
|
||||||
|
skyRenderer = null;
|
||||||
|
console.warn('GPS sky WebGL renderer failed, falling back to 2D', err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
skyRendererInitPromise = (async function() {
|
skyRendererInitPromise = (async function() {
|
||||||
const globeContainer = document.getElementById('gpsSkyGlobe');
|
const globeContainer = document.getElementById('gpsSkyGlobe');
|
||||||
if (globeContainer) {
|
if (globeContainer) {
|
||||||
try {
|
try {
|
||||||
const globeRenderer = await createGlobeSkyRenderer(globeContainer);
|
const globeRenderer = await createGlobeSkyRenderer(globeContainer);
|
||||||
if (globeRenderer) {
|
if (globeRenderer) {
|
||||||
|
if (fallbackRenderer && fallbackRenderer !== globeRenderer && typeof fallbackRenderer.destroy === 'function') {
|
||||||
|
fallbackRenderer.destroy();
|
||||||
|
}
|
||||||
setSkyCanvasFallbackMode(false);
|
setSkyCanvasFallbackMode(false);
|
||||||
skyRenderer = globeRenderer;
|
skyRenderer = globeRenderer;
|
||||||
return skyRenderer;
|
return skyRenderer;
|
||||||
@@ -90,19 +110,17 @@ const GPS = (function() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
setSkyCanvasFallbackMode(true);
|
setSkyCanvasFallbackMode(true);
|
||||||
|
if (!fallbackRenderer && fallbackCanvas) {
|
||||||
const canvas = document.getElementById('gpsSkyCanvas');
|
try {
|
||||||
if (!canvas) return null;
|
fallbackRenderer = createWebGlSkyRenderer(fallbackCanvas, fallbackOverlay);
|
||||||
|
} catch (err) {
|
||||||
const overlay = document.getElementById('gpsSkyOverlay');
|
fallbackRenderer = null;
|
||||||
try {
|
console.warn('GPS sky WebGL renderer failed, falling back to 2D', err);
|
||||||
skyRenderer = createWebGlSkyRenderer(canvas, overlay);
|
}
|
||||||
return skyRenderer;
|
|
||||||
} catch (err) {
|
|
||||||
skyRenderer = null;
|
|
||||||
console.warn('GPS sky WebGL renderer failed, falling back to 2D', err);
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
skyRenderer = fallbackRenderer;
|
||||||
|
return skyRenderer;
|
||||||
})();
|
})();
|
||||||
|
|
||||||
return skyRendererInitPromise;
|
return skyRendererInitPromise;
|
||||||
@@ -158,10 +176,35 @@ const GPS = (function() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function loadGpsGlobeScript(src) {
|
function loadGpsGlobeScript(src) {
|
||||||
|
const state = getSharedGlobeScriptState();
|
||||||
|
if (!state.promises[src]) {
|
||||||
|
state.promises[src] = loadSharedGlobeScript(src);
|
||||||
|
}
|
||||||
|
return state.promises[src].catch((error) => {
|
||||||
|
delete state.promises[src];
|
||||||
|
throw error;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function getSharedGlobeScriptState() {
|
||||||
|
const key = '__interceptGlobeScriptState';
|
||||||
|
if (!window[key]) {
|
||||||
|
window[key] = {
|
||||||
|
promises: Object.create(null),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return window[key];
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadSharedGlobeScript(src) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
const existing = document.querySelector(
|
const selector = [
|
||||||
`script[data-websdr-src="${src}"], script[data-gps-globe-src="${src}"], script[src="${src}"]`
|
`script[data-intercept-globe-src="${src}"]`,
|
||||||
);
|
`script[data-websdr-src="${src}"]`,
|
||||||
|
`script[data-gps-globe-src="${src}"]`,
|
||||||
|
`script[src="${src}"]`,
|
||||||
|
].join(', ');
|
||||||
|
const existing = document.querySelector(selector);
|
||||||
|
|
||||||
if (existing) {
|
if (existing) {
|
||||||
if (existing.dataset.loaded === 'true') {
|
if (existing.dataset.loaded === 'true') {
|
||||||
@@ -181,6 +224,7 @@ const GPS = (function() {
|
|||||||
script.src = src;
|
script.src = src;
|
||||||
script.async = true;
|
script.async = true;
|
||||||
script.crossOrigin = 'anonymous';
|
script.crossOrigin = 'anonymous';
|
||||||
|
script.dataset.interceptGlobeSrc = src;
|
||||||
script.dataset.gpsGlobeSrc = src;
|
script.dataset.gpsGlobeSrc = src;
|
||||||
script.onload = () => {
|
script.onload = () => {
|
||||||
script.dataset.loaded = 'true';
|
script.dataset.loaded = 'true';
|
||||||
@@ -521,7 +565,14 @@ const GPS = (function() {
|
|||||||
fetch('/gps/status')
|
fetch('/gps/status')
|
||||||
.then(r => r.json())
|
.then(r => r.json())
|
||||||
.then(data => {
|
.then(data => {
|
||||||
if (!connected || !data || data.running !== true) return;
|
if (!connected || !data) return;
|
||||||
|
if (data.running !== true) {
|
||||||
|
connected = false;
|
||||||
|
stopSkyPolling();
|
||||||
|
stopStatusPolling();
|
||||||
|
updateConnectionUI(false, false, 'error', data.message || 'GPS disconnected');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (data.position) {
|
if (data.position) {
|
||||||
lastPosition = data.position;
|
lastPosition = data.position;
|
||||||
|
|||||||
@@ -185,8 +185,34 @@ async function ensureWebsdrGlobeLibrary() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function loadWebsdrScript(src) {
|
function loadWebsdrScript(src) {
|
||||||
|
const state = getSharedGlobeScriptState();
|
||||||
|
if (!state.promises[src]) {
|
||||||
|
state.promises[src] = loadSharedGlobeScript(src);
|
||||||
|
}
|
||||||
|
return state.promises[src].catch((error) => {
|
||||||
|
delete state.promises[src];
|
||||||
|
throw error;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function getSharedGlobeScriptState() {
|
||||||
|
const key = '__interceptGlobeScriptState';
|
||||||
|
if (!window[key]) {
|
||||||
|
window[key] = {
|
||||||
|
promises: Object.create(null),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return window[key];
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadSharedGlobeScript(src) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
const selector = `script[data-websdr-src="${src}"], script[data-gps-globe-src="${src}"], script[src="${src}"]`;
|
const selector = [
|
||||||
|
`script[data-intercept-globe-src="${src}"]`,
|
||||||
|
`script[data-websdr-src="${src}"]`,
|
||||||
|
`script[data-gps-globe-src="${src}"]`,
|
||||||
|
`script[src="${src}"]`,
|
||||||
|
].join(', ');
|
||||||
const existing = document.querySelector(selector);
|
const existing = document.querySelector(selector);
|
||||||
|
|
||||||
if (existing) {
|
if (existing) {
|
||||||
@@ -207,6 +233,7 @@ function loadWebsdrScript(src) {
|
|||||||
script.src = src;
|
script.src = src;
|
||||||
script.async = true;
|
script.async = true;
|
||||||
script.crossOrigin = 'anonymous';
|
script.crossOrigin = 'anonymous';
|
||||||
|
script.dataset.interceptGlobeSrc = src;
|
||||||
script.dataset.websdrSrc = src;
|
script.dataset.websdrSrc = src;
|
||||||
script.onload = () => {
|
script.onload = () => {
|
||||||
script.dataset.loaded = 'true';
|
script.dataset.loaded = 'true';
|
||||||
|
|||||||
@@ -61,3 +61,18 @@ def test_auto_connect_attaches_callbacks_when_reader_already_running(client, mon
|
|||||||
assert payload['status'] == 'connected'
|
assert payload['status'] == 'connected'
|
||||||
assert reader.position_callbacks == [gps_routes._position_callback]
|
assert reader.position_callbacks == [gps_routes._position_callback]
|
||||||
assert reader.sky_callbacks == [gps_routes._sky_callback]
|
assert reader.sky_callbacks == [gps_routes._sky_callback]
|
||||||
|
|
||||||
|
|
||||||
|
def test_satellites_returns_waiting_when_reader_not_running(client, monkeypatch):
|
||||||
|
"""Satellite endpoint should return a non-error waiting state when reader is down."""
|
||||||
|
monkeypatch.setattr(gps_routes, 'get_gps_reader', lambda: None)
|
||||||
|
|
||||||
|
with client.session_transaction() as sess:
|
||||||
|
sess['logged_in'] = True
|
||||||
|
|
||||||
|
response = client.get('/gps/satellites')
|
||||||
|
payload = response.get_json()
|
||||||
|
|
||||||
|
assert response.status_code == 200
|
||||||
|
assert payload['status'] == 'waiting'
|
||||||
|
assert payload['running'] is False
|
||||||
|
|||||||
Reference in New Issue
Block a user