mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-04 18:34:02 +00:00
The flight, military and vessel feeds were named after the providers the bundled server uses (/api/opensky, /api/adsblol/mil, /api/ais-live and their track routes; createOpenSkySource, createAdsbLolSource, createAisStreamSource). Any server should be able to answer a feed from its own provider, so the feeds are now: /api/flights /api/flights/track?icao24= /api/military /api/military/track?hex= /api/vessels /api/vessels/track?mmsi= with createFlightSource, createMilitarySource and createVesselSource. The old routes are removed. Each server names its provider in X-Feed-Source (the bundled server sends OpenSky Network, adsb.lol and AISStream, so its attribution is unchanged) and the military feed's cache state and age in X-Feed-Cache and X-Feed-Age-Ms. Sources report the provider the server names and fall back to the feed's name.
115 lines
5.1 KiB
JavaScript
115 lines
5.1 KiB
JavaScript
/**
|
|
* The default services Core's tools read: the layers' portable source
|
|
* factories and the application request services. `fetchImpl` must resolve
|
|
* the sources' relative `/api/...` paths; in a browser the page's own fetch
|
|
* does, and elsewhere a caller supplies a resolving fetch. `appUrl` is the
|
|
* address the app is served from; `app.fetch` requests the app's own paths.
|
|
* `panelKey`, when the panel is offered, is the key its page carries, which
|
|
* the panel's requests must include.
|
|
*/
|
|
|
|
import { createAlprTileSource } from '../layers/alpr/source.js';
|
|
import { GBFS_CITY_REGISTRY } from '../layers/bikeshare/registry.js';
|
|
import { createBikeshareSource } from '../layers/bikeshare/source.js';
|
|
import { createCctvSource } from '../layers/cctv/source.js';
|
|
import { createCycloneSource } from '../layers/cyclones/source.js';
|
|
import { createUsgsEarthquakeSource } from '../layers/earthquakes/source.js';
|
|
import { createFirmsSource } from '../layers/firms/source.js';
|
|
import { createInstallationSource } from '../layers/installations/source.js';
|
|
import { createLaunchSource } from '../layers/launches/source.js';
|
|
import { createWfigsPerimeterSource } from '../layers/perimeters/source.js';
|
|
import { createRadioSource } from '../layers/radio/source.js';
|
|
import { createBundledCableSource } from '../layers/submarineCables/bundledSource.js';
|
|
import { searchHls } from '../layers/recentImagery/catalog.js';
|
|
import { rankLatest, wvsSnapshotUrl } from '../layers/recentImagery/model.js';
|
|
import { createSatelliteSource } from '../layers/satellites/source.js';
|
|
import { createTrafficSource } from '../layers/traffic/source.js';
|
|
import { createTransitSource } from '../layers/transit/source.js';
|
|
import { createWeatherSource } from '../layers/weather/source.js';
|
|
import { createWindSource } from '../layers/wind/source.js';
|
|
import { createApplicationRequestServices } from '../services/requests.js';
|
|
import { createEventPackSource } from '../sources/eventPacks.js';
|
|
import { createInfrastructureSource } from '../sources/infrastructureData.js';
|
|
import {
|
|
createMilitarySource,
|
|
createVesselSource,
|
|
createFlightSource,
|
|
} from '../sources/live/standalone.js';
|
|
import {
|
|
createGeocodePlaceService,
|
|
createPlaceSearchService,
|
|
createRouteService,
|
|
} from './places.js';
|
|
|
|
/** Construct every service Core's tools read. */
|
|
export function createToolServices({ fetchImpl, appUrl, panelKey }) {
|
|
if (typeof fetchImpl !== 'function')
|
|
throw new TypeError('A fetch implementation is required');
|
|
const requests = createApplicationRequestServices({ fetchImpl });
|
|
return {
|
|
app: { baseUrl: appUrl, fetch: fetchImpl, panelKey },
|
|
earthquakes: createUsgsEarthquakeSource({ fetchImpl }),
|
|
fires: createFirmsSource({ fetchImpl }),
|
|
launches: createLaunchSource({ fetchImpl }),
|
|
aircraft: createFlightSource({ fetchImpl }),
|
|
military: createMilitarySource({ fetchImpl }),
|
|
vessels: createVesselSource({
|
|
fetchImpl,
|
|
origin: () => new URL(appUrl).origin,
|
|
}),
|
|
satellites: createSatelliteSource({ fetchImpl }),
|
|
cctv: createCctvSource({ fetchImpl }),
|
|
radio: createRadioSource({ fetchImpl }),
|
|
placeSearch: createPlaceSearchService({ fetchImpl }),
|
|
routing: createRouteService({ fetchImpl }),
|
|
bikeshare: {
|
|
systems: GBFS_CITY_REGISTRY,
|
|
getStations: createBikeshareSource({ fetchImpl }).getStations,
|
|
},
|
|
transit: createTransitSource({ fetchImpl }),
|
|
traffic: createTrafficSource({ fetchImpl, tileFetchImpl: fetchImpl }),
|
|
weather: requests.weather,
|
|
weatherMaps: createWeatherSource({ fetchImpl }),
|
|
wind: createWindSource({ fetchImpl }),
|
|
imagery: createImageryService({ fetchImpl }),
|
|
cables: createBundledCableSource({ fetchImpl }),
|
|
alpr: createAlprTileSource({ tileFetchImpl: fetchImpl }),
|
|
infrastructure: createInfrastructureSource({ fetchImpl }),
|
|
events: createEventPackSource({ fetchImpl }),
|
|
regional: requests.regional,
|
|
terrain: requests.terrain,
|
|
summary: requests.summary,
|
|
features: requests.features,
|
|
cyclones: createCycloneSource({ fetchImpl }),
|
|
perimeters: createWfigsPerimeterSource({ fetchImpl }),
|
|
installations: createInstallationSource({
|
|
fetchImpl,
|
|
tileFetchImpl: fetchImpl,
|
|
}),
|
|
places: createGeocodePlaceService({ fetchImpl }),
|
|
};
|
|
}
|
|
|
|
/** Recent keyless satellite imagery: the clearest recent day and its image. */
|
|
function createImageryService({ fetchImpl }) {
|
|
return {
|
|
async latest({ box, signal }) {
|
|
const result = await searchHls({ box, fetchImpl, signal });
|
|
return {
|
|
...rankLatest(result.candidates, { truncated: result.truncated }),
|
|
errors: result.errors,
|
|
};
|
|
},
|
|
async getSnapshot({ product, day, box, width, height, signal }) {
|
|
const response = await fetchImpl(
|
|
wvsSnapshotUrl({ product, day, box, width, height }),
|
|
{ signal },
|
|
);
|
|
if (!response.ok) throw new Error(`Imagery HTTP ${response.status}`);
|
|
const bytes = new Uint8Array(await response.arrayBuffer());
|
|
const type = response.headers.get('content-type') || '';
|
|
return { contentType: type.split(';')[0].trim().toLowerCase(), bytes };
|
|
},
|
|
};
|
|
}
|