Coverage for gws-app/gws/gis/mpx/config.py: 0%
77 statements
« prev ^ index » next coverage.py v7.8.0, created at 2025-04-17 01:37 +0200
« prev ^ index » next coverage.py v7.8.0, created at 2025-04-17 01:37 +0200
1from typing import Optional, cast
3import yaml
5from mapproxy.wsgiapp import make_wsgi_app
7import gws
8import gws.lib.osx
10CONFIG_PATH = gws.c.CONFIG_DIR + '/mapproxy.yaml'
12DEFAULT_CONFIG = {
13 "services": {
14 "wmts": {
15 }
16 },
17 "sources": {
18 "test": {
19 "type": "tile",
20 "url": "https://osmtiles.gbd-consult.de/ows/%(z)s/%(x)s/%(y)s.png",
21 }
22 },
23 "layers": [
24 {
25 "name": "test",
26 "title": "test",
27 "sources": [
28 "test"
29 ]
30 }
31 ]
32}
35class _Config:
36 def __init__(self):
37 self.c = 0
39 self.services = {
40 'wms': {
41 'image_formats': ['image/png'],
42 'max_output_pixels': [9000, 9000]
43 },
44 'wmts': {
45 'kvp': True,
46 'restful': False
47 }
48 }
50 self.globals = {
51 # https://mapproxy.org/docs/1.11.0/configuration.html#id14
52 # "By default MapProxy assumes lat/long (north/east) order for all geographic and x/y (east/north) order for all projected SRS."
53 # we need to change that because our extents are always x/y (lon/lat) even if a CRS says otherwise
54 'srs': {
55 'axis_order_en': ['EPSG:4326']
56 },
57 'cache': {
58 'base_dir': gws.c.MAPPROXY_CACHE_DIR,
59 'lock_dir': gws.u.ensure_dir(gws.c.TRANSIENT_DIR + '/mpx_locks_' + gws.u.random_string(16)),
60 'tile_lock_dir': gws.u.ensure_dir(gws.c.TRANSIENT_DIR + '/mpx_tile_locks_' + gws.u.random_string(16)),
61 'concurrent_tile_creators': 1,
62 'max_tile_limit': 5000,
64 },
65 'image': {
66 'resampling_method': 'bicubic',
67 'stretch_factor': 1.15,
68 'max_shrink_factor': 4.0,
70 'formats': {
71 'png8': {
72 'format': 'image/png',
73 'mode': 'P',
74 'colors': 256,
75 'transparent': True,
76 'resampling_method': 'bicubic',
77 },
78 'png24': {
79 'format': 'image/png',
80 'mode': 'RGBA',
81 'colors': 0,
82 'transparent': True,
83 'resampling_method': 'bicubic',
84 }
86 }
87 },
88 'http': {
89 'hide_error_details': False,
90 }
91 }
93 self.cfg = {}
95 def _add(self, kind, c):
96 # mpx doesn't like tuples
97 for k, v in c.items():
98 if isinstance(v, tuple):
99 c[k] = list(v)
101 uid = kind + '_' + gws.u.sha256(c)
103 # clients might add their hash params starting with '$'
104 c = {
105 k: v
106 for k, v in c.items()
107 if not k.startswith('$')
108 }
110 self.cfg[uid] = {'kind': kind, 'c': c}
111 return uid
113 def _items(self, kind):
114 for k, v in self.cfg.items():
115 if v['kind'] == kind:
116 yield k, v['c']
118 def cache(self, c):
119 return self._add('cache', c)
121 def source(self, c):
122 return self._add('source', c)
124 def grid(self, c):
125 # self._transform_extent(c)
126 return self._add('grid', c)
128 def layer(self, c):
129 c['title'] = ''
130 return self._add('layer', c)
132 def to_dict(self):
133 d = {
134 'services': self.services,
135 'globals': self.globals,
136 }
138 kinds = ['source', 'grid', 'cache', 'layer']
139 for kind in kinds:
140 d[kind + 's'] = {
141 key: c
142 for key, c in self._items(kind)
143 }
145 d['layers'] = sorted(d['layers'].values(), key=lambda x: x['name'])
147 return d
150def create(root: gws.Root):
151 mc = _Config()
153 for layer in root.find_all(gws.ext.object.layer):
154 m = getattr(layer, 'mapproxy_config', None)
155 if m:
156 m(mc)
158 cfg = mc.to_dict()
159 if not cfg.get('layers'):
160 return
162 crs: list[gws.Crs] = []
163 for p in root.find_all(gws.ext.object.map):
164 crs.append(cast(gws.Map, p).bounds.crs)
165 for p in root.find_all(gws.ext.object.owsService):
166 crs.extend(gws.u.get(p, 'supported_crs', default=[]))
167 cfg['services']['wms']['srs'] = sorted(set(c.epsg for c in crs))
169 return cfg
172def create_and_save(root: gws.Root):
173 cfg = create(root)
175 if not cfg:
176 force = root.app.cfg('server.mapproxy.forceStart')
177 if force:
178 gws.log.warning('mapproxy: no configuration, using default')
179 cfg = DEFAULT_CONFIG
180 else:
181 gws.log.warning('mapproxy: no configuration, not starting')
182 gws.lib.osx.unlink(CONFIG_PATH)
183 return
185 cfg_str = yaml.dump(cfg)
187 # make sure the config is ok before starting the server!
188 test_path = CONFIG_PATH + '.test.yaml'
189 gws.u.write_file(test_path, cfg_str)
191 try:
192 make_wsgi_app(test_path)
193 except Exception as e:
194 raise gws.Error(f'MAPPROXY ERROR: {e!r}') from e
196 gws.lib.osx.unlink(test_path)
198 # write into the real config path
199 gws.u.write_file(CONFIG_PATH, cfg_str)
201 return cfg