forked from MapComplete/MapComplete
95 lines
3.5 KiB
TypeScript
95 lines
3.5 KiB
TypeScript
import { Server } from "./server"
|
|
import Script from "./Script"
|
|
import { OfflineBasemapManager } from "../src/Logic/OfflineBasemapManager"
|
|
import http from "node:http"
|
|
import { ServerResponse } from "http"
|
|
import { existsSync, statSync, writeFileSync } from "fs"
|
|
import ScriptUtils from "./ScriptUtils"
|
|
import { PmTilesExtractGenerator } from "./pmTilesExtractGenerator"
|
|
|
|
class ServerPmTileExtracts extends Script {
|
|
private static FILE_IS_STALE_AFTER_SEC = 30 * 24 * 60 * 60
|
|
|
|
constructor() {
|
|
super(
|
|
"Starts a server that serves PMtiles. Usage:\n" +
|
|
"sourceFile cachedir [portnumber??2346]"
|
|
)
|
|
}
|
|
|
|
async main(args: string[]): Promise<void> {
|
|
if (args.length < 2) {
|
|
this.printHelp()
|
|
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)
|
|
|
|
const creationDates = new Map<string, Date>()
|
|
|
|
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(", ")}`
|
|
}
|
|
|
|
const targetFile = generator.getFilename(z, x, y)
|
|
|
|
let targetCreationDate = creationDates.get(targetFile)
|
|
let isStale =
|
|
targetCreationDate === undefined
|
|
? false
|
|
: new Date().getTime() - targetCreationDate.getTime() >
|
|
1000 * ServerPmTileExtracts.FILE_IS_STALE_AFTER_SEC
|
|
|
|
if (isStale || !existsSync(targetFile)) {
|
|
ScriptUtils.createParentDir(targetFile)
|
|
console.log("Creating", targetFile)
|
|
const start = new Date()
|
|
await generator.generateArchive(z, x, y)
|
|
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)
|
|
}
|
|
|
|
if (req.destroyed) {
|
|
return null
|
|
}
|
|
res.writeHead(200, { "Content-Type": "application/octet-stream" })
|
|
Server.sendFile(targetFile, res)
|
|
|
|
return null
|
|
},
|
|
},
|
|
])
|
|
}
|
|
}
|
|
|
|
new ServerPmTileExtracts().run()
|