import { readFile, mkdir, rename, rm, writeFile } from 'node:fs/promises'; import { writeFileSync } from 'node:fs'; import { fetchOverpass, type BBox } from '../src/osm/overpass'; import { generateWorldSync } from '../src/gen/generate'; import { exportCity } from './export/index'; const job = JSON.parse(await readFile(process.argv[2], 'utf8')) as { bbox: BBox; name: string; seed: number; cityId: string; output: string; maxBuildings: number; progress: string; input?:string; }; const progress = async (stage: string) => writeFile(job.progress,JSON.stringify({stage})); async function run() { await progress('Загрузка OSM'); const elements = job.input ? JSON.parse(await readFile(job.input,'utf8')).elements : await fetchOverpass(job.bbox, stage => writeFileSync(job.progress, JSON.stringify({stage}))); if (elements.filter(e => e.tags?.building && e.tags.building !== 'no').length > job.maxBuildings) throw new Error('Превышен лимит зданий'); await progress('Генерация'); const world = generateWorldSync(elements,job.bbox,job.name,job.seed); if (world.buildings.length > job.maxBuildings) throw new Error('Превышен лимит зданий'); world.id = job.cityId; await progress('Экспорт'); const temporary = `${job.output}.pending`; try { // A timed-out worker may leave its unpublished staging directory behind. await rm(temporary,{recursive:true,force:true}); await mkdir(temporary,{recursive:true}); await exportCity(world,temporary); await rename(temporary,job.output); } catch (error) { await rm(temporary,{recursive:true,force:true}); throw error; } await progress('Готово'); } await run().catch(error => { console.error(`CITYGEN_ERROR:${JSON.stringify({message: error instanceof Error ? error.message : String(error)})}`); process.exitCode = 1; });