Showing posts with label maxmind. Show all posts
Showing posts with label maxmind. Show all posts

Wednesday, May 6, 2015

Сервис определения страны по IP

Итак, возникла необходимость вычислять, так сказать по IP. А точнее - определять страну для автоматической подстановки телефонного кода. Как оказалось, за эту услугу хотят брать денюжки, например тут. Но хочется то халявного. Ну и по общим правилам опенсорса, если что-то надо - напиши сам. Тем более, база, пусть и не такая точная есть у того же MaxMind
Есть также и такая штука, но я что-то не очень уверен в ее скорости. Но можно попробовать.
В любом случае, родился такой сервис.
Абсолютно бесплатно, поддерживает https.
Используется связка Nginx + uwsgi + flask + postgresql. Почему так? Потому что хотелось попробовать, что есть фласк и постгре. Написано крайне коряво, потому что только учусь. Сейчас получается каждый запрос - это отдельное подключение к базе. Т.к. это все-таки сервер есть мнение переписать это под вариант одно подключение - много запросов и подключение держать постоянно. Но как это сделать я пока не знаю, посмотрим на нагрузку.
Ну и по традиции - код. Да, я знаю, он ужасен, в связи с чем попрошу в комментах наставить на путь истинный.

--
upd:

  • Постарался сделать так, чтобы соединение к базе было одно, а не дергать каждый раз.
  • Добавил метод автоопределения места запроса https://geoip.webcall.today/getcountry?ip=auto



from flask import Flask,request,jsonify
import socket
import psycopg2

def ip_address_is_valid(address):
    try: socket.inet_aton(address)
    except socket.error: return False
    else: return address.count('.') == 3

application = Flask(__name__)
con  = psycopg2.connect(database='geoip', user='geoip', host='localhost', password = 'geoipuser')

@application.route('/')
def hello_world():
    return "<b>Geoserver welcomes you. Usage = https://geoip.webcall.today/getcountry?ip=X.X.X.X</b><br> This product includes GeoLite2 data created by MaxMind, available from<br> <a href=\"http://www.maxmind.com\">http://www.maxmind.com</a>."

@application.route('/getcountry')
def getcountry():
    global con
    ip = request.args.get('ip', '')
    if ip == 'auto':
        ip = '%s' % request.remote_addr
    if ip_address_is_valid(ip):
        try:
            cur = con.cursor()
            cur.execute("SELECT code,location,fullname FROM countrydata WHERE geodata = (SELECT geodata FROM ipdata WHERE subnet >>= '%s'::inet LIMIT 1) LIMIT 1" % ip)
            result = cur.fetchone()
            if result:
                result = jsonify(code = result[0],
                                   location = result[1],
                                   name = result[2]), 200
            else:
                result = jsonify(code = 'none',
                                 location = 'None',
                                 name = 'None'), 404
        except psycopg2.DatabaseError, e:
            if con:
                con.rollback()
            con  = psycopg2.connect(database='geoip', user='geoip', host='localhost', password = 'geoipuser')
            result = jsonify(code = 'Error %s' % e,
                            location = 'None',
                            name = 'None'), 500
        finally:
            pass
    else:
        result = jsonify(code = 'none',
                         location = 'None',
                         name = 'None'), 404
    return result

if __name__ == '__main__':
    application.run(host='127.0.0.1')


Ну и ip_address_is_valid можно переписать с использованием регулярок. Что-то типа

--import socket
++import re

def ip_address_is_valid(address):
    regex_ip = "^(\d|[1-9]\d|1\d\d|2([0-4]\d|5[0-5]))\.(\d|[1-9]\d|1\d\d|2([0-4]\d|5[0-5]))\.(\d|[1-9]\d|1\d\d|2([0-4]\d|5[0-5]))\.(\d|[1-9]\d|1\d\d|2([0-4]\d|5[0-5]))$"
    if re.match(regex_ip, address):
        return True
    return False