diff --git a/packages/lambda-tiler/src/arcgis/__tests__/arcgis.style.json.test.ts b/packages/lambda-tiler/src/arcgis/__tests__/arcgis.style.json.test.ts deleted file mode 100644 index c9f186e4d..000000000 --- a/packages/lambda-tiler/src/arcgis/__tests__/arcgis.style.json.test.ts +++ /dev/null @@ -1,157 +0,0 @@ -import { BaseConfig, ConfigProviderMemory, StyleJson } from '@basemaps/config'; -import { Env } from '@basemaps/shared'; -import o from 'ospec'; -import { createSandbox } from 'sinon'; -import { handler } from '../../index.js'; -import { ConfigLoader } from '../../util/config.loader.js'; -import { FakeData } from '../../__tests__/config.data.js'; -import { Api, mockRequest, mockUrlRequest } from '../../__tests__/xyz.util.js'; - -o.spec('arcgis/stylejson', () => { - const host = 'https://tiles.test'; - const sandbox = createSandbox(); - const config = new ConfigProviderMemory(); - - o.before(() => { - process.env[Env.PublicUrlBase] = host; - }); - - o.beforeEach(() => { - sandbox.stub(ConfigLoader, 'getDefaultConfig').resolves(config); - config.objects.clear(); - }); - - o.afterEach(() => { - sandbox.restore(); - }); - - o('should not found tile set', async () => { - const request = mockRequest('/v1/arcgis/rest/services/topographic/VectorTileServer/root.json', 'get', Api.header); - - const res = await handler.router.handle(request); - o(res.status).equals(404); - }); - - o('should not found style', async () => { - const request = mockRequest('/v1/arcgis/rest/services/topographic/VectorTileServer/root.json', 'get', Api.header); - config.put(FakeData.tileSetVector('topographic')); - - const res = await handler.router.handle(request); - o(res.status).equals(404); - }); - - const fakeStyle: StyleJson = { - version: 8, - id: 'test', - name: 'topographic', - sources: { - basemaps_vector: { - type: 'vector', - url: `/vector`, - }, - basemaps_raster: { - type: 'raster', - tiles: [`/raster`], - }, - }, - layers: [ - { - source: 'basemaps_vector', - layout: { - visibility: 'visible', - }, - paint: { - 'background-color': 'rgba(206, 229, 242, 1)', - }, - id: 'Background-vector', - type: 'background', - minzoom: 0, - }, - { - source: 'basemaps_raster', - layout: { - visibility: 'visible', - }, - paint: { - 'background-color': 'rgba(222, 229, 132, 1)', - }, - id: 'Background-raster', - type: 'background', - minzoom: 0, - }, - ], - glyphs: '/glyphs', - sprite: '/sprite', - metadata: { id: 'test' }, - }; - - const fakeRecord = { - id: 'st_topographic', - name: 'topographic', - style: fakeStyle, - }; - - o('should serve style json and remove the raster source and layers, then replace the vector url', async () => { - const request = mockRequest('/v1/arcgis/rest/services/topographic/VectorTileServer/root.json', 'get', Api.header); - - config.put(FakeData.tileSetVector('topographic')); - config.put(fakeRecord); - - const res = await handler.router.handle(request); - o(res.status).equals(200); - o(res.header('content-type')).equals('application/json'); - o(res.header('cache-control')).equals('no-store'); - - const body = Buffer.from(res.body ?? '', 'base64').toString(); - fakeStyle.sources.basemaps_vector = { - type: 'vector', - url: `${host}/v1/arcgis/rest/services/topographic/VectorTileServer?api=${Api.key}&f=json`, - }; - delete fakeStyle.sources.basemaps_raster; - fakeStyle.layers = [fakeStyle.layers[0]]; - - fakeStyle.sprite = `${host}/sprite`; - fakeStyle.glyphs = `${host}/glyphs`; - - o(JSON.parse(body)).deepEquals(fakeStyle); - }); - - o('should not found for raster tileset', async () => { - const request = mockRequest('/v1/arcgis/rest/services/raster/VectorTileServer/root.json', 'get', Api.header); - - config.put(FakeData.tileSetRaster('raster')); - config.put(fakeRecord); - - const res = await handler.router.handle(request); - o(res.status).equals(404); - }); - - o('should fine the new style with url query', async () => { - const request = mockUrlRequest( - '/v1/arcgis/rest/services/topographic/VectorTileServer/root.json', - 'style=topolite', - Api.header, - ); - - config.put({ id: 'st_topolite', name: 'topographic', style: fakeStyle } as BaseConfig); - config.put(FakeData.tileSetVector('topographic')); - - const res = await handler.router.handle(request); - o(res.status).equals(200); - o(res.header('content-type')).equals('application/json'); - o(res.header('cache-control')).equals('no-store'); - - const body = Buffer.from(res.body ?? '', 'base64').toString(); - fakeStyle.sources.basemaps_vector = { - type: 'vector', - url: `${host}/v1/arcgis/rest/services/topographic/VectorTileServer?api=${Api.key}&f=json`, - }; - delete fakeStyle.sources.basemaps_raster; - fakeStyle.layers = [fakeStyle.layers[0]]; - - fakeStyle.sprite = `${host}/sprite`; - fakeStyle.glyphs = `${host}/glyphs`; - - o(JSON.parse(body)).deepEquals(fakeStyle); - }); -}); diff --git a/packages/lambda-tiler/src/arcgis/__tests__/vector.tiler.server.test.ts b/packages/lambda-tiler/src/arcgis/__tests__/vector.tiler.server.test.ts deleted file mode 100644 index 03567f520..000000000 --- a/packages/lambda-tiler/src/arcgis/__tests__/vector.tiler.server.test.ts +++ /dev/null @@ -1,70 +0,0 @@ -import { ConfigProviderMemory } from '@basemaps/config'; -import { Env } from '@basemaps/shared'; -import o from 'ospec'; -import { createSandbox } from 'sinon'; -import { handler } from '../../index.js'; -import { ConfigLoader } from '../../util/config.loader.js'; -import { FakeData } from '../../__tests__/config.data.js'; -import { Api, mockRequest, mockUrlRequest } from '../../__tests__/xyz.util.js'; - -o.spec('arcgis/VectorTileServer', () => { - const host = 'https://tiles.test'; - const sandbox = createSandbox(); - const config = new ConfigProviderMemory(); - - o.before(() => { - process.env[Env.PublicUrlBase] = host; - }); - - o.beforeEach(() => { - sandbox.stub(ConfigLoader, 'getDefaultConfig').resolves(config); - config.objects.clear(); - }); - - o.afterEach(() => { - sandbox.restore(); - }); - - o('should not found tile set', async () => { - const request = mockUrlRequest('/v1/arcgis/rest/services/topographic/VectorTileServer', 'f=json', Api.header); - - const res = await handler.router.handle(request); - o(res.status).equals(404); - }); - o('should return the vector tile server', async () => { - const request = mockUrlRequest('/v1/arcgis/rest/services/topographic/VectorTileServer', 'f=json', Api.header); - - config.put(FakeData.tileSetVector('topographic')); - - const res = await handler.router.handle(request); - o(res.status).equals(200); - o(res.header('content-type')).equals('application/json'); - o(res.header('cache-control')).equals('no-store'); - - const body = JSON.parse(Buffer.from(res.body ?? '', 'base64').toString()); - o(body.tiles[0]).equals(`${host}/v1/tiles/topographic/WebMercatorQuad/{z}/{x}/{y}.pbf?api=${Api.key}`); - o(body.tileInfo.lods.length).equals(17); - }); - o('should not return with no f=json query', async () => { - const request = mockRequest('/v1/arcgis/rest/services/topographic/VectorTileServer', 'get', Api.header); - - config.put(FakeData.tileSetVector('topographic')); - - const res = await handler.router.handle(request); - o(res.status).equals(404); - }); - o('should return ok for post request', async () => { - const request = mockUrlRequest( - '/v1/arcgis/rest/services/topographic/VectorTileServer', - 'f=json', - Api.header, - 'POST', - ); - - config.put(FakeData.tileSetVector('topographic')); - - const res = await handler.router.handle(request); - o(res.status).equals(200); - o(res.body).deepEquals(`{"id":"${request.id}","correlationId":"${request.correlationId}","message":"ok"}`); - }); -}); diff --git a/packages/lambda-tiler/src/arcgis/arcgis.info.ts b/packages/lambda-tiler/src/arcgis/arcgis.info.ts deleted file mode 100644 index e58fc0a7e..000000000 --- a/packages/lambda-tiler/src/arcgis/arcgis.info.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { Env } from '@basemaps/shared'; -import { HttpHeader, LambdaHttpRequest, LambdaHttpResponse } from '@linzjs/lambda'; -import { Etag } from '../util/etag.js'; -import { NotFound, NotModified } from '../util/response.js'; - -export async function arcgisInfoGet(req: LambdaHttpRequest): Promise { - const host = Env.get(Env.PublicUrlBase); - if (host == null) return NotFound(); - const info = { - currentVersion: 10.1, - fullVersion: '10.1', - owningSystemUrl: host, - }; - - const json = JSON.stringify(info); - const data = Buffer.from(json); - - const cacheKey = Etag.key(data); - if (Etag.isNotModified(req, cacheKey)) return NotModified(); - - const response = new LambdaHttpResponse(200, 'ok'); - response.header(HttpHeader.CacheControl, 'public, max-age=604800, stale-while-revalidate=86400'); - response.buffer(data, 'application/json'); - req.set('bytes', data.byteLength); - return response; -} diff --git a/packages/lambda-tiler/src/arcgis/arcgis.style.json.ts b/packages/lambda-tiler/src/arcgis/arcgis.style.json.ts deleted file mode 100644 index 33d0fe0c3..000000000 --- a/packages/lambda-tiler/src/arcgis/arcgis.style.json.ts +++ /dev/null @@ -1,83 +0,0 @@ -import { Sources, StyleJson, TileSetType } from '@basemaps/config'; -import { Env, fsa } from '@basemaps/shared'; -import { HttpHeader, LambdaHttpRequest, LambdaHttpResponse } from '@linzjs/lambda'; -import { convertRelativeUrl } from '../routes/tile.style.json.js'; -import { ConfigLoader } from '../util/config.loader.js'; -import { Etag } from '../util/etag.js'; -import { NotFound, NotModified } from '../util/response.js'; -import { Validate } from '../util/validate.js'; - -interface StyleGet { - Params: { - tileSet: string; - }; -} - -function tileserverUrl(tileSet: string, apiKey: string): string { - const host = Env.get(Env.PublicUrlBase) ?? ''; - const url = `/v1/arcgis/rest/services/${tileSet}/VectorTileServer`; - const fullUrl = new URL(fsa.join(host, url)); - fullUrl.searchParams.set('api', apiKey); - fullUrl.searchParams.set('f', 'json'); - return fullUrl.toString().replace(/%7B/g, '{').replace(/%7D/g, '}'); -} - -function convertStyleJson(tileSet: string, style: StyleJson, apiKey: string): StyleJson { - const sources: Sources = JSON.parse(JSON.stringify(style.sources)); - // Only keep the vector layer and update the source url - for (const [key, value] of Object.entries(sources)) { - if (value.type === 'vector') { - value.url = tileserverUrl(tileSet, apiKey); - sources[key] = value; - } else { - delete sources[key]; - } - } - - // Remove all the not vector layers. - const layers = []; - for (const layer of style.layers) { - if (layer.source != null && !sources.hasOwnProperty(layer.source)) continue; - layers.push(layer); - } - - return { - version: 8, - id: style.id, - name: style.name, - sources, - layers, - metadata: style.metadata ?? {}, - glyphs: convertRelativeUrl(style.glyphs), - sprite: convertRelativeUrl(style.sprite), - } as StyleJson; -} - -export async function arcgisStyleJsonGet(req: LambdaHttpRequest): Promise { - const apiKey = Validate.apiKey(req); - const config = await ConfigLoader.load(req); - const tileSet = await config.TileSet.get(config.TileSet.id(req.params.tileSet)); - if (tileSet?.type !== TileSetType.Vector) return NotFound(); - - const style = req.query.get('style'); - const styleName = style ? style : 'topographic'; // Defalut to topographic style - - // Get style Config from db - const dbId = config.Style.id(styleName); - const styleConfig = await config.Style.get(dbId); - if (styleConfig == null) return NotFound(); - - // Prepare sources and add linz source - const styleJson = convertStyleJson(tileSet.name, styleConfig.style, apiKey); - const data = Buffer.from(JSON.stringify(styleJson)); - - const cacheKey = Etag.key(data); - if (Etag.isNotModified(req, cacheKey)) return NotModified(); - - const response = new LambdaHttpResponse(200, 'ok'); - response.header(HttpHeader.ETag, cacheKey); - response.header(HttpHeader.CacheControl, 'no-store'); - response.buffer(data, 'application/json'); - req.set('bytes', data.byteLength); - return response; -} diff --git a/packages/lambda-tiler/src/arcgis/vector.tile.server.ts b/packages/lambda-tiler/src/arcgis/vector.tile.server.ts deleted file mode 100644 index e776f3594..000000000 --- a/packages/lambda-tiler/src/arcgis/vector.tile.server.ts +++ /dev/null @@ -1,81 +0,0 @@ -import { TileSetType } from '@basemaps/config'; -import { GoogleTms } from '@basemaps/geo'; -import { HttpHeader, LambdaHttpRequest, LambdaHttpResponse } from '@linzjs/lambda'; -import { convertRelativeUrl } from '../routes/tile.style.json.js'; -import { ConfigLoader } from '../util/config.loader.js'; -import { NotFound } from '../util/response.js'; -import { Validate } from '../util/validate.js'; - -/** Zoom level for the tilematrix which will be slice by 1 during the covertion to arcgis tileserve lods */ -const MaxTileMatrixZoom = 18; -const MinTileMatrixZoom = 1; - -export interface VectorTileServer { - Params: { - tileSet: string; - }; -} - -export async function arcgisTileServerGet(req: LambdaHttpRequest): Promise { - const config = await ConfigLoader.load(req); - - const tileSet = await config.TileSet.get(config.TileSet.id(req.params.tileSet)); - if (tileSet?.type !== TileSetType.Vector) return NotFound(); - const apiKey = Validate.apiKey(req); - const f = req.query.get('f'); - if (f !== 'json') return NotFound(); - const extent = { - xmin: GoogleTms.extent.x, - ymin: GoogleTms.extent.y, - xmax: GoogleTms.extent.right, - ymax: GoogleTms.extent.bottom, - // TODO where is wkid from - spatialReference: { wkid: 102100, latestWkid: GoogleTms.projection.code }, - }; - const vectorTileServer = { - currentVersion: 10.81, - name: tileSet.name, - capabilities: 'TilesOnly', - type: 'indexedVector', - defaultStyles: '', - tiles: [convertRelativeUrl(`/v1/tiles/${tileSet.name}/WebMercatorQuad/{z}/{x}/{y}.pbf`, apiKey)], - exportTilesAllowed: false, - maxExportTilesCount: 0, - initialExtent: extent, - fullExtent: extent, - minScale: 0.0, - maxScale: 0.0, - tileInfo: { - rows: 512, - cols: 512, - dpi: 96, - format: 'pbf', - origin: { x: GoogleTms.extent.x, y: GoogleTms.extent.bottom }, - spatialReference: { wkid: 102100, latestWkid: GoogleTms.projection.code }, - lods: GoogleTms.zooms.slice(MinTileMatrixZoom, MaxTileMatrixZoom).map((c, i) => { - return { - level: i, - resolution: c.scaleDenominator * 0.28e-3, - scale: c.scaleDenominator, - }; - }), - }, - maxzoom: 22, - minLOD: 0, - maxLOD: 15, - resourceInfo: { - styleVersion: 8, - tileCompression: 'gzip', - cacheInfo: { storageInfo: { packetSize: 128, storageFormat: 'compactV2' } }, - }, - }; - - const json = JSON.stringify(vectorTileServer, null, 2); - const data = Buffer.from(json); - - const response = new LambdaHttpResponse(200, 'ok'); - response.header(HttpHeader.CacheControl, 'no-store'); - response.buffer(data, 'application/json'); - req.set('bytes', data.byteLength); - return response; -} diff --git a/packages/lambda-tiler/src/index.ts b/packages/lambda-tiler/src/index.ts index 062073ccd..c4693f0e1 100644 --- a/packages/lambda-tiler/src/index.ts +++ b/packages/lambda-tiler/src/index.ts @@ -1,25 +1,22 @@ import { LogConfig } from '@basemaps/shared'; import { LambdaHttpResponse, lf } from '@linzjs/lambda'; -import { arcgisInfoGet } from './arcgis/arcgis.info.js'; -import { arcgisStyleJsonGet } from './arcgis/arcgis.style.json.js'; -import { arcgisTileServerGet } from './arcgis/vector.tile.server.js'; import { tileAttributionGet } from './routes/attribution.js'; import { configImageryGet, configTileSetGet } from './routes/config.js'; import { fontGet, fontList } from './routes/fonts.js'; import { healthGet } from './routes/health.js'; import { imageryGet } from './routes/imagery.js'; import { pingGet } from './routes/ping.js'; +import { previewIndexGet } from './routes/preview.index.js'; +import { tilePreviewGet } from './routes/preview.js'; import { spriteGet } from './routes/sprites.js'; import { tileJsonGet } from './routes/tile.json.js'; import { styleJsonGet } from './routes/tile.style.json.js'; import { wmtsCapabilitiesGet } from './routes/tile.wmts.js'; import { tileXyzGet } from './routes/tile.xyz.js'; import { versionGet } from './routes/version.js'; -import { NotFound, OkResponse } from './util/response.js'; +import { NotFound } from './util/response.js'; import { CoSources } from './util/source.cache.js'; import { St } from './util/source.tracer.js'; -import { tilePreviewGet } from './routes/preview.js'; -import { previewIndexGet } from './routes/preview.index.js'; export const handler = lf.http(LogConfig.get()); @@ -108,9 +105,3 @@ handler.router.get('/v1/attribution/:tileSet/:tileMatrix/summary.json', tileAttr handler.router.get('/v1/tiles/:tileSet/:tileMatrix/WMTSCapabilities.xml', wmtsCapabilitiesGet); handler.router.get('/v1/tiles/:tileSet/WMTSCapabilities.xml', wmtsCapabilitiesGet); handler.router.get('/v1/tiles/WMTSCapabilities.xml', wmtsCapabilitiesGet); - -// Arcgis Vector -handler.router.get('/v1/arcgis/rest/services/:tileSet/VectorTileServer', arcgisTileServerGet); -handler.router.post('/v1/arcgis/rest/services/:tileSet/VectorTileServer', OkResponse); -handler.router.get('/v1/arcgis/rest/services/:tileSet/VectorTileServer/root.json', arcgisStyleJsonGet); -handler.router.get('/v1/arcgis/rest/info', arcgisInfoGet);