From 91359f61ac1af4a7e8885184e275a02ea426e4d0 Mon Sep 17 00:00:00 2001 From: qhd <1766646056@qq.com> Date: Tue, 2 Jun 2026 19:52:07 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E4=BC=98=E5=8C=96=E9=9B=AA=E8=8A=B1ID?= =?UTF-8?q?=E7=94=9F=E6=88=90=E5=8F=8A=E6=B7=BB=E5=8A=A0=E6=9C=AC=E5=9C=B0?= =?UTF-8?q?=E5=9C=B0=E5=9D=80=E5=B7=A5=E5=85=B7=E5=87=BD=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- db/gfdb/gfdb.go | 23 +++++---- utils/utils.go | 130 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 144 insertions(+), 9 deletions(-) diff --git a/db/gfdb/gfdb.go b/db/gfdb/gfdb.go index 72508a6..b7f23e6 100644 --- a/db/gfdb/gfdb.go +++ b/db/gfdb/gfdb.go @@ -27,7 +27,8 @@ import ( // ==================== 缓存管理器(单例) ==================== var ( - localCache *gcache.Cache + localCache *gcache.Cache + snowflakeNode *snowflake.Node ) // getLocalCache 获取本地缓存实例 @@ -165,18 +166,22 @@ func insertHook(ctx context.Context, in *gdb.HookInsertInput) (result sql.Result return nil, err } - nodeId := genv.Get("APP_NODE", "").Int64() - if g.IsEmpty(nodeId) { - nodeId = 1 + // 懒加载初始化全局snowflake节点,只创建一次 + if snowflakeNode == nil { + nodeId := genv.Get("APP_NODE", "").Int64() + if g.IsEmpty(nodeId) { + nodeId = 1 + } + node, err := snowflake.NewNode(nodeId) + if err != nil { + return nil, err + } + snowflakeNode = node } - node, err := snowflake.NewNode(nodeId) - if err != nil { - return nil, err - } for i := range in.Data { if _, ok := in.Data[i]["id"]; ok { - in.Data[i]["id"] = node.Generate().Int64() + in.Data[i]["id"] = snowflakeNode.Generate().Int64() } if _, ok := in.Data[i]["tenant_id"]; ok { if g.IsEmpty(in.Data[i]["tenant_id"]) { diff --git a/utils/utils.go b/utils/utils.go index 32a75ba..87463cc 100644 --- a/utils/utils.go +++ b/utils/utils.go @@ -460,3 +460,133 @@ func IsLocalIP(ip string) bool { } return false } + +// GetLocalIP 获取本机有效的局域网 IPv4 地址 +func GetLocalIP() string { + addrs, err := net.InterfaceAddrs() + if err != nil { + return "127.0.0.1" + } + + var validIPs []string + + for _, addr := range addrs { + ipnet, ok := addr.(*net.IPNet) + if !ok { + continue + } + + ip := ipnet.IP + + if isIPValid(ip) { + validIPs = append(validIPs, ip.String()) + } + } + + // 优先返回非 169.254.x.x 的 IP + for _, ip := range validIPs { + if !strings.HasPrefix(ip, "169.254.") { + return ip + } + } + + // 其次返回 169.254.x.x(最后的选择) + if len(validIPs) > 0 { + return validIPs[0] + } + + return "127.0.0.1" +} + +// isIPValid 判断 IP 是否有效 +func isIPValid(ip net.IP) bool { + // 不是 loopback (127.0.0.1) + if ip.IsLoopback() { + return false + } + + // 是 IPv4 + if ip.To4() == nil { + return false + } + + // 不是链路本地地址 (169.254.0.0/16) + if ip[0] == 169 && ip[1] == 254 { + return false + } + + // 不是组播地址 + if ip.IsMulticast() { + return false + } + + // 不是未指定地址 (0.0.0.0) + if ip.IsUnspecified() { + return false + } + + return true +} + +func GetServerPort(ctx context.Context) string { + address := g.Cfg().MustGet(ctx, "server.address", ":8080").String() + // address 格式如 ":3009",去掉冒号 + if strings.HasPrefix(address, ":") { + return address[1:] + } + return "8080" +} + +// GetLocalAddress 获取局域网地址(IP:端口) +func GetLocalAddress(ctx context.Context) string { + ip := GetLocalIP() + port := GetServerPort(ctx) + + if port == "80" || port == "443" { + return ip + } + return ip + ":" + port +} + +// GetSchemaFromRequest 从当前请求中获取协议(http/https) +func GetSchemaFromRequest(ctx context.Context) string { + r := g.RequestFromCtx(ctx) + if r == nil { + return "http" + } + + // 1. 代理场景:X-Forwarded-Proto + if proto := r.Header.Get("X-Forwarded-Proto"); proto != "" { + return proto + } + + // 2. 代理场景:X-Forwarded-Scheme + if proto := r.Header.Get("X-Forwarded-Scheme"); proto != "" { + return proto + } + + // 3. TLS 连接(直接 HTTPS) + if r.TLS != nil { + return "https" + } + + // 4. 默认 HTTP(这行很重要!) + return "http" // ← 确保有这行 +} + +// GetLocalBaseURL 获取局域网基础 URL(动态协议 + IP + 端口) +func GetLocalBaseURL(ctx context.Context) string { + schema := GetSchemaFromRequest(ctx) + addr := GetLocalAddress(ctx) + return schema + "://" + addr +} + +// GetCallbackURL 获取回调地址(完整 URL) +func GetCallbackURL(ctx context.Context, path string) string { + baseURL := GetLocalBaseURL(ctx) + // 确保 path 以 / 开头 + if !strings.HasPrefix(path, "/") { + path = "/" + path + } + return baseURL + path +}