| 
									
										
										
										
											2024-02-15 17:39:59 +01:00
										 |  |  | import { Tiles } from "../../src/Models/TileRange" | 
					
						
							| 
									
										
										
										
											2024-02-22 11:55:32 +01:00
										 |  |  | import { Server } from "../server" | 
					
						
							| 
									
										
										
										
											2024-03-19 00:12:12 +01:00
										 |  |  | import Script from "../Script" | 
					
						
							| 
									
										
										
										
											2024-08-19 19:09:16 +02:00
										 |  |  | import { OsmPoiDatabase } from "./osmPoiDatabase" | 
					
						
							| 
									
										
										
										
											2024-02-15 17:39:59 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-02-19 14:22:16 +01:00
										 |  |  | class CachedSqlCount { | 
					
						
							|  |  |  |     private readonly _cache: Record< | 
					
						
							|  |  |  |         string, | 
					
						
							|  |  |  |         Record< | 
					
						
							|  |  |  |             number, | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 date: Date | 
					
						
							| 
									
										
										
										
											2024-02-19 15:06:54 +01:00
										 |  |  |                 entry: { count: number; lat: number; lon: number } | 
					
						
							| 
									
										
										
										
											2024-02-19 14:22:16 +01:00
										 |  |  |             } | 
					
						
							|  |  |  |         > | 
					
						
							|  |  |  |     > = {} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     private readonly _poiDatabase: OsmPoiDatabase | 
					
						
							|  |  |  |     private readonly _maxAge: number | 
					
						
							| 
									
										
										
										
											2024-02-19 15:06:54 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-02-19 14:22:16 +01:00
										 |  |  |     constructor(poiDatabase: OsmPoiDatabase, maxAge: number) { | 
					
						
							|  |  |  |         this._poiDatabase = poiDatabase | 
					
						
							|  |  |  |         this._maxAge = maxAge | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-02-19 15:06:54 +01:00
										 |  |  |     public async getCount( | 
					
						
							|  |  |  |         layer: string, | 
					
						
							|  |  |  |         tileId: number | 
					
						
							|  |  |  |     ): Promise<{ count: number; lat: number; lon: number }> { | 
					
						
							| 
									
										
										
										
											2024-02-19 14:22:16 +01:00
										 |  |  |         const cachedEntry = this._cache[layer]?.[tileId] | 
					
						
							|  |  |  |         if (cachedEntry) { | 
					
						
							|  |  |  |             const age = (new Date().getTime() - cachedEntry.date.getTime()) / 1000 | 
					
						
							|  |  |  |             if (age < this._maxAge) { | 
					
						
							| 
									
										
										
										
											2024-02-19 15:06:54 +01:00
										 |  |  |                 return cachedEntry.entry | 
					
						
							| 
									
										
										
										
											2024-02-19 14:22:16 +01:00
										 |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         const bbox = Tiles.tile_bounds_lon_lat(...Tiles.tile_from_index(tileId)) | 
					
						
							|  |  |  |         const count = await this._poiDatabase.getCount(layer, bbox) | 
					
						
							|  |  |  |         if (!this._cache[layer]) { | 
					
						
							|  |  |  |             this._cache[layer] = {} | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2024-02-19 15:06:54 +01:00
										 |  |  |         this._cache[layer][tileId] = { entry: count, date: new Date() } | 
					
						
							| 
									
										
										
										
											2024-02-19 14:22:16 +01:00
										 |  |  |         return count | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-19 00:12:12 +01:00
										 |  |  | class TileCountServer extends Script { | 
					
						
							|  |  |  |     constructor() { | 
					
						
							| 
									
										
										
										
											2024-04-13 02:40:21 +02:00
										 |  |  |         super( | 
					
						
							|  |  |  |             "Starts the tilecount server which calculates summary for a given tile, based on the database. Usage: [db-connection-string] [port=2345]" | 
					
						
							|  |  |  |         ) | 
					
						
							| 
									
										
										
										
											2024-03-19 00:12:12 +01:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     async main(args: string[]): Promise<void> { | 
					
						
							| 
									
										
										
										
											2024-08-19 19:09:16 +02:00
										 |  |  |         const connectionString = args[0] ?? "postgresql://user:password@localhost:5444" | 
					
						
							| 
									
										
										
										
											2024-03-19 00:12:12 +01:00
										 |  |  |         const port = Number(args[1] ?? 2345) | 
					
						
							| 
									
										
										
										
											2024-03-19 00:20:15 +01:00
										 |  |  |         console.log("Connecting to database", connectionString) | 
					
						
							| 
									
										
										
										
											2024-03-19 00:12:12 +01:00
										 |  |  |         const tcs = new OsmPoiDatabase(connectionString) | 
					
						
							|  |  |  |         const withCache = new CachedSqlCount(tcs, 14 * 60 * 60 * 24) | 
					
						
							|  |  |  |         new Server(port, { ignorePathPrefix: ["summary"] }, [ | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 mustMatch: "status.json", | 
					
						
							|  |  |  |                 mimetype: "application/json", | 
					
						
							|  |  |  |                 handle: async () => { | 
					
						
							|  |  |  |                     const layers = await tcs.getLayers() | 
					
						
							|  |  |  |                     const meta = await tcs.getMeta() | 
					
						
							| 
									
										
										
										
											2024-10-22 14:21:27 +02:00
										 |  |  |                     const mostSuitable = await tcs.findSuitableDatabases() | 
					
						
							| 
									
										
										
										
											2024-10-24 01:19:58 +02:00
										 |  |  |                     return JSON.stringify({ | 
					
						
							|  |  |  |                         meta, | 
					
						
							| 
									
										
										
										
											2024-10-22 14:21:27 +02:00
										 |  |  |                         suitableDatabases: mostSuitable, | 
					
						
							| 
									
										
										
										
											2024-10-24 01:19:58 +02:00
										 |  |  |                         layers: Array.from(layers), | 
					
						
							|  |  |  |                     }) | 
					
						
							| 
									
										
										
										
											2024-03-19 00:12:12 +01:00
										 |  |  |                 }, | 
					
						
							|  |  |  |             }, | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 mustMatch: /[a-zA-Z0-9+_-]+\/[0-9]+\/[0-9]+\/[0-9]+\.json/, | 
					
						
							|  |  |  |                 mimetype: "application/json", // "application/vnd.geo+json",
 | 
					
						
							|  |  |  |                 async handle(path) { | 
					
						
							|  |  |  |                     const [layers, z, x, y] = path.split(".")[0].split("/") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                     let sum = 0 | 
					
						
							|  |  |  |                     const properties: Record<string, number> = {} | 
					
						
							|  |  |  |                     const availableLayers = await tcs.getLayers() | 
					
						
							|  |  |  |                     let latSum = 0 | 
					
						
							|  |  |  |                     let lonSum = 0 | 
					
						
							|  |  |  |                     for (const layer of layers.split("+")) { | 
					
						
							|  |  |  |                         if (!availableLayers.has(layer)) { | 
					
						
							|  |  |  |                             continue | 
					
						
							|  |  |  |                         } | 
					
						
							|  |  |  |                         const count = await withCache.getCount( | 
					
						
							|  |  |  |                             layer, | 
					
						
							|  |  |  |                             Tiles.tile_index(Number(z), Number(x), Number(y)) | 
					
						
							|  |  |  |                         ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                         properties[layer] = count.count | 
					
						
							|  |  |  |                         if (count.count !== 0) { | 
					
						
							|  |  |  |                             latSum += count.lat * count.count | 
					
						
							|  |  |  |                             lonSum += count.lon * count.count | 
					
						
							|  |  |  |                             sum += count.count | 
					
						
							|  |  |  |                         } | 
					
						
							|  |  |  |                     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                     properties["lon"] = lonSum / sum | 
					
						
							|  |  |  |                     properties["lat"] = latSum / sum | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                     return JSON.stringify({ ...properties, total: sum }) | 
					
						
							|  |  |  |                 }, | 
					
						
							|  |  |  |             }, | 
					
						
							|  |  |  |         ]) | 
					
						
							| 
									
										
										
										
											2024-03-19 00:20:15 +01:00
										 |  |  |         console.log("Started server on port", port) | 
					
						
							| 
									
										
										
										
											2024-03-19 00:12:12 +01:00
										 |  |  |         console.log( | 
					
						
							|  |  |  |             ">>>", | 
					
						
							|  |  |  |             await tcs.getCount("drinking_water", [ | 
					
						
							|  |  |  |                 [3.194358020772171, 51.228073636083394], | 
					
						
							|  |  |  |                 [3.2839964396059145, 51.172701162680994], | 
					
						
							|  |  |  |             ]) | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | new TileCountServer().run() |