128 lines
2.5 KiB
Go
128 lines
2.5 KiB
Go
package pkg
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"io"
|
|
"net/http"
|
|
"os"
|
|
"time"
|
|
|
|
"github.com/gofiber/fiber/v2"
|
|
"github.com/gofiber/fiber/v2/log"
|
|
)
|
|
|
|
// GetPublicIP 获取公网 IP
|
|
func GetPublicIP() (string, error) {
|
|
client := http.Client{
|
|
Timeout: 5 * time.Second,
|
|
}
|
|
|
|
// 多个备用服务,提高可用性
|
|
services := []struct {
|
|
url string
|
|
isJSON bool
|
|
parseFn func([]byte) (string, error)
|
|
}{
|
|
{
|
|
url: "https://api.ipify.org?format=json",
|
|
isJSON: true,
|
|
parseFn: func(body []byte) (string, error) {
|
|
var result map[string]string
|
|
if err := json.Unmarshal(body, &result); err != nil {
|
|
return "", err
|
|
}
|
|
if ip, ok := result["ip"]; ok {
|
|
return ip, nil
|
|
}
|
|
return "", fmt.Errorf("未找到 IP 字段")
|
|
},
|
|
},
|
|
{
|
|
url: "https://ipinfo.io/ip",
|
|
isJSON: false,
|
|
parseFn: func(body []byte) (string, error) {
|
|
return string(body), nil
|
|
},
|
|
},
|
|
{
|
|
url: "https://api.my-ip.io/ip",
|
|
isJSON: false,
|
|
parseFn: func(body []byte) (string, error) {
|
|
return string(body), nil
|
|
},
|
|
},
|
|
{
|
|
url: "https://httpbin.org/ip",
|
|
isJSON: true,
|
|
parseFn: func(body []byte) (string, error) {
|
|
var result map[string]string
|
|
if err := json.Unmarshal(body, &result); err != nil {
|
|
return "", err
|
|
}
|
|
if ip, ok := result["origin"]; ok {
|
|
return ip, nil
|
|
}
|
|
return "", fmt.Errorf("未找到 IP 字段")
|
|
},
|
|
},
|
|
}
|
|
|
|
for _, service := range services {
|
|
resp, err := client.Get(service.url)
|
|
if err != nil {
|
|
continue
|
|
}
|
|
|
|
body, err := io.ReadAll(resp.Body)
|
|
resp.Body.Close()
|
|
if err != nil {
|
|
continue
|
|
}
|
|
|
|
ip, err := service.parseFn(body)
|
|
if err == nil && ip != "" {
|
|
return ip, nil
|
|
}
|
|
}
|
|
|
|
return "", fmt.Errorf("所有服务都无法获取公网 IP")
|
|
}
|
|
|
|
func HandleResponse(c *fiber.Ctx, data interface{}) (err error) {
|
|
if os.Getenv("env") == "unit_test" {
|
|
log.Debug(data)
|
|
}
|
|
|
|
switch data.(type) {
|
|
case error:
|
|
err = data.(error)
|
|
case int, int32, int64, float32, float64, string, bool:
|
|
c.Response().SetBody([]byte(fmt.Sprintf("%s", data)))
|
|
case []byte:
|
|
c.Response().SetBody(data.([]byte))
|
|
default:
|
|
dataByte, _ := json.Marshal(data)
|
|
c.Response().SetBody(dataByte)
|
|
}
|
|
return
|
|
}
|
|
|
|
// StructToMap 将结构体转换为 map[string]any
|
|
func StructToMap(v any) (map[string]any, error) {
|
|
b, err := json.Marshal(v)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
var m map[string]any
|
|
err = json.Unmarshal(b, &m)
|
|
return m, err
|
|
}
|
|
|
|
func StructToMapWithOutErr(v any) map[string]any {
|
|
b, _ := json.Marshal(v)
|
|
var m map[string]any
|
|
_ = json.Unmarshal(b, &m)
|
|
return m
|
|
}
|