Show live OpenSky air traffic on the Overview Live map

Add GET /api/integrations/opensky/states: resolves the caller's OpenSky
cascade and returns trimmed aircraft state vectors (icao24, callsign,
country, lat/lng, heading, velocity, altitude, onGround) for their bbox.
Reuses the settings gates (global master / org / personal opt-in) and is
backed by a new Manager.InvokeWith that runs the plugin's states.bbox
action on a transient instance. Proxied through the Web App BFF.

DeviceMap now overlays these as rotatable plane markers (accent when
airborne, grey on ground) with tooltips; Dashboard polls every 30s while
Overview is visible and shows an aircraft count badge.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
tajniak81
2026-07-13 22:15:18 +02:00
co-authored by Claude Opus 4.8
parent 97c19083cf
commit a578555b43
11 changed files with 377 additions and 46 deletions
+18
View File
@@ -339,6 +339,24 @@ func (m *Manager) HealthCheckWith(ctx context.Context, name string, cfg map[stri
return p.HealthCheck(ctx), nil
}
// InvokeWith calls a plugin action using a caller-supplied config instead of the
// stored record. Like HealthCheckWith it always builds a transient instance, so it
// never disturbs the live instance. Used by per-user integration flows that resolve
// their own effective config (e.g. the OpenSky live-map states query).
func (m *Manager) InvokeWith(ctx context.Context, name string, cfg map[string]string, action string, payload json.RawMessage) (json.RawMessage, error) {
m.mu.Lock()
rec := m.records[name]
p := construct(name, m.factories[name], rec)
m.mu.Unlock()
if p == nil {
return nil, errUnknown
}
_ = p.Init(ctx, cfg)
defer func() { _ = p.Shutdown(context.Background()) }()
return p.Invoke(ctx, action, payload)
}
// RawConfig returns a plugin's stored config UNMASKED, together with its enabled
// flag and whether the plugin is known. Server-side callers use it to resolve a
// layered effective config (which needs the real secret values); it must never be