-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This PR replaces geolix with locus to simplify self-hosted setup. locus can auto-update maxmind dbs which are recommended for self-hosters if they want city-level geolocation. locus is also a bit faster. This PR also uses a test mmdb file from https://github.com/maxmind/MaxMind-DB for e2e geolocation tests without stubs.
- Loading branch information
1 parent
2a4061d
commit 166748d
Showing
16 changed files
with
290 additions
and
109 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,189 @@ | ||
defmodule Plausible.Geo do | ||
@moduledoc """ | ||
This module provides an API for fetching IP geolocation. | ||
""" | ||
|
||
require Logger | ||
|
||
@db :geolocation | ||
|
||
@doc """ | ||
Starts the geodatabase loading process. Two modes are supported: local file | ||
and MaxMind license key. | ||
## Options | ||
* `:path` - the path to the .mmdb database local file. When present, | ||
`:license_key` and `:edition` are not required. | ||
* `:license_key` - the [license key](https://support.maxmind.com/hc/en-us/articles/4407111582235-Generate-a-License-Key) | ||
from MaxMind to authenticate requests to MaxMind. | ||
* `:edition` - the name of the MaxMind database to be downloaded from MaxMind | ||
servers. Defaults to `GeoLite2-City`. | ||
* `:async` - when used, configures the database loading to run | ||
asynchronously. | ||
## Examples | ||
Loading from a local file: | ||
iex> load_db(path: "/etc/plausible/dbip-city.mmdb") | ||
:ok | ||
Downloading a MaxMind DB (this license key is no longer active): | ||
iex> load_db(license_key: "LNpsJCCKPis6XvBP", edition: "GeoLite2-City", async: true) | ||
:ok | ||
""" | ||
def load_db(opts) do | ||
cond do | ||
license_key = opts[:license_key] -> | ||
edition = opts[:edition] || "GeoLite2-City" | ||
:ok = :locus.start_loader(@db, {:maxmind, edition}, license_key: license_key) | ||
|
||
path = opts[:path] -> | ||
:ok = :locus.start_loader(@db, path) | ||
|
||
true -> | ||
raise "failed to load geolocation db: need :path or :license_key to be provided" | ||
end | ||
|
||
unless opts[:async] do | ||
{:ok, _version} = :locus.await_loader(@db) | ||
end | ||
|
||
:ok | ||
end | ||
|
||
@doc """ | ||
Waits for the database to start after calling `load_db/1` with the async option. | ||
""" | ||
def await_loader, do: :locus.await_loader(@db) | ||
|
||
@doc """ | ||
Returns geodatabase type. | ||
Used for deciding whether to show the DB-IP disclaimer or not. | ||
## Examples | ||
In the case of a DB-IP database: | ||
iex> database_type() | ||
"DBIP-City-Lite" | ||
In the case of a MaxMind database: | ||
iex> database_type() | ||
"GeoLite2-City" | ||
""" | ||
def database_type do | ||
case :locus.get_info(@db, :metadata) do | ||
{:ok, %{database_type: type}} -> type | ||
_other -> nil | ||
end | ||
end | ||
|
||
@doc """ | ||
Looks up geo info about an IP address. | ||
## Examples | ||
iex> lookup("8.7.6.5") | ||
%{ | ||
"city" => %{ | ||
"geoname_id" => 5349755, | ||
"names" => %{ | ||
"de" => "Fontana", | ||
"en" => "Fontana", | ||
"ja" => "フォンタナ", | ||
"ru" => "Фонтана" | ||
} | ||
}, | ||
"continent" => %{ | ||
"code" => "NA", | ||
"geoname_id" => 6255149, | ||
"names" => %{ | ||
"de" => "Nordamerika", | ||
"en" => "North America", | ||
"es" => "Norteamérica", | ||
"fr" => "Amérique du Nord", | ||
"ja" => "北アメリカ", | ||
"pt-BR" => "América do Norte", | ||
"ru" => "Северная Америка", | ||
"zh-CN" => "北美洲" | ||
} | ||
}, | ||
"country" => %{ | ||
"geoname_id" => 6252001, | ||
"iso_code" => "US", | ||
"names" => %{ | ||
"de" => "Vereinigte Staaten", | ||
"en" => "United States", | ||
"es" => "Estados Unidos", | ||
"fr" => "États Unis", | ||
"ja" => "アメリカ", | ||
"pt-BR" => "EUA", | ||
"ru" => "США", | ||
"zh-CN" => "美国" | ||
} | ||
}, | ||
"location" => %{ | ||
"accuracy_radius" => 50, | ||
"latitude" => 34.1211, | ||
"longitude" => -117.4362, | ||
"metro_code" => 803, | ||
"time_zone" => "America/Los_Angeles" | ||
}, | ||
"postal" => %{"code" => "92336"}, | ||
"registered_country" => %{ | ||
"geoname_id" => 6252001, | ||
"iso_code" => "US", | ||
"names" => %{ | ||
"de" => "Vereinigte Staaten", | ||
"en" => "United States", | ||
"es" => "Estados Unidos", | ||
"fr" => "États Unis", | ||
"ja" => "アメリカ", | ||
"pt-BR" => "EUA", | ||
"ru" => "США", | ||
"zh-CN" => "美国" | ||
} | ||
}, | ||
"subdivisions" => [ | ||
%{ | ||
"geoname_id" => 5332921, | ||
"iso_code" => "CA", | ||
"names" => %{ | ||
"de" => "Kalifornien", | ||
"en" => "California", | ||
"es" => "California", | ||
"fr" => "Californie", | ||
"ja" => "カリフォルニア州", | ||
"pt-BR" => "Califórnia", | ||
"ru" => "Калифорния", | ||
"zh-CN" => "加州" | ||
} | ||
} | ||
] | ||
} | ||
""" | ||
def lookup(ip_address) do | ||
case :locus.lookup(@db, ip_address) do | ||
{:ok, entry} -> | ||
entry | ||
|
||
:not_found -> | ||
nil | ||
|
||
{:error, reason} -> | ||
Logger.error("failed to lookup ip address: " <> inspect(reason)) | ||
nil | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.