93 lines
2.0 KiB
TypeScript
93 lines
2.0 KiB
TypeScript
import 'dotenv/config';
|
|
|
|
import { URL } from 'url';
|
|
import fetch from 'node-fetch';
|
|
import type { Response } from 'node-fetch';
|
|
|
|
import { createLog } from '../log';
|
|
import type { Logger } from 'winston';
|
|
import { envString } from '../env';
|
|
import type { DB, LatLng } from '../db';
|
|
|
|
export class Geocode {
|
|
private log : Logger = createLog('geocode');
|
|
private baseUrl : string = 'https://geocode.maps.co/search';
|
|
private apiKey : string = envString('GEOCODE_API_KEY', null);
|
|
private db : DB;
|
|
|
|
constructor (db : DB) {
|
|
this.db = db;
|
|
}
|
|
|
|
public async query (location : string) : Promise<LatLng> {
|
|
let res : LatLng = await this.db.getLocation(location);
|
|
if (res === null) {
|
|
res = await this.api(location);
|
|
}
|
|
return res;
|
|
}
|
|
|
|
private toLatLng (obj : any) : LatLng {
|
|
return {
|
|
latitude : parseFloat(obj.lat),
|
|
longitude : parseFloat(obj.lon)
|
|
};
|
|
}
|
|
|
|
//https://geocode.maps.co/search?q=&api_key=675738aa38619885468998kehbf6458
|
|
private async api (location : string) : Promise<LatLng> {
|
|
const url : URL = new URL(this.baseUrl);
|
|
let response : Response;
|
|
let json : any;
|
|
let res : LatLng = null;
|
|
|
|
url.searchParams.append('q', location);
|
|
|
|
this.log.info(`Querying API: ${url.href}`);
|
|
url.searchParams.append('api_key', this.apiKey);
|
|
|
|
await this.delay(1000); //rate limit to 1/sec
|
|
|
|
try {
|
|
response = await fetch(url.href);
|
|
} catch (err) {
|
|
this.log.error('Error getting response', err);
|
|
return null;
|
|
}
|
|
|
|
if (response.status !== 200) {
|
|
this.log.warn(`Invalid response from API [${response.status}]`);
|
|
return null;
|
|
}
|
|
|
|
try {
|
|
json = await response.json();
|
|
} catch (err) {
|
|
this.log.error('Error parsing json', err);
|
|
return null;
|
|
}
|
|
|
|
if (json.length < 1) {
|
|
return null;
|
|
}
|
|
|
|
res = this.toLatLng(json[0]);
|
|
|
|
await this.db.cacheLocation(location, res);
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
private async delay (ms : number) {
|
|
return new Promise ((resolve : Function, reject : Function) => {
|
|
return setTimeout(resolve, ms);
|
|
});
|
|
}
|
|
|
|
private cache (location : string, latitude : number, longitude : number) {
|
|
|
|
}
|
|
}
|
|
|
|
module.exports = { Geocode }; |