-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathapp.js
138 lines (128 loc) · 3.89 KB
/
app.js
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
const config = require('config')
const fs = require('fs')
const express = require('express')
const spdy = require('spdy')
const cors = require('cors')
const morgan = require('morgan')
const MBTiles = require('@mapbox/mbtiles')
const TimeFormat = require('hh-mm-ss')
const winston = require('winston')
const DailyRotateFile = require('winston-daily-rotate-file')
// config constants
const morganFormat = config.get('morganFormat')
const htdocsPath = config.get('htdocsPath')
const privkeyPath = config.get('privkeyPath')
const fullchainPath = config.get('fullchainPath')
const port = config.get('port')
const defaultZ = config.get('defaultZ')
const mbtilesDir = config.get('mbtilesDir')
const fontsDir = config.get('fontsDir')
const logDirPath = config.get('logDirPath')
// global variables
let mbtilesPool = {}
let tz = config.get('tz')
let busy = false
// logger configuration
const logger = winston.createLogger({
transports: [
new winston.transports.Console(),
new DailyRotateFile({
filename: `${logDirPath}/onyx-%DATE%.log`,
datePattern: 'YYYY-MM-DD'
})
]
})
logger.stream = {
write: (message) => { logger.info(message.trim()) }
}
// app
const app = express()
app.use(cors())
app.use(morgan(morganFormat, {
stream: logger.stream
}))
app.use(express.static(htdocsPath))
const getMBTiles = async (t, z, x, y) => {
let mbtilesPath = ''
if (!tz[t]) tz[t] = defaultZ
if (z < tz[t]) {
mbtilesPath = `${mbtilesDir}/${t}/0-0-0.mbtiles`
} else {
mbtilesPath =
`${mbtilesDir}/${t}/${tz[t]}-${x >> (z - tz[t])}-${y >> (z - tz[t])}.mbtiles`
}
return new Promise((resolve, reject) => {
if (mbtilesPool[mbtilesPath]) {
resolve(mbtilesPool[mbtilesPath].mbtiles)
} else {
if (fs.existsSync(mbtilesPath)) {
new MBTiles(`${mbtilesPath}?mode=ro`, (err, mbtiles) => {
if (err) {
reject(new Error(`${mbtilesPath} could not open.`))
} else {
mbtilesPool[mbtilesPath] = {
mbtiles: mbtiles, openTime: new Date()
}
resolve(mbtilesPool[mbtilesPath].mbtiles)
}
})
} else {
reject(new Error(`${mbtilesPath} was not found.`))
}
}
})
}
const getTile = async (mbtiles, z, x, y) => {
return new Promise((resolve, reject) => {
mbtiles.getTile(z, x, y, (err, tile, headers) => {
if (err) {
reject()
} else {
resolve({tile: tile, headers: headers})
}
})
})
}
app.get(`/zxy/:t/:z/:x/:y.pbf`, async (req, res) => {
busy = true
const t = req.params.t
const z = parseInt(req.params.z)
const x = parseInt(req.params.x)
const y = parseInt(req.params.y)
getMBTiles(t, z, x, y).then(mbtiles => {
getTile(mbtiles, z, x, y).then(r => {
if (r.tile) {
res.set('content-type', 'application/vnd.mapbox-vector-tile')
res.set('content-encoding', 'gzip')
res.set('last-modified', r.headers['Last-Modified'])
res.set('etag', r.headers['ETag'])
res.send(r.tile)
busy = false
} else {
res.status(404).send(`tile not found: /zxy/${t}/${z}/${x}/${y}.pbf`)
busy = false
}
}).catch(e => {
res.status(404).send(`tile not found: /zxy/${t}/${z}/${x}/${y}.pbf`)
busy = false
})
}).catch(e => {
res.status(404).send(`mbtiles not found for /zxy/${t}/${z}/${x}/${y}.pbf`)
})
})
app.get(`/fonts/:fontstack/:range.pbf`, (req, res) => {
res.set('content-type', 'application/x-protobuf')
res.set('content-encoding', 'gzip')
for(const fontstack of req.params.fontstack.split(',')) {
const path = `${fontsDir}/${fontstack}/${req.params.range}.pbf.gz`
if (fs.existsSync(path)) {
res.send(fs.readFileSync(path))
return
}
}
res.status(404).send(`font not found: ${req.params.fontstack}/${req.params.range}`)
})
spdy.createServer({
key: fs.readFileSync(privkeyPath),
cert: fs.readFileSync(fullchainPath)
}, app).listen(port)