websocket
This commit is contained in:
+166
-70
@@ -2,7 +2,7 @@
|
||||
import enhance from "../core/enhance.tsx";
|
||||
import {Button, InputNumber, message, Select, Space, Switch, Tag, Typography} from "antd";
|
||||
import axios from "axios";
|
||||
import {baseURL, darkenColor, lightenColor, Prefix, row_style, StateHolder} from "../Global.tsx";
|
||||
import {baseURL, darkenColor, lightenColor, Prefix, row_style, server_url, StateHolder} from "../Global.tsx";
|
||||
import {Base_Station} from "../Map/Base_Station.tsx";
|
||||
import {Aircraft, Aircraft_Track_Point} from "../Map/Aircraft.tsx";
|
||||
import {app} from "../App.tsx";
|
||||
@@ -35,10 +35,6 @@ export type Data_Source_Map_Display_Config = {
|
||||
map2d: Data_Source_Map_Display_Data
|
||||
map3d: Data_Source_Map_Display_Data
|
||||
}
|
||||
type Aircraft_Track_Request_Item = {
|
||||
icao: string
|
||||
last_size: number
|
||||
}
|
||||
export function default_map_display_data(): Data_Source_Map_Display_Data {
|
||||
return {
|
||||
base_station_show: true,
|
||||
@@ -121,6 +117,7 @@ export class Data_Source extends enhance.Base {
|
||||
active_aircraft: Aircraft = null;
|
||||
manual_track_icao_set: Set<string> = new Set();
|
||||
monitor_all_aircraft_mode: boolean = false;
|
||||
aircraft_change_versions: Map<string, string> = new Map();
|
||||
connect_list: [] = []
|
||||
first: boolean = true;
|
||||
|
||||
@@ -163,10 +160,10 @@ export class Data_Source extends enhance.Base {
|
||||
if (this.key) {
|
||||
await this.refresh_base_station_location();
|
||||
}
|
||||
await this.loadList();
|
||||
aircraft_stream.ensure_open();
|
||||
aircraft_stream.schedule_subscribe();
|
||||
if (this.active_aircraft && !this.is_aircraft_track_monitored(this.active_aircraft.icao)) {
|
||||
// console.log(`air:${this.active_aircraft.icao} show path`)
|
||||
this.active_aircraft.append_path();
|
||||
aircraft_stream.schedule_subscribe();
|
||||
}
|
||||
}
|
||||
manual_track_icao_list(): string[] {
|
||||
@@ -178,6 +175,9 @@ export class Data_Source extends enhance.Base {
|
||||
is_aircraft_track_monitored(icao: string): boolean {
|
||||
return this.monitor_all_aircraft_mode || this.is_manual_tracking_aircraft(icao);
|
||||
}
|
||||
request_aircraft_stream_update() {
|
||||
aircraft_stream.send_subscription();
|
||||
}
|
||||
async set_manual_tracking_aircraft(icao: string, enabled: boolean) {
|
||||
if (enabled) {
|
||||
this.manual_track_icao_set.add(icao);
|
||||
@@ -186,7 +186,7 @@ export class Data_Source extends enhance.Base {
|
||||
const aircraft = this.aircraftMap.get(icao);
|
||||
aircraft?.hide_path();
|
||||
}
|
||||
await this.refresh_manual_tracked_aircraft();
|
||||
aircraft_stream.send_subscription();
|
||||
this.refresh_manual_tracking_views();
|
||||
}
|
||||
async set_monitor_all_aircraft_mode(enabled: boolean) {
|
||||
@@ -198,7 +198,7 @@ export class Data_Source extends enhance.Base {
|
||||
}
|
||||
}
|
||||
}
|
||||
await this.refresh_manual_tracked_aircraft();
|
||||
aircraft_stream.send_subscription();
|
||||
this.refresh_manual_tracking_views();
|
||||
}
|
||||
clear_manual_tracking_aircraft(icao?: string) {
|
||||
@@ -211,6 +211,7 @@ export class Data_Source extends enhance.Base {
|
||||
}
|
||||
this.manual_track_icao_set.clear();
|
||||
}
|
||||
aircraft_stream.send_subscription();
|
||||
this.refresh_manual_tracking_views();
|
||||
}
|
||||
clear_all_aircraft_tracking() {
|
||||
@@ -219,38 +220,9 @@ export class Data_Source extends enhance.Base {
|
||||
aircraft.hide_path();
|
||||
}
|
||||
this.manual_track_icao_set.clear();
|
||||
aircraft_stream.send_subscription();
|
||||
this.refresh_manual_tracking_views();
|
||||
}
|
||||
tracked_aircraft_track_request_items(): Aircraft_Track_Request_Item[] {
|
||||
const tracked_icaos = this.monitor_all_aircraft_mode ? Array.from(this.aircraftMap.keys()) : this.manual_track_icao_list();
|
||||
const ret: Aircraft_Track_Request_Item[] = [];
|
||||
tracked_icaos.forEach((icao) => {
|
||||
const aircraft = this.aircraftMap.get(icao);
|
||||
if (aircraft) {
|
||||
ret.push({icao, last_size: aircraft.last_size});
|
||||
}
|
||||
});
|
||||
return ret;
|
||||
}
|
||||
async refresh_manual_tracked_aircraft() {
|
||||
const items = this.tracked_aircraft_track_request_items();
|
||||
if (items.length === 0) {
|
||||
return;
|
||||
}
|
||||
const res = await axios.post(`${baseURL}/get_aircraft_track_list_batch`, {
|
||||
data_source_key: this.key,
|
||||
items
|
||||
});
|
||||
const list = Array.isArray(res.data?.list) ? res.data.list : [];
|
||||
list.forEach((item: any) => {
|
||||
const aircraft = this.aircraftMap.get(item.icao);
|
||||
if (!aircraft) {
|
||||
return;
|
||||
}
|
||||
aircraft.is_show_path = true;
|
||||
aircraft.append_path_response(item);
|
||||
});
|
||||
}
|
||||
refresh_manual_tracking_views() {
|
||||
app.cesium_map?.sync_data_sources();
|
||||
app.leaflet_map?.data_source_show?.flush();
|
||||
@@ -321,44 +293,51 @@ export class Data_Source extends enhance.Base {
|
||||
}
|
||||
return this.aircraftMap.get(icao)!;
|
||||
}
|
||||
|
||||
|
||||
loadList = async () => {
|
||||
if (!this.enable) return;
|
||||
const ret = await axios.post(`${baseURL}/aircraft_change_list`, {
|
||||
data_source_key: this.key
|
||||
create_or_get_aircraft(item: any): Aircraft {
|
||||
let aircraft: Aircraft = this.get_aircraft(item.icao);
|
||||
if (aircraft == null) {
|
||||
aircraft = new Aircraft(item.icao, this);
|
||||
aircraft.refresh();
|
||||
}
|
||||
return aircraft;
|
||||
}
|
||||
apply_aircraft_items(items: any[]) {
|
||||
items.forEach((item: any) => {
|
||||
const aircraft = this.create_or_get_aircraft(item);
|
||||
aircraft.refresh_from_change_list(item);
|
||||
this.aircraftMap.set(item.icao, aircraft);
|
||||
this.aircraft_change_versions.set(item.icao, String(item.change_version || ""));
|
||||
});
|
||||
|
||||
this.refresh_aircraft_range();
|
||||
}
|
||||
remove_aircraft(icao: string) {
|
||||
const aircraft = this.aircraftMap.get(icao);
|
||||
if (!aircraft) return;
|
||||
aircraft.hide_track()
|
||||
aircraft.pos_marker.remove();
|
||||
this.aircraftMap.delete(icao);
|
||||
this.aircraft_change_versions.delete(icao);
|
||||
if (this.active_aircraft === aircraft) {
|
||||
this.active_aircraft = null;
|
||||
}
|
||||
}
|
||||
refresh_aircraft_range() {
|
||||
let station = this.base_station;
|
||||
let new_map: Map<string, Aircraft> = new Map();
|
||||
let max_distance = 0;
|
||||
let max_plane_pos: L.LatLng | null = null;
|
||||
let max_aircraft_icao = "";
|
||||
ret.data.forEach((item: any) => {
|
||||
let aircraft: Aircraft = this.get_aircraft(item.icao);
|
||||
if (aircraft == null) {
|
||||
aircraft = new Aircraft(item.icao, this);
|
||||
aircraft.refresh();
|
||||
}
|
||||
aircraft.refresh_from_change_list(item);
|
||||
new_map.set(item.icao, aircraft);
|
||||
let lat = item.latitude;
|
||||
let lon = item.longitude;
|
||||
this.aircraftMap.forEach((aircraft) => {
|
||||
let lat = aircraft.data_model.lat;
|
||||
let lon = aircraft.data_model.lon;
|
||||
if (station.pos) {
|
||||
let distance = station.get_distance_from_base_station(lat, lon);
|
||||
if (distance > max_distance) {
|
||||
max_distance = distance;
|
||||
max_plane_pos = new L.LatLng(lat, lon);
|
||||
max_aircraft_icao = item.icao;
|
||||
max_aircraft_icao = aircraft.icao;
|
||||
}
|
||||
}
|
||||
});
|
||||
this.aircraftMap.forEach((aircraft) => {
|
||||
if (!new_map.has(aircraft.icao)) {
|
||||
aircraft.hide_track()
|
||||
aircraft.pos_marker.remove();
|
||||
}
|
||||
});
|
||||
if (max_plane_pos) {
|
||||
station.update_current_range(max_distance, max_plane_pos, max_aircraft_icao);
|
||||
if (!this.keep_mode || !station.max_plane_pos || max_distance > station.maxDistance) {
|
||||
@@ -372,11 +351,32 @@ export class Data_Source extends enhance.Base {
|
||||
station.clear_range();
|
||||
}
|
||||
}
|
||||
this.aircraftMap = new_map;
|
||||
await this.refresh_manual_tracked_aircraft();
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
apply_aircraft_delta(change_list: any[], removed_icaos: string[]) {
|
||||
this.apply_aircraft_items(change_list);
|
||||
removed_icaos.forEach((icao) => this.remove_aircraft(icao));
|
||||
this.refresh_aircraft_range();
|
||||
}
|
||||
apply_aircraft_snapshot(items: any[]) {
|
||||
const alive = new Set<string>();
|
||||
items.forEach((item) => alive.add(item.icao));
|
||||
for (const icao of Array.from(this.aircraftMap.keys())) {
|
||||
if (!alive.has(icao)) {
|
||||
this.remove_aircraft(icao);
|
||||
}
|
||||
}
|
||||
this.apply_aircraft_items(items);
|
||||
}
|
||||
apply_track_stream_list(list: any[]) {
|
||||
list.forEach((item: any) => {
|
||||
const aircraft = this.aircraftMap.get(item.icao);
|
||||
if (!aircraft) {
|
||||
return;
|
||||
}
|
||||
aircraft.is_show_path = true;
|
||||
aircraft.append_path_response(item);
|
||||
});
|
||||
}
|
||||
center_with_add(): React.JSX.Element {
|
||||
return (
|
||||
<div>不应该出现的 Data Source Center!</div>
|
||||
@@ -455,6 +455,102 @@ export class Data_Source extends enhance.Base {
|
||||
}
|
||||
}
|
||||
|
||||
class Aircraft_Stream_Client {
|
||||
ws: WebSocket | null = null;
|
||||
subscribe_timer: number | null = null;
|
||||
reconnect_timer: number | null = null;
|
||||
ensure_open() {
|
||||
if (this.ws && (this.ws.readyState === WebSocket.OPEN || this.ws.readyState === WebSocket.CONNECTING)) {
|
||||
return;
|
||||
}
|
||||
this.ws = new WebSocket(`ws://${server_url}/ws/aircraft_stream`);
|
||||
this.ws.onopen = () => this.send_subscription();
|
||||
this.ws.onmessage = (event) => this.handle_message(event);
|
||||
this.ws.onclose = () => this.schedule_reconnect();
|
||||
this.ws.onerror = () => this.ws?.close();
|
||||
}
|
||||
schedule_reconnect() {
|
||||
this.ws = null;
|
||||
if (this.reconnect_timer !== null) {
|
||||
return;
|
||||
}
|
||||
this.reconnect_timer = window.setTimeout(() => {
|
||||
this.reconnect_timer = null;
|
||||
this.ensure_open();
|
||||
this.schedule_subscribe();
|
||||
}, 1000);
|
||||
}
|
||||
schedule_subscribe() {
|
||||
this.ensure_open();
|
||||
if (this.subscribe_timer !== null) {
|
||||
return;
|
||||
}
|
||||
this.subscribe_timer = window.setTimeout(() => {
|
||||
this.subscribe_timer = null;
|
||||
this.send_subscription();
|
||||
}, 50);
|
||||
}
|
||||
send_subscription() {
|
||||
if (!this.ws || this.ws.readyState !== WebSocket.OPEN) {
|
||||
return;
|
||||
}
|
||||
this.ws.send(JSON.stringify({
|
||||
type: "subscribe",
|
||||
sources: this.source_payloads()
|
||||
}));
|
||||
}
|
||||
source_payloads() {
|
||||
const list = app.setting?.data_source_config.list.list || [];
|
||||
return list.filter((ds: Data_Source) => ds.enable).map((ds: Data_Source) => this.source_payload(ds));
|
||||
}
|
||||
source_payload(ds: Data_Source) {
|
||||
return {
|
||||
key: ds.key,
|
||||
monitor_all_aircraft_mode: ds.monitor_all_aircraft_mode,
|
||||
manual_track_icaos: Array.from(this.track_icaos(ds)),
|
||||
aircraft_versions: Object.fromEntries(ds.aircraft_change_versions),
|
||||
track_last_size: Object.fromEntries(Array.from(this.track_icaos(ds)).map((icao) => [icao, ds.aircraftMap.get(icao)?.last_size || 0]))
|
||||
};
|
||||
}
|
||||
track_icaos(ds: Data_Source): Set<string> {
|
||||
const ret = new Set<string>();
|
||||
if (ds.monitor_all_aircraft_mode) {
|
||||
for (const icao of ds.aircraftMap.keys()) {
|
||||
ret.add(icao);
|
||||
}
|
||||
} else {
|
||||
for (const icao of ds.manual_track_icao_set) {
|
||||
ret.add(icao);
|
||||
}
|
||||
}
|
||||
if (ds.active_aircraft) {
|
||||
ret.add(ds.active_aircraft.icao);
|
||||
}
|
||||
const selected = app.cesium_map?.selected_aircraft as Aircraft | null | undefined;
|
||||
if (selected?.data_source === ds) {
|
||||
ret.add(selected.icao);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
handle_message(event: MessageEvent) {
|
||||
const data = JSON.parse(String(event.data));
|
||||
if (data.type !== "aircraft_update" || !Array.isArray(data.sources)) {
|
||||
return;
|
||||
}
|
||||
for (const source of data.sources) {
|
||||
const ds = app.get_Data_Source(source.key);
|
||||
if (!ds) {
|
||||
continue;
|
||||
}
|
||||
ds.apply_aircraft_delta(Array.isArray(source.change_list) ? source.change_list : [], Array.isArray(source.removed_icaos) ? source.removed_icaos : []);
|
||||
ds.apply_track_stream_list(Array.isArray(source.tracks) ? source.tracks : []);
|
||||
}
|
||||
app.cesium_map?.sync_data_sources();
|
||||
app.leaflet_map?.data_source_show?.flush();
|
||||
}
|
||||
}
|
||||
const aircraft_stream = new Aircraft_Stream_Client();
|
||||
|
||||
|
||||
export class Serial_Data_Source extends Data_Source {
|
||||
port_name: string = "";
|
||||
|
||||
+3
-11
@@ -475,15 +475,6 @@ export class Aircraft {
|
||||
}
|
||||
]
|
||||
}*/
|
||||
async load_track_data() {
|
||||
const res = await axios.post(`${baseURL}/get_aircraft_track_list`, {
|
||||
data_source_key: this.data_source.key,
|
||||
icao: this.icao,
|
||||
last_size: this.last_size
|
||||
})
|
||||
return this.apply_track_data(res.data)
|
||||
}
|
||||
|
||||
apply_track_data(data: any) {
|
||||
if (!data) {
|
||||
return []
|
||||
@@ -508,7 +499,8 @@ export class Aircraft {
|
||||
}
|
||||
|
||||
append_path() {
|
||||
return this.load_track_data().then(list => this.append_loaded_path(list))
|
||||
this.data_source.request_aircraft_stream_update();
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
append_loaded_path(list: any[]) {
|
||||
@@ -548,7 +540,7 @@ export class Aircraft {
|
||||
show_path() {
|
||||
if (this.is_show_path == true) return;
|
||||
this.is_show_path = true;
|
||||
this.append_path()
|
||||
this.data_source.request_aircraft_stream_update();
|
||||
}
|
||||
|
||||
hide_path() {
|
||||
|
||||
+4
-23
@@ -77,7 +77,6 @@ type Aircraft_Position = {
|
||||
type Performance_Info = {
|
||||
fps: number
|
||||
frame_ms: number
|
||||
cpu_pressure: number
|
||||
js_heap_mb: number | null
|
||||
gpu_renderer: string
|
||||
tile_state: string
|
||||
@@ -120,9 +119,7 @@ export class Cesium_Map extends enhance.Base {
|
||||
performance_frame_count = 0;
|
||||
performance_frame_time_total = 0;
|
||||
performance_last_render_time = 0;
|
||||
performance_long_task_total = 0;
|
||||
performance_observer: PerformanceObserver | null = null;
|
||||
performance_info: Performance_Info = {fps: 0, frame_ms: 0, cpu_pressure: 0, js_heap_mb: null, gpu_renderer: "", tile_state: ""};
|
||||
performance_info: Performance_Info = {fps: 0, frame_ms: 0, js_heap_mb: null, gpu_renderer: "", tile_state: ""};
|
||||
context_menu: Cesium_Context_Menu | null = null;
|
||||
track_point_selection_entity: Cesium.Entity | null = null;
|
||||
prevent_context_menu_listener: ((event: Event) => void) | null = null;
|
||||
@@ -176,8 +173,6 @@ export class Cesium_Map extends enhance.Base {
|
||||
window.clearInterval(this.performance_timer);
|
||||
this.performance_timer = null;
|
||||
}
|
||||
this.performance_observer?.disconnect();
|
||||
this.performance_observer = null;
|
||||
if (this.viewer && this.post_render_listener) {
|
||||
this.viewer.scene.postRender.removeEventListener(this.post_render_listener);
|
||||
this.post_render_listener = null;
|
||||
@@ -430,16 +425,6 @@ export class Cesium_Map extends enhance.Base {
|
||||
this.post_render_listener = () => this.capture_performance_frame();
|
||||
this.viewer.scene.postRender.addEventListener(this.post_render_listener);
|
||||
this.performance_timer = window.setInterval(() => this.flush_performance_info(), 1000);
|
||||
try {
|
||||
this.performance_observer = new PerformanceObserver((list) => {
|
||||
for (const entry of list.getEntries()) {
|
||||
this.performance_long_task_total += entry.duration;
|
||||
}
|
||||
});
|
||||
this.performance_observer.observe({entryTypes: ["longtask"]});
|
||||
} catch {
|
||||
this.performance_observer = null;
|
||||
}
|
||||
}
|
||||
capture_performance_frame() {
|
||||
const now = performance.now();
|
||||
@@ -455,14 +440,12 @@ export class Cesium_Map extends enhance.Base {
|
||||
this.performance_info = {
|
||||
fps: frame_count,
|
||||
frame_ms,
|
||||
cpu_pressure: Math.min(100, Math.round(this.performance_long_task_total / 10)),
|
||||
js_heap_mb: this.read_js_heap_mb(),
|
||||
gpu_renderer: this.performance_info.gpu_renderer,
|
||||
tile_state: this.viewer?.scene.globe.tilesLoaded ? "loaded" : "loading"
|
||||
};
|
||||
this.performance_frame_count = 0;
|
||||
this.performance_frame_time_total = 0;
|
||||
this.performance_long_task_total = 0;
|
||||
this.flush();
|
||||
}
|
||||
read_js_heap_mb(): number | null {
|
||||
@@ -1266,10 +1249,9 @@ export class Cesium_Map extends enhance.Base {
|
||||
info.drawer.toggleOpen();
|
||||
}
|
||||
aircraft.refresh_base_information();
|
||||
aircraft.load_track_data().then(() => {
|
||||
if (!this.selected_aircraft || this.entity_key(this.selected_aircraft.data_source.key, this.selected_aircraft.icao) !== key) return;
|
||||
this.sync_aircraft(key, aircraft);
|
||||
});
|
||||
aircraft.is_show_path = true;
|
||||
aircraft.data_source.request_aircraft_stream_update();
|
||||
this.sync_aircraft(key, aircraft);
|
||||
this.flush();
|
||||
}
|
||||
clear_selected_aircraft() {
|
||||
@@ -1410,7 +1392,6 @@ export class Cesium_Map extends enhance.Base {
|
||||
<div style={{position: "absolute", left: 12, top: 92, zIndex: 2, minWidth: 170, maxWidth: 260, padding: "8px 10px", borderRadius: 4, background: "rgba(30, 30, 30, 0.72)", color: "#f6f6f6", fontSize: 12, lineHeight: 1.45, pointerEvents: "none"}}>
|
||||
<div style={{fontWeight: 700, color: "#fff000"}}>{`FPS ${info.fps}`}</div>
|
||||
<div>{`Frame ${info.frame_ms.toFixed(1)} ms`}</div>
|
||||
<div>{`CPU估算 ${info.cpu_pressure}%`}</div>
|
||||
<div>{`JS堆 ${info.js_heap_mb === null ? "N/A" : `${info.js_heap_mb.toFixed(1)} MB`}`}</div>
|
||||
<div>{`Tiles ${info.tile_state || "N/A"}`}</div>
|
||||
<div style={{color: "#ff8a33", wordBreak: "break-word"}}>{`GPU ${info.gpu_renderer || "N/A"}`}</div>
|
||||
|
||||
Reference in New Issue
Block a user