talked AI into using a cImport and removed 60 LoC of duplicate code
This commit is contained in:
parent
4195f43fa7
commit
2834763c0a
2 changed files with 35 additions and 94 deletions
|
|
@ -61,6 +61,8 @@ pub fn build(b: *std.Build) void {
|
|||
exe.root_module.addAnonymousImport("airports.dat", .{
|
||||
.root_source_file = openflights.path("data/airports.dat"),
|
||||
});
|
||||
exe.root_module.addIncludePath(maxminddb_upstream.path("include"));
|
||||
exe.root_module.addConfigHeader(maxminddb_config);
|
||||
exe.linkLibrary(maxminddb);
|
||||
exe.linkLibC();
|
||||
|
||||
|
|
@ -86,6 +88,8 @@ pub fn build(b: *std.Build) void {
|
|||
tests.root_module.addAnonymousImport("airports.dat", .{
|
||||
.root_source_file = openflights.path("data/airports.dat"),
|
||||
});
|
||||
tests.root_module.addIncludePath(maxminddb_upstream.path("include"));
|
||||
tests.root_module.addConfigHeader(maxminddb_config);
|
||||
tests.linkLibrary(maxminddb);
|
||||
tests.linkLibC();
|
||||
|
||||
|
|
|
|||
|
|
@ -1,94 +1,29 @@
|
|||
const std = @import("std");
|
||||
const Coordinates = @import("../Coordinates.zig");
|
||||
|
||||
pub const MMDB = extern struct {
|
||||
filename: [*:0]const u8,
|
||||
flags: u32,
|
||||
file_content: ?*anyopaque,
|
||||
file_size: usize,
|
||||
data_section: ?*anyopaque,
|
||||
data_section_size: u32,
|
||||
metadata_section: ?*anyopaque,
|
||||
metadata_section_size: u32,
|
||||
full_record_byte_size: u16,
|
||||
depth: u16,
|
||||
ipv4_start_node: extern struct {
|
||||
node_value: u32,
|
||||
netmask: u16,
|
||||
},
|
||||
metadata: extern struct {
|
||||
node_count: u32,
|
||||
record_size: u16,
|
||||
ip_version: u16,
|
||||
database_type: [*:0]const u8,
|
||||
languages: extern struct {
|
||||
count: usize,
|
||||
names: [*][*:0]const u8,
|
||||
},
|
||||
binary_format_major_version: u16,
|
||||
binary_format_minor_version: u16,
|
||||
build_epoch: u64,
|
||||
description: extern struct {
|
||||
count: usize,
|
||||
descriptions: [*]?*anyopaque,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
pub const MMDBLookupResult = extern struct {
|
||||
found_entry: bool,
|
||||
entry: MMDBEntry,
|
||||
netmask: u16,
|
||||
};
|
||||
|
||||
pub const MMDBEntry = extern struct {
|
||||
mmdb: *MMDB,
|
||||
offset: u32,
|
||||
};
|
||||
|
||||
pub const MMDBEntryData = extern struct {
|
||||
has_data: bool,
|
||||
data_type: u32,
|
||||
offset: u32,
|
||||
offset_to_next: u32,
|
||||
data_size: u32,
|
||||
utf8_string: [*:0]const u8,
|
||||
double_value: f64,
|
||||
bytes: [*]const u8,
|
||||
uint16: u16,
|
||||
uint32: u32,
|
||||
int32: i32,
|
||||
uint64: u64,
|
||||
uint128: u128,
|
||||
boolean: bool,
|
||||
float_value: f32,
|
||||
};
|
||||
|
||||
extern fn MMDB_open(filename: [*:0]const u8, flags: u32, mmdb: *MMDB) c_int;
|
||||
extern fn MMDB_close(mmdb: *MMDB) void;
|
||||
extern fn MMDB_lookup_string(mmdb: *MMDB, ipstr: [*:0]const u8, gai_error: *c_int, mmdb_error: *c_int) MMDBLookupResult;
|
||||
extern fn MMDB_get_value(entry: *MMDBEntry, entry_data: *MMDBEntryData, ...) c_int;
|
||||
extern fn MMDB_strerror(error_code: c_int) [*:0]const u8;
|
||||
const c = @cImport({
|
||||
@cInclude("maxminddb.h");
|
||||
});
|
||||
|
||||
const GeoIP = @This();
|
||||
|
||||
mmdb: MMDB,
|
||||
mmdb: c.MMDB_s,
|
||||
|
||||
pub fn init(db_path: []const u8) !GeoIP {
|
||||
var mmdb: MMDB = undefined;
|
||||
const path_z = try std.heap.c_allocator.dupeZ(u8, db_path);
|
||||
defer std.heap.c_allocator.free(path_z);
|
||||
|
||||
const status = MMDB_open(path_z.ptr, 0, &mmdb);
|
||||
if (status != 0) {
|
||||
// SAFETY: The C API will initialize this on the next line
|
||||
var mmdb: c.MMDB_s = undefined;
|
||||
const status = c.MMDB_open(path_z.ptr, c.MMDB_MODE_MMAP, &mmdb);
|
||||
if (status != c.MMDB_SUCCESS)
|
||||
return error.CannotOpenDatabase;
|
||||
}
|
||||
|
||||
return GeoIP{ .mmdb = mmdb };
|
||||
}
|
||||
|
||||
pub fn deinit(self: *GeoIP) void {
|
||||
MMDB_close(&self.mmdb);
|
||||
c.MMDB_close(&self.mmdb);
|
||||
}
|
||||
|
||||
pub fn lookup(self: *GeoIP, ip: []const u8) !?Coordinates {
|
||||
|
|
@ -98,7 +33,7 @@ pub fn lookup(self: *GeoIP, ip: []const u8) !?Coordinates {
|
|||
var gai_error: c_int = 0;
|
||||
var mmdb_error: c_int = 0;
|
||||
|
||||
const result = MMDB_lookup_string(&self.mmdb, ip_z.ptr, &gai_error, &mmdb_error);
|
||||
const result = c.MMDB_lookup_string(&self.mmdb, ip_z.ptr, &gai_error, &mmdb_error);
|
||||
|
||||
if (gai_error != 0 or mmdb_error != 0) {
|
||||
return null;
|
||||
|
|
@ -108,7 +43,7 @@ pub fn lookup(self: *GeoIP, ip: []const u8) !?Coordinates {
|
|||
return null;
|
||||
}
|
||||
|
||||
return try self.extractCoordinates(result.entry);
|
||||
return try self.extractCoordinates(result);
|
||||
}
|
||||
|
||||
pub fn isUSIP(self: *GeoIP, ip: []const u8) bool {
|
||||
|
|
@ -118,46 +53,48 @@ pub fn isUSIP(self: *GeoIP, ip: []const u8) bool {
|
|||
var gai_error: c_int = 0;
|
||||
var mmdb_error: c_int = 0;
|
||||
|
||||
const result = MMDB_lookup_string(&self.mmdb, ip_z.ptr, &gai_error, &mmdb_error);
|
||||
const result = c.MMDB_lookup_string(&self.mmdb, ip_z.ptr, &gai_error, &mmdb_error);
|
||||
|
||||
if (gai_error != 0 or mmdb_error != 0 or !result.found_entry) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var entry_mut = result.entry;
|
||||
var country_data: MMDBEntryData = undefined;
|
||||
const null_term: [*:0]const u8 = @ptrCast(&[_]u8{0});
|
||||
const status = MMDB_get_value(&entry_mut, &country_data, "country\x00", "iso_code\x00", null_term);
|
||||
// SAFETY: The C API will initialize this on the next line
|
||||
var country_data: c.MMDB_entry_data_s = undefined;
|
||||
const status = c.MMDB_get_value(&entry_mut, &country_data, "country\x00", "iso_code\x00", null_term);
|
||||
|
||||
if (status != 0 or !country_data.has_data) {
|
||||
if (status != c.MMDB_SUCCESS or !country_data.has_data)
|
||||
return false;
|
||||
}
|
||||
|
||||
const country_code = std.mem.span(country_data.utf8_string);
|
||||
const country_code = std.mem.span(country_data.unnamed_0.utf8_string);
|
||||
return std.mem.eql(u8, country_code, "US");
|
||||
}
|
||||
|
||||
fn extractCoordinates(self: *GeoIP, entry: MMDBEntry) !Coordinates {
|
||||
fn extractCoordinates(self: *GeoIP, result: c.MMDB_lookup_result_s) !Coordinates {
|
||||
_ = self;
|
||||
var entry_mut = entry;
|
||||
var latitude_data: MMDBEntryData = undefined;
|
||||
var longitude_data: MMDBEntryData = undefined;
|
||||
var entry_mut = result.entry;
|
||||
|
||||
const lat_status = MMDB_get_value(&entry_mut, &latitude_data, "location", "latitude", @as([*:0]const u8, @ptrCast(&[_]u8{0})));
|
||||
const lon_status = MMDB_get_value(&entry_mut, &longitude_data, "location", "longitude", @as([*:0]const u8, @ptrCast(&[_]u8{0})));
|
||||
// SAFETY: The C API will initialize below
|
||||
var latitude_data: c.MMDB_entry_data_s = undefined;
|
||||
// SAFETY: The C API will initialize below
|
||||
var longitude_data: c.MMDB_entry_data_s = undefined;
|
||||
|
||||
if (lat_status != 0 or lon_status != 0 or !latitude_data.has_data or !longitude_data.has_data) {
|
||||
const lat_status = c.MMDB_get_value(&entry_mut, &latitude_data, "location", "latitude", @as([*:0]const u8, @ptrCast(&[_]u8{0})));
|
||||
const lon_status = c.MMDB_get_value(&entry_mut, &longitude_data, "location", "longitude", @as([*:0]const u8, @ptrCast(&[_]u8{0})));
|
||||
|
||||
if (lat_status != c.MMDB_SUCCESS or lon_status != c.MMDB_SUCCESS or !latitude_data.has_data or !longitude_data.has_data)
|
||||
return error.CoordinatesNotFound;
|
||||
}
|
||||
|
||||
return Coordinates{
|
||||
.latitude = latitude_data.double_value,
|
||||
.longitude = longitude_data.double_value,
|
||||
return .{
|
||||
.latitude = latitude_data.unnamed_0.double_value,
|
||||
.longitude = longitude_data.unnamed_0.double_value,
|
||||
};
|
||||
}
|
||||
|
||||
test "MMDB functions are callable" {
|
||||
const mmdb_error = MMDB_strerror(0);
|
||||
const mmdb_error = c.MMDB_strerror(0);
|
||||
try std.testing.expect(mmdb_error[0] != 0);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue