2017-12-27 18:21:45 +00:00
|
|
|
const http = require('http')
|
|
|
|
const https = require('https')
|
|
|
|
|
|
|
|
// GET YOUR OWN AT: https://openweathermap.org/appid
|
2018-02-23 10:13:13 +00:00
|
|
|
const APP_KEY = require('fs').readFileSync(__dirname + '/.key', {
|
|
|
|
encoding: 'utf-8',
|
|
|
|
flag: 'r'
|
|
|
|
}).trim()
|
2017-12-27 18:48:05 +00:00
|
|
|
|
2017-12-28 16:11:59 +00:00
|
|
|
const LISTEN = '8000'
|
2018-02-23 10:13:13 +00:00
|
|
|
const HOST = '0.0.0.0'
|
2017-12-27 18:21:45 +00:00
|
|
|
|
|
|
|
const REGEXP = {
|
|
|
|
URL: /^\/[\d]{1,8}$/
|
|
|
|
}
|
|
|
|
|
|
|
|
const API = {
|
|
|
|
// Define max 60 calls per 1 Minute
|
|
|
|
MAX_CALLS: 60,
|
|
|
|
INTERVAL: 1000 * 60, // 1 Minute
|
|
|
|
current_calls: 0,
|
|
|
|
last_reset: Date.now(),
|
|
|
|
}
|
|
|
|
|
|
|
|
const CACHE = {}
|
|
|
|
const MAX_AGE = 60 * 1000 // 1 Minute
|
|
|
|
const LAST_UPDATE_KEY = 'last_update'
|
|
|
|
|
|
|
|
function getForZip(zip) {
|
|
|
|
return new Promise((resolve, reject) => {
|
|
|
|
|
|
|
|
// If interval is over, reset max count
|
|
|
|
if (Date.now() - API.last_reset > API.INTERVAL) {
|
|
|
|
API.last_reset = Date.now()
|
|
|
|
API.current_calls = 0
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check if too many calls were already made
|
|
|
|
if (API.current_calls > API.MAX_CALLS)
|
|
|
|
resolve()
|
|
|
|
|
|
|
|
API.current_calls++;
|
|
|
|
|
|
|
|
// Make the call
|
|
|
|
https.get({
|
|
|
|
host: 'api.openweathermap.org',
|
|
|
|
path: `/data/2.5/forecast?APPID=${APP_KEY}&zip=${zip},DE&units=metric`,
|
|
|
|
timeout: 15 * 1000,
|
|
|
|
}, res => {
|
|
|
|
res.setEncoding('utf8')
|
|
|
|
let body = ''
|
|
|
|
res.on('data', data => {
|
|
|
|
body += data
|
|
|
|
})
|
|
|
|
res.on('end', () => {
|
|
|
|
const data = JSON.parse(body)
|
|
|
|
data[LAST_UPDATE_KEY] = Date.now()
|
|
|
|
resolve(data)
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
function getUrlFromPath(path) {
|
|
|
|
// Check if url is valid
|
|
|
|
if (!REGEXP.URL.test(path))
|
|
|
|
return false
|
|
|
|
else
|
|
|
|
// Exctract ZIP code
|
|
|
|
return path.replace('/', '')
|
|
|
|
}
|
|
|
|
|
2018-02-23 10:13:13 +00:00
|
|
|
const server = http.createServer(async (req, res) => {
|
2017-12-27 18:21:45 +00:00
|
|
|
|
|
|
|
const zip = getUrlFromPath(req.url)
|
|
|
|
// Check if url is valid
|
|
|
|
if (zip === false) {
|
|
|
|
res.writeHead(400, {})
|
|
|
|
res.end()
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// If there is no cached version, get it
|
|
|
|
// If the last cached version is older than MAX_AGE, get it
|
|
|
|
if (CACHE[zip] === undefined || Date.now() - CACHE[zip][LAST_UPDATE_KEY] > MAX_AGE)
|
|
|
|
CACHE[zip] = await getForZip(zip)
|
|
|
|
|
|
|
|
res.writeHead(200, {
|
|
|
|
'Content-Type': 'application/json',
|
2017-12-28 16:40:21 +00:00
|
|
|
'Access-Control-Allow-Origin': '*'
|
2017-12-27 18:21:45 +00:00
|
|
|
})
|
|
|
|
res.write(JSON.stringify(CACHE[zip] || {}))
|
|
|
|
res.end()
|
|
|
|
})
|
|
|
|
|
2017-12-27 18:48:05 +00:00
|
|
|
function exit() {
|
|
|
|
console.log('Bye Bye')
|
|
|
|
server.close()
|
|
|
|
}
|
|
|
|
|
|
|
|
function start() {
|
2018-02-23 10:13:13 +00:00
|
|
|
console.log(`Started server on: ${LISTEN}. Using Key: ${APP_KEY}`)
|
|
|
|
server.listen(LISTEN, HOST)
|
2017-12-27 18:48:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Register exit function
|
|
|
|
process.on('exit', exit)
|
|
|
|
process.on('SIGINT', exit)
|
|
|
|
process.on('SIGQUIT', exit)
|
|
|
|
process.on('SIGTERM', exit)
|
|
|
|
process.on('uncaughtException', exit)
|
|
|
|
|
|
|
|
start()
|