Browse Source

Code for cluster-geo service.

Adam Ierymenko 9 years ago
parent
commit
25a84e30fc
4 changed files with 121 additions and 10 deletions
  1. 4 10
      .gitignore
  2. 7 0
      cluster-geo/config.js.sample
  3. 94 0
      cluster-geo/index.js
  4. 16 0
      cluster-geo/package.json

+ 4 - 10
.gitignore

@@ -49,23 +49,17 @@ Thumbs.db
 *.rpm
 *.autosave
 *.tmp
+node_modules
 
-# Root topology build files, temporaries, and never check in secrets
-/root-topology/bin2c
-/root-topology/mktopology
-/root-topology/*.secret
-/root-topology/test/supernodes
-/root-topology/test/test-root-topology
+# cluster-geo stuff
+cluster-geo/config.js
+cluster-geo/cache.*
 
 # MacGap wrapper build files
 /ext/mac-ui-macgap1-wrapper/src/MacGap.xcodeproj/project.xcworkspace/xcuserdata/*
 /ext/mac-ui-macgap1-wrapper/src/MacGap.xcodeproj/xcuserdata/*
 /ext/mac-ui-macgap1-wrapper/src/build
 
-# Web UI dev temporaries
-/ui/.module-cache
-node_modules
-
 # Java/Android/JNI build droppings
 java/obj/
 java/libs/

+ 7 - 0
cluster-geo/config.js.sample

@@ -0,0 +1,7 @@
+// MaxMind GeoIP2 config
+module.exports.maxmind = {
+	userId: 1234,
+	licenseKey: 'asdf',
+	service: 'city',
+	requestTimeout: 1000
+};

+ 94 - 0
cluster-geo/index.js

@@ -0,0 +1,94 @@
+//
+// GeoIP lookup service
+//
+
+// GeoIP cache TTL in ms
+var CACHE_TTL = (60 * 60 * 24 * 60 * 1000); // 60 days
+
+var config = require(__dirname + '/config.js');
+
+if (!config.maxmind) {
+	console.error('FATAL: only MaxMind GeoIP2 is currently supported and is not configured in config.js');
+	process.exit(1);
+}
+var geo = require('geoip2ws')(config.maxmind);
+
+var cache = require('levelup')(__dirname + '/cache.leveldb');
+
+function lookup(ip,callback)
+{
+	cache.get(ip,function(err,cachedEntryJson) {
+		if ((!err)&&(cachedEntryJson)) {
+			try {
+				var cachedEntry = JSON.parse(cachedEntryJson.toString());
+				if (cachedEntry) {
+					var ts = cachedEntry.ts;
+					var r = cachedEntry.r;
+					if ((ts)&&(r)) {
+						if ((Date.now() - ts) < CACHE_TTL) {
+							r._cached = true;
+							return callback(null,r);
+						}
+					}
+				}
+			} catch (e) {}
+		}
+
+		geo(ip,function(err,result) {
+			if (err)
+				return callback(err,null);
+			if ((!result)||(!result.location))
+				return callback(new Error('null result'),null);
+
+			cache.put(ip,JSON.stringify({
+				ts: Date.now(),
+				r: result
+			}),function(err) {
+				if (err)
+					console.error('Error saving to cache: '+err);
+				return callback(null,result);
+			});
+		});
+	});
+};
+
+var linebuf = '';
+process.stdin.on('readable',function() {
+	var chunk;
+	while (null !== (chunk = process.stdin.read())) {
+		for(var i=0;i<chunk.length;++i) {
+			var c = chunk[i];
+			if ((c == 0x0d)||(c == 0x0a)) {
+				if (linebuf.length > 0) {
+					var ip = linebuf;
+					lookup(ip,function(err,result) {
+						if ((err)||(!result)||(!result.location)) {
+							return process.stdout.write(ip+',0,0,0,0,0,0\n');
+						} else {
+							var lat = parseFloat(result.location.latitude);
+							var lon = parseFloat(result.location.longitude);
+
+							// Convert to X,Y,Z coordinates from Earth's origin, Earth-as-sphere approximation.
+							var latRadians = lat * 0.01745329251994; // PI / 180
+							var lonRadians = lon * 0.01745329251994; // PI / 180
+							var cosLat = Math.cos(latRadians);
+							var x = Math.round((-6371.0) * cosLat * Math.cos(lonRadians)); // 6371 == Earth's approximate radius in kilometers
+							var y = Math.round(6371.0 * Math.sin(latRadians));
+							var z = Math.round(6371.0 * cosLat * Math.sin(lonRadians));
+
+							return process.stdout.write(ip+',1,'+lat+','+lon+','+x+','+y+','+z+'\n');
+						}
+					});
+				}
+				linebuf = '';
+			} else {
+				linebuf += String.fromCharCode(c);
+			}
+		}
+	}
+});
+
+process.stdin.on('end',function() {
+	cache.close();
+	process.exit(0);
+});

+ 16 - 0
cluster-geo/package.json

@@ -0,0 +1,16 @@
+{
+  "name": "cluster-geo",
+  "version": "1.0.0",
+  "description": "Cluster GEO-IP Query Service",
+  "main": "index.js",
+  "scripts": {
+    "test": "echo \"Error: no test specified\" && exit 1"
+  },
+  "author": "ZeroTier, Inc.",
+  "license": "GPL-3.0",
+  "dependencies": {
+    "geoip2ws": "^1.7.1",
+    "leveldown": "^1.4.2",
+    "levelup": "^1.2.1"
+  }
+}