MapComplete/scripts/serverPmTileExtracts.ts

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

101 lines
3.8 KiB
TypeScript
Raw Normal View History

import { Server } from "./server"
import Script from "./Script"
import { OfflineBasemapManager } from "../src/Logic/OfflineBasemapManager"
import http from "node:http"
import { ServerResponse } from "http"
2025-09-26 13:51:12 +02:00
import { existsSync, statSync, writeFileSync } from "fs"
import ScriptUtils from "./ScriptUtils"
import { PmTilesExtractGenerator } from "./pmTilesExtractGenerator"
class ServerPmTileExtracts extends Script {
2025-09-26 13:51:12 +02:00
private static FILE_IS_STALE_AFTER_SEC = 30 * 24 * 60 * 60
constructor() {
2025-10-11 14:03:42 +02:00
super(
"Starts a server that serves PMtiles. Usage:\n" +
"sourceFile cachedir [portnumber??2346]"
)
}
async main(args: string[]): Promise<void> {
2025-10-11 14:03:42 +02:00
if (args.length < 2) {
this.printHelp()
2025-10-11 14:03:42 +02:00
throw "!!! Please, specify a source- and cachedir !!!"
}
const sourcefile = args[0]
const targetDir = args[1]
const port = Number(args[2] ?? "2346")
const zoomlevels = OfflineBasemapManager.zoomelevels
const generator = new PmTilesExtractGenerator(sourcefile, targetDir)
2025-09-26 13:51:12 +02:00
const creationDates = new Map<string, Date>()
2025-10-11 14:03:42 +02:00
new Server(port, {}, [
{
mustMatch: /\d+\/\d+\/\d+.pmtiles/,
unmanaged: true,
mimetype: "application/octet-stream",
handle: async (
path: string,
queryParams: URLSearchParams,
req: http.IncomingMessage,
body: string,
res: ServerResponse
) => {
const [z, x, y] = path
.split(".")[0]
.split("/")
.map((x) => Number(x))
if (!(z in zoomlevels)) {
throw `Invalid zoomlevel ${z} (x: ${x}, y: ${y}, must be one of ${Array.from(
Object.keys(zoomlevels)
).join(", ")}`
}
2025-09-26 13:51:12 +02:00
2025-10-11 14:03:42 +02:00
const targetFile = generator.getFilename(z, x, y)
2025-09-26 13:51:12 +02:00
2025-10-11 14:03:42 +02:00
let targetCreationDate = creationDates.get(targetFile)
let isStale =
targetCreationDate === undefined
? false
: new Date().getTime() - targetCreationDate.getTime() >
1000 * ServerPmTileExtracts.FILE_IS_STALE_AFTER_SEC
2025-10-11 14:03:42 +02:00
if (isStale || !existsSync(targetFile)) {
ScriptUtils.createParentDir(targetFile)
console.log("Creating", targetFile)
const start = new Date()
const maxzoom = OfflineBasemapManager.zoomelevels[z]
await generator.generateArchive(z, x, y, maxzoom)
2025-10-11 14:03:42 +02:00
const stop = new Date()
console.log(
"Creating ",
targetFile,
"took",
stop.getTime() - start.getTime() + "ms"
)
} else if (targetCreationDate === undefined) {
const stats = statSync(targetFile)
creationDates.set(targetFile, stats.mtime)
}
2025-10-11 14:03:42 +02:00
if (req.destroyed) {
return null
2025-10-11 14:03:42 +02:00
}
const stats = statSync(targetFile)
res.writeHead(200, { "Content-Type": "application/octet-stream" ,
"Content-Length": stats.size
})
2025-10-11 14:03:42 +02:00
Server.sendFile(targetFile, res)
return null
},
2025-10-11 14:03:42 +02:00
},
])
}
}
new ServerPmTileExtracts().run()