2023-01-19 12:06:23 +01:00
const log = require ( '../../log' )
const nominatim = require ( '../../services/geocoding/nominatim' )
const photon = require ( '../../services/geocoding/photon' )
const axios = require ( 'axios' )
const { version } = require ( '../../../package.json' )
let d = 0 // departure time
let h = 0 // hit geocoding provider time (aka Latency)
const geocodingController = {
/ * *
* Limit provider api usage .
* From https : //operations.osmfoundation.org/policies/nominatim/
* [ Requirements ] No heavy uses ( an absolute maximum of 1 request per second ) .
* [ Websites and Apps ]
* - Note that the usage limits above apply per website / application : the sum of traffic by all your users should not exceed the limits .
* - If at all possible , set up a proxy and also enable caching of requests .
* /
2023-01-21 01:18:16 +01:00
providerRateLimit ( req , res , next , providerCache ) {
2023-01-19 12:06:23 +01:00
let a = Date . now ( ) ; // arrival time
let dprev = d
d = dprev + 1000 + h
2023-01-19 12:20:52 +01:00
// console.log('a: ' + a)
// console.log('dprev: ' + dprev)
// console.log('d: ' + d)
2023-01-19 12:06:23 +01:00
// if the same request was already cached skip the delay mechanism
2023-01-21 01:18:16 +01:00
if ( providerCache . get ( req . params . place _details ) ) {
2023-01-19 12:06:23 +01:00
if ( a < d ) {
2023-01-19 12:20:52 +01:00
log . warn ( 'More than 1 request per second to geocoding api. This from ' + req . ip + ' . The response data is served from memory-cache.' )
2023-01-19 12:06:23 +01:00
}
// reset departure time because there is no need to ask provider
d = dprev
return next ( )
}
if ( d === 0 || a > d ) {
// no-queue or old-queue
2023-01-19 12:20:52 +01:00
// console.log('No queue or Old queue')
2023-01-19 12:06:23 +01:00
// arrival time + 10ms estimated computing time
d = a + 10
next ( )
} else {
// fresh queue
2023-01-19 12:20:52 +01:00
// console.log('Fresh queue')
2023-01-19 12:06:23 +01:00
let wait = d - a
2023-01-19 12:20:52 +01:00
// console.log('Waiting '+ wait)
2023-01-19 12:06:23 +01:00
log . warn ( 'More than 1 request per second to geocoding api. This from ' + req . ip + ' . Applying ToS padding before asking to provider. The response data is now cached.' )
setTimeout ( ( ) => {
next ( )
} , wait )
}
} ,
async nominatimRateLimit ( req , res , next ) {
2023-03-28 19:04:41 +02:00
process . env . NODE _ENV === 'test' ? next ( ) : geocodingController . providerRateLimit ( req , res , next , nominatim . cache )
2023-01-19 12:06:23 +01:00
} ,
async photonRateLimit ( req , res , next ) {
2023-03-28 19:04:41 +02:00
process . env . NODE _ENV === 'test' ? next ( ) : geocodingController . providerRateLimit ( req , res , next , photon . cache )
2023-01-19 12:06:23 +01:00
} ,
2023-01-21 01:18:16 +01:00
async checkInCache ( req , res , details , providerCache ) {
const ret = await providerCache . get ( details )
if ( ret ) {
2023-01-19 12:06:23 +01:00
return ret
} else {
return
}
} ,
async queryProvider ( req , res , details , provider ) {
let RTTstart = Date . now ( )
2023-01-19 12:20:52 +01:00
// console.log('Asking Provider: ' + RTTstart)
2023-01-19 12:06:23 +01:00
const ret = await axios . get ( ` ${ provider . endpoint ( req , res ) } ` , {
params : provider . getParams ( req , res ) ,
headers : { 'User-Agent' : ` gancio ${ version } ` }
} )
if ( ret ) {
let RTTend = Date . now ( )
2023-01-19 12:20:52 +01:00
// console.log('Asking Provider: ' + RTTend)
2023-01-19 12:06:23 +01:00
// Save the hit time (aka Latency)
2023-01-19 12:20:52 +01:00
// console.log('Saving latency h: ' + h)
2023-01-19 12:06:23 +01:00
h = ( RTTend - RTTstart ) / 2
}
// Cache the response data
2023-01-21 01:18:16 +01:00
provider . cache . put ( details , ret . data , 1000 * 60 * 60 * 24 ) ;
2023-01-19 12:20:52 +01:00
// console.log(cache.keys())
// console.log(cache.exportJson())
2023-01-19 12:06:23 +01:00
return ret . data
} ,
async _nominatim ( req , res ) {
const details = req . params . place _details
2023-01-21 01:18:16 +01:00
const ret = await geocodingController . checkInCache ( req , res , details , nominatim . cache ) ||
2023-01-19 12:06:23 +01:00
await geocodingController . queryProvider ( req , res , details , nominatim )
return res . json ( ret )
} ,
async _photon ( req , res ) {
const details = req . params . place _details
2023-01-21 01:18:16 +01:00
const ret = await geocodingController . checkInCache ( req , res , details , photon . cache ) ||
2023-01-19 12:06:23 +01:00
await geocodingController . queryProvider ( req , res , details , photon )
return res . json ( ret )
} ,
}
module . exports = geocodingController