More work on layerserver, generate

This commit is contained in:
Pieter Vander Vennet 2024-02-18 15:59:28 +01:00
parent f0823f4c4d
commit 6b507504f8
13 changed files with 124 additions and 70 deletions

9
Docs/ServerConfig/cache/Caddyfile vendored Normal file
View file

@ -0,0 +1,9 @@
cache.mapcomplete.org {
reverse_proxy /mvt {
to http://127.0.0.1:7800
}
reverse_proxy /summary {
to http://127.0.0.1:2345
}
}

15
Docs/ServerConfig/cache/cache.txt vendored Normal file
View file

@ -0,0 +1,15 @@
# Cache.mapComplete.org server config
The "cache"-server is hosted at nerdlab.
It has a full OSM-copy on disk, and has a Postgis/Postgres database with a table for every layer for quick access. It should run the tileserver and the summaryserver
## Dyndns
https://dynamicdns.park-your-domain.com/update?host=cache&domain=mapcomplete.org&password=[ddns_password]
## Setup
See SettingUpPSQL.md

View file

@ -0,0 +1,5 @@
# Hetzner
This server hosts the studio files and is used for expermintal builds.
For used hosts, see the Caddyfile

View file

@ -54,7 +54,7 @@ pg_tileserv kan hier gedownload worden: https://github.com/CrunchyData/pg_tilese
```` ````
export DATABASE_URL=postgresql://user:password@localhost:5444/osm-poi export DATABASE_URL=postgresql://user:password@localhost:5444/osm-poi
./pg_tileserv nohup ./pg_tileserv &
```` ````
Tiles are available at: Tiles are available at:
@ -64,3 +64,8 @@ map.addSource("drinking_water", {
"tiles": ["http://127.0.0.2:7800/public.drinking_water/{z}/{x}/{y}.pbf"] // http://127.0.0.2:7800/public.drinking_water.json", "tiles": ["http://127.0.0.2:7800/public.drinking_water/{z}/{x}/{y}.pbf"] // http://127.0.0.2:7800/public.drinking_water.json",
}) })
```` ````
# Rebooting:
-> Restart the docker container
->

View file

@ -1,2 +1,2 @@
SPDX-FileCopyrightText: Pieter Vander Vennet SPDX-FileCopyrightText: Pieter Vander Vennet
SPDX-License-Identifier: CC0 SPDX-License-Identifier: CC0-1.0

View file

@ -1,2 +1,2 @@
SPDX-FileCopyrightText: Pieter Vander Vennet SPDX-FileCopyrightText: Pieter Vander Vennet
SPDX-License-Identifier: CC0 SPDX-License-Identifier: CC0-1.0

View file

@ -59,4 +59,3 @@
"minzoom": 16 "minzoom": 16
} }
} }
}

View file

@ -21,7 +21,7 @@
"oauth_secret": "NBWGhWDrD3QDB35xtVuxv4aExnmIt4FA_WgeLtwxasg", "oauth_secret": "NBWGhWDrD3QDB35xtVuxv4aExnmIt4FA_WgeLtwxasg",
"url": "https://www.openstreetmap.org" "url": "https://www.openstreetmap.org"
}, },
"mvt_layer_server": "http://127.0.0.1:7800/public.{type}_{layer}/{z}/{x}/{y}.pbf", "mvt_layer_server": "http://cache.mapcomplete.org/mvt/public.{type}_{layer}/{z}/{x}/{y}.pbf",
"disabled:oauth_credentials": { "disabled:oauth_credentials": {
"##": "DEV", "##": "DEV",
"#": "This client-id is registered by 'MapComplete' on https://master.apis.dev.openstreetmap.org/", "#": "This client-id is registered by 'MapComplete' on https://master.apis.dev.openstreetmap.org/",

View file

@ -28,7 +28,7 @@ class OsmPoiDatabase {
private static readonly prefixes: ReadonlyArray<string> = ["pois", "lines", "polygons"] private static readonly prefixes: ReadonlyArray<string> = ["pois", "lines", "polygons"]
private readonly _client: Client private readonly _client: Client
private isConnected = false private isConnected = false
private supportedLayers: string[] = undefined private supportedLayers: Set<string> = undefined
private metaCache: PoiDatabaseMeta = undefined private metaCache: PoiDatabaseMeta = undefined
private metaCacheDate: Date = undefined private metaCacheDate: Date = undefined
@ -64,7 +64,7 @@ class OsmPoiDatabase {
this._client.end() this._client.end()
} }
async getLayers(): Promise<string[]> { async getLayers(): Promise<Set<string>> {
if (this.supportedLayers !== undefined) { if (this.supportedLayers !== undefined) {
return this.supportedLayers return this.supportedLayers
} }
@ -74,8 +74,8 @@ class OsmPoiDatabase {
"WHERE table_schema = 'public' AND table_name LIKE 'lines_%';" "WHERE table_schema = 'public' AND table_name LIKE 'lines_%';"
) )
const layers = result.rows.map((r) => r.table_name.substring("lines_".length)) const layers = result.rows.map((r) => r.table_name.substring("lines_".length))
this.supportedLayers = layers this.supportedLayers = new Set(layers)
return layers return this.supportedLayers
} }
async getMeta(): Promise<PoiDatabaseMeta> { async getMeta(): Promise<PoiDatabaseMeta> {
@ -218,7 +218,12 @@ const server = new Server(2345, [
let sum = 0 let sum = 0
let properties: Record<string, number> = {} let properties: Record<string, number> = {}
const availableLayers = await tcs.getLayers()
for (const layer of layers.split("+")) { for (const layer of layers.split("+")) {
console.log("Getting layer", layer)
if (!availableLayers.has(layer)) {
continue
}
const count = await tcs.getCount( const count = await tcs.getCount(
layer, layer,
Tiles.tile_bounds_lon_lat(Number(z), Number(x), Number(y)) Tiles.tile_bounds_lon_lat(Number(z), Number(x), Number(y))

View file

@ -11,9 +11,7 @@ import DynamicGeoJsonTileSource from "../TiledFeatureSource/DynamicGeoJsonTileSo
import { BBox } from "../../BBox" import { BBox } from "../../BBox"
import LocalStorageFeatureSource from "../TiledFeatureSource/LocalStorageFeatureSource" import LocalStorageFeatureSource from "../TiledFeatureSource/LocalStorageFeatureSource"
import FullNodeDatabaseSource from "../TiledFeatureSource/FullNodeDatabaseSource" import FullNodeDatabaseSource from "../TiledFeatureSource/FullNodeDatabaseSource"
import { Features } from "@rgossiaux/svelte-headlessui/types"
import DynamicMvtileSource from "../TiledFeatureSource/DynamicMvtTileSource" import DynamicMvtileSource from "../TiledFeatureSource/DynamicMvtTileSource"
import { layouts } from "chart.js"
/** /**
* This source will fetch the needed data from various sources for the given layout. * This source will fetch the needed data from various sources for the given layout.
@ -21,17 +19,18 @@ import { layouts } from "chart.js"
* Note that special layers (with `source=null` will be ignored) * Note that special layers (with `source=null` will be ignored)
*/ */
export default class LayoutSource extends FeatureSourceMerger { export default class LayoutSource extends FeatureSourceMerger {
private readonly _isLoading: UIEventSource<boolean> = new UIEventSource<boolean>(false)
/** /**
* Indicates if a data source is loading something * Indicates if a data source is loading something
*/ */
public readonly isLoading: Store<boolean> = this._isLoading public readonly isLoading: Store<boolean>
constructor( constructor(
layers: LayerConfig[], layers: LayerConfig[],
featureSwitches: FeatureSwitchState, featureSwitches: FeatureSwitchState,
mapProperties: { bounds: Store<BBox>; zoom: Store<number> }, mapProperties: { bounds: Store<BBox>; zoom: Store<number> },
backend: string, backend: string,
isDisplayed: (id: string) => Store<boolean>, isDisplayed: (id: string) => Store<boolean>,
mvtAvailableLayers: Set<string>,
fullNodeDatabaseSource?: FullNodeDatabaseSource fullNodeDatabaseSource?: FullNodeDatabaseSource
) { ) {
const { bounds, zoom } = mapProperties const { bounds, zoom } = mapProperties
@ -47,47 +46,60 @@ export default class LayoutSource extends FeatureSourceMerger {
maxAge: l.maxAgeOfCache, maxAge: l.maxAgeOfCache,
}) })
) )
console.log(mapProperties) const mvtSources: FeatureSource[] = osmLayers
const mvtSources: FeatureSource[] = osmLayers.map(l => LayoutSource.setupMvtSource(l, mapProperties, isDisplayed(l.id))) .filter((f) => mvtAvailableLayers.has(f.id))
.map((l) => LayoutSource.setupMvtSource(l, mapProperties, isDisplayed(l.id)))
const nonMvtSources = []
const nonMvtLayers = osmLayers.filter((l) => !mvtAvailableLayers.has(l.id))
const isLoading = new UIEventSource(false)
if (nonMvtLayers.length > 0) {
console.log(
"Layers ",
nonMvtLayers.map((l) => l.id),
" cannot be fetched from the cache server, defaulting to overpass/OSM-api"
)
const overpassSource = LayoutSource.setupOverpass(
osmLayers,
bounds,
zoom,
featureSwitches
)
const osmApiSource = LayoutSource.setupOsmApiSource(
osmLayers,
bounds,
zoom,
backend,
featureSwitches,
fullNodeDatabaseSource
)
nonMvtSources.push(overpassSource, osmApiSource)
/* function setIsLoading() {
const overpassSource = LayoutSource.setupOverpass( const loading = overpassSource?.runningQuery?.data || osmApiSource?.isRunning?.data
osmLayers, isLoading.setData(loading)
bounds, }
zoom, overpassSource?.runningQuery?.addCallbackAndRun((_) => setIsLoading())
featureSwitches osmApiSource?.isRunning?.addCallbackAndRun((_) => setIsLoading())
)//*/ }
/*
const osmApiSource = LayoutSource.setupOsmApiSource(
osmLayers,
bounds,
zoom,
backend,
featureSwitches,
fullNodeDatabaseSource
)*/
const geojsonSources: FeatureSource[] = geojsonlayers.map((l) => const geojsonSources: FeatureSource[] = geojsonlayers.map((l) =>
LayoutSource.setupGeojsonSource(l, mapProperties, isDisplayed(l.id)) LayoutSource.setupGeojsonSource(l, mapProperties, isDisplayed(l.id))
) )
super(...geojsonSources, ...fromCache, ...mvtSources, ...nonMvtSources)
super(...geojsonSources, ...fromCache, ...mvtSources) this.isLoading = isLoading
const self = this
function setIsLoading() {
// const loading = overpassSource?.runningQuery?.data || osmApiSource?.isRunning?.data
// self._isLoading.setData(loading)
}
// overpassSource?.runningQuery?.addCallbackAndRun((_) => setIsLoading())
// osmApiSource?.isRunning?.addCallbackAndRun((_) => setIsLoading())
} }
private static setupMvtSource(layer: LayerConfig, mapProperties: { zoom: Store<number>; bounds: Store<BBox> }, isActive?: Store<boolean>): FeatureSource{ private static setupMvtSource(
layer: LayerConfig,
mapProperties: { zoom: Store<number>; bounds: Store<BBox> },
isActive?: Store<boolean>
): FeatureSource {
return new DynamicMvtileSource(layer, mapProperties, { isActive }) return new DynamicMvtileSource(layer, mapProperties, { isActive })
} }
private static setupGeojsonSource( private static setupGeojsonSource(
layer: LayerConfig, layer: LayerConfig,
mapProperties: { zoom: Store<number>; bounds: Store<BBox> }, mapProperties: { zoom: Store<number>; bounds: Store<BBox> },

View file

@ -7,6 +7,7 @@ import Combine from "./UI/Base/Combine"
import { SubtleButton } from "./UI/Base/SubtleButton" import { SubtleButton } from "./UI/Base/SubtleButton"
import { Utils } from "./Utils" import { Utils } from "./Utils"
import Download from "./assets/svg/Download.svelte" import Download from "./assets/svg/Download.svelte"
import Constants from "./Models/Constants"
function webgl_support() { function webgl_support() {
try { try {
@ -19,38 +20,41 @@ function webgl_support() {
return false return false
} }
} }
async function availableLayers(): Promise<Set<string>> {
const status = await Utils.downloadJson(Constants.VectorTileServer + "/status.json")
return new Set<string>(status.layers)
}
async function main() {
// @ts-ignore
try {
if (!webgl_support()) {
throw "WebGL is not supported or not enabled. This is essential for MapComplete to function, please enable this."
}
const [layout, availableLayers] = await Promise.all([
DetermineLayout.GetLayout(),
await availableLayers(),
])
const state = new ThemeViewState(layout)
const main = new SvelteUIElement(ThemeViewGUI, { state })
main.AttachTo("maindiv")
} catch (err) {
console.error("Error while initializing: ", err, err.stack)
const customDefinition = DetermineLayout.getCustomDefinition()
new Combine([
new FixedUiElement(err).SetClass("block alert"),
// @ts-ignore customDefinition?.length > 0
try { ? new SubtleButton(new SvelteUIElement(Download), "Download the raw file").onClick(
if (!webgl_support()) { () =>
throw "WebGL is not supported or not enabled. This is essential for MapComplete to function, please enable this."
}
DetermineLayout.GetLayout()
.then((layout) => {
const state = new ThemeViewState(layout)
const main = new SvelteUIElement(ThemeViewGUI, { state })
main.AttachTo("maindiv")
})
.catch((err) => {
console.error("Error while initializing: ", err, err.stack)
const customDefinition = DetermineLayout.getCustomDefinition()
new Combine([
new FixedUiElement(err).SetClass("block alert"),
customDefinition?.length > 0
? new SubtleButton(
new SvelteUIElement(Download),
"Download the raw file"
).onClick(() =>
Utils.offerContentsAsDownloadableFile( Utils.offerContentsAsDownloadableFile(
DetermineLayout.getCustomDefinition(), DetermineLayout.getCustomDefinition(),
"mapcomplete-theme.json", "mapcomplete-theme.json",
{ mimetype: "application/json" } { mimetype: "application/json" }
) )
) )
: undefined, : undefined,
]).AttachTo("maindiv") ]).AttachTo("maindiv")
}) }
} catch (err) {
new FixedUiElement(err).SetClass("block alert").AttachTo("maindiv")
} }
main().then((_) => {})