kopia lustrzana https://github.com/FacilMap/facilmap
Clean up search code
rodzic
16b7ae18fa
commit
42ee410634
205
server/search.js
205
server/search.js
|
@ -1,21 +1,19 @@
|
|||
var request = require("request-promise");
|
||||
var Promise = require("bluebird");
|
||||
var cheerio = require("cheerio");
|
||||
var zlib = require("zlib");
|
||||
var compressjs = require("compressjs");
|
||||
|
||||
var utils = require("./utils");
|
||||
|
||||
request = request.defaults({
|
||||
const cheerio = require("cheerio");
|
||||
const compressjs = require("compressjs");
|
||||
const Promise = require("bluebird");
|
||||
const request = require("request-promise").defaults({
|
||||
gzip: true,
|
||||
headers: {
|
||||
'User-Agent': process.env.fmUserAgent
|
||||
}
|
||||
});
|
||||
const zlib = require("zlib");
|
||||
|
||||
var nameFinderUrl = "https://nominatim.openstreetmap.org";
|
||||
var limit = 25;
|
||||
var stateAbbr = {
|
||||
const utils = require("./utils");
|
||||
|
||||
const nameFinderUrl = "https://nominatim.openstreetmap.org";
|
||||
const limit = 25;
|
||||
const stateAbbr = {
|
||||
"us" : {
|
||||
"alabama":"AL","alaska":"AK","arizona":"AZ","arkansas":"AR","california":"CA","colorado":"CO","connecticut":"CT",
|
||||
"delaware":"DE","florida":"FL","georgia":"GA","hawaii":"HI","idaho":"ID","illinois":"IL","indiana":"IN","iowa":"IA",
|
||||
|
@ -53,81 +51,44 @@ var stateAbbr = {
|
|||
}
|
||||
};
|
||||
|
||||
function find(query, loadUrls) {
|
||||
|
||||
const search = module.exports = {
|
||||
|
||||
find(query, loadUrls) {
|
||||
return Promise.resolve().then(function() {
|
||||
query = query.replace(/^\s+/, "").replace(/\s+$/, "");
|
||||
|
||||
if(loadUrls) {
|
||||
var m = query.match(/^(node|way|relation)\s+(\d+)$/);
|
||||
let m = query.match(/^(node|way|relation)\s+(\d+)$/);
|
||||
if(m)
|
||||
return loadUrl("https://api.openstreetmap.org/api/0.6/" + m[1] + "/" + m[2] + (m[1] != "node" ? "/full" : ""), true);
|
||||
return search._loadUrl("https://api.openstreetmap.org/api/0.6/" + m[1] + "/" + m[2] + (m[1] != "node" ? "/full" : ""), true);
|
||||
|
||||
m = query.match(/^trace\s+(\d+)$/);
|
||||
if(m)
|
||||
return loadUrl("https://www.openstreetmap.org/trace/" + m[1] + "/data");
|
||||
return search._loadUrl("https://www.openstreetmap.org/trace/" + m[1] + "/data");
|
||||
|
||||
if(query.match(/^https?:\/\//))
|
||||
return loadUrl(query);
|
||||
return search._loadUrl(query);
|
||||
}
|
||||
|
||||
var lonlat_match = query.match(/^(geo\s*:\s*)?(-?\s*\d+([.,]\d+)?)\s*[,;]\s*(-?\s*\d+([.,]\d+)?)(\s*\?z\s*=\s*(\d+))?$/);
|
||||
var osm_match = query.match(/^([nwr])(\d+)$/i);
|
||||
if(lonlat_match || osm_match)
|
||||
{ // Reverse search
|
||||
var url = nameFinderUrl + "/reverse?format=json&addressdetails=1&polygon_geojson=1&extratags=1&namedetails=1";
|
||||
var lonlat;
|
||||
|
||||
let lonlat_match = query.match(/^(geo\s*:\s*)?(-?\s*\d+([.,]\d+)?)\s*[,;]\s*(-?\s*\d+([.,]\d+)?)(\s*\?z\s*=\s*(\d+))?$/);
|
||||
if(lonlat_match) {
|
||||
lonlat = {
|
||||
return search._findLonLat({
|
||||
lat: 1*lonlat_match[2].replace(",", ".").replace(/\s+/, ""),
|
||||
lon : 1*lonlat_match[4].replace(",", ".").replace(/\s+/, ""),
|
||||
zoom : lonlat_match[7] != null ? 1*lonlat_match[7] : null
|
||||
};
|
||||
url += "&lat=" + lonlat.lat
|
||||
+ "&lon=" + lonlat.lon
|
||||
+ "&zoom=" + (lonlat.zoom != null ? (lonlat.zoom >= 12 ? lonlat.zoom+2 : lonlat.zoom) : 17);
|
||||
} else {
|
||||
url += "&osm_type=" + osm_match[1].toUpperCase()
|
||||
+ "&osm_id=" + osm_match[2]
|
||||
}).then((res) => (res.map((res) => (Object.assign(res, {id: query})))));
|
||||
}
|
||||
|
||||
return request({
|
||||
url: url,
|
||||
json: true
|
||||
}).then(function(body) {
|
||||
if(!body || body.error) {
|
||||
if(lonlat) {
|
||||
var name = utils.round(lonlat.lat, 5) + ", " + utils.round(lonlat.lon, 5);
|
||||
return [ {
|
||||
lat: lonlat.lat,
|
||||
lon : lonlat.lon,
|
||||
type : "coordinates",
|
||||
short_name: name,
|
||||
display_name : name,
|
||||
zoom: lonlat.zoom != null ? lonlat.zoom : 15,
|
||||
icon: null
|
||||
} ];
|
||||
} else
|
||||
throw body ? body.error : "Invalid response from name finder";
|
||||
}
|
||||
let osm_match = query.match(/^([nwr])(\d+)$/i);
|
||||
if(osm_match)
|
||||
return search._findOsmObject(osm_match[1], osm_match[2]);
|
||||
|
||||
if(lonlat) {
|
||||
body.lat = lonlat.lat;
|
||||
body.lon = lonlat.lon;
|
||||
|
||||
if(lonlat.zoom != null)
|
||||
body.zoom = lonlat.zoom;
|
||||
}
|
||||
|
||||
var res = prepareSearchResult(body);
|
||||
|
||||
if(lonlat)
|
||||
res.id = query;
|
||||
|
||||
return [ res ];
|
||||
return search._findQuery(query);
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
_findQuery(query) {
|
||||
return request({
|
||||
url: nameFinderUrl + "/search?format=jsonv2&polygon_geojson=1&addressdetails=1&namedetails=1&limit=" + encodeURIComponent(limit) + "&extratags=1&q=" + encodeURIComponent(query),
|
||||
json: true
|
||||
|
@ -138,13 +99,53 @@ function find(query, loadUrls) {
|
|||
if(body.error)
|
||||
throw body.error;
|
||||
|
||||
return body.map(prepareSearchResult);
|
||||
return body.map(search._prepareSearchResult);
|
||||
});
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
function prepareSearchResult(result) {
|
||||
var displayName = makeDisplayName(result);
|
||||
_findOsmObject(type, id) {
|
||||
return request({
|
||||
url: `${nameFinderUrl}/reverse?format=json&addressdetails=1&polygon_geojson=1&extratags=1&namedetails=1&osm_type=${encodeURI(type.toUpperCase())}&osm_id=${encodeURI(id)}`,
|
||||
json: true
|
||||
}).then(function(body) {
|
||||
if(!body || body.error) {
|
||||
throw body ? body.error : "Invalid response from name finder";
|
||||
}
|
||||
|
||||
return [ search._prepareSearchResult(body) ];
|
||||
});
|
||||
},
|
||||
|
||||
_findLonLat(lonlatWithZoom) {
|
||||
return request({
|
||||
url: `${nameFinderUrl}/reverse?format=json&addressdetails=1&polygon_geojson=1&extratags=1&namedetails=1&lat=${encodeURI(lonlatWithZoom.lat)}&lon=${encodeURI(lonlatWithZoom.lon)}&zoom=${encodeURI(lonlatWithZoom.zoom != null ? (lonlatWithZoom.zoom >= 12 ? lonlatWithZoom.zoom+2 : lonlatWithZoom.zoom) : 17)}`,
|
||||
json: true
|
||||
}).then(function(body) {
|
||||
if(!body || body.error) {
|
||||
let name = utils.round(lonlatWithZoom.lat, 5) + ", " + utils.round(lonlatWithZoom.lon, 5);
|
||||
return [ {
|
||||
lat: lonlatWithZoom.lat,
|
||||
lon : lonlatWithZoom.lon,
|
||||
type : "coordinates",
|
||||
short_name: name,
|
||||
display_name : name,
|
||||
zoom: lonlatWithZoom.zoom != null ? lonlatWithZoom.zoom : 15,
|
||||
icon: null
|
||||
} ];
|
||||
}
|
||||
|
||||
body.lat = lonlatWithZoom.lat;
|
||||
body.lon = lonlatWithZoom.lon;
|
||||
|
||||
if(lonlatWithZoom.zoom != null)
|
||||
body.zoom = lonlatWithZoom.zoom;
|
||||
|
||||
return [ search._prepareSearchResult(body) ];
|
||||
});
|
||||
},
|
||||
|
||||
_prepareSearchResult(result) {
|
||||
let displayName = search._makeDisplayName(result);
|
||||
return {
|
||||
short_name: result.namedetails.name || displayName.split(',')[0],
|
||||
display_name: displayName,
|
||||
|
@ -158,30 +159,30 @@ function prepareSearchResult(result) {
|
|||
type: result.type == "yes" ? result.category : result.type,
|
||||
id: result.osm_id ? result.osm_type.charAt(0) + result.osm_id : null
|
||||
};
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
/**
|
||||
* Tries to format a search result in a readable way according to the address notation habits in
|
||||
* the appropriate country.
|
||||
* @param result {Object} A place object as returned by Nominatim
|
||||
* @return {String} A readable name for the search result
|
||||
*/
|
||||
function makeDisplayName(result) {
|
||||
_makeDisplayName(result) {
|
||||
// See http://en.wikipedia.org/wiki/Address_%28geography%29#Mailing_address_format_by_country for
|
||||
// address notation guidelines
|
||||
|
||||
var type = result.type;
|
||||
var name = result.namedetails.name;
|
||||
var countryCode = result.address.country_code;
|
||||
let type = result.type;
|
||||
let name = result.namedetails.name;
|
||||
let countryCode = result.address.country_code;
|
||||
|
||||
var road = result.address.road;
|
||||
var housenumber = result.address.house_number;
|
||||
var suburb = result.address.town || result.address.suburb || result.address.village || result.address.hamlet || result.address.residential;
|
||||
var postcode = result.address.postcode;
|
||||
var city = result.address.city;
|
||||
var county = result.address.county;
|
||||
var state = result.address.state;
|
||||
var country = result.address.country;
|
||||
let road = result.address.road;
|
||||
let housenumber = result.address.house_number;
|
||||
let suburb = result.address.town || result.address.suburb || result.address.village || result.address.hamlet || result.address.residential;
|
||||
let postcode = result.address.postcode;
|
||||
let city = result.address.city;
|
||||
let county = result.address.county;
|
||||
let state = result.address.state;
|
||||
let country = result.address.country;
|
||||
|
||||
if([ "road", "residential", "town", "suburb", "village", "hamlet", "residential", "city", "county", "state" ].indexOf(type) != -1)
|
||||
name = "";
|
||||
|
@ -316,7 +317,7 @@ function makeDisplayName(result) {
|
|||
case "us":
|
||||
if(city && state)
|
||||
{
|
||||
var thisStateAbbr = stateAbbr[countryCode][state.toLowerCase()];
|
||||
let thisStateAbbr = stateAbbr[countryCode][state.toLowerCase()];
|
||||
if(thisStateAbbr)
|
||||
{
|
||||
city += " "+thisStateAbbr;
|
||||
|
@ -333,7 +334,7 @@ function makeDisplayName(result) {
|
|||
{
|
||||
if(county)
|
||||
{
|
||||
var countyAbbr = stateAbbr.it[county.toLowerCase().replace(/ì/g, "i")];
|
||||
let countyAbbr = stateAbbr.it[county.toLowerCase().replace(/ì/g, "i")];
|
||||
if(countyAbbr)
|
||||
{
|
||||
city += " ("+countyAbbr+")";
|
||||
|
@ -373,7 +374,7 @@ function makeDisplayName(result) {
|
|||
break;
|
||||
}
|
||||
|
||||
var ret = [ ];
|
||||
let ret = [ ];
|
||||
|
||||
if(name)
|
||||
ret.push(name);
|
||||
|
@ -395,9 +396,9 @@ function makeDisplayName(result) {
|
|||
ret.push(country);
|
||||
|
||||
return ret.join(", ");
|
||||
}
|
||||
},
|
||||
|
||||
function loadUrl(url, completeOsmObjects) {
|
||||
_loadUrl(url, completeOsmObjects) {
|
||||
return request(url, { encoding: null }).then(function(bodyBuf) {
|
||||
if(!bodyBuf)
|
||||
throw "Invalid response from server.";
|
||||
|
@ -410,22 +411,22 @@ function loadUrl(url, completeOsmObjects) {
|
|||
else
|
||||
return bodyBuf;
|
||||
}).then(function(bodyBuf) {
|
||||
var body = bodyBuf.toString();
|
||||
let body = bodyBuf.toString();
|
||||
|
||||
if(url.match(/^https?:\/\/www\.freietonne\.de\/seekarte\/getOpenLayerPois\.php\?/))
|
||||
return body;
|
||||
else if(body.match(/^\s*</)) {
|
||||
var $ = cheerio.load(body, { xmlMode: true });
|
||||
var rootEl = $.root().children();
|
||||
let $ = cheerio.load(body, { xmlMode: true });
|
||||
let rootEl = $.root().children();
|
||||
|
||||
if(rootEl.is("osm") && completeOsmObjects) {
|
||||
return _loadSubRelations($).then(function() { return $.xml(); });
|
||||
return search._loadSubRelations($).then(function() { return $.xml(); });
|
||||
} else if(rootEl.is("gpx,kml,osm"))
|
||||
return body;
|
||||
else
|
||||
throw "Unknown file format.";
|
||||
} else if(body.match(/^\s*\{/)) {
|
||||
var content = JSON.parse(body);
|
||||
let content = JSON.parse(body);
|
||||
if(content.type)
|
||||
return body;
|
||||
else
|
||||
|
@ -434,12 +435,12 @@ function loadUrl(url, completeOsmObjects) {
|
|||
throw "Unknown file format.";
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
function _loadSubRelations($) {
|
||||
var ret = [ ];
|
||||
_loadSubRelations($) {
|
||||
let ret = [ ];
|
||||
$("member[type='relation']").each(function() {
|
||||
var relId = $(this).attr("ref");
|
||||
let relId = $(this).attr("ref");
|
||||
if($("relation[id='" + relId + "']").length == 0) {
|
||||
ret.push(request("https://api.openstreetmap.org/api/0.6/relation/" + relId + "/full"));
|
||||
}
|
||||
|
@ -451,13 +452,11 @@ function _loadSubRelations($) {
|
|||
$.root().children().append(cheerio.load(relation, { xmlMode: true }).root().children().children());
|
||||
});
|
||||
|
||||
return _loadSubRelations($);
|
||||
return search._loadSubRelations($);
|
||||
});
|
||||
} else {
|
||||
return Promise.resolve();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
find: find
|
||||
};
|
Ładowanie…
Reference in New Issue