@mediocre/bloodhound
Version:
Bloodhound is a Node.js package that allows you to retrieve tracking data from shipping carriers (Amazon, DHL, FedEx, UPS, USPS) in a common format.
128 lines (102 loc) • 3.86 kB
JavaScript
const async = require('async');
const NodeGeocoder = require('node-geocoder');
const normalize = require('us-states-normalize');
const PettyCache = require('petty-cache');
const tzlookup = require('tz-lookup');
let pettyCache;
function geocode(location, callback) {
async.auto({
geocode: function(callback) {
// Geocode the location
async.retry(function(callback) {
exports.geocoder.geocode(location, callback);
}, function(err, results) {
if (err) {
return callback(err);
}
if (!results.length) {
return callback();
}
var firstResult = results[0];
// Handle Google results
if (!firstResult.state && firstResult.administrativeLevels && firstResult.administrativeLevels.level1short) {
firstResult.state = firstResult.administrativeLevels.level1short;
}
// Check to see if the first result has the data we need
if (firstResult.city && firstResult.state && firstResult.zipcode) {
return callback(null, firstResult);
}
// Reverse geocode to ensure we get a city, state, and zip
async.retry(function(callback) {
exports.geocoder.reverse({ lat: firstResult.latitude, lon: firstResult.longitude }, callback);
}, function(err, results) {
if (err) {
return callback(err);
}
var firstResult = results[0];
// Handle Google results
if (!firstResult.state && firstResult.administrativeLevels && firstResult.administrativeLevels.level1short) {
firstResult.state = firstResult.administrativeLevels.level1short;
}
callback(null, results[0]);
});
});
}
}, function(err, results) {
if (err) {
return callback(err);
}
if (!results.geocode) {
return callback();
}
callback(null, {
city: results.geocode.city,
state: normalize(results.geocode.state),
timezone: tzlookup(results.geocode.latitude, results.geocode.longitude)
});
});
}
exports.addressToString = function(address) {
let value = '';
if (address.city) {
value += address.city.trim();
}
if (address.state) {
if (value) {
value += ',';
}
value += ` ${address.state.trim()}`;
}
if (address.zip) {
value += ` ${address.zip.trim()}`;
}
if (address.country) {
if (value) {
value += ',';
}
value += ` ${address.country.trim()}`;
}
return value.trim();
};
exports.parseLocation = async.memoize(function(location, options, callback) {
// Options are optional
if (typeof options === 'function') {
callback = options;
options = undefined;
}
if (!location) {
return callback();
}
// Use Redis (via Petty Cache)
if (options?.pettyCache) {
if (!pettyCache) {
pettyCache = new PettyCache(options.pettyCache.port, options.pettyCache.host, options.pettyCache.options);
}
// Cache between 11-12 months
return pettyCache.fetch(`bloodhound.geocode:${location}`, function(callback) {
geocode(location, callback);
}, { ttl: { min: 28512000000, max: 31104000000 } }, callback);
}
geocode(location, callback);
});
exports.geocoder = NodeGeocoder({ apiKey: process.env.GOOGLE_API_KEY, language: 'en', provider: 'google', region: '.us' });