mirror of
https://github.com/Crosstalk-Solutions/project-nomad.git
synced 2026-04-03 23:36:17 +02:00
feat(Maps): automatically download base assets if missing
This commit is contained in:
parent
e7336f2a8e
commit
c8de767052
|
|
@ -13,7 +13,7 @@ export default class MapsController {
|
||||||
constructor(private mapService: MapService) {}
|
constructor(private mapService: MapService) {}
|
||||||
|
|
||||||
async index({ inertia }: HttpContext) {
|
async index({ inertia }: HttpContext) {
|
||||||
const baseAssetsCheck = await this.mapService.checkBaseAssetsExist()
|
const baseAssetsCheck = await this.mapService.ensureBaseAssets()
|
||||||
const regionFiles = await this.mapService.listRegions()
|
const regionFiles = await this.mapService.listRegions()
|
||||||
return inertia.render('maps', {
|
return inertia.render('maps', {
|
||||||
maps: {
|
maps: {
|
||||||
|
|
@ -23,11 +23,6 @@ export default class MapsController {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async checkBaseAssets({}: HttpContext) {
|
|
||||||
const exists = await this.mapService.checkBaseAssetsExist()
|
|
||||||
return { exists }
|
|
||||||
}
|
|
||||||
|
|
||||||
async downloadBaseAssets({ request }: HttpContext) {
|
async downloadBaseAssets({ request }: HttpContext) {
|
||||||
const payload = await request.validateUsing(remoteDownloadValidatorOptional)
|
const payload = await request.validateUsing(remoteDownloadValidatorOptional)
|
||||||
await this.mapService.downloadBaseAssets(payload.url)
|
await this.mapService.downloadBaseAssets(payload.url)
|
||||||
|
|
@ -75,6 +70,15 @@ export default class MapsController {
|
||||||
}
|
}
|
||||||
|
|
||||||
async styles({ response }: HttpContext) {
|
async styles({ response }: HttpContext) {
|
||||||
|
// Automatically ensure base assets are present before generating styles
|
||||||
|
const baseAssetsExist = await this.mapService.ensureBaseAssets()
|
||||||
|
if (!baseAssetsExist) {
|
||||||
|
return response.status(500).send({
|
||||||
|
message:
|
||||||
|
'Base map assets are missing and could not be downloaded. Please check your connection and try again.',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
const styles = await this.mapService.generateStylesJSON()
|
const styles = await this.mapService.generateStylesJSON()
|
||||||
return response.json(styles)
|
return response.json(styles)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,7 @@ export default class SettingsController {
|
||||||
}
|
}
|
||||||
|
|
||||||
async maps({ inertia }: HttpContext) {
|
async maps({ inertia }: HttpContext) {
|
||||||
const baseAssetsCheck = await this.mapService.checkBaseAssetsExist();
|
const baseAssetsCheck = await this.mapService.ensureBaseAssets();
|
||||||
const regionFiles = await this.mapService.listRegions();
|
const regionFiles = await this.mapService.listRegions();
|
||||||
return inertia.render('settings/maps', {
|
return inertia.render('settings/maps', {
|
||||||
maps: {
|
maps: {
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,6 @@ import { extract } from 'tar'
|
||||||
import env from '#start/env'
|
import env from '#start/env'
|
||||||
import {
|
import {
|
||||||
listDirectoryContentsRecursive,
|
listDirectoryContentsRecursive,
|
||||||
listDirectoryContents,
|
|
||||||
getFileStatsIfExists,
|
getFileStatsIfExists,
|
||||||
deleteFileIfExists,
|
deleteFileIfExists,
|
||||||
getFile,
|
getFile,
|
||||||
|
|
@ -50,6 +49,7 @@ export class MapService implements IMapService {
|
||||||
private readonly basemapsAssetsDir = 'basemaps-assets'
|
private readonly basemapsAssetsDir = 'basemaps-assets'
|
||||||
private readonly baseAssetsTarFile = 'base-assets.tar.gz'
|
private readonly baseAssetsTarFile = 'base-assets.tar.gz'
|
||||||
private readonly baseDirPath = join(process.cwd(), this.mapStoragePath)
|
private readonly baseDirPath = join(process.cwd(), this.mapStoragePath)
|
||||||
|
private baseAssetsExistCache: boolean | null = null
|
||||||
|
|
||||||
async listRegions() {
|
async listRegions() {
|
||||||
const files = (await this.listAllMapStorageItems()).filter(
|
const files = (await this.listAllMapStorageItems()).filter(
|
||||||
|
|
@ -93,6 +93,9 @@ export class MapService implements IMapService {
|
||||||
|
|
||||||
await deleteFileIfExists(tempTarPath)
|
await deleteFileIfExists(tempTarPath)
|
||||||
|
|
||||||
|
// Invalidate cache since we just downloaded new assets
|
||||||
|
this.baseAssetsExistCache = true
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -170,6 +173,15 @@ export class MapService implements IMapService {
|
||||||
|
|
||||||
const filepath = join(process.cwd(), this.mapStoragePath, 'pmtiles', filename)
|
const filepath = join(process.cwd(), this.mapStoragePath, 'pmtiles', filename)
|
||||||
|
|
||||||
|
|
||||||
|
// First, ensure base assets are present - regions depend on them
|
||||||
|
const baseAssetsExist = await this.ensureBaseAssets()
|
||||||
|
if (!baseAssetsExist) {
|
||||||
|
throw new Error(
|
||||||
|
'Base map assets are missing and could not be downloaded. Please check your connection and try again.'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
// Dispatch background job
|
// Dispatch background job
|
||||||
const result = await RunDownloadJob.dispatch({
|
const result = await RunDownloadJob.dispatch({
|
||||||
url,
|
url,
|
||||||
|
|
@ -250,18 +262,6 @@ export class MapService implements IMapService {
|
||||||
return styles
|
return styles
|
||||||
}
|
}
|
||||||
|
|
||||||
async checkBaseAssetsExist() {
|
|
||||||
const storageContents = await this.listMapStorageItems()
|
|
||||||
const baseStyleItem = storageContents.find(
|
|
||||||
(item) => item.type === 'file' && item.name === this.baseStylesFile
|
|
||||||
)
|
|
||||||
const basemapsAssetsItem = storageContents.find(
|
|
||||||
(item) => item.type === 'directory' && item.name === this.basemapsAssetsDir
|
|
||||||
)
|
|
||||||
|
|
||||||
return !!baseStyleItem && !!basemapsAssetsItem
|
|
||||||
}
|
|
||||||
|
|
||||||
async listCuratedCollections(): Promise<CuratedCollectionWithStatus[]> {
|
async listCuratedCollections(): Promise<CuratedCollectionWithStatus[]> {
|
||||||
const collections = await CuratedCollection.query().where('type', 'map').preload('resources')
|
const collections = await CuratedCollection.query().where('type', 'map').preload('resources')
|
||||||
return collections.map((collection) => ({
|
return collections.map((collection) => ({
|
||||||
|
|
@ -303,9 +303,37 @@ export class MapService implements IMapService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async listMapStorageItems(): Promise<FileEntry[]> {
|
async ensureBaseAssets(): Promise<boolean> {
|
||||||
|
const exists = await this.checkBaseAssetsExist()
|
||||||
|
if (exists) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return await this.downloadBaseAssets()
|
||||||
|
}
|
||||||
|
|
||||||
|
private async checkBaseAssetsExist(useCache: boolean = true): Promise<boolean> {
|
||||||
|
// Return cached result if available and caching is enabled
|
||||||
|
if (useCache && this.baseAssetsExistCache !== null) {
|
||||||
|
return this.baseAssetsExistCache
|
||||||
|
}
|
||||||
|
|
||||||
await ensureDirectoryExists(this.baseDirPath)
|
await ensureDirectoryExists(this.baseDirPath)
|
||||||
return await listDirectoryContents(this.baseDirPath)
|
|
||||||
|
const baseStylePath = join(this.baseDirPath, this.baseStylesFile)
|
||||||
|
const basemapsAssetsPath = join(this.baseDirPath, this.basemapsAssetsDir)
|
||||||
|
|
||||||
|
const [baseStyleExists, basemapsAssetsExists] = await Promise.all([
|
||||||
|
getFileStatsIfExists(baseStylePath),
|
||||||
|
getFileStatsIfExists(basemapsAssetsPath),
|
||||||
|
])
|
||||||
|
|
||||||
|
const exists = !!baseStyleExists && !!basemapsAssetsExists
|
||||||
|
|
||||||
|
// update cache
|
||||||
|
this.baseAssetsExistCache = exists
|
||||||
|
|
||||||
|
return exists
|
||||||
}
|
}
|
||||||
|
|
||||||
private async listAllMapStorageItems(): Promise<FileEntry[]> {
|
private async listAllMapStorageItems(): Promise<FileEntry[]> {
|
||||||
|
|
|
||||||
|
|
@ -60,7 +60,6 @@ router
|
||||||
.group(() => {
|
.group(() => {
|
||||||
router.get('/regions', [MapsController, 'listRegions'])
|
router.get('/regions', [MapsController, 'listRegions'])
|
||||||
router.get('/styles', [MapsController, 'styles'])
|
router.get('/styles', [MapsController, 'styles'])
|
||||||
router.get('/preflight', [MapsController, 'checkBaseAssets'])
|
|
||||||
router.get('/curated-collections', [MapsController, 'listCuratedCollections'])
|
router.get('/curated-collections', [MapsController, 'listCuratedCollections'])
|
||||||
router.post('/fetch-latest-collections', [MapsController, 'fetchLatestCollections'])
|
router.post('/fetch-latest-collections', [MapsController, 'fetchLatestCollections'])
|
||||||
router.post('/download-base-assets', [MapsController, 'downloadBaseAssets'])
|
router.post('/download-base-assets', [MapsController, 'downloadBaseAssets'])
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user