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}
93 lines
2.6 KiB
Go
93 lines
2.6 KiB
Go
// Copyright 2026 Arctel.net
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
package geoip
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
"net"
|
|
"net/http"
|
|
"time"
|
|
)
|
|
|
|
// GeoJSService resolves geographic information using the geojs.io service.
|
|
type GeoJSService struct {
|
|
Client *http.Client
|
|
}
|
|
|
|
// geoJSResponse 定义了 geojs.io 服务返回的 JSON 响应的结构。
|
|
// 我们只定义我们需要的字段。
|
|
type geoJSResponse struct {
|
|
Country string `json:"country"`
|
|
CountryCode string `json:"country_code"`
|
|
Latitude float64 `json:"latitude,string"`
|
|
Longitude float64 `json:"longitude,string"`
|
|
// 可以根据需要添加其他字段,例如:
|
|
// City string `json:"city"`
|
|
// Region string `json:"region"`
|
|
}
|
|
|
|
// NewGeoJSService 创建并返回一个 GeoJSService 的新实例。
|
|
func NewGeoJSService() (*GeoJSService, error) {
|
|
return &GeoJSService{
|
|
Client: &http.Client{
|
|
Timeout: 5 * time.Second, // 设置一个合理的超时时间
|
|
},
|
|
}, nil
|
|
}
|
|
|
|
// Name 返回服务的名称。
|
|
func (s *GeoJSService) Name() string {
|
|
return "geojs.io"
|
|
}
|
|
|
|
// GetGeoInfo 使用 geojs.io 服务检索给定 IP 地址的地理位置信息。
|
|
func (s *GeoJSService) GetGeoInfo(ip net.IP) (*GeoInfo, error) {
|
|
// GeoJS 的 API 端点
|
|
apiURL := fmt.Sprintf("https://get.geojs.io/v1/ip/geo/%s.json", ip.String())
|
|
|
|
req, err := http.NewRequestWithContext(context.Background(), http.MethodGet, apiURL, nil)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to create request for geojs.io: %w", err)
|
|
}
|
|
resp, err := s.Client.Do(req)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to get geo info from geojs.io: %w", err)
|
|
}
|
|
defer func() { _ = resp.Body.Close() }()
|
|
|
|
// 检查响应状态码
|
|
if resp.StatusCode != http.StatusOK {
|
|
return nil, fmt.Errorf("geojs.io returned non-200 status code: %d", resp.StatusCode)
|
|
}
|
|
|
|
var apiResp geoJSResponse
|
|
if err := json.NewDecoder(resp.Body).Decode(&apiResp); err != nil {
|
|
return nil, fmt.Errorf("failed to decode geojs.io response: %w", err)
|
|
}
|
|
|
|
// 检查国家代码是否为空,因为 geojs 对无效/私有IP可能返回200 OK但内容为空
|
|
if apiResp.CountryCode == "" {
|
|
return nil, fmt.Errorf("geojs.io returned empty geo info for ip: %s", ip.String())
|
|
}
|
|
|
|
return &GeoInfo{
|
|
ISOCode: apiResp.CountryCode,
|
|
Name: apiResp.Country,
|
|
Latitude: float64Pointer(apiResp.Latitude),
|
|
Longitude: float64Pointer(apiResp.Longitude),
|
|
}, nil
|
|
}
|
|
|
|
// UpdateDatabase 对于 geojs.io 是一个空操作,因为它是一个 Web 服务。
|
|
func (s *GeoJSService) UpdateDatabase() error {
|
|
return nil
|
|
}
|
|
|
|
// Close 对于 geojs.io 是一个空操作。
|
|
func (s *GeoJSService) Close() error {
|
|
return nil
|
|
}
|