-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathgeolocate.py
More file actions
102 lines (84 loc) · 2.88 KB
/
Copy pathgeolocate.py
File metadata and controls
102 lines (84 loc) · 2.88 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
#!/usr/bin/env python3
"""
Add lat/lon to peers.json by geolocating IPs via ip-api.com batch API.
Free tier: 15 req/min for single, but batch endpoint handles 100 IPs per request.
"""
import json
import time
import urllib.request
from pathlib import Path
PEERS_PATH = Path(__file__).parent / "static" / "data" / "peers.json"
BATCH_URL = "http://ip-api.com/batch"
BATCH_SIZE = 100 # max per request
RATE_LIMIT_PAUSE = 1.5 # seconds between batch requests
def geolocate_batch(ips: list[str]) -> dict[str, dict]:
"""Send batch of IPs to ip-api.com, return {ip: {lat, lon, country, city, isp}}."""
payload = json.dumps([
{"query": ip, "fields": "query,status,lat,lon,country,city,isp,as"}
for ip in ips
]).encode()
req = urllib.request.Request(
BATCH_URL,
data=payload,
headers={"Content-Type": "application/json"},
)
try:
with urllib.request.urlopen(req, timeout=10) as resp:
results = json.loads(resp.read())
except Exception as e:
print(f" Batch request failed: {e}")
return {}
out = {}
for r in results:
if r.get("status") == "success":
out[r["query"]] = {
"lat": r["lat"],
"lon": r["lon"],
"country": r.get("country", ""),
"city": r.get("city", ""),
"isp": r.get("isp", ""),
"as": r.get("as", ""),
}
return out
def main():
print("Loading peers.json...")
with open(PEERS_PATH) as f:
peers = json.load(f)
# Collect unique IPs
ip_to_peers = {}
for pubkey, p in peers.items():
ip = p.get("ip")
if ip:
ip_to_peers.setdefault(ip, []).append(pubkey)
unique_ips = list(ip_to_peers.keys())
print(f" {len(unique_ips)} unique IPs to geolocate")
# Batch geolocate
geo_cache = {}
batches = [unique_ips[i:i + BATCH_SIZE] for i in range(0, len(unique_ips), BATCH_SIZE)]
for i, batch in enumerate(batches):
print(f" Batch {i + 1}/{len(batches)} ({len(batch)} IPs)...")
results = geolocate_batch(batch)
geo_cache.update(results)
if i < len(batches) - 1:
time.sleep(RATE_LIMIT_PAUSE)
print(f" Geolocated {len(geo_cache)}/{len(unique_ips)} IPs")
# Enrich peers
enriched = 0
for pubkey, p in peers.items():
ip = p.get("ip")
if ip and ip in geo_cache:
geo = geo_cache[ip]
p["lat"] = geo["lat"]
p["lon"] = geo["lon"]
p["country"] = geo["country"]
p["city"] = geo["city"]
p["isp"] = geo["isp"]
p["as_info"] = geo["as"]
enriched += 1
print(f" Enriched {enriched} peers with geolocation")
# Write back
with open(PEERS_PATH, "w") as f:
json.dump(peers, f)
print(f" Written to {PEERS_PATH}")
if __name__ == "__main__":
main()