PlaytimeHistory 0.1.0: sessions and team/alive segments in MySQL, DB-IP locations
This commit is contained in:
commit
a56dbad03a
11 changed files with 1989 additions and 0 deletions
53
Geo.cs
Normal file
53
Geo.cs
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
using System.Net;
|
||||
using MaxMind.Db;
|
||||
|
||||
namespace PlaytimeHistory;
|
||||
|
||||
// Country and city for an IP, from DB-IP's City Lite database (MaxMind DB format, CC BY 4.0:
|
||||
// "IP Geolocation by DB-IP", https://db-ip.com). Only the result is kept; the IP never is.
|
||||
public sealed class Geo : IDisposable
|
||||
{
|
||||
public sealed record Location(string? CountryIso, string? CountryName, string? City);
|
||||
|
||||
private readonly Reader _reader;
|
||||
|
||||
private Geo(Reader reader) => _reader = reader;
|
||||
|
||||
public string DatabaseType => _reader.Metadata.DatabaseType;
|
||||
public DateTime BuildDate => _reader.Metadata.BuildDate;
|
||||
|
||||
// Null when the file isn't there.
|
||||
public static Geo? Open(string path) =>
|
||||
File.Exists(path) ? new Geo(new Reader(path, FileAccessMode.MemoryMapped)) : null;
|
||||
|
||||
// `address` is "ip" or "ip:port", as CCSPlayerController.IpAddress gives it.
|
||||
public Location? Lookup(string? address)
|
||||
{
|
||||
if (string.IsNullOrEmpty(address))
|
||||
return null;
|
||||
var colon = address.LastIndexOf(':');
|
||||
var host = colon > 0 && address.IndexOf(':') == colon ? address[..colon] : address;
|
||||
if (!IPAddress.TryParse(host, out var ip))
|
||||
return null;
|
||||
|
||||
var data = _reader.Find<Dictionary<string, object>>(ip);
|
||||
if (data == null)
|
||||
return null;
|
||||
|
||||
string? iso = null, country = null, city = null;
|
||||
if (data.TryGetValue("country", out var c) && c is Dictionary<string, object> countryData)
|
||||
{
|
||||
iso = countryData.TryGetValue("iso_code", out var code) ? code as string : null;
|
||||
country = EnglishName(countryData);
|
||||
}
|
||||
if (data.TryGetValue("city", out var ct) && ct is Dictionary<string, object> cityData)
|
||||
city = EnglishName(cityData);
|
||||
return iso == null && city == null ? null : new Location(iso, country, city);
|
||||
}
|
||||
|
||||
private static string? EnglishName(Dictionary<string, object> data) =>
|
||||
data.TryGetValue("names", out var n) && n is Dictionary<string, object> names &&
|
||||
names.TryGetValue("en", out var en) ? en as string : null;
|
||||
|
||||
public void Dispose() => _reader.Dispose();
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue