diff --git a/docker-compose.yml b/docker-compose.yml index 831c8f9..acfc5c0 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -2,10 +2,11 @@ services: ip-info: build: . ports: - - "8080:8080" + - "28080:8080" restart: always volumes: - ./data:/app/data environment: + - GIN_MODE=release - GIN_TRUSTED_PROXY_IP=127.0.0.1 - TZ=Asia/Ho_Chi_Minh \ No newline at end of file diff --git a/internal/data/ipdb.go b/internal/data/ipdb.go index 1a63327..0742d5a 100644 --- a/internal/data/ipdb.go +++ b/internal/data/ipdb.go @@ -8,7 +8,8 @@ import ( import reader "github.com/oschwald/maxminddb-golang" type IpDb struct { - r *reader.Reader + r *reader.Reader + mu sync.RWMutex } var ( @@ -25,6 +26,9 @@ func Ins() *IpDb { } func (d *IpDb) Reload() error { + d.mu.Lock() + defer d.mu.Unlock() + if d.r != nil { _ = d.r.Close() } @@ -37,3 +41,7 @@ func (d *IpDb) Reload() error { d.r = r return nil } + +func (d *IpDb) IsLoaded() bool { + return d.r != nil +} diff --git a/internal/services/api/handler_json.go b/internal/services/api/handler_json.go index 9d4053e..8d976eb 100644 --- a/internal/services/api/handler_json.go +++ b/internal/services/api/handler_json.go @@ -9,6 +9,12 @@ import ( func HandleJson(c *gin.Context) { ip := c.ClientIP() + if !data.Ins().IsLoaded() { + log.Error().Msg("DB is not loaded") + c.String(http.StatusInternalServerError, "Try again later") + return + } + ipData, _, err := data.Ins().Query(ip) if err != nil { log.Err(err).Msg("Failed to query IP") @@ -17,6 +23,8 @@ func HandleJson(c *gin.Context) { }) return } + ipData["ip"] = ip c.JSON(http.StatusOK, ipData) + } diff --git a/internal/services/db_updater/downloader.go b/internal/services/db_updater/downloader.go index a2b04a7..e14b31c 100644 --- a/internal/services/db_updater/downloader.go +++ b/internal/services/db_updater/downloader.go @@ -4,12 +4,11 @@ import ( "github.com/go-resty/resty/v2" "github.com/rs/zerolog/log" "net/http" + "os" "path" "thuanle.me/ip-info/configs" ) -var etags = map[string]string{} - func download(url string) bool { log.Info().Str("url", url).Msg("Downloading DB") filename := configs.GeoDbFolder + path.Base(url) @@ -17,7 +16,7 @@ func download(url string) bool { client := resty.New() resp, err := client.R(). SetOutput(filename). - SetHeader("If-None-Match", etags[url]). + SetHeader("If-None-Match", readETag(filename)). Get(url) if err != nil { @@ -28,15 +27,31 @@ func download(url string) bool { } if resp.StatusCode() == http.StatusOK { - etags[url] = resp.Header().Get("Etag") + writeETag(filename, resp.Header().Get("Etag")) } else { //log.Printf("No update needed: %v", resp.Status()) return false } log.Info(). - Str("Etag", etags[url]). Str("filename", filename). Msg("Downloaded DB") return true } + +// readETag reads the ETag from the file +func readETag(baseFile string) string { + data, err := os.ReadFile(baseFile + ".etag") + if err != nil { + return "" + } + return string(data) +} + +// writeETag writes the ETag to the file +func writeETag(baseFile, etag string) { + err := os.WriteFile(baseFile+".etag", []byte(etag), 0644) + if err != nil { + log.Err(err).Msg("Failed to write ETag") + } +}