Giter Club home page Giter Club logo

geolix's Introduction

Geolix

IP information lookup provider.

Package Setup

To use Geolix with your projects, edit your mix.exs file and add the project as a dependency:

defp deps do
  [
    # ...
    {:geolix, "~> 2.0"},
    # ...
  ]
end

If you want to use a manual supervision approach (without starting the application) please look at the inline documentation of Geolix.Supervisor.

Application Configuration

Every lookup request is passed to all configured databases:

config :geolix,
  databases: [
    %{
      id: :city,
      adapter: MyAdapter,
      source: "/absolute/path/to/city.db"
    },
    %{
      id: :country,
      adapter: MyAdapter,
      source: "/absolute/path/to/country.db"
    }
  ]

Above configuration will use the adapter MyAdapter and return a result for an example :city and :country database. The exact configuration values you need to provide are defined by the adapter you are using.

More details on database configuration can be found inline at the main Geolix module.

Adapters

All the work done by Geolix is handled using adapters. These adapters can use a database, a webservice or any other means available to handle your lookup requests.

Known adapters:

For detailed information how to configure the adapter of your choice please read the adapter's configuration.

Fake Adapter

Pre-packaged is a fake/static adapter (Geolix.Adapter.Fake) working on a plain Agent holding your IP lookup responses. An example of how you might use this adapter:

config :geolix,
  databases: [
    %{
      id: :country,
      adapter: Geolix.Adapter.Fake,
      data: %{
        {1, 1, 1, 1} => %{country: %{iso_code: "US"}},
        {2, 2, 2, 2} => %{country: %{iso_code: "GB"}}
      }
    }
  ]

Please refer to the inline documentation of the Geolix.Adapter.Fake module for more details.

Custom Adapters

Adapters are expected to adhere to the Geolix.Adapter behaviour. As a starting point for writing a custom adapter you can look at the packaged Geolix.Adapter.Fake.

Basic Usage

Lookups are done using Geolix.lookup/1,2:

iex(1)> Geolix.lookup("127.0.0.1")
%{
  city: %{...},
  country: %{...}
}

iex(2)> Geolix.lookup({127, 0, 0, 1}, where: :my_database)
%{...}

Full documentation is available inline in the Geolix module and at https://hexdocs.pm/geolix.

License

Apache License, Version 2.0

geolix's People

Contributors

coladarci avatar mneudert avatar ook avatar s-stepien avatar tcitworld avatar whitfin avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

geolix's Issues

Add instructions on how to setup in a Supervision tree

Right now it doesn't look like there's a clear way to link the Geolix Supervisor to an Application Supervisor. It'd be cool if this was more easily supported - for example if Geolix.start_link/2 existed and would allow you to link to it (and was documented).

Use struct instead of generic %{} map

It would be better to define a struct, say %Geolix.Result{} where the map keys are always present, as opposed to building it up with Map.put, because right now, some keys, like subdivisions, are not added to the map for certain addresses, causing a crash.

Error: bad request with valid filename

Geolix.set_database(:city, "https://s3-us-west-2.amazonaws.com/ip-profiler/GeoLite2-City.mmdb")

Returns an error claiming the file doesn't exist, but you can go to it here and it is perfectly valid. I'm currently running:

  • Erlang 18.1.3
  • Elixir 1.1.1
  • Phoenix 1.0.4
  • Geolix 0.9

I set up the plugin exactly as specified in the documentation. If you need any more information or help let me know!

Incorrect record for IPv6 GeoIP2 City lookups

I am getting incorrect results as compared to libmaxminddb's mmdblookup:

iex(1)> Geolix.set_database(:city, "/usr/local/share/GeoIP/GeoIP2-City.mmdb")
:ok
iex(2)> Geolix.lookup("2001:200::", [ as: :raw, where: :city ])        
%{continent: %{code: "OC", geoname_id: 6255151,
    names: %{de: "Ozeanien", en: "Oceania", es: "Oceanía", fr: "Océanie",
      ja: "オセアニア", "pt-BR": "Oceania", ru: "Океания",
      "zh-CN": "大洋洲"}},
  country: %{geoname_id: 2077456, iso_code: "AU",
    names: %{de: "Australien", en: "Australia", es: "Australia",
      fr: "Australie", ja: "オーストラリア", "pt-BR": "Austrália",
      ru: "Австралия", "zh-CN": "澳大利亚"}},
  ip_address: {8193, 512, 0, 0, 0, 0, 0, 0},
  location: %{latitude: -27.0, longitude: 133.0},
  registered_country: %{geoname_id: 2077456, iso_code: "AU",
    names: %{de: "Australien", en: "Australia", es: "Australia",
      fr: "Australie", ja: "オーストラリア", "pt-BR": "Austrália",
      ru: "Австралия", "zh-CN": "澳大利亚"}}}
mmdblookup -f /usr/local/share/GeoIP/GeoIP2-City.mmdb -i 2001:200:: -v

  Database metadata
    Node count:    9224264
    Record size:   28 bits
    IP version:    IPv6
    Binary format: 2.0
    Build epoch:   1412772358 (2014-10-08 12:45:58 UTC)
    Type:          GeoIP2-City
    Languages:     de en es fr ja pt-BR ru zh-CN
    Description:
      en:   GeoIP2 City database


  {
    "city": 
      {
        "geoname_id": 
          2110683 <uint32>
        "names": 
          {
            "en": 
              "Tsukuba" <utf8_string>
          }
      }
    "continent": 
      {
        "code": 
          "AS" <utf8_string>
        "geoname_id": 
          6255147 <uint32>
        "names": 
          {
            "de": 
              "Asien" <utf8_string>
            "en": 
              "Asia" <utf8_string>
            "es": 
              "Asia" <utf8_string>
            "fr": 
              "Asie" <utf8_string>
            "ja": 
              "アジア" <utf8_string>
            "pt-BR": 
              "Ásia" <utf8_string>
            "ru": 
              "Азия" <utf8_string>
            "zh-CN": 
              "亚洲" <utf8_string>
          }
      }
    "country": 
      {
        "geoname_id": 
          1861060 <uint32>
        "iso_code": 
          "JP" <utf8_string>
        "names": 
          {
            "de": 
              "Japan" <utf8_string>
            "en": 
              "Japan" <utf8_string>
            "es": 
              "Japón" <utf8_string>
            "fr": 
              "Japon" <utf8_string>
            "ja": 
              "日本" <utf8_string>
            "pt-BR": 
              "Japão" <utf8_string>
            "ru": 
              "Япония" <utf8_string>
            "zh-CN": 
              "日本" <utf8_string>
          }
      }
    "location": 
      {
        "latitude": 
          36.083300 <double>
        "longitude": 
          140.116700 <double>
        "time_zone": 
          "Asia/Tokyo" <utf8_string>
      }
    "subdivisions": 
      [
        {
          "geoname_id": 
            2112669 <uint32>
          "iso_code": 
            "08" <utf8_string>
          "names": 
            {
              "en": 
                "Ibaraki" <utf8_string>
              "ja": 
                "茨城県" <utf8_string>
            }
        }
      ]
  }

Compilation error on master

I get a compilation error on master:

==> geolix
Compiling 37 files (.ex)

== Compilation error on file lib/geolix/adapter/mmdb2/decoder.ex ==
** (CompileError) Elixir.Geolix.Adapter.MMDB2.Decoder: function value/2+15:
  Internal consistency check failed - please report this bug.
  Instruction: {call,2,{f,7}}
  Error:       {multiple_match_contexts,[{x,1},0]}:

    (stdlib) lists.erl:1338: :lists.foreach/2
    (stdlib) erl_eval.erl:670: :erl_eval.do_apply/6

could not compile dependency :geolix, "mix compile" failed. You can recompile this dependency with "mix deps.compile geolix", update it with "mix deps.update geolix" or clean it with "mix deps.clean geolix"

Using as Geocoding Database

Hi I am wondering if someone has used this project as a base for geocoding purposes?

If for example all you need, is to search for cities, by name or by lng/lat.

Thank you

Search by city name?

Hi. Have you considered adding a feature to look up results by city names?
It would be useful if you want to know the timezone identifier for a certain city name, but you don't have an IP address.

For instance if you want to know what the timezone identifier is for Houston, Texas you could do a lookup by "Houston" and it would return results for matching cities containing time_zone: "America/Chicago".

Question: Are database lookups done in parallel?

Hi there

Thanks for this great library.

I have a system where I need to get the result of looking up an IP in several maxmind databases; country, isp, connection type and anonymous proxy. I was planning to kick off lookups using Task.async, but I'm not sure if that would have any benefit.

Does geolix lookup each registered database concurrently, or in series?

David

Incorrect results for some IP addresses

The IP address 69.180.1.1 returns incorrect data:

iex> Geolix.lookup("69.180.1.1").city.city.names.en
"Houston"

Using the MaxMindDB Ruby gem yields the correct result (as confirmed by the MaxMind web service):

> db.lookup('69.180.1.1').city.name
 => "Cartersville" 

Both are using the same GeoLite2-City.mmdb database, so this seems to be some kind of parsing bug.

Using remote database source results in time out when app first starts

When I config the database source as a link to a remote file I can't use the Geolix.lookup/2 function until the database has been loaded from the remote source.

How can I check if the remote geoip database has been loaded before I run any functions like Geolix.lookup/2?

This is my current config:

config :geolix,
  databases: [
    %{
      id: :city,
      adapter: Geolix.Adapter.MMDB2,
      source: "https://example.com/geoip/GeoLite2-City.mmdb"
    },
    %{
      id: :country,
      adapter: Geolix.Adapter.MMDB2,
      source: "https://example.com/geoip/GeoLite2-Country.mmdb"
    }
  ]

And the timeout error message:

[error] GenServer #PID<0.603.0> terminating
** (stop) exited in: GenServer.call(Geolix.Database.Loader, :loaded, 5000)
    ** (EXIT) time out
    (elixir) lib/gen_server.ex:834: GenServer.call/3
    (geolix) lib/geolix/server/worker.ex:26: Geolix.Server.Worker.lookup_all/2
    (geolix) lib/geolix/server/worker.ex:20: Geolix.Server.Worker.handle_call/3
    (stdlib) gen_server.erl:636: :gen_server.try_handle_call/4
    (stdlib) gen_server.erl:665: :gen_server.handle_msg/6
    (stdlib) proc_lib.erl:247: :proc_lib.init_p_do_apply/3
Last message (from #PID<0.604.0>): {:lookup, '127, 0, 0, 1', [as: :struct, locale: :en, where: nil]}

The readme mentions: "Note: Please be aware of the drawbacks of remote files! You should take into account the startup times as the file will be requested during GenServer.init/1. Unstable or slow networks could result in nasty timeouts." When I start my app however I don't experience any extra startup time. I'm using Elixir 1.6 and phoenix 1.3.

Doing twice the same lookup give different results

I'm using a paid maxmind account to fetch the up to date country code from IP.
I notice that I have many nil for some hundred of IPs, but when I retry the lookup just some lines after, the lookup give "positive" results. How is it possible? Does the Worker can crash and GenServer return nil "by default" ? How could I test this?
(I get the same behavior with 0.17, 0.18 and master)

Completely crash if Maxmind returns 503

Seems like Geolix will crash the app completely if the backend returns a 503

 ** (CaseClauseError) no case clause matching: {:ok, {{'HTTP/1.1', 503, 'Service Temporarily Unavailable'}, [{'cache-control', 'no-cache'}, {'connection', 'close'}, {'date', 'Wed, 11 Sep 2019 16:52:35 GMT'}, {'server', 'cloudflare'}, {'content-length', '8322'}, {'content-type', 'text/html; charset=UTF-8'}, {'x-frame-options', 'SAMEORIGIN'}, {'set-cookie', '__cfduid=de45f29ad402707842e8335e79bcfb4b51568220755; expires=Thu, 10-Sep-20 16:52:35 GMT; path=/; domain=.geolite.maxmind.com; HttpOnly'}, {'expect-ct', 'max-age=604800, report-uri="https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct"'}, {'cf-ray', '514b272c4a61cefc-IAD'}], '<!DOCTYPE HTML>\n<html lang="en-US">\n<head>\n  <meta charset="UTF-8" />\n  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />\n  <meta http-equiv="X-UA-Compatible" content="IE=Edge,chrome=1" />\n  <meta name="robots" content="noindex, nofollow" />\n  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1" />\n  <title>Just a moment...</title>\n  <style type="text/css">\n    html, body {width: 100%; height: 100%; margin: 0; padding: 0;}\n    body {background-color: #ffffff; font-family: Helvetica, Arial, sans-serif; font-size: 100%;}\n    h1 {font-size: 1.5em; color: #404040; text-align: center;}\n    p {font-size: 1em; color: #404040; text-align: center; margin: 10px 0 0 0;}\n    #spinner {margin: 0 auto 30px auto; display: block;}\n    .attribution {margin-top: 20px;}\n    @-webkit-keyframes bubbles { 33%: { -webkit-transform: translateY(10px); transform: translateY(10px); } 66% { -webkit-transform: translateY(-10px); transform: translateY(-10px); } 100% { -webkit-transform: translateY(0); transform: translateY(0); } }\n    @keyframes bubbles { 33%: { -webkit-transform: translateY(10px); transform: translateY(10px); } 66% { -webkit-transform: translateY(-10px); transform: translateY(-10px); } 100% { -webkit-transform: translateY(0); transform: translateY(0); } }\n    .bubbles { background-color: #404040; width:15px; height: 15px; margin:2px; border-radius:100%; -webkit-animation:bubbles 0.6s 0.07s infinite ease-in-out; animation:bubbles 0.6s 0.07s infinite ease-in-out; -webkit-animation-fill-mode:both; animation-fill-mode:both; display:inline-block; }\n  </style>\n\n    <script type="text/javascript">\n  //<![CDATA[\n  (function(){\n    var a = function() {try{return !!window.addEventListener} catch(e) {return !1} },\n    b = function(b, c) {a() ? document.addEventListener("DOMContentLoaded", b, c) : document.attachEvent("onreadystatechange", b)};\n    b(function(){\n      var a = document.getElementById(\'cf-content\');a.style.display = \'block\';\n      setTimeout(function(){\n        var s,t,o,p,b,r,e,a,k,i,n,g,f, yIvmnzq={"APHx":+((!+[]+!![]+!![]+!![]+!![]+!![]+!![]+!![]+!![]+[])+(!+[]+!![]+!![]+!![])+(+!![])+(+[])+(!+[]+!![]+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]+!![]+!![])+(!+[]+!![]+!![]+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]+!![]+!![]+!![]+!![]+!![]+!![]+!![])+(+!![]))/+((!+[]+!![]+!![]+!![]+!![]+[])+(!+[]+!![]+!![]+!![]+!![]+!![])+(!+[]+!![]+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]+!![]+!![])+(!+[]+!![]+!![]+!![]+!![])+(!+[]+!![])+(!+[]+!![]+!![]+!![])+(+[])+(!+[]+!![]))};\n        g = String.fromCharCode;\n        o = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";\n        e = function(s) {\n          s += "==".slice(2 - (s.length & 3));\n          var bm, r = "", r1, r2, i = 0;\n          for (; i < s.length;) {\n              bm = o.indexOf(s.charAt(i++)) << 18 | o.indexOf(s.charAt(i++)) << 12\n                      | (r1 = o.indexOf(s.charAt(i++))) << 6 | (r2 = o.indexOf(s.charAt(i++)));\n              r += r1 === 64 ? g(bm >> 16 & 255)\n                      : r2 === 64 ? g(bm >> 16 & 255, bm >> 8 & 255)\n                      : g(bm >> 16 & 255, bm >> 8 & 255, bm & 255);\n          }\n          return r;\n        };\n        t = document.createElement(\'div\');\n        t.innerHTML="<a href=\'/\'>x</a>";\n        t = t.firstChild.href;r = t.match(/https?:\\/\\//)[0];\n        t = t.substr(r.length); t = t.substr(0,t.length-1); \n        a = document.getElementById(\'jschl-answer\');\n        f = document.getElementById(\'challenge-form\');\n        ;yIvmnzq.APHx-=+((!+[]+!![]+!![]+!![]+!![]+!![]+!![]+!![]+!![]+[])+(!+[]+!![]+!![]+!![])+(+!![])+(+[])+(!+[]+!![]+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]+!![]+!![])+(!+[]+!![]+!![]+!![]+!![]+!![]+!![]+!![]+!![])+(!+[]+!![]+!![]+!![]+!![]+!![]+!![]+!![])+(+!![]))/+((!+[]+!![]+!![]+!![]+[])+(+!![])+(!+[]+!![]+!![]+!![]+!![])+(!+[]+!![]+!![]+!![]+!![]+!![]+!![])+(+[])+(!+[]+!![]+!![]+!![]+!![]+!![])+(!+[]+!![]+!![]+!![])+(+[])+(!+[]+!![]+!![]+!![]+!![]+!![]+!![]));yIvmnzq.APHx+=+((!+[]+!![]+!![]+!![]+!![]+!![]+!![]+[])+(!+[]+!![]+!![]+!![]+!![]+!![]+!![]+!![]+!![])+(!' ++ ...}}
agentrisk_1    |     (geolix) lib/geolix/adapter/mmdb2/reader.ex:13: Geolix.Adapter.MMDB2.Reader.read_database/1
agentrisk_1    |     (geolix) lib/geolix/adapter/mmdb2/loader.ex:33: Geolix.Adapter.MMDB2.Loader.load_database/1
agentrisk_1    |     (geolix) lib/geolix/database/loader.ex:66: anonymous fn/1 in Geolix.Database.Loader.handle_cast/2
agentrisk_1    |     (elixir) lib/enum.ex:769: Enum."-each/2-lists^foreach/1-0-"/2
agentrisk_1    |     (elixir) lib/enum.ex:769: Enum.each/2
agentrisk_1    |     (geolix) lib/geolix/database/loader.ex:64: Geolix.Database.Loader.handle_cast/2
agentrisk_1    |     (stdlib) gen_server.erl:637: :gen_server.try_dispatch/4
agentrisk_1    |     (stdlib) gen_server.erl:711: :gen_server.handle_msg/6

lookup geoname_id

Hi @mneudert,

I am using your library to convert my user ip into their location geoname_id and then I am saving this information in a database. I am saving the geoname_id instead of the country/city name, because my platform is multi-language and for size concerns I don't want to store duplicated data.

In my web interface, I am currently looking up the geoname_id against a mysql database that contains maxmind data. It works fine but it feels somehow dirty to rely on two different database for the same information. I think this library could be improve to give methods to do a lookup from the geoname_id to the actual location information. It is also useful for one country or subdivision to get the list of its subdivision or cities. (I am thinking about populating a drop down used to filter my user data).

the new added function of the geolix library would be:

get_countries(opts \\ [language: :en])
get_country(geoname_id, opts \\ [language: :en])
get_subdivisions(geoname_id, opts \\ [language: :en])
get_subdivision(geoname_id, opts \\ [language: :en])
get_cities(geoname_id, opts \\ [language: :en])
get_city(geoname_id, opts \\ [language: :en])

This data would be stored into an ETS table once converted from the maxmind format for fast access.

I wrote a gist to implement this: https://gist.github.com/adrienmo/eaca761f8d1539810bce722521797ef7

At the moment I am generating these ETS table from the city database. It takes around 30 seconds on my computer to process the geolite2 city data this is because the operation is not parallelized, this could be improved. Once the database created we could also give a function to store it into dets, so it does not need to regenerate this database at each startup.

I would like to know your thoughts on these improvements. If you think it can be useful I will implement this properly and make a merge request, otherwise I might do a separate library or a fork.

Cheers!

City is not being returned in lookup result

Hi

I have downloaded the mmdb database from here

https://dev.maxmind.com/geoip/geoip2/geolite2/

And I use Geolix.set_database(:city, "city.mmdb.gz") \\ :ok to set the path.

However, I get the following results (note how the name field for both country and city is missing)

Geolix.lookup "some ip address"

%{city: %Geolix.Result.City{city: nil,
   continent: %Geolix.Record.Continent{code: "EU", geoname_id: 6324238,
    name: nil,
    names: %{de: "Europa", en: "Europe", es: "Europa", fr: "Europe",
      ja: "ヨーロッパ", "pt-BR": "Europa", ru: "Европа",
      "zh-CN": "欧洲"}},
   country: %Geolix.Record.Country{geoname_id: 26221321, iso_code: "DK",
    name: nil,
    names: %{de: "Dänemark", en: "Denmark", es: "Dinamarca", fr: "Danemark",
      ja: "デンマーク王国", "pt-BR": "Dinamarca", ru: "Дания",
      "zh-CN": "丹麦"}},
   location: %Geolix.Record.Location{latitude: 55.6761, longitude: 12.5683,
    metro_code: nil, time_zone: "Europe/Copenhagen"}, postal: nil,
   registered_country: %Geolix.Record.Country{geoname_id: 2623242,
    iso_code: "DK", name: nil,
    names: %{de: "Dänemark", en: "Denmark", es: "Dinamarca", fr: "Danemark",
      ja: "デンマーク王国", "pt-BR": "Dinamarca", ru: "Дания",
      "zh-CN": "丹麦"}}, represented_country: nil, subdivisions: nil,
   traits: %{ip_address: {some ip...}}}

geolix does'nt work with elixir 1.9 release

In elixir 1.9, it added mix release task to build a release without using distillery.

However it doesn't work with geolix lib, since in the mix.exs,

  def application do
    [
      applications: [:logger, :poolboy],
      included_applications: [:mmdb2_decoder],
      mod: {Geolix, []}
    ]
  end

The included_application part will make mix release complain.

➜ MIX_ENV=prod mix release
===> Compiling poolboy
==> mmdb2_decoder
Compiling 5 files (.ex)
Generated mmdb2_decoder app
==> geolix
Compiling 38 files (.ex)
Generated geolix app
==> a
Compiling 1 file (.ex)
Generated a app
Release a-0.1.0 already exists. Overwrite? [Yn]
* assembling a-0.1.0 on MIX_ENV=prod
* skipping runtime configuration (config/releases.exs not found)
** (Mix) Undefined applications: [mmdb2_decoder]

The solution is to move the mmdb2_decoder to applications would work.

  def application do
    [
      applications: [:logger, :poolboy, :mmdb2_decoder],
      included_applications: [],
      mod: {Geolix, []}
    ]
  end

Would it be possible to implement caching?

A lot of the Maxmind implementations contain caching to avoid multiple lookups (which happens often when relying on IP). Is there such a caching implementation in Geolix? I've taken a look and I can't really see anything (forgive me if I'm missing something) so it might be a good idea to go for something like that. I'm not really sure of the implications of hitting cache because I don't have an accurate benchmark of Geolix at the moment. A cache hit would take a couple of microseconds at the most.

Also as a bit of self promotion, you could potentially use https://github.com/zackehh/cachex.

unit tests failing the majority of the time

The code executes normally and successfully in dev, but when running mix test, the test is failing the majority of the time. It sometimes succeeds, which is utterly baffling.

config.exs

config :geolix, :databases, [
      %{
        id: :city,
        adapter: Geolix.Adapter.MMDB2,
        source: "#{priv}/GeoLite2-City_20191015.tar.gz"

      }
  ]


Failing test:

defmodule Geeks.LocationTest do
  use ExUnit.Case, async: false

  test "gets a geopoint for an ip" do
     ip = {161,185,160,93}
     actual = Geeks.Location.get_ip(ip)
     {:ok, %{ coordinates: [lon, lat], srid: "4326"}} = actual
     assert [-73.9501, 40.781] = [ lon, lat ]
  end

end

Code under test:


  def get_ip(ip) do
    ip_string =  Tuple.to_list(ip) |> Enum.join(".")
    case Geolix.lookup(ip_string, where: :city) do
      %{ location: %{ latitude: lat, longitude: lon }} -> {:ok, %Geo.Point{ coordinates: [lon, lat], srid: "4326"}}
       _ -> {:error, "location not found for ip #{ip_string}"}
    end
  end

mix.lock

%{
  "argon2_elixir": {:hex, :argon2_elixir, "1.3.3", "487ffa071ef78c51d9b16e50ff3cf30cf8204e0aa4bdc8afd3765fdd8195e213", [:make, :mix], [{:elixir_make, "~> 0.4", [hex: :elixir_make, repo: "hexpm", optional: false]}], "hexpm"},
  "better_params": {:hex, :better_params, "0.5.0", "fc20b88a809cf34548392a2436b5974814b0f0abdd52ed4598db8ba21767d94f", [:mix], [{:plug, ">= 1.0.0", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"},
  "certifi": {:hex, :certifi, "2.5.1", "867ce347f7c7d78563450a18a6a28a8090331e77fa02380b4a21962a65d36ee5", [:rebar3], [{:parse_trans, "~>3.3", [hex: :parse_trans, repo: "hexpm", optional: false]}], "hexpm"},
  "combine": {:hex, :combine, "0.10.0", "eff8224eeb56498a2af13011d142c5e7997a80c8f5b97c499f84c841032e429f", [:mix], [], "hexpm"},
  "comeonin": {:hex, :comeonin, "4.1.2", "3eb5620fd8e35508991664b4c2b04dd41e52f1620b36957be837c1d7784b7592", [:mix], [{:argon2_elixir, "~> 1.2", [hex: :argon2_elixir, repo: "hexpm", optional: true]}, {:bcrypt_elixir, "~> 0.12.1 or ~> 1.0", [hex: :bcrypt_elixir, repo: "hexpm", optional: true]}, {:pbkdf2_elixir, "~> 0.12", [hex: :pbkdf2_elixir, repo: "hexpm", optional: true]}], "hexpm"},
  "connection": {:hex, :connection, "1.0.4", "a1cae72211f0eef17705aaededacac3eb30e6625b04a6117c1b2db6ace7d5976", [:mix], [], "hexpm"},
  "cowboy": {:hex, :cowboy, "2.6.3", "99aa50e94e685557cad82e704457336a453d4abcb77839ad22dbe71f311fcc06", [:rebar3], [{:cowlib, "~> 2.7.3", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "~> 1.7.1", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm"},
  "cowlib": {:hex, :cowlib, "2.7.3", "a7ffcd0917e6d50b4d5fb28e9e2085a0ceb3c97dea310505f7460ff5ed764ce9", [:rebar3], [], "hexpm"},
  "crontab": {:hex, :crontab, "1.1.8", "2ce0e74777dfcadb28a1debbea707e58b879e6aa0ffbf9c9bb540887bce43617", [:mix], [{:ecto, "~> 1.0 or ~> 2.0 or ~> 3.0", [hex: :ecto, repo: "hexpm", optional: true]}], "hexpm"},
  "csv": {:hex, :csv, "2.3.1", "9ce11eff5a74a07baf3787b2b19dd798724d29a9c3a492a41df39f6af686da0e", [:mix], [{:parallel_stream, "~> 1.0.4", [hex: :parallel_stream, repo: "hexpm", optional: false]}], "hexpm"},
  "db_connection": {:hex, :db_connection, "2.2.0", "e923e88887cd60f9891fd324ac5e0290954511d090553c415fbf54be4c57ee63", [:mix], [{:connection, "~> 1.0.2", [hex: :connection, repo: "hexpm", optional: false]}], "hexpm"},
  "decimal": {:hex, :decimal, "1.8.1", "a4ef3f5f3428bdbc0d35374029ffcf4ede8533536fa79896dd450168d9acdf3c", [:mix], [], "hexpm"},
  "dotenv": {:hex, :dotenv, "3.0.0", "52a28976955070d8312a81d59105b57ecf5d6a755c728b49c70a7e2120e6cb40", [:mix], [], "hexpm"},
  "earmark": {:hex, :earmark, "1.4.2", "3aa0bd23bc4c61cf2f1e5d752d1bb470560a6f8539974f767a38923bb20e1d7f", [:mix], [], "hexpm"},
  "ecto": {:hex, :ecto, "3.3.1", "82ab74298065bf0c64ca299f6c6785e68ea5d6b980883ee80b044499df35aba1", [:mix], [{:decimal, "~> 1.6", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm"},
  "ecto_enum": {:hex, :ecto_enum, "1.3.2", "659f7251b6a201a236db9dceef0f713319f095a23ad1d8718efd7a3d3ef3e21b", [:mix], [{:ecto, ">= 2.0.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:mariaex, ">= 0.0.0", [hex: :mariaex, repo: "hexpm", optional: true]}, {:postgrex, ">= 0.0.0", [hex: :postgrex, repo: "hexpm", optional: true]}], "hexpm"},
  "ecto_morph": {:hex, :ecto_morph, "0.1.13", "e52cea7f437c604d887cbb5bb0331bc99c68ef8cc519ac890a8886024dcf83a1", [:mix], [{:ecto, ">= 3.0.3", [hex: :ecto, repo: "hexpm", optional: false]}], "hexpm"},
  "ecto_sql": {:hex, :ecto_sql, "3.3.2", "92804e0de69bb63e621273c3492252cb08a29475c05d40eeb6f41ad2d483cfd3", [:mix], [{:db_connection, "~> 2.2", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.3", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.3.0", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.15.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm"},
  "elixir_make": {:hex, :elixir_make, "0.6.0", "38349f3e29aff4864352084fc736fa7fa0f2995a819a737554f7ebd28b85aaab", [:mix], [], "hexpm"},
  "file_system": {:hex, :file_system, "0.2.7", "e6f7f155970975789f26e77b8b8d8ab084c59844d8ecfaf58cbda31c494d14aa", [:mix], [], "hexpm"},
  "floki": {:hex, :floki, "0.23.0", "956ab6dba828c96e732454809fb0bd8d43ce0979b75f34de6322e73d4c917829", [:mix], [{:html_entities, "~> 0.4.0", [hex: :html_entities, repo: "hexpm", optional: false]}], "hexpm"},
  "gen_stage": {:hex, :gen_stage, "0.14.2", "6a2a578a510c5bfca8a45e6b27552f613b41cf584b58210f017088d3d17d0b14", [:mix], [], "hexpm"},
  "gen_state_machine": {:hex, :gen_state_machine, "2.0.5", "9ac15ec6e66acac994cc442dcc2c6f9796cf380ec4b08267223014be1c728a95", [:mix], [], "hexpm"},
  "geo": {:hex, :geo, "3.3.3", "1119302b20d21515fbcec0a180b82653524067873ed333e7fa1f55e39959d702", [:mix], [], "hexpm"},
  "geo_postgis": {:hex, :geo_postgis, "3.3.0", "a40774f26c69411c016426e45dbd354139eaa172903fe512862de78b7e8f1e79", [:mix], [{:geo, "~> 3.3", [hex: :geo, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:poison, "~> 2.2 or ~> 3.0 or ~> 4.0", [hex: :poison, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.14", [hex: :postgrex, repo: "hexpm", optional: false]}], "hexpm"},
  "geolix": {:hex, :geolix, "1.0.0", "b225d930fb0418871ce7d89dabf293bd80eb5bd66db1887f80510c122f4ef271", [:mix], [{:poolboy, "~> 1.0", [hex: :poolboy, repo: "hexpm", optional: false]}], "hexpm"},
  "geolix_adapter_mmdb2": {:hex, :geolix_adapter_mmdb2, "0.3.0", "ff36c4c0df390854e0266280c20dfa57ca68d9a0c2ff42c22bf3af5725b5bdcb", [:mix], [{:geolix, "~> 1.0", [hex: :geolix, repo: "hexpm", optional: false]}, {:mmdb2_decoder, "~> 2.1", [hex: :mmdb2_decoder, repo: "hexpm", optional: false]}], "hexpm"},
  "gettext": {:hex, :gettext, "0.17.0", "abe21542c831887a2b16f4c94556db9c421ab301aee417b7c4fbde7fbdbe01ec", [:mix], [], "hexpm"},
  "hackney": {:hex, :hackney, "1.15.2", "07e33c794f8f8964ee86cebec1a8ed88db5070e52e904b8f12209773c1036085", [:rebar3], [{:certifi, "2.5.1", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "6.0.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "1.0.1", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~>1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "1.1.5", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}], "hexpm"},
  "html_entities": {:hex, :html_entities, "0.4.0", "f2fee876858cf6aaa9db608820a3209e45a087c5177332799592142b50e89a6b", [:mix], [], "hexpm"},
  "html_sanitize_ex": {:hex, :html_sanitize_ex, "1.3.0", "f005ad692b717691203f940c686208aa3d8ffd9dd4bb3699240096a51fa9564e", [:mix], [{:mochiweb, "~> 2.15", [hex: :mochiweb, repo: "hexpm", optional: false]}], "hexpm"},
  "httpoison": {:hex, :httpoison, "1.6.0", "0a148c836e8e5fbec82c3cea37465a603bd42e314b73a8448ad50020757a00bd", [:mix], [{:hackney, "~> 1.15 and >= 1.15.2", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm"},
  "idna": {:hex, :idna, "6.0.0", "689c46cbcdf3524c44d5f3dde8001f364cd7608a99556d8fbd8239a5798d4c10", [:rebar3], [{:unicode_util_compat, "0.4.1", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm"},
  "jason": {:hex, :jason, "1.1.2", "b03dedea67a99223a2eaf9f1264ce37154564de899fd3d8b9a21b1a6fd64afe7", [:mix], [{:decimal, "~> 1.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm"},
  "libring": {:hex, :libring, "1.4.0", "41246ba2f3fbc76b3971f6bce83119dfec1eee17e977a48d8a9cfaaf58c2a8d6", [:mix], [], "hexpm"},
  "metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], [], "hexpm"},
  "mime": {:hex, :mime, "1.3.1", "30ce04ab3175b6ad0bdce0035cba77bba68b813d523d1aac73d9781b4d193cf8", [:mix], [], "hexpm"},
  "mimerl": {:hex, :mimerl, "1.2.0", "67e2d3f571088d5cfd3e550c383094b47159f3eee8ffa08e64106cdf5e981be3", [:rebar3], [], "hexpm"},
  "mmdb2_decoder": {:hex, :mmdb2_decoder, "2.1.0", "91933e121e5370c89fdac37bba85a84116869a7267e1e93b4a8e1fa5c6ef89e7", [:mix], [], "hexpm"},
  "mochiweb": {:hex, :mochiweb, "2.18.0", "eb55f1db3e6e960fac4e6db4e2db9ec3602cc9f30b86cd1481d56545c3145d2e", [:rebar3], [], "hexpm"},
  "nanoid": {:hex, :nanoid, "2.0.2", "f3f7b4bf103ab6667f22beb00b6315825ee3f30100dd2c93d534e5c02164e857", [:mix], [], "hexpm"},
  "parallel_stream": {:hex, :parallel_stream, "1.0.6", "b967be2b23f0f6787fab7ed681b4c45a215a81481fb62b01a5b750fa8f30f76c", [:mix], [], "hexpm"},
  "parse_trans": {:hex, :parse_trans, "3.3.0", "09765507a3c7590a784615cfd421d101aec25098d50b89d7aa1d66646bc571c1", [:rebar3], [], "hexpm"},
  "phoenix": {:hex, :phoenix, "1.4.10", "619e4a545505f562cd294df52294372d012823f4fd9d34a6657a8b242898c255", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 1.1", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:plug, "~> 1.8.1 or ~> 1.9", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 1.0 or ~> 2.0", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm"},
  "phoenix_ecto": {:hex, :phoenix_ecto, "4.0.0", "c43117a136e7399ea04ecaac73f8f23ee0ffe3e07acfcb8062fe5f4c9f0f6531", [:mix], [{:ecto, "~> 3.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.9", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"},
  "phoenix_html": {:hex, :phoenix_html, "2.13.3", "850e292ff6e204257f5f9c4c54a8cb1f6fbc16ed53d360c2b780a3d0ba333867", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"},
  "phoenix_live_reload": {:hex, :phoenix_live_reload, "1.2.1", "274a4b07c4adbdd7785d45a8b0bb57634d0b4f45b18d2c508b26c0344bd59b8f", [:mix], [{:file_system, "~> 0.2.1 or ~> 0.3", [hex: :file_system, repo: "hexpm", optional: false]}, {:phoenix, "~> 1.4", [hex: :phoenix, repo: "hexpm", optional: false]}], "hexpm"},
  "phoenix_live_view": {:hex, :phoenix_live_view, "0.3.1", "5474c9e70db4e5bb23c1d1200d9a119ee76b927f3352554d31f5f31eaa1ea568", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix, "~> 1.4.9", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.13.2", [hex: :phoenix_html, repo: "hexpm", optional: false]}], "hexpm"},
  "phoenix_pubsub": {:hex, :phoenix_pubsub, "1.1.2", "496c303bdf1b2e98a9d26e89af5bba3ab487ba3a3735f74bf1f4064d2a845a3e", [:mix], [], "hexpm"},
  "plug": {:hex, :plug, "1.8.3", "12d5f9796dc72e8ac9614e94bda5e51c4c028d0d428e9297650d09e15a684478", [:mix], [{:mime, "~> 1.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: true]}], "hexpm"},
  "plug_cowboy": {:hex, :plug_cowboy, "2.1.0", "b75768153c3a8a9e8039d4b25bb9b14efbc58e9c4a6e6a270abff1cd30cbe320", [:mix], [{:cowboy, "~> 2.5", [hex: :cowboy, repo: "hexpm", optional: false]}, {:plug, "~> 1.7", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"},
  "plug_crypto": {:hex, :plug_crypto, "1.0.0", "18e49317d3fa343f24620ed22795ec29d4a5e602d52d1513ccea0b07d8ea7d4d", [:mix], [], "hexpm"},
  "poison": {:hex, :poison, "3.1.0", "d9eb636610e096f86f25d9a46f35a9facac35609a7591b3be3326e99a0484665", [:mix], [], "hexpm"},
  "poolboy": {:hex, :poolboy, "1.5.2", "392b007a1693a64540cead79830443abf5762f5d30cf50bc95cb2c1aaafa006b", [:rebar3], [], "hexpm"},
  "postgrex": {:hex, :postgrex, "0.15.3", "5806baa8a19a68c4d07c7a624ccdb9b57e89cbc573f1b98099e3741214746ae4", [:mix], [{:connection, "~> 1.0", [hex: :connection, repo: "hexpm", optional: false]}, {:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm"},
  "quantum": {:hex, :quantum, "2.3.4", "72a0e8855e2adc101459eac8454787cb74ab4169de6ca50f670e72142d4960e9", [:mix], [{:calendar, "~> 0.17", [hex: :calendar, repo: "hexpm", optional: true]}, {:crontab, "~> 1.1", [hex: :crontab, repo: "hexpm", optional: false]}, {:gen_stage, "~> 0.12", [hex: :gen_stage, repo: "hexpm", optional: false]}, {:swarm, "~> 3.3", [hex: :swarm, repo: "hexpm", optional: false]}, {:timex, "~> 3.1", [hex: :timex, repo: "hexpm", optional: true]}], "hexpm"},
  "ranch": {:hex, :ranch, "1.7.1", "6b1fab51b49196860b733a49c07604465a47bdb78aa10c1c16a3d199f7f8c881", [:rebar3], [], "hexpm"},
  "slugify": {:hex, :slugify, "1.2.0", "72da0ec72c42dc00703ff73a4755ba3c035fa5e5828addc3dd633846d7ef7491", [:mix], [], "hexpm"},
  "ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.5", "6eaf7ad16cb568bb01753dbbd7a95ff8b91c7979482b95f38443fe2c8852a79b", [:make, :mix, :rebar3], [], "hexpm"},
  "swarm": {:hex, :swarm, "3.4.0", "64f8b30055d74640d2186c66354b33b999438692a91be275bb89cdc7e401f448", [:mix], [{:gen_state_machine, "~> 2.0", [hex: :gen_state_machine, repo: "hexpm", optional: false]}, {:libring, "~> 1.0", [hex: :libring, repo: "hexpm", optional: false]}], "hexpm"},
  "telemetry": {:hex, :telemetry, "0.4.1", "ae2718484892448a24470e6aa341bc847c3277bfb8d4e9289f7474d752c09c7f", [:rebar3], [], "hexpm"},
  "tesla": {:hex, :tesla, "1.3.0", "f35d72f029e608f9cdc6f6d6fcc7c66cf6d6512a70cfef9206b21b8bd0203a30", [:mix], [{:castore, "~> 0.1", [hex: :castore, repo: "hexpm", optional: true]}, {:exjsx, ">= 3.0.0", [hex: :exjsx, repo: "hexpm", optional: true]}, {:fuse, "~> 2.4", [hex: :fuse, repo: "hexpm", optional: true]}, {:gun, "~> 1.3", [hex: :gun, repo: "hexpm", optional: true]}, {:hackney, "~> 1.6", [hex: :hackney, repo: "hexpm", optional: true]}, {:ibrowse, "~> 4.4.0", [hex: :ibrowse, repo: "hexpm", optional: true]}, {:jason, ">= 1.0.0", [hex: :jason, repo: "hexpm", optional: true]}, {:mime, "~> 1.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mint, "~> 0.4", [hex: :mint, repo: "hexpm", optional: true]}, {:poison, ">= 1.0.0", [hex: :poison, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.3", [hex: :telemetry, repo: "hexpm", optional: true]}], "hexpm"},
  "timex": {:hex, :timex, "3.6.1", "efdf56d0e67a6b956cc57774353b0329c8ab7726766a11547e529357ffdc1d56", [:mix], [{:combine, "~> 0.10", [hex: :combine, repo: "hexpm", optional: false]}, {:gettext, "~> 0.10", [hex: :gettext, repo: "hexpm", optional: false]}, {:tzdata, "~> 0.1.8 or ~> 0.5 or ~> 1.0.0", [hex: :tzdata, repo: "hexpm", optional: false]}], "hexpm"},
  "tzdata": {:hex, :tzdata, "1.0.1", "f6027a331af7d837471248e62733c6ebee86a72e57c613aa071ebb1f750fc71a", [:mix], [{:hackney, "~> 1.0", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm"},
  "unicode_util_compat": {:hex, :unicode_util_compat, "0.4.1", "d869e4c68901dd9531385bb0c8c40444ebf624e60b6962d95952775cac5e90cd", [:rebar3], [], "hexpm"},
}

Here's the successful execution in iex:

iex(6)> Geeks.Location.get_ip({81, 2, 69, 160})
{:ok,
%Geo.Point{coordinates: [-1.3614, 51.7095], properties: %{}, srid: "4326"}}

Extremely slow database loading performance

Loading the GeoLite2-Country database takes about 16 seconds on my machine. I attempted to load the city database and it was taking more than a minute before I killed it (the VM was using 4 GB memory at this point).

I ran the profiler with some interesting results:

iex> :eprof.analyze :total

FUNCTION                                                    CALLS      %     TIME  [uS / CALLS] 
--------                                                    -----    ---     ----  [----------] 
...
'Elixir.Enum':'-take/2-fun-0-'/2                          2218334   2.77  1197035  [      0.54] 
erlang:dt_spread_tag/1                                    4567753   2.92  1260774  [      0.28] 
prim_file:'-drv_command/4-after$^0/0-0-'/1                4567749   2.97  1283892  [      0.28] 
prim_file:drv_get_response/2                              4567749   3.18  1373420  [      0.30] 
prim_file:translate_response/2                            4567749   3.23  1395798  [      0.31] 
prim_file:get_uint64/1                                    4567743   3.47  1497280  [      0.33] 
prim_file:drv_command/2                                   4567749   3.69  1591292  [      0.35] 
'Elixir.Enumerable.File.Stream':'-reduce/3-fun-2-'/2      4567741   3.83  1653058  [      0.36] 
erlang:port_command/2                                     4567749   3.85  1660263  [      0.36] 
'Elixir.IO':binread/2                                     4567741   4.22  1819476  [      0.40] 
file:read/2                                               4567741   4.57  1974177  [      0.43] 
erlang:bump_reductions/1                                  4567749   5.51  2378091  [      0.52] 
prim_file:read/2                                          4567741   7.93  3421982  [      0.75] 
prim_file:get_uint32/1                                    9135486  12.39  5347104  [      0.59] 
erts_internal:port_command/3                              4567749  15.10  6516964  [      1.43] 

If I understand the profiler results correctly, it seems that most of the time is being spent in I/O and overhead. Any idea why?

FYI, I'm running Elixir 1.0.2 on Erlang R17.

README.md Wrong

In the README.md to download I used:

defp deps do
  [ { :geolix, "~> 0.10" } ]
end

And followed the documentation in the README I could not start the Database.Loader correctly. After exploring my deps and the current source code it seems that the README should work for the 0.11.0 code, whereas it does not work for ~> 0.10. Maybe updating the version should be the same version in the mix.exs file?

0.16 crashes at startup

I upgraded my codebase to Geolix 0.16.0 and it no longer starts up, instead it crashes on:

[info] Application geolix exited: Geolix.start(:normal, []) returned an error: exited in: GenServer.call(Geolix.Database.Loader, {:load_database, %{adapter: Geolix.Adapter.MMDB2, id: :city, source: "/Users/nicd/svn/code-stats/_build/dev/lib/code_stats/priv/geoip-cities.gz"}}, :infinity)
    ** (EXIT) no process: the process is not alive or there's no process currently associated with the given name, possibly because its application isn't started

I did not change anything related to the startup procedure from 0.15.1.

My config:

config :geolix, init: {CodeStatsWeb.Geolix, :init}

The init module:

defmodule CodeStatsWeb.Geolix do
  @moduledoc """
  Module for initialising Geolix databases at runtime instead of config time.
  """

  def init() do
    priv_dir = Application.app_dir(:code_stats, "priv")

    Geolix.load_database(%{
      id: :city,
      adapter: Geolix.Adapter.MMDB2,
      source: Path.join([priv_dir, "geoip-cities.gz"])
    })

    Geolix.load_database(%{
      id: :country,
      adapter: Geolix.Adapter.MMDB2,
      source: Path.join([priv_dir, "geoip-countries.gz"])
    })
  end
end

If I put prints to that init module, I can see that it is called. I tried adding the Geolix supervisor to my main supervisor's child list and adding :geolix to extra_applications, but it still happens. If I downgrade to 0.15.1, it works like it used to. Did I miss something?

For now I have changed my configuration to the new style of:

config :geolix,
  databases: [
    %{id: :city, init: {CodeStatsWeb.Geolix, :init_cities}},
    %{id: :country, init: {CodeStatsWeb.Geolix, :init_countries}}
  ]

where init_cities and init_countries return the configuration. But I'm left wondering why my earlier way doesn't work. I didn't see an outright deprecation in the changelog.

(UndefinedFunctionError) function nil.node_count/0 is undefined (module nil is not available)

Thanks for working on this library - just what I was looking for!

I seem to run into a problem when doing a lookup, like this:

Geolix.lookup("131.231.23.11")

My guess is that it's just a configuration problem on my side. Following the complete error message:

[error] Task #PID<0.653.0> started from #PID<0.608.0> terminating
** (UndefinedFunctionError) function nil.node_count/0 is undefined (module nil is not available)
    nil.node_count()
    (geolix) lib/geolix/adapter/mmdb2/lookup_tree.ex:59: Geolix.Adapter.MMDB2.LookupTree.traverse/6
    (geolix) lib/geolix/adapter/mmdb2/database.ex:35: Geolix.Adapter.MMDB2.Database.lookup/5
    (elixir) lib/task/supervised.ex:85: Task.Supervised.do_apply/2
    (elixir) lib/task/supervised.ex:36: Task.Supervised.reply/5
    (stdlib) proc_lib.erl:247: :proc_lib.init_p_do_apply/3
Function: #Function<2.65470077/0 in Geolix.Server.Worker.lookup_all/3>
    Args: []
** (exit) exited in: GenServer.call(#PID<0.608.0>, {:lookup, {131, 231, 23, 11}, [as: :struct, locale: :en, where: nil]}, 5000)
    ** (EXIT) an exception was raised:
        ** (UndefinedFunctionError) function nil.node_count/0 is undefined or private
            nil.node_count()
            (geolix) lib/geolix/adapter/mmdb2/lookup_tree.ex:59: Geolix.Adapter.MMDB2.LookupTree.traverse/6
            (geolix) lib/geolix/adapter/mmdb2/database.ex:35: Geolix.Adapter.MMDB2.Database.lookup/5
            (elixir) lib/task/supervised.ex:85: Task.Supervised.do_apply/2
            (elixir) lib/task/supervised.ex:36: Task.Supervised.reply/5
            (stdlib) proc_lib.erl:247: :proc_lib.init_p_do_apply/3
     (elixir) lib/gen_server.ex:737: GenServer.call/3
    (poolboy) src/poolboy.erl:76: :poolboy.transaction/3

And this is my configuration:

config :geolix,
  databases: [
    %{
      id:      :city,
      adapter: Geolix.Adapter.MMDB2,
      source:  "./data/maxmind/geolite2-city.tar.gz"
    },
    %{
      id:      :country,
      adapter: Geolix.Adapter.MMDB2,
      source:  "./data/maxmind/geolite2-county.tar.gz"
    }
  ]

Hope that gives you enough information to help me get things running. Thanks a lot in advance!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.