mirror of
https://github.com/Rain-kl/OpenFlare.git
synced 2026-09-28 05:46:36 +08:00
aa4faddade
Result: {"status":"keep","total_issues":8,"golint_canonicalheader":0,"golint_errname":0,"golint_errorlint":1,"golint_exhaustive":0,"golint_forcetypeassert":0,"golint_gosec":0,"golint_intrange":0,"golint_modernize":3,"golint_nilnil":3,"golint_perfsprint":0,"golint_prealloc":0,"golint_recvcheck":1,"golint_usestdlibvars":0,"golint_wastedassign":0,"golint_total":8,"golint_test_testifylint":0,"golint_test_thelper":0,"golint_test_usetesting":0,"golint_test_total":0,"golint_vetx_total":0,"eslint_problems":0,"eslint_errors":0,"eslint_warnings":0,"tsc_errors":0,"vitest_failed":0,"vitest_total":116,"measure_s":81}
96 lines
2.8 KiB
Go
96 lines
2.8 KiB
Go
// Copyright 2026 Arctel.net
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
package geoip
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
"net"
|
|
"net/http"
|
|
"time"
|
|
)
|
|
|
|
// IPAPIService resolves geographic information using the ip-api.com service.
|
|
type IPAPIService struct {
|
|
Client *http.Client
|
|
}
|
|
|
|
// ipAPIResponse 定义了 ip-api.com 服务返回的 JSON 响应的结构。
|
|
type ipAPIResponse struct {
|
|
Status string `json:"status"`
|
|
Message string `json:"message"` // 当 status 为 fail 时出现
|
|
Country string `json:"country"`
|
|
CountryCode string `json:"countryCode"`
|
|
Region string `json:"region"`
|
|
RegionName string `json:"regionName"`
|
|
City string `json:"city"`
|
|
Zip string `json:"zip"`
|
|
Lat float64 `json:"lat"`
|
|
Lon float64 `json:"lon"`
|
|
Timezone string `json:"timezone"`
|
|
ISP string `json:"isp"`
|
|
Org string `json:"org"`
|
|
As string `json:"as"`
|
|
Query string `json:"query"`
|
|
}
|
|
|
|
// Name returns the provider identifier for the ip-api.com service.
|
|
func (s *IPAPIService) Name() string {
|
|
return "ip-api.com"
|
|
}
|
|
|
|
// NewIPAPIService 创建并返回一个 IPAPIService 的新实例。
|
|
func NewIPAPIService() (*IPAPIService, error) {
|
|
return &IPAPIService{
|
|
Client: &http.Client{
|
|
Timeout: 5 * time.Second, // 设置请求超时
|
|
},
|
|
}, nil
|
|
}
|
|
|
|
// GetGeoInfo 使用 ip-api.com 服务检索给定 IP 地址的地理位置信息。
|
|
func (s *IPAPIService) GetGeoInfo(ip net.IP) (*GeoInfo, error) {
|
|
// API URL, 使用 fields 参数来仅请求需要的字段
|
|
apiURL := fmt.Sprintf("http://ip-api.com/json/%s?fields=status,message,country,countryCode", ip.String())
|
|
|
|
req, err := http.NewRequestWithContext(context.Background(), http.MethodGet, apiURL, nil)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to create request for ip-api.com: %w", err)
|
|
}
|
|
resp, err := s.Client.Do(req)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to get geo info from ip-api.com: %w", err)
|
|
}
|
|
defer func() { _ = resp.Body.Close() }()
|
|
|
|
var apiResp ipAPIResponse
|
|
if err := json.NewDecoder(resp.Body).Decode(&apiResp); err != nil {
|
|
return nil, fmt.Errorf("failed to decode ip-api.com response: %w", err)
|
|
}
|
|
|
|
if apiResp.Status != "success" {
|
|
return nil, fmt.Errorf("ip-api.com returned an error: %s", apiResp.Message)
|
|
}
|
|
|
|
return &GeoInfo{
|
|
ISOCode: apiResp.CountryCode,
|
|
Name: apiResp.Country,
|
|
Latitude: float64Pointer(apiResp.Lat),
|
|
Longitude: float64Pointer(apiResp.Lon),
|
|
}, nil
|
|
}
|
|
|
|
// UpdateDatabase 对于 ip-api.com 是一个空操作,因为它是一个 Web 服务。
|
|
func (s *IPAPIService) UpdateDatabase() error {
|
|
// 无需执行任何操作,因为数据由外部服务提供
|
|
return nil
|
|
}
|
|
|
|
// Close 对于 ip-api.com 是一个空操作,因为没有需要关闭的持久连接。
|
|
func (s *IPAPIService) Close() error {
|
|
// 无需执行任何操作
|
|
return nil
|
|
}
|