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
pull/1232/head
neolegshishov 2026-04-13 11:16:57 +03:00 committed by GitHub
parent cdd85b659c
commit c8a1fd8e4b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
1 changed files with 30 additions and 17 deletions

View File

@ -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():