forked from go-spatial/tegola
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathprovider.go
266 lines (227 loc) · 7.23 KB
/
provider.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
package provider
import (
"context"
"fmt"
"regexp"
"github.com/go-spatial/geom"
"github.com/go-spatial/geom/slippy"
"github.com/go-spatial/tegola/dict"
"github.com/go-spatial/tegola/internal/log"
)
// providerType defines the type of providers we have in the system.
// Standard providers allow layers to be co-mingled from different data sources
// because Tegola takes care of the geometry processing and mvt generation.
// MVT providers do not allow layers to be co-mingled and bypasses tegola's geometry
// processing and mvt generation.
type providerType uint8
const (
// TypeStd declares a provider to be a standard provider
TypeStd providerType = 1 << iota
// TypeMvt declares a provider to be an mvt provider.
TypeMvt
// TypeAll should be all the types
TypeAll = TypeStd & TypeMvt
)
func (pt providerType) Prefix() string {
if pt == TypeMvt {
return "mvt_"
}
return ""
}
func (pt providerType) String() string {
if pt == TypeMvt {
return "MVT Provider"
}
return "Standard Provider"
}
type providerFilter uint8
func providerFilterInclude(filters ...providerType) providerFilter {
ret := uint8(0)
for _, v := range filters {
ret |= uint8(v)
}
return providerFilter(ret)
}
// Is will check to see if the filter is one of the provider types. Is acts as an or, returning
// true if any one of the provided types matches
// false if none of them match
func (pf providerFilter) Is(ps ...providerType) bool {
t := providerFilterInclude(ps...)
return (uint8(pf) & uint8(t)) != 0
}
// tile_t is an implementation of the Tile interface, it is
// named as such as to not confuse from the 4 other possible meanings
// of the symbol "tile" in this code base. It should be removed after
// the geom port is mostly done as part of issue #499 (removing the
// Tile interface in this package)
// TODO(@ear7h) remove this atrocity from the code base
type tile_t struct {
slippy.Tile
buffer uint
}
// NewTile creates a new slippy tile with a Buffer
func NewTile(z, x, y, buf, srid uint) Tile {
return &tile_t{
Tile: slippy.Tile{
Z: z,
X: x,
Y: y,
},
buffer: buf,
}
}
// Extent returns the extent of the tile
func (tile *tile_t) Extent() (ext *geom.Extent, srid uint64) {
return tile.Extent3857(), 3857
}
// BufferedExtent returns a the extent of the tile, with the define buffer
func (tile *tile_t) BufferedExtent() (ext *geom.Extent, srid uint64) {
return tile.Extent3857().ExpandBy(slippy.Pixels2Webs(tile.Z, tile.buffer)), 3857
}
// Tile is an interface used by Tiler, it is an unnecessary abstraction and is
// due to be removed. The tiler interface will, instead take a, *geom.Extent.
type Tile interface {
// ZXY returns the z, x and y values of the tile
ZXY() (uint, uint, uint)
// Extent returns the extent of the tile excluding any buffer
Extent() (extent *geom.Extent, srid uint64)
// BufferedExtent returns the extent of the tile including any buffer
BufferedExtent() (extent *geom.Extent, srid uint64)
}
// ParameterTokenRegexp to validate QueryParameters
var ParameterTokenRegexp = regexp.MustCompile("![a-zA-Z0-9_-]+!")
// Tiler is a Layers that allows one to encode features in that layer
type Tiler interface {
Layerer
// TileFeature will stream decoded features to the callback function fn
// if fn returns ErrCanceled, the TileFeatures method should stop processing
TileFeatures(ctx context.Context, layer string, t Tile, params Params, fn func(f *Feature) error) error
}
// TilerUnion represents either a Std Tiler or and MVTTiler; only one should be not nil.
type TilerUnion struct {
Std Tiler
Mvt MVTTiler
}
// Layers return the layers of the Tiler. It will only return Std layers if
// STD is defined other the MVT layers
func (tu TilerUnion) Layers() ([]LayerInfo, error) {
if tu.Std != nil {
return tu.Std.Layers()
}
if tu.Mvt != nil {
return tu.Mvt.Layers()
}
return nil, ErrNilInitFunc
}
// InitFunc initialize a provider given a config map. The init function should validate the config map, and report any errors. This is called by the For function.
type InitFunc func(dicter dict.Dicter, maps []Map) (Tiler, error)
// CleanupFunc is called to when the system is shutting down, this allows the provider to cleanup.
type CleanupFunc func()
type pfns struct {
// init will be filled out if it's a standard provider
init InitFunc
// mvtInit will be filled out if it's a mvt provider
mvtInit MVTInitFunc
cleanup CleanupFunc
}
var providers map[string]pfns
// Register the provider with the system. This call is generally made in the init functions of the provider.
// the clean up function will be called during shutdown of the provider to allow the provider to do any cleanup.
// The init function can not be nil, the cleanup function may be nil
func Register(name string, init InitFunc, cleanup CleanupFunc) error {
if init == nil {
return ErrNilInitFunc
}
if providers == nil {
providers = make(map[string]pfns)
}
if _, ok := providers[name]; ok {
return fmt.Errorf("provider %v already exists", name)
}
providers[name] = pfns{
init: init,
cleanup: cleanup,
}
return nil
}
// MVTRegister the provider with the system. This call is generally made in the init functions of the provider.
// the clean up function will be called during shutdown of the provider to allow the provider to do any cleanup.
// The init function can not be nil, the cleanup function may be nil
func MVTRegister(name string, init MVTInitFunc, cleanup CleanupFunc) error {
if init == nil {
return ErrNilInitFunc
}
if providers == nil {
providers = make(map[string]pfns)
}
if _, ok := providers[name]; ok {
return fmt.Errorf("provider %v already exists", name)
}
providers[name] = pfns{
mvtInit: init,
cleanup: cleanup,
}
return nil
}
// Drivers returns a list of registered drivers.
func Drivers(types ...providerType) (l []string) {
if providers == nil {
return l
}
filter := providerFilterInclude(types...)
// An empty list of types should be all drivers. We do not provider a way
// to filter out all drivers
all := filter == 0 || filter == providerFilter(TypeAll)
mvt := filter.Is(TypeMvt)
std := filter.Is(TypeStd)
for k, v := range providers {
switch {
case all:
case mvt:
if v.mvtInit == nil { // not of type mvt
continue
}
case std:
if v.init == nil { //not of type std
continue
}
default:
continue
}
l = append(l, k)
}
return l
}
// For function returns a configure provider of the given type; The provider may be a mvt provider or
// a std provider. The correct entry in TilerUnion will not be nil. If there is an error both entries
// will be nil.
func For(name string, config dict.Dicter, maps []Map) (val TilerUnion, err error) {
var (
driversList = Drivers()
)
if providers == nil {
return val, ErrUnknownProvider{KnownProviders: driversList}
}
p, ok := providers[name]
if !ok {
return val, ErrUnknownProvider{KnownProviders: driversList, Name: name}
}
if p.init != nil {
val.Std, err = p.init(config, maps)
return val, err
}
if p.mvtInit != nil {
val.Mvt, err = p.mvtInit(config, maps)
return val, err
}
return val, ErrInvalidRegisteredProvider{Name: name}
}
// Cleanup is called at the end of the run to allow providers to cleanup
func Cleanup() {
log.Info("cleaning up providers")
for _, p := range providers {
if p.cleanup != nil {
p.cleanup()
}
}
}