Skip to content

Commit 799c23b

Browse files
committed
Update.
1 parent 1f73d16 commit 799c23b

3 files changed

Lines changed: 99 additions & 18 deletions

File tree

model/config.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,9 @@ type Config struct {
9999
DatabaseType string // 数据库类型,可选:sqlite、badger
100100
DatabaseLocation string // 数据库文件路径
101101

102+
// GeoIP 配置
103+
GeoIPDB string `yaml:"geoipdb" koanf:"geoipdb"` // 自定义 GeoIP 数据库路径(MMDB 格式),留空则使用内嵌数据库
104+
102105
k *koanf.Koanf
103106
filePath string
104107
}

pkg/geoip/geoip.go

Lines changed: 89 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"fmt"
66
"log"
77
"net"
8+
"os"
89
"strings"
910
"sync"
1011

@@ -14,11 +15,7 @@ import (
1415
//go:embed geoip.db
1516
var geoDBFS embed.FS
1617

17-
var (
18-
dbData []byte
19-
err error
20-
)
21-
18+
// IPInfo 表示 IP 地理位置信息
2219
type IPInfo struct {
2320
Country string `maxminddb:"country"`
2421
CountryName string `maxminddb:"country_name"`
@@ -28,30 +25,104 @@ type IPInfo struct {
2825

2926
var (
3027
db *maxminddb.Reader
28+
dbMu sync.RWMutex
3129
dbOnce sync.Once
30+
dbPath string // 当前加载的外部数据库路径
3231
)
3332

34-
func init() {
35-
dbData, err = geoDBFS.ReadFile("geoip.db")
36-
if err != nil {
37-
log.Printf("NG>> Failed to open geoip database: %v", err)
33+
// Init 初始化 GeoIP 数据库
34+
// 如果 path 不为空,优先从外部文件加载;否则使用内嵌数据库
35+
func Init(path string) error {
36+
dbMu.Lock()
37+
defer dbMu.Unlock()
38+
39+
// 关闭旧的数据库
40+
if db != nil {
41+
db.Close()
42+
db = nil
3843
}
39-
}
4044

41-
// initDB 初始化GeoIP数据库,只执行一次
42-
func initDB() {
43-
if dbData != nil {
44-
var err error
45-
db, err = maxminddb.FromBytes(dbData)
45+
// 尝试从外部 MMDB 文件加载
46+
if path != "" {
47+
reader, err := loadFromFile(path)
4648
if err != nil {
47-
log.Printf("NG>> Failed to initialize geoip database: %v", err)
49+
log.Printf("NG>> 无法加载外部 GeoIP 数据库 %s: %v,回退到内嵌数据库", path, err)
50+
} else {
51+
db = reader
52+
dbPath = path
53+
log.Printf("NG>> 已加载外部 GeoIP 数据库: %s", path)
54+
return nil
4855
}
4956
}
57+
58+
// 回退到内嵌数据库
59+
reader, err := loadEmbedded()
60+
if err != nil {
61+
return fmt.Errorf("无法加载内嵌 GeoIP 数据库: %w", err)
62+
}
63+
db = reader
64+
dbPath = ""
65+
log.Printf("NG>> 已加载内嵌 GeoIP 数据库")
66+
return nil
67+
}
68+
69+
// Reload 重新加载 GeoIP 数据库(用于配置热更新)
70+
func Reload(path string) error {
71+
return Init(path)
72+
}
73+
74+
// loadFromFile 从外部 MMDB 文件加载数据库
75+
func loadFromFile(path string) (*maxminddb.Reader, error) {
76+
if _, err := os.Stat(path); err != nil {
77+
return nil, fmt.Errorf("文件不存在: %w", err)
78+
}
79+
reader, err := maxminddb.Open(path)
80+
if err != nil {
81+
return nil, fmt.Errorf("打开 MMDB 文件失败: %w", err)
82+
}
83+
return reader, nil
84+
}
85+
86+
// loadEmbedded 从内嵌资源加载数据库
87+
func loadEmbedded() (*maxminddb.Reader, error) {
88+
data, err := geoDBFS.ReadFile("geoip.db")
89+
if err != nil {
90+
return nil, fmt.Errorf("读取内嵌数据失败: %w", err)
91+
}
92+
reader, err := maxminddb.FromBytes(data)
93+
if err != nil {
94+
return nil, fmt.Errorf("解析内嵌数据失败: %w", err)
95+
}
96+
return reader, nil
97+
}
98+
99+
// ensureInit 确保数据库已初始化(兼容未显式调用 Init 的场景)
100+
func ensureInit() {
101+
dbOnce.Do(func() {
102+
dbMu.RLock()
103+
initialized := db != nil
104+
dbMu.RUnlock()
105+
if !initialized {
106+
if err := Init(""); err != nil {
107+
log.Printf("NG>> GeoIP 自动初始化失败: %v", err)
108+
}
109+
}
110+
})
50111
}
51112

113+
// GetDBPath 返回当前加载的数据库路径,空字符串表示使用内嵌数据库
114+
func GetDBPath() string {
115+
dbMu.RLock()
116+
defer dbMu.RUnlock()
117+
return dbPath
118+
}
119+
120+
// Lookup 查询 IP 对应的国家/地区代码
52121
func Lookup(ip net.IP, record *IPInfo) (string, error) {
53-
// 确保数据库只初始化一次
54-
dbOnce.Do(initDB)
122+
ensureInit()
123+
124+
dbMu.RLock()
125+
defer dbMu.RUnlock()
55126

56127
if db == nil {
57128
return "", fmt.Errorf("geoip database not available")

service/singleton/singleton.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import (
2222

2323
"github.com/xos/serverstatus/db"
2424
"github.com/xos/serverstatus/model"
25+
"github.com/xos/serverstatus/pkg/geoip"
2526
"github.com/xos/serverstatus/pkg/utils"
2627
)
2728

@@ -238,6 +239,12 @@ func LoadSingleton() {
238239
}
239240
}()
240241

242+
// 初始化 GeoIP 数据库
243+
log.Println("正在初始化 GeoIP 数据库...")
244+
if err := geoip.Init(Conf.GeoIPDB); err != nil {
245+
log.Printf("GeoIP 数据库初始化失败: %v", err)
246+
}
247+
241248
// 加载通知服务
242249
log.Println("正在加载通知服务...")
243250
func() {

0 commit comments

Comments
 (0)