Add best-effort geolocation to the IP lookup from geojs and DB-IP City Lite (closes #239)
check / check (push) Successful in 3m58s

Each result gains `geo`. One request to geojs carries every address, 1 second in all. On a timeout, an error or an answer with no country, city or coordinates, the lookup reads DB-IP City Lite, downloaded monthly into the state directory. geojs answers stay in memory (250,000, least recently used dropped) and in a new `cache.db` table for 7 days.

Judgement call: a reserved address goes to neither source, and its `geo` is null.
Judgement call: `updated` for DB-IP is when the copy was downloaded.
Deviation: the cache is SQLite, by sneak's words.

Model: opus-5-5
This commit is contained in:
sneak committed 2026-11-10 13:38:19 +00:00
1 parent b2553f044d
commit c8ae355787
16 files changed
+2372 -22

No files matched your search

+2
View File
@@ -544,6 +544,8 @@
<span>{{appLicense}}</span>
<span class="separator">|</span>
<span><a href="{{appGitCommitURL}}">{{appGitRevision}}</a></span>
<span class="separator">|</span>
<span>IP Geolocation by <a href="https://db-ip.com">DB-IP</a></span>
</footer>
<script nonce="{{.CSPNonce}}">
+17
View File
@@ -67,6 +67,23 @@ func TestFooterLicense(t *testing.T) {
}
}
// TestHomePageCreditsDBIP expects the home page's footer to carry the credit
// to DB-IP.
func TestHomePageCreditsDBIP(t *testing.T) {
t.Parallel()
const attribution = `IP Geolocation by <a href="https://db-ip.com">DB-IP</a>`
_, footer, found := strings.Cut(renderPage(t, templates.IndexTemplate()), "<footer")
if !found {
t.Fatal("the page has no footer")
}
if !strings.Contains(footer, attribution) {
t.Errorf("footer does not credit DB-IP: %q", footer)
}
}
// TestFreshnessIndicator renders the home and status pages and expects each to
// have, right after the status element, the element where the page's script
// shows its spinner or "stale".