@@ -3,6 +3,7 @@ package http
33import (
44 "encoding/json"
55 "fmt"
6+ "io"
67 "log"
78 "net"
89 "net/http"
6768 }
6869)
6970
71+ const geoLite2URL = "https://codeberg.org/Vo/GOWebServer-Depedencies/raw/branch/main/GeoLite2-City.mmdb"
72+
73+ // @note progress writer for tracking download progress
74+ type progressWriter struct {
75+ total int64
76+ downloaded int64
77+ startTime time.Time
78+ lastUpdate time.Time
79+ }
80+
81+ func (pw * progressWriter ) Write (p []byte ) (int , error ) {
82+ n := len (p )
83+ pw .downloaded += int64 (n )
84+
85+ now := time .Now ()
86+ if now .Sub (pw .lastUpdate ) >= 500 * time .Millisecond || pw .downloaded == pw .total {
87+ elapsed := now .Sub (pw .startTime ).Seconds ()
88+ speed := float64 (pw .downloaded ) / elapsed / 1024 / 1024
89+ progress := float64 (pw .downloaded ) / float64 (pw .total ) * 100
90+
91+ downloadedMB := float64 (pw .downloaded ) / 1024 / 1024
92+ totalMB := float64 (pw .total ) / 1024 / 1024
93+
94+ logger .Infof ("Downloading: %.2f/%.2f MB (%.1f%%) - %.2f MB/s" ,
95+ downloadedMB , totalMB , progress , speed )
96+
97+ pw .lastUpdate = now
98+ }
99+
100+ return n , nil
101+ }
102+
103+ // @note download GeoLite2 database from remote repository
104+ func downloadGeoLite2DB (filepath string ) error {
105+ dir := "mmdb/GOWebServer-Depedencies"
106+ if err := os .MkdirAll (dir , 0755 ); err != nil {
107+ return fmt .Errorf ("failed to create directory: %w" , err )
108+ }
109+
110+ client := & http.Client {
111+ Timeout : 120 * time .Second ,
112+ }
113+
114+ resp , err := client .Get (geoLite2URL )
115+ if err != nil {
116+ return fmt .Errorf ("failed to download: %w" , err )
117+ }
118+ defer resp .Body .Close ()
119+
120+ if resp .StatusCode != http .StatusOK {
121+ return fmt .Errorf ("download failed with status: %d" , resp .StatusCode )
122+ }
123+
124+ out , err := os .Create (filepath )
125+ if err != nil {
126+ return fmt .Errorf ("failed to create file: %w" , err )
127+ }
128+ defer out .Close ()
129+
130+ pw := & progressWriter {
131+ total : resp .ContentLength ,
132+ startTime : time .Now (),
133+ lastUpdate : time .Now (),
134+ }
135+
136+ writer := io .MultiWriter (out , pw )
137+
138+ if _ , err := io .Copy (writer , resp .Body ); err != nil {
139+ return fmt .Errorf ("failed to write file: %w" , err )
140+ }
141+
142+ return nil
143+ }
144+
70145type IPAPIResponse struct {
71146 Query string `json:"query"`
72147 Status string `json:"status"`
@@ -291,10 +366,27 @@ func Initialize() *fiber.App {
291366 var err error
292367
293368 if config .EnableGeo {
294- if db , err = geoip2 .Open ("mmdb/GOWebServer-Depedencies/GeoLite2-City.mmdb" ); err != nil {
295- logger .Error ("Failed to open GeoLite2-City.mmdb: " , err )
296- logger .Error ("Did you use --recursive when cloning? See README.md" )
297- config .EnableGeo = false
369+ mmdbPath := "mmdb/GOWebServer-Depedencies/GeoLite2-City.mmdb"
370+
371+ if _ , err := os .Stat (mmdbPath ); os .IsNotExist (err ) {
372+ logger .Info ("GeoLite2-City.mmdb not found, attempting to download..." )
373+ if err := downloadGeoLite2DB (mmdbPath ); err != nil {
374+ logger .Error ("Failed to download GeoLite2-City.mmdb: " , err )
375+ logger .Info ("Geo Location will be disabled" )
376+ config .EnableGeo = false
377+ } else {
378+ logger .Info ("GeoLite2-City.mmdb downloaded successfully" )
379+ }
380+ }
381+
382+ if config .EnableGeo {
383+ if db , err = geoip2 .Open (mmdbPath ); err != nil {
384+ logger .Error ("Failed to open GeoLite2-City.mmdb: " , err )
385+ logger .Info ("Deleting corrupted database file..." )
386+ os .Remove (mmdbPath )
387+ logger .Info ("Geo Location will be disabled" )
388+ config .EnableGeo = false
389+ }
298390 }
299391 }
300392
0 commit comments