Skip to content

Commit c5353d8

Browse files
authored
Give support to serving mvt-tippecanoe tiles from an url (#1507)
* - give support to serving mvt-tippecanoe tiles from an url * - replaced use of os.path by Path
1 parent 3f991a2 commit c5353d8

File tree

1 file changed

+75
-12
lines changed

1 file changed

+75
-12
lines changed

pygeoapi/provider/mvt_tippecanoe.py

Lines changed: 75 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,15 @@
2929

3030
import json
3131
import logging
32+
import requests
3233
from pathlib import Path
3334
from urllib.parse import urlparse
3435

3536
from pygeoapi.provider.tile import (
3637
ProviderTileNotFoundError)
37-
from pygeoapi.provider.base import ProviderConnectionError
38+
from pygeoapi.provider.base import (ProviderConnectionError,
39+
ProviderInvalidQueryError,
40+
ProviderGenericError)
3841
from pygeoapi.provider.base_mvt import BaseMVTProvider
3942
from pygeoapi.models.provider.base import (
4043
TileSetMetadata, LinkType)
@@ -69,20 +72,29 @@ def __init__(self, BaseMVTProvider):
6972
if is_url(self.data):
7073
url = urlparse(self.data)
7174
baseurl = f'{url.scheme}://{url.netloc}'
72-
param_type = '?f=mvt'
75+
extension = Path(url.path).suffix # e.g. ".pbf"
7376
layer = f'/{self.get_layer()}'
7477

7578
LOGGER.debug('Extracting layer name from URL')
7679
LOGGER.debug(f'Layer: {layer}')
7780

7881
tilepath = f'{layer}/tiles'
79-
servicepath = f'{tilepath}/{{tileMatrixSetId}}/{{tileMatrix}}/{{tileRow}}/{{tileCol}}{param_type}' # noqa
82+
servicepath = f'{tilepath}/{{tileMatrixSetId}}/{{tileMatrix}}/{{tileRow}}/{{tileCol}}{extension}' # noqa
8083

8184
self._service_url = url_join(baseurl, servicepath)
8285

8386
self._service_metadata_url = url_join(
8487
self.service_url.split('{tileMatrix}/{tileRow}/{tileCol}')[0],
8588
'metadata')
89+
90+
metadata_path = f'{baseurl}/{layer}/metadata.json'
91+
head = requests.head(metadata_path)
92+
if head.status_code != 200:
93+
msg = f'Service metadata does not exist: {metadata_path}'
94+
LOGGER.error(msg)
95+
LOGGER.warning(msg)
96+
self._service_metadata_url = metadata_path
97+
8698
# Pre-rendered tiles served from a local path
8799
else:
88100
data_path = Path(self.data)
@@ -144,6 +156,60 @@ def get_tiles_service(self, baseurl=None, servicepath=None,
144156
self._service_url = servicepath
145157
return self.get_tms_links()
146158

159+
def get_tiles_from_url(self, layer=None, tileset=None,
160+
z=None, y=None, x=None, format_=None):
161+
"""
162+
Gets tile from a static url (e.g.: bucket, file server)
163+
164+
:param layer: mvt tile layer
165+
:param tileset: mvt tileset
166+
:param z: z index
167+
:param y: y index
168+
:param x: x index
169+
:param format_: tile format
170+
171+
:returns: an encoded mvt tile
172+
"""
173+
174+
url = urlparse(self.data)
175+
base_url = f'{url.scheme}://{url.netloc}'
176+
177+
extension = Path(url.path).suffix # e.g. ".pbf"
178+
179+
try:
180+
with requests.Session() as session:
181+
session.get(base_url)
182+
resp = session.get(f'{base_url}/{layer}/{z}/{y}/{x}{extension}') # noqa
183+
resp.raise_for_status()
184+
return resp.content
185+
except requests.exceptions.RequestException as e:
186+
LOGGER.debug(e)
187+
if resp.status_code < 500:
188+
raise ProviderInvalidQueryError # Client is sending an invalid request # noqa
189+
raise ProviderGenericError # Server error
190+
191+
def get_tiles_from_disk(self, layer=None, tileset=None,
192+
z=None, y=None, x=None, format_=None):
193+
"""
194+
Gets tile from a path on disk
195+
196+
:param layer: mvt tile layer
197+
:param tileset: mvt tileset
198+
:param z: z index
199+
:param y: y index
200+
:param x: x index
201+
:param format_: tile format
202+
203+
:returns: an encoded mvt tile
204+
"""
205+
206+
try:
207+
service_url_path = self.service_url.joinpath(f'{z}/{y}/{x}.{format_}') # noqa
208+
with open(service_url_path, mode='rb') as tile:
209+
return tile.read()
210+
except FileNotFoundError as err:
211+
raise ProviderTileNotFoundError(err)
212+
147213
def get_tiles(self, layer=None, tileset=None,
148214
z=None, y=None, x=None, format_=None):
149215
"""
@@ -162,17 +228,14 @@ def get_tiles(self, layer=None, tileset=None,
162228
if format_ == 'mvt':
163229
format_ = self.format_type
164230

165-
if not isinstance(self.service_url, Path):
166-
msg = f'Wrong data path configuration: {self.service_url}'
231+
if isinstance(self.service_url, Path):
232+
return self.get_tiles_from_disk(layer, tileset, z, y, x, format_)
233+
elif is_url(self.data):
234+
return self.get_tiles_from_url(layer, tileset, z, y, x, format_)
235+
else:
236+
msg = 'Wrong input format for Tippecanoe MVT'
167237
LOGGER.error(msg)
168238
raise ProviderConnectionError(msg)
169-
else:
170-
try:
171-
service_url_path = self.service_url.joinpath(f'{z}/{y}/{x}.{format_}') # noqa
172-
with open(service_url_path, mode='rb') as tile:
173-
return tile.read()
174-
except FileNotFoundError as err:
175-
raise ProviderTileNotFoundError(err)
176239

177240
def get_html_metadata(self, dataset, server_url, layer, tileset,
178241
title, description, keywords, **kwargs):

0 commit comments

Comments
 (0)