4 Commits

4 changed files with 158 additions and 12 deletions

View File

@@ -7,6 +7,7 @@ import (
"fmt" "fmt"
"regexp" "regexp"
"strings" "strings"
"sync"
"time" "time"
"gitea.com/red-future/common/beans" "gitea.com/red-future/common/beans"
@@ -28,8 +29,29 @@ import (
var ( var (
localCache *gcache.Cache localCache *gcache.Cache
snowflakeNode *snowflake.Node
snowflakeOnce sync.Once
) )
func init() {
ctx := context.Background()
snowflakeOnce.Do(func() {
nodeId := genv.Get("APP_NODE", 1).Int64()
// 安全范围 0~1023
if nodeId < 0 || nodeId > 1023 {
nodeId = 1
}
node, err := snowflake.NewNode(nodeId)
if err != nil {
g.Log().Errorf(ctx, "snowflake init failed: %v", err)
return
}
snowflakeNode = node
})
}
// getLocalCache 获取本地缓存实例 // getLocalCache 获取本地缓存实例
func getLocalCache() *gcache.Cache { func getLocalCache() *gcache.Cache {
if localCache == nil { if localCache == nil {
@@ -165,18 +187,13 @@ func insertHook(ctx context.Context, in *gdb.HookInsertInput) (result sql.Result
return nil, err return nil, err
} }
nodeId := genv.Get("APP_NODE", "").Int64() if g.IsEmpty(snowflakeNode) {
if g.IsEmpty(nodeId) { return nil, fmt.Errorf("snowflakeNode is nil")
nodeId = 1
} }
node, err := snowflake.NewNode(nodeId)
if err != nil {
return nil, err
}
for i := range in.Data { for i := range in.Data {
if _, ok := in.Data[i]["id"]; ok { 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 _, ok := in.Data[i]["tenant_id"]; ok {
if g.IsEmpty(in.Data[i]["tenant_id"]) { if g.IsEmpty(in.Data[i]["tenant_id"]) {

3
go.mod
View File

@@ -1,5 +1,4 @@
module gitea.com/red-future/common module common
go 1.26.0 go 1.26.0
require ( require (

View File

@@ -92,7 +92,7 @@ func UserLimiter(r *ghttp.Request) {
var userName string var userName string
user, err := utils.GetUserInfo(r.GetCtx()) user, err := utils.GetUserInfo(r.GetCtx())
if err != nil { if err != nil {
r.Response.WriteStatusExit(429, err.Error()) r.Response.WriteStatusExit(401, err.Error())
return return
} }
userName = gconv.String(user.UserName) userName = gconv.String(user.UserName)

View File

@@ -460,3 +460,133 @@ func IsLocalIP(ip string) bool {
} }
return false 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
}