photosite/src/geocode/index.ts

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 };