Skip to content

Commit a7fa62e

Browse files
authored
revert: use ip3country library instead of inlined version (#304)
leaving the option to disable ip3c
1 parent e22c18f commit a7fa62e

File tree

3 files changed

+2
-142
lines changed

3 files changed

+2
-142
lines changed

build.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ dependencies {
3434
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.6.4")
3535
implementation("com.squareup.okhttp3:okhttp:4.11.0")
3636
implementation("com.github.ua-parser:uap-java:1.6.1")
37+
implementation("com.statsig:ip3country:0.1.5")
3738
implementation("com.squareup.okhttp3:logging-interceptor:4.11.0")
3839
}
3940

src/main/kotlin/com/statsig/sdk/CountryLookup.kt

Lines changed: 0 additions & 139 deletions
Original file line numberDiff line numberDiff line change
@@ -3,142 +3,3 @@ package com.statsig.sdk
33
private const val IP_TABLE_FILE: String = "ip_supalite.table"
44
private const val NULL_CC: String = "--"
55
private const val LOOKUP_TABLE_TERMINATOR: Int = '*'.code
6-
7-
class CountryLookup {
8-
companion object {
9-
val countryCodes: MutableList<String> = mutableListOf()
10-
val ipRanges: MutableList<Long> = mutableListOf()
11-
12-
private val countryTable: MutableList<String> = mutableListOf()
13-
private var initialized = false
14-
private val lock = Any()
15-
16-
@JvmStatic
17-
fun initialize() {
18-
synchronized(lock) {
19-
if (initialized) {
20-
return
21-
}
22-
23-
// optimistically set initialized to true - otherwise we could reinitialize every check
24-
initialized = true
25-
26-
val resourceAsStream = CountryLookup::class.java.classLoader.getResourceAsStream(IP_TABLE_FILE)
27-
resourceAsStream?.use { inputStream ->
28-
val bytes = inputStream.readBytes()
29-
initializeWithBytes(bytes)
30-
} ?: return
31-
}
32-
}
33-
34-
fun cleanup() {
35-
synchronized(lock) {
36-
this.countryCodes.clear()
37-
this.ipRanges.clear()
38-
this.countryTable.clear()
39-
initialized = false
40-
}
41-
}
42-
43-
@JvmStatic
44-
fun lookupIPString(ipAddressString: String): String? {
45-
initialize()
46-
if (ipAddressString.isEmpty()) {
47-
return null
48-
}
49-
50-
val components = ipAddressString.split(".")
51-
if (components.size != 4) {
52-
return null
53-
}
54-
55-
return try {
56-
val ipNumber = components[0].toLong() * 16777216 +
57-
components[1].toLong() * 65536 +
58-
components[2].toLong() * 256 +
59-
components[3].toLong()
60-
61-
lookupIPNumber(ipNumber)
62-
} catch (_e: Exception) {
63-
null
64-
}
65-
}
66-
67-
@JvmStatic
68-
fun lookupIPNumber(ipNumber: Long): String? {
69-
initialize()
70-
val index = binarySearch(ipNumber)
71-
val cc = countryCodes[index]
72-
if (cc == NULL_CC) {
73-
return null
74-
}
75-
return cc
76-
}
77-
78-
/**
79-
* The binary is packed as follows:
80-
* c1.c2.c3.....**: Country code look up table, terminated by **
81-
82-
* n1.c: if n is < 240, c is country code index
83-
* 242.n2.n3.c: if n >= 240 but < 65536. n2 being lower order byte
84-
* 243.n2.n3.n4.c: if n >= 65536. n2 being lower order byte
85-
*/
86-
private fun initializeWithBytes(bytes: ByteArray) {
87-
var index = 0
88-
while (index < bytes.size) {
89-
val c1 = bytes[index++]
90-
val c2 = bytes[index++]
91-
92-
countryTable.add(String(byteArrayOf(c1, c2)))
93-
if (c1.toInt() == LOOKUP_TABLE_TERMINATOR) {
94-
break
95-
}
96-
}
97-
var lastEndRange: Long = 0
98-
while (index < bytes.size) {
99-
var count: Long = 0
100-
val n1 = bytes[index++].toInt().and(0xff)
101-
when {
102-
n1 < 240 -> {
103-
count = n1.toLong()
104-
}
105-
n1 == 242 -> {
106-
val n2 = bytes[index++].toInt().and(0xff)
107-
val n3 = bytes[index++].toInt().and(0xff)
108-
count = (n2.or((n3 shl 8))).toLong()
109-
}
110-
n1 == 243 -> {
111-
val n2 = bytes[index++].toInt().and(0xff)
112-
val n3 = bytes[index++].toInt().and(0xff)
113-
val n4 = bytes[index++].toInt().and(0xff)
114-
count = ((n2.or((n3 shl 8))).or((n4 shl 16))).toLong()
115-
}
116-
}
117-
lastEndRange += count * 256
118-
119-
val cc = bytes[index++].toInt().and(0xff)
120-
121-
ipRanges.add(lastEndRange)
122-
countryCodes.add(countryTable[cc])
123-
}
124-
125-
initialized = true
126-
}
127-
128-
private fun binarySearch(ipNumber: Long): Int {
129-
var min = 0
130-
var max = ipRanges.size - 1
131-
132-
while (min < max) {
133-
val mid = (min + max) shr 1
134-
if (ipRanges[mid] <= ipNumber) {
135-
min = mid + 1
136-
} else {
137-
max = mid
138-
}
139-
}
140-
141-
return min
142-
}
143-
}
144-
}

src/main/kotlin/com/statsig/sdk/Evaluator.kt

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package com.statsig.sdk
22

33
import com.google.gson.GsonBuilder
44
import com.google.gson.ToNumberPolicy
5+
import ip3country.CountryLookup
56
import kotlinx.coroutines.CoroutineScope
67
import kotlinx.coroutines.launch
78
import ua_parser.Parser
@@ -87,9 +88,6 @@ internal class Evaluator(
8788

8889
fun shutdown() {
8990
specStore.shutdown()
90-
if (!options.disableIPResolution) {
91-
CountryLookup.cleanup()
92-
}
9391
}
9492

9593
private fun createEvaluationDetails(reason: EvaluationReason): EvaluationDetails {

0 commit comments

Comments
 (0)