From c8a1fd8e4bd708a2140e188d5820185757518c0c Mon Sep 17 00:00:00 2001 From: neolegshishov <143963760+neolegshishov@users.noreply.github.com> Date: Mon, 13 Apr 2026 11:16:57 +0300 Subject: [PATCH] Fix: batch IP geolocation requests (limit 100), add deduplication and caching - Added batching of IP addresses into chunks of 100 to comply with ip-api limits - Implemented deduplication to avoid repeated geolocation requests for identical IPs - Added in-memory cache to reuse results across batches - Preserved original order and length of geolocation list in API response - Improved error handling around external API failures --- src/dashboard.py | 47 ++++++++++++++++++++++++++++++----------------- 1 file changed, 30 insertions(+), 17 deletions(-) diff --git a/src/dashboard.py b/src/dashboard.py index e4d4eefb..8679db36 100644 --- a/src/dashboard.py +++ b/src/dashboard.py @@ -1075,23 +1075,36 @@ def API_GetPeerHistoricalEndpoints(): if not configurationName or not id: return ResponseObject(False, "Please provide configurationName and id") fp, p = WireguardConfigurations.get(configurationName).searchPeer(id) - if fp: - result = p.getEndpoints() - geo = {} - try: - r = requests.post(f"http://ip-api.com/batch?fields=city,country,lat,lon,query", - data=json.dumps([x['endpoint'] for x in result])) - d = r.json() - - - except Exception as e: - return ResponseObject(data=result, message="Failed to request IP address geolocation. " + str(e)) - - return ResponseObject(data={ - "endpoints": p.getEndpoints(), - "geolocation": d - }) - return ResponseObject(False, "Peer does not exist") + if not fp: + return ResponseObject(False, "Peer does not exist") + endpoints = p.getEndpoints() + ips = [x['endpoint'] for x in endpoints] + unique_ips = list(set(ips)) + def chunks(lst, size=100): + for i in range(0, len(lst), size): + yield lst[i:i + size] + geo_cache = {} + try: + for batch in chunks(unique_ips, 100): + r = requests.post( + "http://ip-api.com/batch?fields=city,country,lat,lon,query", + data=json.dumps(batch), + timeout=5 + ) + r.raise_for_status() + data = r.json() + for item in data: + geo_cache[item["query"]] = item + geolocation = [geo_cache[ip] for ip in ips] + except Exception as e: + return ResponseObject( + data={"endpoints": endpoints}, + message="Failed to request IP address geolocation. " + str(e) + ) + return ResponseObject(data={ + "endpoints": endpoints, + "geolocation": geolocation + }) @app.get(f'{APP_PREFIX}/api/getPeerSessions') def API_GetPeerSessions():