diff --git a/GeoLite2-City.mmdb b/GeoLite2-City.mmdb new file mode 100644 index 0000000..3f9887f Binary files /dev/null and b/GeoLite2-City.mmdb differ diff --git a/geohash/__init__.py b/geohash/__init__.py new file mode 100644 index 0000000..2a92614 --- /dev/null +++ b/geohash/__init__.py @@ -0,0 +1,21 @@ +""" +Copyright (C) 2008 Leonard Norrgard +Copyright (C) 2015 Leonard Norrgard + +This file is part of Geohash. + +Geohash is free software: you can redistribute it and/or modify it +under the terms of the GNU Affero General Public License as published +by the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Geohash is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public +License for more details. + +You should have received a copy of the GNU Affero General Public +License along with Geohash. If not, see +. +""" +from .geohash import decode_exactly, decode, encode diff --git a/geohash/geohash.py b/geohash/geohash.py new file mode 100644 index 0000000..26040d8 --- /dev/null +++ b/geohash/geohash.py @@ -0,0 +1,109 @@ +""" +Copyright (C) 2008 Leonard Norrgard +Copyright (C) 2015 Leonard Norrgard + +This file is part of Geohash. + +Geohash is free software: you can redistribute it and/or modify it +under the terms of the GNU Affero General Public License as published +by the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Geohash is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public +License for more details. + +You should have received a copy of the GNU Affero General Public +License along with Geohash. If not, see +. +""" +from math import log10 + +# Note: the alphabet in geohash differs from the common base32 +# alphabet described in IETF's RFC 4648 +# (http://tools.ietf.org/html/rfc4648) +__base32 = '0123456789bcdefghjkmnpqrstuvwxyz' +__decodemap = { } +for i in range(len(__base32)): + __decodemap[__base32[i]] = i +del i + +def decode_exactly(geohash): + """ + Decode the geohash to its exact values, including the error + margins of the result. Returns four float values: latitude, + longitude, the plus/minus error for latitude (as a positive + number) and the plus/minus error for longitude (as a positive + number). + """ + lat_interval, lon_interval = (-90.0, 90.0), (-180.0, 180.0) + lat_err, lon_err = 90.0, 180.0 + is_even = True + for c in geohash: + cd = __decodemap[c] + for mask in [16, 8, 4, 2, 1]: + if is_even: # adds longitude info + lon_err /= 2 + if cd & mask: + lon_interval = ((lon_interval[0]+lon_interval[1])/2, lon_interval[1]) + else: + lon_interval = (lon_interval[0], (lon_interval[0]+lon_interval[1])/2) + else: # adds latitude info + lat_err /= 2 + if cd & mask: + lat_interval = ((lat_interval[0]+lat_interval[1])/2, lat_interval[1]) + else: + lat_interval = (lat_interval[0], (lat_interval[0]+lat_interval[1])/2) + is_even = not is_even + lat = (lat_interval[0] + lat_interval[1]) / 2 + lon = (lon_interval[0] + lon_interval[1]) / 2 + return lat, lon, lat_err, lon_err + +def decode(geohash): + """ + Decode geohash, returning two strings with latitude and longitude + containing only relevant digits and with trailing zeroes removed. + """ + lat, lon, lat_err, lon_err = decode_exactly(geohash) + # Format to the number of decimals that are known + lats = "%.*f" % (max(1, int(round(-log10(lat_err)))) - 1, lat) + lons = "%.*f" % (max(1, int(round(-log10(lon_err)))) - 1, lon) + if '.' in lats: lats = lats.rstrip('0') + if '.' in lons: lons = lons.rstrip('0') + return lats, lons + +def encode(latitude, longitude, precision=12): + """ + Encode a position given in float arguments latitude, longitude to + a geohash which will have the character count precision. + """ + lat_interval, lon_interval = (-90.0, 90.0), (-180.0, 180.0) + geohash = [] + bits = [ 16, 8, 4, 2, 1 ] + bit = 0 + ch = 0 + even = True + while len(geohash) < precision: + if even: + mid = (lon_interval[0] + lon_interval[1]) / 2 + if longitude > mid: + ch |= bits[bit] + lon_interval = (mid, lon_interval[1]) + else: + lon_interval = (lon_interval[0], mid) + else: + mid = (lat_interval[0] + lat_interval[1]) / 2 + if latitude > mid: + ch |= bits[bit] + lat_interval = (mid, lat_interval[1]) + else: + lat_interval = (lat_interval[0], mid) + even = not even + if bit < 4: + bit += 1 + else: + geohash += __base32[ch] + bit = 0 + ch = 0 + return ''.join(geohash) diff --git a/geoparser.py b/geoparser.py index e991ea7..0bb4033 100755 --- a/geoparser.py +++ b/geoparser.py @@ -11,7 +11,7 @@ import re import sys import time import geoip2.database -import Geohash +import geohash import configparser from influxdb import InfluxDBClient from IPy import IP as ipadd @@ -56,7 +56,7 @@ def logparse(LOGPATH, INFLUXHOST, INFLUXPORT, INFLUXDBDB, INFLUXUSER, INFLUXUSER if ipadd(IP).iptype() == 'PUBLIC' and IP: INFO = GI.city(IP) if INFO is not None: - HASH = Geohash.encode(INFO.location.latitude, INFO.location.longitude) # NOQA + HASH = geohash.encode(INFO.location.latitude, INFO.location.longitude) # NOQA COUNT['count'] = 1 GEOHASH['geohash'] = HASH GEOHASH['host'] = HOSTNAME diff --git a/geostat.service.template b/geostat.service.template index 4a05964..e62db52 100644 --- a/geostat.service.template +++ b/geostat.service.template @@ -5,7 +5,7 @@ StartLimitIntervalSec=0 [Service] Type=simple -ExecStart=$PWD/venv/bin/python geoparser.py +ExecStart=$PWD/venv/bin/python3 geoparser.py User=root WorkingDirectory=$PWD Restart=always diff --git a/requirements.txt b/requirements.txt index ba2bd41..b9d0bca 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,4 @@ configparser==3.5.0 influxdb==5.2.0 -Geohash==1.0 geoip2==2.9.0 IPy==1.00 diff --git a/settings.ini.back b/settings.ini.back index cdeacc2..bd99eea 100644 --- a/settings.ini.back +++ b/settings.ini.back @@ -8,15 +8,15 @@ geoipdb = ./GeoLite2-City.mmdb [INFLUXDB] # Database URL -host = ip_address +host = 185.27.96.227 port = 8086 #Database name -database = db_name +database = telegraf # HTTP Auth -username = "username" -password = "password" +username = telegraf +password = itieh0eeMo # Measurement name measurement = geodata