Skip to content

Commit ce05ee4

Browse files
committed
Added admin 1 and 2 codes scaffolding.
1 parent 272a7bf commit ce05ee4

File tree

2 files changed

+166
-30
lines changed

2 files changed

+166
-30
lines changed

Procfile

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
web: node app.js

geocoder.js

+165-30
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@
2929

3030
'use strict';
3131

32+
var DEBUG = true;
33+
3234
var fs = require('fs');
3335
var kdTree = require('kdt');
3436
var request = require('request');
@@ -38,7 +40,9 @@ var async = require('async');
3840

3941
// All data from http://download.geonames.org/export/dump/
4042
var GEONAMES_URL = 'http://download.geonames.org/export/dump/';
41-
var GEONAMES_FILE = 'cities1000';
43+
var CITIES_FILE = 'cities1000';
44+
var ADMIN_1_CODES_FILE = 'admin1CodesASCII';
45+
var ADMIN_2_CODES_FILE = 'admin2Codes';
4246
var GEONAMES_DUMP = './geonames_dump';
4347
/* jshint maxlen: false */
4448
var GEONAMES_COLUMNS = [
@@ -64,51 +68,146 @@ var GEONAMES_COLUMNS = [
6468
];
6569
/* jshint maxlen: 80 */
6670

67-
var DEBUG = false;
68-
6971
var geocoder = {
7072
_kdTree: null,
73+
_admin1Codes: null,
74+
_admin2Codes: null,
75+
76+
_getGeoNamesData: function() {
77+
78+
},
79+
80+
_getGeoNamesAdmin1CodesData: function(callback) {
81+
var now = (new Date()).toISOString().substr(0, 10);
82+
if (fs.existsSync(GEONAMES_DUMP + '/admin1_codes/' + ADMIN_1_CODES_FILE +
83+
'_' + now + '.csv')) {
84+
DEBUG && console.log('Using cached GeoNames admin 1 codes data from ' +
85+
GEONAMES_URL + ADMIN_1_CODES_FILE + '.txt');
86+
return callback(null, GEONAMES_DUMP + '/admin1_codes/' +
87+
ADMIN_1_CODES_FILE + '_' + now + '.csv');
88+
}
89+
DEBUG && console.log('Getting GeoNames admin 1 codes data from ' +
90+
GEONAMES_URL + ADMIN_1_CODES_FILE + '.txt (this may take a while)');
91+
var url = GEONAMES_URL + ADMIN_1_CODES_FILE + '.txt';
92+
request.get(url, function(err, response, body) {
93+
if (err || response.statusCode !== 200) {
94+
return callback('Error downloading GeoNames admin 1 codes data' +
95+
(err ? ': ' + err : ''));
96+
}
97+
// Store a dump locally
98+
if (!fs.existsSync(GEONAMES_DUMP + '/admin1_codes')) {
99+
fs.mkdirSync(GEONAMES_DUMP + '/admin1_codes');
100+
}
101+
var fileName = GEONAMES_DUMP + '/admin1_codes/' + ADMIN_1_CODES_FILE +
102+
'_' + now + '.csv';
103+
try {
104+
fs.writeFileSync(fileName, body);
105+
// Housekeeping, remove old files
106+
var currentFileName = ADMIN_1_CODES_FILE + '_' + now + '.csv';
107+
fs.readdirSync(GEONAMES_DUMP + '/admin1_codes').forEach(function(file) {
108+
if (file !== currentFileName) {
109+
fs.unlink(GEONAMES_DUMP + '/admin1_codes/' + file);
110+
}
111+
});
112+
} catch(e) {
113+
throw(e);
114+
}
115+
return callback(null, fileName);
116+
});
117+
},
118+
119+
_parseGeoNamesAdmin1CodesCsv: function(pathToCsv, callback) {
120+
return callback();
121+
},
122+
123+
_getGeoNamesAdmin2CodesData: function(callback) {
124+
var now = (new Date()).toISOString().substr(0, 10);
125+
if (fs.existsSync(GEONAMES_DUMP + '/admin2_codes/' + ADMIN_2_CODES_FILE +
126+
'_' + now + '.csv')) {
127+
DEBUG && console.log('Using cached GeoNames admin 2 codes data from ' +
128+
GEONAMES_URL + ADMIN_2_CODES_FILE + '.txt');
129+
return callback(null, GEONAMES_DUMP + '/admin2_codes/' +
130+
ADMIN_2_CODES_FILE + '_' + now + '.csv');
131+
}
132+
DEBUG && console.log('Getting GeoNames admin 2 codes data from ' +
133+
GEONAMES_URL + ADMIN_2_CODES_FILE + '.txt (this may take a while)');
134+
var url = GEONAMES_URL + ADMIN_2_CODES_FILE + '.txt';
135+
request.get(url, function(err, response, body) {
136+
if (err || response.statusCode !== 200) {
137+
return callback('Error downloading GeoNames admin 2 codes data' +
138+
(err ? ': ' + err : ''));
139+
}
140+
// Store a dump locally
141+
if (!fs.existsSync(GEONAMES_DUMP + '/admin2_codes')) {
142+
fs.mkdirSync(GEONAMES_DUMP + '/admin2_codes');
143+
}
144+
var fileName = GEONAMES_DUMP + '/admin2_codes/' + ADMIN_2_CODES_FILE +
145+
'_' + now + '.csv';
146+
try {
147+
fs.writeFileSync(fileName, body);
148+
// Housekeeping, remove old files
149+
var currentFileName = ADMIN_2_CODES_FILE + '_' + now + '.csv';
150+
fs.readdirSync(GEONAMES_DUMP + '/admin2_codes').forEach(function(file) {
151+
if (file !== currentFileName) {
152+
fs.unlink(GEONAMES_DUMP + '/admin2_codes/' + file);
153+
}
154+
});
155+
} catch(e) {
156+
throw(e);
157+
}
158+
return callback(null, fileName);
159+
});
160+
},
71161

72-
_getGeoNamesData: function(callback) {
162+
_parseGeoNamesAdmin2CodesCsv: function(pathToCsv, callback) {
163+
return callback();
164+
},
165+
166+
_getGeoNamesCititesData: function(callback) {
73167
var now = (new Date()).toISOString().substr(0, 10);
74-
if (fs.existsSync(GEONAMES_DUMP + '/' + now + '.csv')) {
75-
DEBUG && console.log('Using cached GeoNames data from ' + GEONAMES_URL +
76-
GEONAMES_FILE + '.zip');
77-
return callback(null, GEONAMES_DUMP + '/' + now + '.csv');
168+
if (fs.existsSync(GEONAMES_DUMP + '/cities/' + CITIES_FILE + '_' + now +
169+
'.csv')) {
170+
DEBUG && console.log('Using cached GeoNames cities data from ' +
171+
GEONAMES_URL + CITIES_FILE + '.zip');
172+
return callback(null, GEONAMES_DUMP + '/cities/' + CITIES_FILE + '_' +
173+
now + '.csv');
78174
}
79-
DEBUG && console.log('Getting GeoNames data from ' + GEONAMES_URL +
80-
GEONAMES_FILE + '.zip (this may take a while)');
175+
DEBUG && console.log('Getting GeoNames cities data from ' + GEONAMES_URL +
176+
CITIES_FILE + '.zip (this may take a while)');
81177
var options = {
82-
url: GEONAMES_URL + GEONAMES_FILE + '.zip',
178+
url: GEONAMES_URL + CITIES_FILE + '.zip',
83179
encoding: null
84180
};
85181
request.get(options, function(err, response, body) {
86182
if (err || response.statusCode !== 200) {
87-
return callback('Error downloading GeoNames data' +
183+
return callback('Error downloading GeoNames cities data' +
88184
(err ? ': ' + err : ''));
89185
}
90-
DEBUG && console.log('Received zipped GeoNames data');
186+
DEBUG && console.log('Received zipped GeoNames cities data');
91187
// Store a dump locally
92-
if (!fs.existsSync(GEONAMES_DUMP)) {
93-
fs.mkdirSync(GEONAMES_DUMP);
188+
if (!fs.existsSync(GEONAMES_DUMP + '/cities')) {
189+
fs.mkdirSync(GEONAMES_DUMP + '/cities');
94190
}
95-
var oldName = GEONAMES_DUMP + '/' + GEONAMES_FILE + '.txt';
191+
var oldName = GEONAMES_DUMP + '/cities/' + CITIES_FILE + '.txt';
96192
// Name files like a timestamp so we can easily remove old files
97-
var newName = GEONAMES_DUMP + '/' + now + '.csv';
98-
var fileName = GEONAMES_DUMP + '/' + now + '.zip';
193+
var newName = GEONAMES_DUMP + '/cities/' + CITIES_FILE + '_' + now +
194+
'.csv';
195+
var fileName = GEONAMES_DUMP + '/cities/' + CITIES_FILE + '_' + now +
196+
'.zip';
99197
try {
100198
fs.writeFileSync(fileName, body);
101199
var zipped = new zip(fileName);
102-
zipped.extractEntryTo(GEONAMES_FILE + '.txt', GEONAMES_DUMP, false,
103-
true);
200+
zipped.extractEntryTo(CITIES_FILE + '.txt', GEONAMES_DUMP + '/cities',
201+
false, true);
104202
fs.renameSync(oldName, newName);
105-
fs.unlink(GEONAMES_DUMP + '/' + now + '.zip');
106-
DEBUG && console.log('Unzipped GeoNames data');
203+
fs.unlink(GEONAMES_DUMP + '/cities/' + CITIES_FILE + '_' + now +
204+
'.zip');
205+
DEBUG && console.log('Unzipped GeoNames cities data');
107206
// Housekeeping, remove old files
108-
var currentFileName = now + '.csv';
109-
fs.readdirSync(GEONAMES_DUMP).forEach(function(file) {
207+
var currentFileName = CITIES_FILE + '_' + now + '.csv';
208+
fs.readdirSync(GEONAMES_DUMP + '/cities').forEach(function(file) {
110209
if (file !== currentFileName) {
111-
fs.unlink(GEONAMES_DUMP + '/' + file);
210+
fs.unlink(GEONAMES_DUMP + '/cities/' + file);
112211
}
113212
});
114213
} catch(e) {
@@ -118,7 +217,7 @@ var geocoder = {
118217
});
119218
},
120219

121-
_parseGeoNamesCsv: function(pathToCsv, callback) {
220+
_parseGeoNamesCitiesCsv: function(pathToCsv, callback) {
122221
var data = [];
123222
var lenI = GEONAMES_COLUMNS.length;
124223
var that = this;
@@ -166,10 +265,45 @@ var geocoder = {
166265

167266
_init: function(callback) {
168267
DEBUG && console.log('Initializing local reverse geocoder');
169-
async.waterfall([
170-
this._getGeoNamesData.bind(this),
171-
this._parseGeoNamesCsv.bind(this)
172-
], function() {
268+
// Create local cache folder
269+
if (!fs.existsSync(GEONAMES_DUMP)) {
270+
fs.mkdirSync(GEONAMES_DUMP);
271+
}
272+
var that = this;
273+
async.parallel([
274+
// Get GeoNames cities
275+
function(waterfallCallback) {
276+
async.waterfall([
277+
that._getGeoNamesCititesData.bind(that),
278+
that._parseGeoNamesCitiesCsv.bind(that)
279+
], function() {
280+
return waterfallCallback();
281+
});
282+
},
283+
// Get GeoNames admin 1 codes
284+
function(waterfallCallback) {
285+
async.waterfall([
286+
that._getGeoNamesAdmin1CodesData.bind(that),
287+
that._parseGeoNamesAdmin1CodesCsv.bind(that)
288+
], function() {
289+
return waterfallCallback();
290+
});
291+
},
292+
// Get GeoNames admin 2 codes
293+
function(waterfallCallback) {
294+
async.waterfall([
295+
that._getGeoNamesAdmin2CodesData.bind(that),
296+
that._parseGeoNamesAdmin2CodesCsv.bind(that)
297+
], function() {
298+
return waterfallCallback();
299+
});
300+
}
301+
],
302+
// Main callback
303+
function(err) {
304+
if (err) {
305+
throw(err);
306+
}
173307
return callback();
174308
});
175309
},
@@ -195,6 +329,7 @@ var geocoder = {
195329
async.series(
196330
functions,
197331
function(err, results) {
332+
DEBUG && console.log('Delivering results');
198333
return callback(null, results);
199334
});
200335
}

0 commit comments

Comments
 (0)