From db3e858a6b95d7eb90149f33cb0ea6bf5f33e548 Mon Sep 17 00:00:00 2001 From: Mygod Date: Wed, 5 May 2021 12:37:25 -0400 Subject: [PATCH] Handle rate limits --- .../be/mygod/vpnhotspot/client/MacLookup.kt | 32 ++++++++++++------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/mobile/src/main/java/be/mygod/vpnhotspot/client/MacLookup.kt b/mobile/src/main/java/be/mygod/vpnhotspot/client/MacLookup.kt index e3802164..dc3b6791 100644 --- a/mobile/src/main/java/be/mygod/vpnhotspot/client/MacLookup.kt +++ b/mobile/src/main/java/be/mygod/vpnhotspot/client/MacLookup.kt @@ -8,16 +8,14 @@ import be.mygod.vpnhotspot.R import be.mygod.vpnhotspot.net.MacAddressCompat import be.mygod.vpnhotspot.room.AppDatabase import be.mygod.vpnhotspot.widget.SmartSnackbar -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.GlobalScope -import kotlinx.coroutines.Job -import kotlinx.coroutines.launch +import kotlinx.coroutines.* import org.json.JSONException import org.json.JSONObject import timber.log.Timber import java.io.IOException import java.net.HttpURLConnection import java.net.URL +import kotlin.math.max /** * This class generates a default nickname for new clients. @@ -30,21 +28,32 @@ object MacLookup { override fun getLocalizedMessage() = formatMessage(app) } - private val macLookupBusy = mutableMapOf>() + private data class Work(@Volatile var conn: HttpURLConnection, var job: Job? = null) + private val macLookupBusy = mutableMapOf() @MainThread - fun abort(mac: MacAddressCompat) = macLookupBusy.remove(mac)?.let { (conn, job) -> - job.cancel() - if (Build.VERSION.SDK_INT >= 26) conn.disconnect() else GlobalScope.launch(Dispatchers.IO) { conn.disconnect() } + fun abort(mac: MacAddressCompat) = macLookupBusy.remove(mac)?.let { work -> + work.job!!.cancel() + if (Build.VERSION.SDK_INT < 26) GlobalScope.launch(Dispatchers.IO) { + work.conn.disconnect() + } else work.conn.disconnect() } @MainThread fun perform(mac: MacAddressCompat, explicit: Boolean = false) { abort(mac) - val conn = URL("https://api.maclookup.app/v2/macs/${mac.toOui()}").openConnection() as HttpURLConnection - macLookupBusy[mac] = conn to GlobalScope.launch(Dispatchers.IO) { + val url = URL("https://api.maclookup.app/v2/macs/${mac.toOui()}") + val work = Work(url.openConnection() as HttpURLConnection) + work.job = GlobalScope.launch(Dispatchers.IO) { try { - val response = conn.inputStream.bufferedReader().readText() + while (work.conn.responseCode != 200) { + if (work.conn.responseCode != 429) { + throw UnexpectedError(mac, work.conn.inputStream.bufferedReader().readText()) + } + work.conn = url.openConnection() as HttpURLConnection + delay(max(1, work.conn.getHeaderField("Retry-After").toLongOrNull() ?: 1) * 1000) + } + val response = work.conn.inputStream.bufferedReader().readText() val obj = JSONObject(response) if (!obj.getBoolean("success")) throw UnexpectedError(mac, response) if (!obj.getBoolean("found")) { @@ -70,5 +79,6 @@ object MacLookup { if (explicit) SmartSnackbar.make(e).show() } } + macLookupBusy[mac] = work } }