Mon 21 Jul 22:43:21 CEST 2025
This commit is contained in:
parent
3d9ecd1714
commit
b90dc89bcb
285
js/geoip/geoloc5.js
Normal file
285
js/geoip/geoloc5.js
Normal file
|
@ -0,0 +1,285 @@
|
|||
|
||||
var Options = {
|
||||
// stage1
|
||||
locate : {
|
||||
primary : {http:'ag-0.de:9999',https:'ag-0.de:9998',path:'/json',timeout:1000},
|
||||
secondary : {http:'ip-api.com:80',https:'ip-api.com:80',path:'/json',timeout:2000},
|
||||
},
|
||||
// stage2
|
||||
locate5 : {
|
||||
// secondary : {https:'api.beacondb.net:443',path:'/v1/geolocate?key=test'},
|
||||
},
|
||||
// stage 3: lat,lon -> location info lookup
|
||||
reverse : {
|
||||
primary : {https:'api.opencagedata.com',path:'/geocode/v1/json?q=LAT+LON&key=f4280d4685bd4241b2f754957b86dac6'},
|
||||
secondary: {https:'nominatim.openstreetmap.org',path:'/reverse/?format=json&lat=LAT&lon=LON'},
|
||||
},
|
||||
verbose : 0
|
||||
}
|
||||
|
||||
var http=Require("http"),https; /* https on demand */
|
||||
|
||||
function ip(url) { return url.split(':')[0] }
|
||||
function port(url) { return url.split(':')[1] }
|
||||
|
||||
// 1. GPS/GEO via IP and external database service
|
||||
function stage1 (cb,options,location) {
|
||||
var e,r;
|
||||
if (!http.xhr && http.request) {
|
||||
// node.js
|
||||
e={hostname:ip(options.http),
|
||||
path:options.path||'',method:"GET",
|
||||
port:port(options.http)};
|
||||
if (Options.verbose) console.log('locate.stage1',e);
|
||||
r=http.request(e,function(a){
|
||||
a.setEncoding("utf8");
|
||||
var c="";
|
||||
a.on("data",function(a){c+=a}),
|
||||
a.on("end",function(){
|
||||
try {
|
||||
var info=JSON.parse(c);
|
||||
if (Options.verbose) console.log('locate.stage1.res',info);
|
||||
Object.assign(location,{
|
||||
ip:info.query,
|
||||
gps:{lat:info.lat,lon:info.lon},
|
||||
geo:{city:info.city,country:info.country,countryCode:info.countryCode,region:info.region,zip:info.zip}
|
||||
})
|
||||
return cb(location);
|
||||
} catch (err) {
|
||||
return cb(err);
|
||||
}
|
||||
})
|
||||
});
|
||||
r.on("error",function(a) {
|
||||
if (Options.verbose) console.log('locate.stage1.err',a);
|
||||
return cb(a);
|
||||
})
|
||||
r.setTimeout(options.timeout,function() {
|
||||
if (Options.verbose) console.log('locate.stage1.err',"ETIMEOUT");
|
||||
return cb(new Error("ETIMEOUT"));
|
||||
})
|
||||
r.end();
|
||||
} else {
|
||||
// Browser
|
||||
var proto=document.URL.indexOf('https')==0?'https':'http';
|
||||
e={uri:proto+'://'+options[proto]+'/'+options.path,
|
||||
method:"GET",
|
||||
headers:{}};
|
||||
if (Options.verbose) console.log('stage1',e);
|
||||
http.request(e,function(err,xhr,body){
|
||||
if (err) {
|
||||
if (Options.verbose) console.log('locate.stage1.err',err);
|
||||
return cb(err);
|
||||
}
|
||||
try {
|
||||
var info=JSON.parse(body);
|
||||
if (Options.verbose) console.log('locate.stage1.res',info);
|
||||
Object.assign(location,{
|
||||
ip:info.query,
|
||||
gps:{lat:info.lat,lon:info.lon},
|
||||
geo:{city:info.city,country:info.country,countryCode:info.countryCode,region:info.region,zip:info.zip}
|
||||
})
|
||||
return cb(location);
|
||||
} catch (err) {
|
||||
if (Options.verbose) console.log('locate.stage1.err',err);
|
||||
return cb(err);
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// 2. GPS via IP and external database service
|
||||
function stage2 (cb,options,location) {
|
||||
if (!https || !https.request) return cb(new Error('ENETWORK'));
|
||||
if (!https.xhr && https.request) {
|
||||
var e = {
|
||||
hostname: ip(options.https),
|
||||
port: port(options.https),
|
||||
path: options.path,
|
||||
method: 'GET'
|
||||
}
|
||||
if (Options.verbose) console.log('locate.stage2',e);
|
||||
var req = https.request(e, function (res) {
|
||||
res.on('data', function (d){
|
||||
try {
|
||||
var pos = JSON.parse(d);
|
||||
if (Options.verbose) console.log('locate.stage3.res',pos);
|
||||
location.gps5 = { lat: pos.location.lat, lon:pos.location.lng }
|
||||
cb(location)
|
||||
} catch (e) { if (Options.verbose) console.log('locate.stage2.err',e); cb(e) };
|
||||
});
|
||||
})
|
||||
|
||||
req.on('error', function (e) {
|
||||
cb(e);
|
||||
});
|
||||
req.end();
|
||||
} else {
|
||||
// Browser
|
||||
e={uri:'https://'+options.https+'/'+options.path,
|
||||
method:"GET",
|
||||
headers:{}};
|
||||
if (Options.verbose) console.log('locate.stage2',e);
|
||||
https.request(e,function(err,xhr,body){
|
||||
if (err) {
|
||||
if (Options.verbose) console.log('locate.stage2.err',err);
|
||||
return cb(err);
|
||||
}
|
||||
try {
|
||||
var pos = JSON.parse(body);
|
||||
if (Options.verbose) console.log('locate.stage2.res',pos);
|
||||
location.gps5 = { lat: pos.location.lat, lon:pos.location.lng }
|
||||
return cb(location);
|
||||
} catch (err) {
|
||||
if (Options.verbose) console.log('locate.stage2.err',err);
|
||||
return cb(err);
|
||||
}
|
||||
})
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// GPS -> GEO mapping by external database service, more precise information
|
||||
// Should use only gps5 (based on GPS), not gps (based in IP address)
|
||||
function stage3 (cb,options,location) {
|
||||
if (!https || !https.request) return cb(new Error('ENETWORK'));
|
||||
// location.gps is @IP location
|
||||
var gps = location.gps5 // || location.gps
|
||||
if (!gps) return cb(new Error("No GPS location"));
|
||||
options.path=options.path
|
||||
.replace(/LAT/,gps.lat)
|
||||
.replace(/LON/,gps.lon);
|
||||
if (!https.xhr && https.request) {
|
||||
var e = {
|
||||
hostname: ip(options.https),
|
||||
port: port(options.https),
|
||||
path: options.path,
|
||||
method: 'GET'
|
||||
}
|
||||
if (Options.verbose) console.log('locate.stage3',e);
|
||||
var req = https.request(e, function (res) {
|
||||
res.on('data', function (d){
|
||||
try {
|
||||
var res = JSON.parse(d);
|
||||
var loc;
|
||||
if (Options.verbose) console.log('locate.stage3.res',res);
|
||||
if (res.address) loc=res.address;
|
||||
else if (res.results && res.results[0]) loc=res.results[0].components;
|
||||
location.geo5 = {
|
||||
city:loc.city,
|
||||
zip:loc.postcode,
|
||||
street:loc.road,
|
||||
number:loc.house_number,
|
||||
country:loc.country
|
||||
}
|
||||
cb(location)
|
||||
} catch (e) { if (Options.verbose) console.log('locate.stage3.err',e); cb(e) };
|
||||
});
|
||||
})
|
||||
|
||||
req.on('error', function (e) {
|
||||
if (Options.verbose) console.log('locate.stage3.err',e);
|
||||
cb(e);
|
||||
});
|
||||
req.end();
|
||||
} else {
|
||||
// Browser
|
||||
e={uri:'https://'+options.https+'/'+options.path,
|
||||
method:"GET",
|
||||
headers:{}};
|
||||
if (Options.verbose) console.log('locate.stage3',e);
|
||||
https.request(e,function(err,xhr,body){
|
||||
if (err) {
|
||||
if (Options.verbose) console.log('locate.stage3.err',err);
|
||||
return cb(err);
|
||||
}
|
||||
try {
|
||||
var res = JSON.parse(body);
|
||||
var loc;
|
||||
if (Options.verbose) console.log('locate.stage3.res',res);
|
||||
if (res.address) loc=res.address;
|
||||
else if (res.results && res.results[0]) loc=res.results[0].components;
|
||||
location.geo5 = {
|
||||
city:loc.city,
|
||||
zip:loc.postcode,
|
||||
street:loc.road,
|
||||
number:loc.house_number,
|
||||
country:loc.country
|
||||
}
|
||||
return cb(location);
|
||||
} catch (err) {
|
||||
if (Options.verbose) console.log('locate.stage3.err',err);
|
||||
return cb(err);
|
||||
}
|
||||
})
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
var todo = {
|
||||
// 1. Direct ISP - IP - GPS/GEO lookup
|
||||
// 1a. with proxy
|
||||
stage1A: function (cb,errors,location) {
|
||||
stage1(function (res) {
|
||||
if (res instanceof Error) {
|
||||
errors.push({url:Options.locate.primary,error:res});
|
||||
todo.stage1B(cb,errors,location);
|
||||
} else {
|
||||
todo.stage2A(cb,errors,location);
|
||||
}
|
||||
},Options.locate.primary,location);
|
||||
},
|
||||
// 1b. w/o proxy
|
||||
stage1B: function (cb,errors,location) {
|
||||
stage1(function (res) {
|
||||
if (res instanceof Error) {
|
||||
errors.push({url:Options.locate.secondary,error:res});
|
||||
todo.stage2A(cb,errors,location);
|
||||
} else {
|
||||
todo.stage2A(cb,errors,location);
|
||||
}
|
||||
},Options.locate.secondary,location);
|
||||
},
|
||||
// 2. Get geo position (lat,lon)
|
||||
stage2A: function (cb,errors,location) {
|
||||
if (Options.locate5.secondary) stage2(function (res) {
|
||||
if (res instanceof Error) {
|
||||
errors.push({url:Options.locate5.secondary,error:res});
|
||||
todo.finalize(cb,errors,location);
|
||||
} else {
|
||||
todo.stage2B(cb,errors,location);
|
||||
}
|
||||
},Options.locate5.secondary,location);
|
||||
else
|
||||
todo.stage2B(cb,errors,location);
|
||||
},
|
||||
// 3. Get geo location (country,..)
|
||||
stage2B: function (cb,errors,location) {
|
||||
stage3(function (res) {
|
||||
if (res instanceof Error) {
|
||||
errors.push({url:Options.reverse.primary,x:1,error:res});
|
||||
todo.finalize(cb,errors,location);
|
||||
} else {
|
||||
todo.finalize(cb,errors,location);
|
||||
}
|
||||
},Options.reverse.primary,location);
|
||||
},
|
||||
finalize : function (cb,errors,location) {
|
||||
cb(location,errors);
|
||||
}
|
||||
}
|
||||
|
||||
function locate (cb,options) {
|
||||
var e;
|
||||
if (options) Options=Object.assign(Options,options);
|
||||
if (typeof require == 'function' && !https) try {
|
||||
https = require('https');
|
||||
} catch (e) { /* TODO Browser */ } else if (http.xhr) https = http;
|
||||
if (!http) return cb(new Error('ENOTSUPPORTED'));
|
||||
todo.stage1A(cb,[],{});
|
||||
return;
|
||||
}
|
||||
|
||||
module.exports={locate:locate,options:Options};
|
||||
|
Loading…
Reference in New Issue
Block a user