In its current state this hackery fits our needs.
Signed-off-by: Adam Rocska <adam.rocska@adams.solutions>
This commit is contained in:
parent
c9bee263df
commit
7b487ccc60
|
@ -6,19 +6,6 @@ sound like to plan for a breaking change befor the first initial version's
|
||||||
release, but hey, there's a time pressure on my shoulder right now + MaxMind's
|
release, but hey, there's a time pressure on my shoulder right now + MaxMind's
|
||||||
"binary format" "desgined" by its script kiddos slowed things down baadly._
|
"binary format" "desgined" by its script kiddos slowed things down baadly._
|
||||||
|
|
||||||
## Replace CIDR Strings with proper intelligence
|
|
||||||
|
|
||||||
[Wikipedia](https://en.wikipedia.org/wiki/Classless_Inter-Domain_Routing)
|
|
||||||
|
|
||||||
At the time of writing I just had to port the dumbass php style "String
|
|
||||||
representation" of networks. That's bad. That's so bad, that normally I wouldn't
|
|
||||||
permit such a crap in my company.
|
|
||||||
|
|
||||||
What I want is to create a unit (most probably it'll be a struct?) that not only
|
|
||||||
represents the network, but also provides utilities that can check whether an
|
|
||||||
`IpAddress` belongs to that network for example. Should be representable in many
|
|
||||||
different forms, etc.
|
|
||||||
|
|
||||||
## Error handling
|
## Error handling
|
||||||
|
|
||||||
There used to be an original concept of how to do proper error handling &
|
There used to be an original concept of how to do proper error handling &
|
||||||
|
@ -41,4 +28,15 @@ For example if you get **128bit unsigned int index pointers**, you'll face quite
|
||||||
bit of fun.
|
bit of fun.
|
||||||
|
|
||||||
I'll do my best to massage things out. Once the public API is stable, and neat,
|
I'll do my best to massage things out. Once the public API is stable, and neat,
|
||||||
the underlying crap can be cleaned up.
|
the underlying crap can be cleaned up.
|
||||||
|
|
||||||
|
## Redesign the retarded modeling
|
||||||
|
|
||||||
|
At the library's initial stage the decision was to reproduce in a somewhat
|
||||||
|
similar state what MaxMind's php scritpers made with their PHP, Java, and C#
|
||||||
|
libraries.
|
||||||
|
|
||||||
|
That modeling is awful.
|
||||||
|
|
||||||
|
The way the API will return models will definitely change, so there will be a
|
||||||
|
2.0.0 API break at some point.
|
10
README.md
10
README.md
|
@ -1,11 +1 @@
|
||||||
# GeoIP2-swift
|
# GeoIP2-swift
|
||||||
|
|
||||||
**HEAVILY WORK IN PROGRESS.**
|
|
||||||
|
|
||||||
Progress postponed for a few days.
|
|
||||||
In its current state it mostly works, but is unacceptably slow to initialize.
|
|
||||||
The lookup time is fast, but it's an unacceptable speed to initialize.
|
|
||||||
|
|
||||||
Initialization performance problems root mainly from the poor DB design.
|
|
||||||
|
|
||||||
**Will revisit after 8th of July.**
|
|
||||||
|
|
|
@ -6,6 +6,12 @@ public struct CityModel: Equatable {
|
||||||
public let location: LocationRecord
|
public let location: LocationRecord
|
||||||
public let postal: PostalRecord
|
public let postal: PostalRecord
|
||||||
public let subdivisions: [SubdivisionRecord]
|
public let subdivisions: [SubdivisionRecord]
|
||||||
|
public let continent: ContinentRecord
|
||||||
|
public let country: CountryRecord
|
||||||
|
public let maxmind: MaxMindRecord
|
||||||
|
public let registeredCountry: CountryRecord
|
||||||
|
public let representedCountry: RepresentedCountryRecord
|
||||||
|
public let traits: TraitsRecord
|
||||||
public let ipAddress: IpAddress
|
public let ipAddress: IpAddress
|
||||||
public let netmask: IpAddress
|
public let netmask: IpAddress
|
||||||
public var mostSpecificSubdivision: SubdivisionRecord { get { return subdivisions.last ?? SubdivisionRecord(nil) } }
|
public var mostSpecificSubdivision: SubdivisionRecord { get { return subdivisions.last ?? SubdivisionRecord(nil) } }
|
||||||
|
@ -20,6 +26,12 @@ extension CityModel: DictionaryInitialisableModel {
|
||||||
subdivisions: (dictionary?["subdivisions"]?.unwrap() ?? [] as [Payload]).compactMap(
|
subdivisions: (dictionary?["subdivisions"]?.unwrap() ?? [] as [Payload]).compactMap(
|
||||||
{ SubdivisionRecord($0.unwrap()) }
|
{ SubdivisionRecord($0.unwrap()) }
|
||||||
),
|
),
|
||||||
|
continent: ContinentRecord(dictionary?["continent"]?.unwrap()),
|
||||||
|
country: CountryRecord(dictionary?["country"]?.unwrap()),
|
||||||
|
maxmind: MaxMindRecord(dictionary?["maxmind"]?.unwrap()),
|
||||||
|
registeredCountry: CountryRecord(dictionary?["registered_country"]?.unwrap()),
|
||||||
|
representedCountry: RepresentedCountryRecord(dictionary?["represented_country"]?.unwrap()),
|
||||||
|
traits: TraitsRecord(dictionary?["traits"]?.unwrap()),
|
||||||
ipAddress: ip,
|
ipAddress: ip,
|
||||||
netmask: netmask
|
netmask: netmask
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,9 +1,39 @@
|
||||||
import Foundation
|
import Foundation
|
||||||
|
import enum Decoder.Payload
|
||||||
|
|
||||||
// TODO : Untangle php scripter retardnes. Theses people at maxmind shouldn't write code that gets executed by a processor. Honestly.
|
|
||||||
// See stupid fucking php scripter stupidity : https://github.com/maxmind/GeoIP2-php/blob/master/src/Model/Enterprise.php
|
|
||||||
// Apparently they are so dumb, they needed 2 people to produce an empty class, with a nonsense API doc'.
|
|
||||||
// Their Java, and C# code is as retaarded as the php one. I never saw throughout my career Java being raped so badly.
|
|
||||||
public struct EnterpriseModel: Equatable {
|
public struct EnterpriseModel: Equatable {
|
||||||
|
public let city: CityRecord
|
||||||
|
public let location: LocationRecord
|
||||||
|
public let postal: PostalRecord
|
||||||
|
public let subdivisions: [SubdivisionRecord]
|
||||||
|
public let continent: ContinentRecord
|
||||||
|
public let country: CountryRecord
|
||||||
|
public let maxmind: MaxMindRecord
|
||||||
|
public let registeredCountry: CountryRecord
|
||||||
|
public let representedCountry: RepresentedCountryRecord
|
||||||
|
public let traits: TraitsRecord
|
||||||
|
public let ipAddress: IpAddress
|
||||||
|
public let netmask: IpAddress
|
||||||
|
public var mostSpecificSubdivision: SubdivisionRecord { get { return subdivisions.last ?? SubdivisionRecord(nil) } }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extension EnterpriseModel: DictionaryInitialisableModel {
|
||||||
|
public init(ip: IpAddress, netmask: IpAddress, _ dictionary: [String: Payload]?) {
|
||||||
|
self.init(
|
||||||
|
city: CityRecord(dictionary?["city"]?.unwrap()),
|
||||||
|
location: LocationRecord(dictionary?["location"]?.unwrap()),
|
||||||
|
postal: PostalRecord(dictionary?["postal"]?.unwrap()),
|
||||||
|
subdivisions: (dictionary?["subdivisions"]?.unwrap() ?? [] as [Payload]).compactMap(
|
||||||
|
{ SubdivisionRecord($0.unwrap()) }
|
||||||
|
),
|
||||||
|
continent: ContinentRecord(dictionary?["continent"]?.unwrap()),
|
||||||
|
country: CountryRecord(dictionary?["country"]?.unwrap()),
|
||||||
|
maxmind: MaxMindRecord(dictionary?["maxmind"]?.unwrap()),
|
||||||
|
registeredCountry: CountryRecord(dictionary?["registered_country"]?.unwrap()),
|
||||||
|
representedCountry: RepresentedCountryRecord(dictionary?["represented_country"]?.unwrap()),
|
||||||
|
traits: TraitsRecord(dictionary?["traits"]?.unwrap()),
|
||||||
|
ipAddress: ip,
|
||||||
|
netmask: netmask
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,9 +1,39 @@
|
||||||
import Foundation
|
import Foundation
|
||||||
|
import enum Decoder.Payload
|
||||||
|
|
||||||
// TODO : Untangle php scripter retardnes. Theses people at maxmind shouldn't write code that gets executed by a processor. Honestly.
|
|
||||||
// See stupid fucking php scripter stupidity : https://github.com/maxmind/GeoIP2-php/blob/master/src/Model/Insights.php
|
|
||||||
// Apparently they are so dumb, they needed 2 people to produce an empty class, with a nonsense API doc'.
|
|
||||||
// Their Java, and C# code is as retaarded as the php one. I never saw throughout my career Java being raped so badly.
|
|
||||||
public struct InsightsModel: Equatable {
|
public struct InsightsModel: Equatable {
|
||||||
|
public let city: CityRecord
|
||||||
|
public let location: LocationRecord
|
||||||
|
public let postal: PostalRecord
|
||||||
|
public let subdivisions: [SubdivisionRecord]
|
||||||
|
public let continent: ContinentRecord
|
||||||
|
public let country: CountryRecord
|
||||||
|
public let maxmind: MaxMindRecord
|
||||||
|
public let registeredCountry: CountryRecord
|
||||||
|
public let representedCountry: RepresentedCountryRecord
|
||||||
|
public let traits: TraitsRecord
|
||||||
|
public let ipAddress: IpAddress
|
||||||
|
public let netmask: IpAddress
|
||||||
|
public var mostSpecificSubdivision: SubdivisionRecord { get { return subdivisions.last ?? SubdivisionRecord(nil) } }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extension InsightsModel: DictionaryInitialisableModel {
|
||||||
|
public init(ip: IpAddress, netmask: IpAddress, _ dictionary: [String: Payload]?) {
|
||||||
|
self.init(
|
||||||
|
city: CityRecord(dictionary?["city"]?.unwrap()),
|
||||||
|
location: LocationRecord(dictionary?["location"]?.unwrap()),
|
||||||
|
postal: PostalRecord(dictionary?["postal"]?.unwrap()),
|
||||||
|
subdivisions: (dictionary?["subdivisions"]?.unwrap() ?? [] as [Payload]).compactMap(
|
||||||
|
{ SubdivisionRecord($0.unwrap()) }
|
||||||
|
),
|
||||||
|
continent: ContinentRecord(dictionary?["continent"]?.unwrap()),
|
||||||
|
country: CountryRecord(dictionary?["country"]?.unwrap()),
|
||||||
|
maxmind: MaxMindRecord(dictionary?["maxmind"]?.unwrap()),
|
||||||
|
registeredCountry: CountryRecord(dictionary?["registered_country"]?.unwrap()),
|
||||||
|
representedCountry: RepresentedCountryRecord(dictionary?["represented_country"]?.unwrap()),
|
||||||
|
traits: TraitsRecord(dictionary?["traits"]?.unwrap()),
|
||||||
|
ipAddress: ip,
|
||||||
|
netmask: netmask
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
# Good to know about the API module
|
||||||
|
|
||||||
|
It was intentionally designed to reproduce the php scripter fantasies, and awful
|
||||||
|
modeling to reduce risks of having a broken library behavior, and data provision.
|
||||||
|
|
||||||
|
Depending on how widespread the library may become, the new fancy API of which
|
||||||
|
I could be proud of will be delivered either :
|
||||||
|
* **as a backwards incompatible way**, by simply throwing it all out in the
|
||||||
|
garbage, and providing a proper professional api
|
||||||
|
* **as a backwards compatible way**, by doing a minor release, marking this pile
|
||||||
|
of shit I wrote as deprecated, providing a neat API module, and throwing this
|
||||||
|
trash in the garbage in the future.
|
|
@ -15,7 +15,7 @@ extension SubdivisionRecord: DictionaryInitialisableRecord {
|
||||||
self.init(
|
self.init(
|
||||||
confidence: dictionary?["confidence"]?.unwrap(),
|
confidence: dictionary?["confidence"]?.unwrap(),
|
||||||
geonameId: dictionary?["geoname_id"]?.unwrap(),
|
geonameId: dictionary?["geoname_id"]?.unwrap(),
|
||||||
isoCode: dictionary?["iso_cod"]?.unwrap(),
|
isoCode: dictionary?["iso_code"]?.unwrap(),
|
||||||
names: (dictionary?["names"]?.unwrap() ?? [:] as [String: Payload]).compactMapValues({ $0.unwrap() })
|
names: (dictionary?["names"]?.unwrap() ?? [:] as [String: Payload]).compactMapValues({ $0.unwrap() })
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,8 +6,6 @@ public struct TraitsRecord: Equatable {
|
||||||
let autonomousSystemOrganization: String?
|
let autonomousSystemOrganization: String?
|
||||||
let connectionType: String?
|
let connectionType: String?
|
||||||
let domain: String?
|
let domain: String?
|
||||||
// todo
|
|
||||||
// let ipAddress: IpAddress
|
|
||||||
let isAnonymous: Bool
|
let isAnonymous: Bool
|
||||||
let isAnonymousProxy: Bool
|
let isAnonymousProxy: Bool
|
||||||
let isAnonymousVpn: Bool
|
let isAnonymousVpn: Bool
|
||||||
|
@ -17,7 +15,6 @@ public struct TraitsRecord: Equatable {
|
||||||
let isSatelliteProvider: Bool
|
let isSatelliteProvider: Bool
|
||||||
let isTorExitNode: Bool
|
let isTorExitNode: Bool
|
||||||
let isp: String?
|
let isp: String?
|
||||||
let network: String
|
|
||||||
let organization: String?
|
let organization: String?
|
||||||
let staticIPScore: Float?
|
let staticIPScore: Float?
|
||||||
let userCount: Int?
|
let userCount: Int?
|
||||||
|
@ -31,8 +28,6 @@ extension TraitsRecord: DictionaryInitialisableRecord {
|
||||||
autonomousSystemOrganization: dictionary?["autonomous_system_organization"]?.unwrap(),
|
autonomousSystemOrganization: dictionary?["autonomous_system_organization"]?.unwrap(),
|
||||||
connectionType: dictionary?["connection_type"]?.unwrap(),
|
connectionType: dictionary?["connection_type"]?.unwrap(),
|
||||||
domain: dictionary?["domain"]?.unwrap(),
|
domain: dictionary?["domain"]?.unwrap(),
|
||||||
// TODO
|
|
||||||
// ipAddress: dictionary?["ipAddress"]?.unwrap(),
|
|
||||||
isAnonymous: dictionary?["is_anonymous"]?.unwrap() ?? false,
|
isAnonymous: dictionary?["is_anonymous"]?.unwrap() ?? false,
|
||||||
isAnonymousProxy: dictionary?["is_anonymous_proxy"]?.unwrap() ?? false,
|
isAnonymousProxy: dictionary?["is_anonymous_proxy"]?.unwrap() ?? false,
|
||||||
isAnonymousVpn: dictionary?["is_anonymous_vpn"]?.unwrap() ?? false,
|
isAnonymousVpn: dictionary?["is_anonymous_vpn"]?.unwrap() ?? false,
|
||||||
|
@ -42,8 +37,6 @@ extension TraitsRecord: DictionaryInitialisableRecord {
|
||||||
isSatelliteProvider: dictionary?["is_satellite_provider"]?.unwrap() ?? false,
|
isSatelliteProvider: dictionary?["is_satellite_provider"]?.unwrap() ?? false,
|
||||||
isTorExitNode: dictionary?["is_tor_exit_node"]?.unwrap() ?? false,
|
isTorExitNode: dictionary?["is_tor_exit_node"]?.unwrap() ?? false,
|
||||||
isp: dictionary?["isp"]?.unwrap(),
|
isp: dictionary?["isp"]?.unwrap(),
|
||||||
// TODO
|
|
||||||
network: dictionary?["network"]?.unwrap() ?? "",
|
|
||||||
organization: dictionary?["organization"]?.unwrap(),
|
organization: dictionary?["organization"]?.unwrap(),
|
||||||
staticIPScore: dictionary?["static_ip_score"]?.unwrap(),
|
staticIPScore: dictionary?["static_ip_score"]?.unwrap(),
|
||||||
userCount: dictionary?["user_count"]?.unwrap(),
|
userCount: dictionary?["user_count"]?.unwrap(),
|
||||||
|
|
|
@ -5,6 +5,15 @@ import class Api.Reader
|
||||||
import class Api.ReaderFactory
|
import class Api.ReaderFactory
|
||||||
import enum Api.IpAddress
|
import enum Api.IpAddress
|
||||||
@testable import struct Api.CityModel
|
@testable import struct Api.CityModel
|
||||||
|
@testable import struct Api.CityRecord
|
||||||
|
@testable import struct Api.ContinentRecord
|
||||||
|
@testable import struct Api.CountryRecord
|
||||||
|
@testable import struct Api.LocationRecord
|
||||||
|
@testable import struct Api.MaxMindRecord
|
||||||
|
@testable import struct Api.PostalRecord
|
||||||
|
@testable import struct Api.RepresentedCountryRecord
|
||||||
|
@testable import struct Api.SubdivisionRecord
|
||||||
|
@testable import struct Api.TraitsRecord
|
||||||
|
|
||||||
class CityLookupTest: XCTestCase {
|
class CityLookupTest: XCTestCase {
|
||||||
|
|
||||||
|
@ -31,11 +40,201 @@ class CityLookupTest: XCTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
func testSuccessfulLookup() {
|
func testSuccessfulLookup() {
|
||||||
"ffff:ffff:ffff:ffff:ffff:ffff:ffff:C000"
|
XCTAssertEqual(
|
||||||
"255.255.255.224"
|
CityModel(
|
||||||
"255.255.255.192"
|
city: CityRecord(
|
||||||
// print(reader.lookup(.v6("::1.128.0.0"))?.netmask)
|
confidence: nil,
|
||||||
print(reader.lookup(.v4(80, 99, 18, 166))?.netmask)
|
geonameId: 3054643,
|
||||||
|
names: [
|
||||||
|
"de": "Budapest",
|
||||||
|
"en": "Budapest",
|
||||||
|
"es": "Budapest",
|
||||||
|
"fr": "Budapest",
|
||||||
|
"ja": "ブダペスト",
|
||||||
|
"pt-BR": "Budapeste",
|
||||||
|
"ru": "Будапешт",
|
||||||
|
"zh-CN": "布达佩斯"
|
||||||
|
]
|
||||||
|
),
|
||||||
|
location: LocationRecord(
|
||||||
|
averageIncome: nil,
|
||||||
|
accuracyRadius: 20,
|
||||||
|
latitude: 47.4984,
|
||||||
|
longitude: 19.0404,
|
||||||
|
populationDensity: nil,
|
||||||
|
metroCode: nil,
|
||||||
|
timeZone: "Europe/Budapest"
|
||||||
|
),
|
||||||
|
postal: PostalRecord(code: "1096", confidence: nil),
|
||||||
|
subdivisions: [
|
||||||
|
SubdivisionRecord(
|
||||||
|
confidence: nil,
|
||||||
|
geonameId: 3054638,
|
||||||
|
isoCode: "BU",
|
||||||
|
names: ["en": "Budapest"]
|
||||||
|
)
|
||||||
|
],
|
||||||
|
continent: ContinentRecord(
|
||||||
|
code: "EU",
|
||||||
|
geonameId: 6255148,
|
||||||
|
names: [
|
||||||
|
"de": "Europa",
|
||||||
|
"en": "Europe",
|
||||||
|
"es": "Europa",
|
||||||
|
"fr": "Europe",
|
||||||
|
"ja": "ヨーロッパ",
|
||||||
|
"pt-BR": "Europa",
|
||||||
|
"ru": "Европа",
|
||||||
|
"zh-CN": "欧洲"
|
||||||
|
]
|
||||||
|
),
|
||||||
|
country: CountryRecord(
|
||||||
|
confidence: nil,
|
||||||
|
geonameId: 719819,
|
||||||
|
isInEuropeanUnion: true,
|
||||||
|
isoCode: "HU",
|
||||||
|
names: [
|
||||||
|
"de": "Ungarn",
|
||||||
|
"en": "Hungary",
|
||||||
|
"es": "Hungría",
|
||||||
|
"fr": "Hongrie",
|
||||||
|
"ja": "ハンガリー共和国",
|
||||||
|
"pt-BR": "Hungria",
|
||||||
|
"ru": "Венгрия",
|
||||||
|
"zh-CN": "匈牙利"
|
||||||
|
]
|
||||||
|
),
|
||||||
|
maxmind: MaxMindRecord(queriesRemaining: nil),
|
||||||
|
registeredCountry: CountryRecord(
|
||||||
|
confidence: nil,
|
||||||
|
geonameId: 719819,
|
||||||
|
isInEuropeanUnion: true,
|
||||||
|
isoCode: "HU",
|
||||||
|
names: [
|
||||||
|
"de": "Ungarn",
|
||||||
|
"en": "Hungary",
|
||||||
|
"es": "Hungría",
|
||||||
|
"fr": "Hongrie",
|
||||||
|
"ja": "ハンガリー共和国",
|
||||||
|
"pt-BR": "Hungria",
|
||||||
|
"ru": "Венгрия",
|
||||||
|
"zh-CN": "匈牙利"
|
||||||
|
]
|
||||||
|
),
|
||||||
|
representedCountry: RepresentedCountryRecord(type: nil),
|
||||||
|
traits: TraitsRecord(
|
||||||
|
autonomousSystemNumber: nil,
|
||||||
|
autonomousSystemOrganization: nil,
|
||||||
|
connectionType: nil,
|
||||||
|
domain: nil,
|
||||||
|
isAnonymous: false,
|
||||||
|
isAnonymousProxy: false,
|
||||||
|
isAnonymousVpn: false,
|
||||||
|
isHostingProvider: false,
|
||||||
|
isLegitimateProxy: false,
|
||||||
|
isPublicProxy: false,
|
||||||
|
isSatelliteProvider: false,
|
||||||
|
isTorExitNode: false,
|
||||||
|
isp: nil,
|
||||||
|
organization: nil,
|
||||||
|
staticIPScore: nil,
|
||||||
|
userCount: nil,
|
||||||
|
userType: nil
|
||||||
|
),
|
||||||
|
ipAddress: .v4(80, 99, 18, 166),
|
||||||
|
netmask: IpAddress.v4Netmask(ofBitLength: 26)
|
||||||
|
),
|
||||||
|
reader.lookup(.v4(80, 99, 18, 166))
|
||||||
|
)
|
||||||
|
|
||||||
|
XCTAssertEqual(
|
||||||
|
CityModel(
|
||||||
|
city: CityRecord(confidence: nil, geonameId: nil, names: [:]),
|
||||||
|
location: LocationRecord(
|
||||||
|
averageIncome: nil,
|
||||||
|
accuracyRadius: 1000,
|
||||||
|
latitude: -33.494,
|
||||||
|
longitude: 143.2104,
|
||||||
|
populationDensity: nil,
|
||||||
|
metroCode: nil,
|
||||||
|
timeZone: "Australia/Sydney"
|
||||||
|
),
|
||||||
|
postal: PostalRecord(code: nil, confidence: nil),
|
||||||
|
subdivisions: [],
|
||||||
|
continent: ContinentRecord(
|
||||||
|
code: "OC",
|
||||||
|
geonameId: 6255151,
|
||||||
|
names: [
|
||||||
|
"de": "Ozeanien",
|
||||||
|
"en": "Oceania",
|
||||||
|
"es": "Oceanía",
|
||||||
|
"fr": "Océanie",
|
||||||
|
"ja": "オセアニア",
|
||||||
|
"pt-BR": "Oceania",
|
||||||
|
"ru": "Океания",
|
||||||
|
"zh-CN": "大洋洲"
|
||||||
|
]
|
||||||
|
),
|
||||||
|
country: CountryRecord(
|
||||||
|
confidence: nil,
|
||||||
|
geonameId: 2077456,
|
||||||
|
isInEuropeanUnion: false,
|
||||||
|
isoCode: "AU",
|
||||||
|
names: [
|
||||||
|
"de": "Australien",
|
||||||
|
"en": "Australia",
|
||||||
|
"es": "Australia",
|
||||||
|
"fr": "Australie",
|
||||||
|
"ja": "オーストラリア",
|
||||||
|
"pt-BR": "Austrália",
|
||||||
|
"ru": "Австралия",
|
||||||
|
"zh-CN": "澳大利亚"
|
||||||
|
]
|
||||||
|
),
|
||||||
|
maxmind: MaxMindRecord(queriesRemaining: nil),
|
||||||
|
registeredCountry: CountryRecord(
|
||||||
|
confidence: nil,
|
||||||
|
geonameId: 2077456,
|
||||||
|
isInEuropeanUnion: false,
|
||||||
|
isoCode: "AU",
|
||||||
|
names: [
|
||||||
|
"de": "Australien",
|
||||||
|
"en": "Australia",
|
||||||
|
"es": "Australia",
|
||||||
|
"fr": "Australie",
|
||||||
|
"ja": "オーストラリア",
|
||||||
|
"pt-BR": "Austrália",
|
||||||
|
"ru": "Австралия",
|
||||||
|
"zh-CN": "澳大利亚"
|
||||||
|
]
|
||||||
|
),
|
||||||
|
representedCountry: RepresentedCountryRecord(type: nil),
|
||||||
|
traits: TraitsRecord(
|
||||||
|
autonomousSystemNumber: nil,
|
||||||
|
autonomousSystemOrganization: nil,
|
||||||
|
connectionType: nil,
|
||||||
|
domain: nil,
|
||||||
|
isAnonymous: false,
|
||||||
|
isAnonymousProxy: false,
|
||||||
|
isAnonymousVpn: false,
|
||||||
|
isHostingProvider: false,
|
||||||
|
isLegitimateProxy: false,
|
||||||
|
isPublicProxy: false,
|
||||||
|
isSatelliteProvider: false,
|
||||||
|
isTorExitNode: false,
|
||||||
|
isp: nil,
|
||||||
|
organization: nil,
|
||||||
|
staticIPScore: nil,
|
||||||
|
userCount: nil,
|
||||||
|
userType: nil
|
||||||
|
),
|
||||||
|
ipAddress: .v6("::1.128.0.0"),
|
||||||
|
netmask: IpAddress.v6Netmask(ofBitLength: 114)
|
||||||
|
),
|
||||||
|
reader.lookup(.v6("::1.128.0.0"))
|
||||||
|
)
|
||||||
|
|
||||||
|
XCTAssertNil(reader.lookup(.v6("2600:7100::")))
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue