From 0e5ce63dc8c57dd673783f8e6bd86548c89296bc Mon Sep 17 00:00:00 2001 From: CarterPerez-dev Date: Sun, 17 May 2026 05:24:29 -0400 Subject: [PATCH] feat(canary): wire geoip into main with NopService fallback openGeoIP opens cfg.GeoIP.Path and returns a (Lookuper, closer) pair; on open failure (missing/unreadable mmdb) it returns geoip.NopService() and a no-op closer so the rest of the wire-up sees a consistent non-nil interface and the binary stays healthy in environments without a MaxMind license. buildEventStack now accepts a geoip.Lookuper and threads it into event.ServiceConfig. Close is deferred in run() so the mmdb file handle releases on graceful shutdown; a close-error is logged at warn (not fatal). --- .../backend/cmd/canary/main.go | 26 ++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/PROJECTS/beginner/canary-token-generator/backend/cmd/canary/main.go b/PROJECTS/beginner/canary-token-generator/backend/cmd/canary/main.go index 1cfa7a99..86be94f3 100644 --- a/PROJECTS/beginner/canary-token-generator/backend/cmd/canary/main.go +++ b/PROJECTS/beginner/canary-token-generator/backend/cmd/canary/main.go @@ -23,6 +23,7 @@ import ( "github.com/CarterPerez-dev/cybersecurity-projects/canary-token-generator/backend/internal/config" "github.com/CarterPerez-dev/cybersecurity-projects/canary-token-generator/backend/internal/core" "github.com/CarterPerez-dev/cybersecurity-projects/canary-token-generator/backend/internal/event" + "github.com/CarterPerez-dev/cybersecurity-projects/canary-token-generator/backend/internal/geoip" "github.com/CarterPerez-dev/cybersecurity-projects/canary-token-generator/backend/internal/health" "github.com/CarterPerez-dev/cybersecurity-projects/canary-token-generator/backend/internal/middleware" "github.com/CarterPerez-dev/cybersecurity-projects/canary-token-generator/backend/internal/notify" @@ -92,8 +93,11 @@ func run(configPath string) error { } logger.Info("redis connected") + geo, geoCloser := openGeoIP(cfg, logger) + defer geoCloser() + notifySvc, eventSvc := buildEventStack( - cfg, logger, eventRepo, tokenRepo, rdb, + cfg, logger, eventRepo, tokenRepo, rdb, geo, ) tokenSvc, verifier, healthH, tokenH := buildHTTPDeps( cfg, logger, db, rdb, eventRepo, tokenRepo, eventSvc, @@ -169,6 +173,7 @@ func buildEventStack( eventRepo *event.Repository, tokenRepo *token.Repository, rdb *core.Redis, + geo geoip.Lookuper, ) (*notify.Service, *event.Service) { tgSender := telegram.NewSender(telegram.Config{ APIBase: cfg.Notify.TelegramAPIBase, @@ -199,11 +204,30 @@ func buildEventStack( event.ServiceConfig{ DedupTTL: cfg.Notify.DedupTTL, Logger: logger, + GeoIP: geo, }, ) return notifySvc, eventSvc } +func openGeoIP( + cfg *config.Config, + logger *slog.Logger, +) (geoip.Lookuper, func()) { + svc, err := geoip.Open(cfg.GeoIP.Path) + if err != nil { + logger.Warn("geoip unavailable, enrichment disabled", + "path", cfg.GeoIP.Path, "error", err) + return geoip.NopService(), func() {} + } + logger.Info("geoip opened", "path", cfg.GeoIP.Path) + return svc, func() { + if cErr := svc.Close(); cErr != nil { + logger.Warn("geoip close error", "error", cErr) + } + } +} + func spawnMySQLListener( ctx context.Context, cfg *config.Config,