@signalk/charts-plugin 2.3.1 → 3.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +80 -17
- package/package.json +27 -8
- package/plugin/charts.d.ts +1 -0
- package/plugin/charts.js +243 -0
- package/plugin/constants.d.ts +4 -0
- package/plugin/constants.js +7 -0
- package/plugin/index.d.ts +1 -0
- package/plugin/index.js +353 -0
- package/plugin/types.d.ts +38 -0
- package/plugin/types.js +2 -0
- package/.github/workflows/publish.yml +0 -18
- package/.github/workflows/release_on_tag.yml +0 -27
- package/.github/workflows/require_pr_label.yml +0 -13
- package/.github/workflows/test.yml +0 -22
- package/index.js +0 -1
- package/src/charts.js +0 -175
- package/src/constants.js +0 -3
- package/src/plugin.js +0 -231
- package/test/charts/empty-test/.gitkeep +0 -0
- package/test/charts/test.mbtiles +0 -0
- package/test/charts/tms-tiles/4/8/10.png +0 -0
- package/test/charts/tms-tiles/4/8/11.png +0 -0
- package/test/charts/tms-tiles/4/9/10.png +0 -0
- package/test/charts/tms-tiles/4/9/11.png +0 -0
- package/test/charts/tms-tiles/5/16/21.png +0 -0
- package/test/charts/tms-tiles/5/16/22.png +0 -0
- package/test/charts/tms-tiles/5/16/23.png +0 -0
- package/test/charts/tms-tiles/5/17/21.png +0 -0
- package/test/charts/tms-tiles/5/17/22.png +0 -0
- package/test/charts/tms-tiles/5/17/23.png +0 -0
- package/test/charts/tms-tiles/5/18/21.png +0 -0
- package/test/charts/tms-tiles/5/18/22.png +0 -0
- package/test/charts/tms-tiles/5/18/23.png +0 -0
- package/test/charts/tms-tiles/tilemapresource.xml +0 -14
- package/test/charts/unpacked-tiles/3/2/3.png +0 -0
- package/test/charts/unpacked-tiles/4/4/6.png +0 -0
- package/test/charts/unpacked-tiles/4/5/6.png +0 -0
- package/test/charts/unpacked-tiles/metadata.json +0 -15
- package/test/charts-2/test2.mbtiles +0 -0
- package/test/expected-charts.json +0 -53
- package/test/plugin-test.js +0 -196
package/src/plugin.js
DELETED
|
@@ -1,231 +0,0 @@
|
|
|
1
|
-
const Promise = require('bluebird')
|
|
2
|
-
const _ = require('lodash')
|
|
3
|
-
const path = require('path')
|
|
4
|
-
const fs = require('fs')
|
|
5
|
-
const Charts = require('./charts')
|
|
6
|
-
const {apiRoutePrefix} = require('./constants')
|
|
7
|
-
|
|
8
|
-
const MIN_ZOOM = 1
|
|
9
|
-
const MAX_ZOOM = 19
|
|
10
|
-
|
|
11
|
-
module.exports = function(app) {
|
|
12
|
-
let chartProviders = []
|
|
13
|
-
let pluginStarted = false
|
|
14
|
-
const configBasePath = app.config.configPath
|
|
15
|
-
const defaultChartsPath = path.join(configBasePath, "/charts")
|
|
16
|
-
ensureDirectoryExists(defaultChartsPath)
|
|
17
|
-
|
|
18
|
-
function start(props) {
|
|
19
|
-
const chartPaths = _.isEmpty(props.chartPaths)
|
|
20
|
-
? [defaultChartsPath]
|
|
21
|
-
: resolveUniqueChartPaths(props.chartPaths, configBasePath)
|
|
22
|
-
const onlineProviders = _.reduce(props.onlineChartProviders, (result, data) => {
|
|
23
|
-
const provider = convertOnlineProviderConfig(data)
|
|
24
|
-
result[provider.identifier] = provider
|
|
25
|
-
return result
|
|
26
|
-
}, {})
|
|
27
|
-
app.debug(`Start charts plugin. Chart paths: ${chartPaths.join(', ')}, online charts: ${onlineProviders.length}`)
|
|
28
|
-
|
|
29
|
-
const loadProviders = Promise.mapSeries(chartPaths, chartPath => Charts.findCharts(chartPath))
|
|
30
|
-
.then(list => _.reduce(list, (result, charts) => _.merge({}, result, charts), {}))
|
|
31
|
-
return loadProviders.then(charts => {
|
|
32
|
-
app.debug(`Chart plugin: Found ${_.keys(charts).length} charts from ${chartPaths.join(', ')}`)
|
|
33
|
-
chartProviders = _.merge({}, charts, onlineProviders)
|
|
34
|
-
// Do not register routes if plugin has been started once already
|
|
35
|
-
pluginStarted === false && registerRoutes()
|
|
36
|
-
pluginStarted = true
|
|
37
|
-
}).catch(e => {
|
|
38
|
-
console.error(`Error loading chart providers`, e.message)
|
|
39
|
-
chartProviders = {}
|
|
40
|
-
})
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
function stop() {
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
function registerRoutes() {
|
|
47
|
-
app.get(apiRoutePrefix + '/charts/:identifier/:z([0-9]*)/:x([0-9]*)/:y([0-9]*)', (req, res) => {
|
|
48
|
-
const { identifier, z, x, y } = req.params
|
|
49
|
-
const provider = chartProviders[identifier]
|
|
50
|
-
if (!provider) {
|
|
51
|
-
res.sendStatus(404)
|
|
52
|
-
return
|
|
53
|
-
}
|
|
54
|
-
switch (provider._fileFormat) {
|
|
55
|
-
case 'directory':
|
|
56
|
-
return serveTileFromFilesystem(res, provider, z, x, y)
|
|
57
|
-
case 'mbtiles':
|
|
58
|
-
return serveTileFromMbtiles(res, provider, z, x, y)
|
|
59
|
-
default:
|
|
60
|
-
console.error(`Unknown chart provider fileformat ${provider._fileFormat}`)
|
|
61
|
-
res.status(500).send()
|
|
62
|
-
}
|
|
63
|
-
})
|
|
64
|
-
|
|
65
|
-
app.get(apiRoutePrefix + "/charts/:identifier", (req, res) => {
|
|
66
|
-
const { identifier } = req.params
|
|
67
|
-
const provider = chartProviders[identifier]
|
|
68
|
-
if (provider) {
|
|
69
|
-
return res.json(sanitizeProvider(provider))
|
|
70
|
-
} else {
|
|
71
|
-
return res.status(404).send('Not found')
|
|
72
|
-
}
|
|
73
|
-
})
|
|
74
|
-
|
|
75
|
-
app.get(apiRoutePrefix + "/charts", (req, res) => {
|
|
76
|
-
const sanitized = _.mapValues(chartProviders, sanitizeProvider)
|
|
77
|
-
res.json(sanitized)
|
|
78
|
-
})
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
return {
|
|
82
|
-
id: 'charts',
|
|
83
|
-
name: 'Signal K Charts',
|
|
84
|
-
description: 'Singal K Charts resource',
|
|
85
|
-
schema: {
|
|
86
|
-
title: 'Signal K Charts',
|
|
87
|
-
description: `Add one or more paths to find charts. Defaults to "${defaultChartsPath}"`,
|
|
88
|
-
type: 'object',
|
|
89
|
-
properties: {
|
|
90
|
-
chartPaths: {
|
|
91
|
-
type: 'array',
|
|
92
|
-
title: 'Chart paths',
|
|
93
|
-
items: {
|
|
94
|
-
type: 'string',
|
|
95
|
-
title: "Path",
|
|
96
|
-
description: `Path for chart files, relative to "${configBasePath}"`
|
|
97
|
-
}
|
|
98
|
-
},
|
|
99
|
-
onlineChartProviders: {
|
|
100
|
-
type: 'array',
|
|
101
|
-
title: 'Online chart providers',
|
|
102
|
-
items: {
|
|
103
|
-
type: 'object',
|
|
104
|
-
title: 'Provider',
|
|
105
|
-
required: ['name', 'minzoom', 'maxzoom', 'format', 'url'],
|
|
106
|
-
properties: {
|
|
107
|
-
name: {
|
|
108
|
-
type: 'string',
|
|
109
|
-
title: 'Name'
|
|
110
|
-
},
|
|
111
|
-
description: {
|
|
112
|
-
type: 'string',
|
|
113
|
-
title: 'Description'
|
|
114
|
-
},
|
|
115
|
-
minzoom: {
|
|
116
|
-
type: 'number',
|
|
117
|
-
title: `Minimum zoom level, between [${MIN_ZOOM}, ${MAX_ZOOM}]`,
|
|
118
|
-
maximum: MAX_ZOOM,
|
|
119
|
-
minimum: MIN_ZOOM,
|
|
120
|
-
default: MIN_ZOOM,
|
|
121
|
-
},
|
|
122
|
-
maxzoom: {
|
|
123
|
-
type: 'number',
|
|
124
|
-
title: `Maximum zoom level, between [${MIN_ZOOM}, ${MAX_ZOOM}]`,
|
|
125
|
-
maximum: MAX_ZOOM,
|
|
126
|
-
minimum: MIN_ZOOM,
|
|
127
|
-
default: 15,
|
|
128
|
-
},
|
|
129
|
-
serverType: {
|
|
130
|
-
type: 'string',
|
|
131
|
-
title: 'Server Type',
|
|
132
|
-
default: 'tilelayer',
|
|
133
|
-
enum: ['tilelayer', 'WMS']
|
|
134
|
-
},
|
|
135
|
-
format: {
|
|
136
|
-
type: 'string',
|
|
137
|
-
title: 'Format',
|
|
138
|
-
default: 'png',
|
|
139
|
-
enum: ['png', 'jpg']
|
|
140
|
-
},
|
|
141
|
-
url: {
|
|
142
|
-
type: 'string',
|
|
143
|
-
title: 'URL',
|
|
144
|
-
description: 'Map URL (for tilelayer include {z}, {x} and {y} parameters, e.g. "http://example.org/{z}/{x}/{y}.png")'
|
|
145
|
-
},
|
|
146
|
-
layers: {
|
|
147
|
-
type: 'array',
|
|
148
|
-
title: 'Layers',
|
|
149
|
-
description: '(WMS only) ',
|
|
150
|
-
items: {
|
|
151
|
-
title: 'Layer Name',
|
|
152
|
-
description: 'Name of layer to display',
|
|
153
|
-
type: 'string'
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
},
|
|
161
|
-
start,
|
|
162
|
-
stop
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
const responseHttpOptions = {
|
|
168
|
-
headers: {
|
|
169
|
-
'Cache-Control': 'public, max-age=7776000' // 90 days
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
function resolveUniqueChartPaths(chartPaths, configBasePath) {
|
|
174
|
-
const paths = _.map(chartPaths, chartPath => path.resolve(configBasePath, chartPath))
|
|
175
|
-
return _.uniq(paths)
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
function convertOnlineProviderConfig(provider) {
|
|
179
|
-
const id = _.kebabCase(_.deburr(provider.name))
|
|
180
|
-
return {
|
|
181
|
-
name: provider.name,
|
|
182
|
-
description: provider.description,
|
|
183
|
-
bounds: [-180, -90, 180, 90],
|
|
184
|
-
minzoom: Math.min(Math.max(1, provider.minzoom), 19),
|
|
185
|
-
maxzoom: Math.min(Math.max(1, provider.maxzoom), 19),
|
|
186
|
-
format: provider.format,
|
|
187
|
-
scale: 'N/A',
|
|
188
|
-
identifier: id,
|
|
189
|
-
tilemapUrl: provider.url,
|
|
190
|
-
type: (provider.serverType) ? provider.serverType : 'tilelayer',
|
|
191
|
-
chartLayers: (provider.layers) ? provider.layers : null
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
function sanitizeProvider(provider) {
|
|
196
|
-
return _.omit(provider, ['_filePath', '_fileFormat', '_mbtilesHandle', '_flipY'])
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
function ensureDirectoryExists (path) {
|
|
200
|
-
if (!fs.existsSync(path)) {
|
|
201
|
-
fs.mkdirSync(path)
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
function serveTileFromFilesystem(res, provider, z, x, y) {
|
|
206
|
-
const {identifier, format, _flipY, _filePath} = provider
|
|
207
|
-
const flippedY = Math.pow(2, z) - 1 - y
|
|
208
|
-
const file = path.resolve(_filePath, `${z}/${x}/${_flipY ? flippedY : y}.${format}`)
|
|
209
|
-
res.sendFile(file, responseHttpOptions, (err) => {
|
|
210
|
-
if (err && err.code === 'ENOENT') {
|
|
211
|
-
res.sendStatus(404)
|
|
212
|
-
} else if (err) {
|
|
213
|
-
throw err
|
|
214
|
-
}
|
|
215
|
-
})
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
function serveTileFromMbtiles(res, provider, z, x, y) {
|
|
219
|
-
provider._mbtilesHandle.getTile(z, x, y, (err, tile, headers) => {
|
|
220
|
-
if (err && err.message && err.message === 'Tile does not exist') {
|
|
221
|
-
res.sendStatus(404)
|
|
222
|
-
} else if (err) {
|
|
223
|
-
console.error(`Error fetching tile ${provider.identifier}/${z}/${x}/${y}:`, err)
|
|
224
|
-
res.sendStatus(500)
|
|
225
|
-
} else {
|
|
226
|
-
headers['Cache-Control'] = responseHttpOptions.headers['Cache-Control']
|
|
227
|
-
res.writeHead(200, headers)
|
|
228
|
-
res.end(tile)
|
|
229
|
-
}
|
|
230
|
-
})
|
|
231
|
-
}
|
|
File without changes
|
package/test/charts/test.mbtiles
DELETED
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
<?xml version="1.0" encoding="utf-8"?>
|
|
2
|
-
<TileMap version="1.0.0" tilemapservice="http://tms.osgeo.org/1.0.0">
|
|
3
|
-
<Title>Översikt Svenska Sjökort</Title>
|
|
4
|
-
<Abstract></Abstract>
|
|
5
|
-
<Metadata scale="4000000" mime-type="text/xml" />
|
|
6
|
-
<SRS>EPSG:900913</SRS>
|
|
7
|
-
<BoundingBox minx="6.924150554004035" miny="53.14584310531994" maxx="25.541777414896345" maxy="66.0258911558707"/>
|
|
8
|
-
<Origin x="6.924150554004035" y="66.0258911558707" />
|
|
9
|
-
<TileFormat width="256" height="256" mime-type="image/png" extension="png"/>
|
|
10
|
-
<TileSets profile="mercator">
|
|
11
|
-
<TileSet href="4" units-per-pixel="9783.93961875" order="4"/>
|
|
12
|
-
<TileSet href="5" units-per-pixel="4891.969809375" order="5"/>
|
|
13
|
-
</TileSets>
|
|
14
|
-
</TileMap>
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"profile": "mercator",
|
|
3
|
-
"attribution": "NOAA",
|
|
4
|
-
"name": "NOAA MBTiles test file",
|
|
5
|
-
"format": "png",
|
|
6
|
-
"basename": "MBTILES_19",
|
|
7
|
-
"bounds": "-82.265625, 36.5978891331, -61.875, 31.952162238",
|
|
8
|
-
"minzoom": "3",
|
|
9
|
-
"version": "1",
|
|
10
|
-
"maxzoom": "4",
|
|
11
|
-
"tilejson": "2.0.0",
|
|
12
|
-
"scheme": "xyz",
|
|
13
|
-
"type": "overlay",
|
|
14
|
-
"description": "CAROLINAS"
|
|
15
|
-
}
|
|
Binary file
|
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"test": {
|
|
3
|
-
"bounds": [
|
|
4
|
-
-82.265625,
|
|
5
|
-
36.5978891331,
|
|
6
|
-
-61.875,
|
|
7
|
-
31.952162238
|
|
8
|
-
],
|
|
9
|
-
"description": "CAROLINAS",
|
|
10
|
-
"format": "png",
|
|
11
|
-
"identifier": "test",
|
|
12
|
-
"maxzoom": 5,
|
|
13
|
-
"minzoom": 3,
|
|
14
|
-
"name": "MBTILES_19",
|
|
15
|
-
"scale": "250000",
|
|
16
|
-
"tilemapUrl": "/signalk/v1/api/resources/charts/test/{z}/{x}/{y}",
|
|
17
|
-
"type": "tilelayer"
|
|
18
|
-
},
|
|
19
|
-
"tms-tiles": {
|
|
20
|
-
"bounds": [
|
|
21
|
-
6.924150554004035,
|
|
22
|
-
53.14584310531994,
|
|
23
|
-
25.541777414896345,
|
|
24
|
-
66.0258911558707
|
|
25
|
-
],
|
|
26
|
-
"description": "Översikt Svenska Sjökort",
|
|
27
|
-
"format": "png",
|
|
28
|
-
"identifier": "tms-tiles",
|
|
29
|
-
"maxzoom": 5,
|
|
30
|
-
"minzoom": 4,
|
|
31
|
-
"name": "Översikt Svenska Sjökort",
|
|
32
|
-
"scale": "4000000",
|
|
33
|
-
"tilemapUrl": "/signalk/v1/api/resources/charts/tms-tiles/{z}/{x}/{y}",
|
|
34
|
-
"type": "tilelayer"
|
|
35
|
-
},
|
|
36
|
-
"unpacked-tiles": {
|
|
37
|
-
"bounds": [
|
|
38
|
-
-82.265625,
|
|
39
|
-
36.5978891331,
|
|
40
|
-
-61.875,
|
|
41
|
-
31.952162238
|
|
42
|
-
],
|
|
43
|
-
"description": "CAROLINAS",
|
|
44
|
-
"format": "png",
|
|
45
|
-
"identifier": "unpacked-tiles",
|
|
46
|
-
"maxzoom": 4,
|
|
47
|
-
"minzoom": 3,
|
|
48
|
-
"name": "NOAA MBTiles test file",
|
|
49
|
-
"scale": "250000",
|
|
50
|
-
"tilemapUrl": "/signalk/v1/api/resources/charts/unpacked-tiles/{z}/{x}/{y}",
|
|
51
|
-
"type": "tilelayer"
|
|
52
|
-
}
|
|
53
|
-
}
|
package/test/plugin-test.js
DELETED
|
@@ -1,196 +0,0 @@
|
|
|
1
|
-
'use strict'
|
|
2
|
-
const fs = require('fs')
|
|
3
|
-
const _ = require('lodash')
|
|
4
|
-
const path = require('path')
|
|
5
|
-
const http = require('http')
|
|
6
|
-
const chai = require('chai')
|
|
7
|
-
const chaiHttp = require('chai-http')
|
|
8
|
-
const Promise = require('bluebird')
|
|
9
|
-
const express = require('express')
|
|
10
|
-
const expect = chai.expect
|
|
11
|
-
const Plugin = require('../src/plugin')
|
|
12
|
-
const expectedCharts = require('./expected-charts.json')
|
|
13
|
-
|
|
14
|
-
chai.use(chaiHttp)
|
|
15
|
-
|
|
16
|
-
describe('GET /resources/charts', () => {
|
|
17
|
-
let plugin
|
|
18
|
-
let testServer
|
|
19
|
-
beforeEach(() =>
|
|
20
|
-
createDefaultApp()
|
|
21
|
-
.then(({app, server}) => {
|
|
22
|
-
plugin = Plugin(app)
|
|
23
|
-
testServer = server
|
|
24
|
-
})
|
|
25
|
-
)
|
|
26
|
-
afterEach(done => testServer.close(() => done()))
|
|
27
|
-
|
|
28
|
-
it('returns all charts for default path', () => {
|
|
29
|
-
return plugin.start({})
|
|
30
|
-
.then(() => get(testServer, '/signalk/v1/api/resources/charts'))
|
|
31
|
-
.then(result => {
|
|
32
|
-
expect(result.status).to.equal(200)
|
|
33
|
-
const resultCharts = result.body
|
|
34
|
-
expect(_.keys(resultCharts).length).to.deep.equal(3)
|
|
35
|
-
expect(resultCharts).to.deep.equal(expectedCharts)
|
|
36
|
-
})
|
|
37
|
-
})
|
|
38
|
-
|
|
39
|
-
it('handle canonical paths', () => {
|
|
40
|
-
return plugin.start({chartPaths: ['charts', path.resolve(__dirname, 'charts').toString()]})
|
|
41
|
-
.then(() => get(testServer, '/signalk/v1/api/resources/charts'))
|
|
42
|
-
.then(result => {
|
|
43
|
-
expect(result.status).to.equal(200)
|
|
44
|
-
const resultCharts = result.body
|
|
45
|
-
expect(_.keys(resultCharts).length).to.deep.equal(3)
|
|
46
|
-
})
|
|
47
|
-
})
|
|
48
|
-
|
|
49
|
-
it('returns all charts for multiple paths', () => {
|
|
50
|
-
return plugin.start({chartPaths: ['charts', 'charts-2']})
|
|
51
|
-
.then(() => get(testServer, '/signalk/v1/api/resources/charts'))
|
|
52
|
-
.then(result => {
|
|
53
|
-
expect(result.status).to.equal(200)
|
|
54
|
-
const resultCharts = result.body
|
|
55
|
-
expect(_.keys(resultCharts).length).to.deep.equal(4)
|
|
56
|
-
expect(resultCharts['test2']).not.to.equal(undefined)
|
|
57
|
-
})
|
|
58
|
-
})
|
|
59
|
-
|
|
60
|
-
it('returns empty charts for custom path', () => {
|
|
61
|
-
return plugin.start({chartPaths: ['../src/']})
|
|
62
|
-
.then(() => get(testServer, '/signalk/v1/api/resources/charts'))
|
|
63
|
-
.then(result => {
|
|
64
|
-
expect(result.status).to.equal(200)
|
|
65
|
-
expect(result.body).to.deep.equal({})
|
|
66
|
-
})
|
|
67
|
-
})
|
|
68
|
-
|
|
69
|
-
it('returns online chart providers', () => {
|
|
70
|
-
return plugin.start({chartPaths: ['charts'], onlineChartProviders: [
|
|
71
|
-
{name: 'Test Name', minzoom: 2, maxzoom: 15, format: 'jpg', url: 'https://example.com'}
|
|
72
|
-
]})
|
|
73
|
-
.then(() => get(testServer, '/signalk/v1/api/resources/charts'))
|
|
74
|
-
.then(result => {
|
|
75
|
-
expect(result.body['test-name']).to.deep.equal({
|
|
76
|
-
bounds: [-180, -90, 180, 90],
|
|
77
|
-
format: 'jpg',
|
|
78
|
-
identifier: 'test-name',
|
|
79
|
-
maxzoom: 15,
|
|
80
|
-
minzoom: 2,
|
|
81
|
-
name: 'Test Name',
|
|
82
|
-
scale: 'N/A',
|
|
83
|
-
tilemapUrl: 'https://example.com',
|
|
84
|
-
type: 'tilelayer'
|
|
85
|
-
})
|
|
86
|
-
})
|
|
87
|
-
})
|
|
88
|
-
|
|
89
|
-
it('returns one chart', () => {
|
|
90
|
-
const identifier = 'test'
|
|
91
|
-
return plugin.start({})
|
|
92
|
-
.then(() => get(testServer, `/signalk/v1/api/resources/charts/${identifier}`))
|
|
93
|
-
.then(result => {
|
|
94
|
-
expect(result.status).to.equal(200)
|
|
95
|
-
expect(result.body).to.deep.equal(expectedCharts[identifier])
|
|
96
|
-
})
|
|
97
|
-
})
|
|
98
|
-
|
|
99
|
-
it('returns 404 for unknown chart', () => {
|
|
100
|
-
return plugin.start({})
|
|
101
|
-
.then(() => get(testServer, `/signalk/v1/api/resources/charts/foo`))
|
|
102
|
-
.catch(e => e.response)
|
|
103
|
-
.then(result => {
|
|
104
|
-
expect(result.status).to.equal(404)
|
|
105
|
-
})
|
|
106
|
-
})
|
|
107
|
-
})
|
|
108
|
-
|
|
109
|
-
describe('GET /resources/charts/:identifier/:z/:x/:y', () => {
|
|
110
|
-
let plugin
|
|
111
|
-
let testServer
|
|
112
|
-
beforeEach(() =>
|
|
113
|
-
createDefaultApp()
|
|
114
|
-
.then(({app, server}) => {
|
|
115
|
-
plugin = Plugin(app)
|
|
116
|
-
testServer = server
|
|
117
|
-
})
|
|
118
|
-
)
|
|
119
|
-
afterEach(done => testServer.close(() => done()))
|
|
120
|
-
|
|
121
|
-
it('returns correct tile from MBTiles file', () => {
|
|
122
|
-
return plugin.start({})
|
|
123
|
-
.then(() => get(testServer, '/signalk/v1/api/resources/charts/test/4/5/6'))
|
|
124
|
-
.then(response => {
|
|
125
|
-
// unpacked-tiles contains same tiles as the test.mbtiles file
|
|
126
|
-
expectTileResponse(response, 'charts/unpacked-tiles/4/5/6.png', 'image/png')
|
|
127
|
-
})
|
|
128
|
-
})
|
|
129
|
-
|
|
130
|
-
it('returns correct tile from directory', () => {
|
|
131
|
-
const expectedTile = fs.readFileSync(path.resolve(__dirname, 'charts/unpacked-tiles/4/4/6.png'))
|
|
132
|
-
return plugin.start({})
|
|
133
|
-
.then(() => get(testServer, '/signalk/v1/api/resources/charts/unpacked-tiles/4/4/6'))
|
|
134
|
-
.then(response => {
|
|
135
|
-
expectTileResponse(response, 'charts/unpacked-tiles/4/4/6.png', 'image/png')
|
|
136
|
-
})
|
|
137
|
-
})
|
|
138
|
-
|
|
139
|
-
it('returns correct tile from TMS directory', () => {
|
|
140
|
-
const expectedTile = fs.readFileSync(path.resolve(__dirname, 'charts/tms-tiles/5/17/21.png'))
|
|
141
|
-
// Y-coordinate flipped
|
|
142
|
-
return plugin.start({})
|
|
143
|
-
.then(() => get(testServer, '/signalk/v1/api/resources/charts/tms-tiles/5/17/10'))
|
|
144
|
-
.then(response => {
|
|
145
|
-
expectTileResponse(response, 'charts/tms-tiles/5/17/21.png', 'image/png')
|
|
146
|
-
})
|
|
147
|
-
})
|
|
148
|
-
|
|
149
|
-
it('returns 404 for missing tile', () => {
|
|
150
|
-
return plugin.start({})
|
|
151
|
-
.then(() => get(testServer, '/signalk/v1/api/resources/charts/tms-tiles/5/55/10'))
|
|
152
|
-
.catch(e => e.response)
|
|
153
|
-
.then(response => {
|
|
154
|
-
expect(response.status).to.equal(404)
|
|
155
|
-
})
|
|
156
|
-
})
|
|
157
|
-
|
|
158
|
-
it('returns 404 for wrong chart identifier', () => {
|
|
159
|
-
return plugin.start({})
|
|
160
|
-
.then(() => get(testServer, '/signalk/v1/api/resources/charts/foo/4/4/6'))
|
|
161
|
-
.catch(e => e.response)
|
|
162
|
-
.then(response => {
|
|
163
|
-
expect(response.status).to.equal(404)
|
|
164
|
-
})
|
|
165
|
-
})
|
|
166
|
-
})
|
|
167
|
-
|
|
168
|
-
const expectTileResponse = (response, expectedTilePath, expectedFormat) => {
|
|
169
|
-
const expectedTile = fs.readFileSync(path.resolve(__dirname, expectedTilePath))
|
|
170
|
-
expect(response.status).to.equal(200)
|
|
171
|
-
expect(response.headers['content-type']).to.equal(expectedFormat)
|
|
172
|
-
expect(response.headers['cache-control']).to.equal('public, max-age=7776000')
|
|
173
|
-
expect(response.body.toString('hex')).to.deep.equal(expectedTile.toString('hex'))
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
const createDefaultApp = () => {
|
|
177
|
-
let app = express()
|
|
178
|
-
app.use(require('body-parser').json())
|
|
179
|
-
app.config = { configPath: path.resolve(__dirname) }
|
|
180
|
-
return new Promise((resolve, reject) => {
|
|
181
|
-
const server = http.createServer(app)
|
|
182
|
-
server.listen(() => {
|
|
183
|
-
const {port} = server.address()
|
|
184
|
-
app.set('port', port)
|
|
185
|
-
console.log(`Test server on port ${port}`)
|
|
186
|
-
resolve({app, server})
|
|
187
|
-
})
|
|
188
|
-
})
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
const get = (server, location) => {
|
|
192
|
-
const baseUrl = `http://localhost:${server.address().port}`
|
|
193
|
-
return chai
|
|
194
|
-
.request(baseUrl)
|
|
195
|
-
.get(location)
|
|
196
|
-
}
|