package router import ( "app.yhyue.com/moapp/jybase/redis" "errors" "fmt" "log" "regexp" "github.com/gogf/gf/v2/net/ghttp" "github.com/gogf/gf/v2/net/gtrace" "github.com/gogf/gf/v2/util/gconv" "jygit.jydev.jianyu360.cn/dataservice/tripartite_gateway/common/db" . "jygit.jydev.jianyu360.cn/dataservice/tripartite_gateway/common/gatecode" "jygit.jydev.jianyu360.cn/dataservice/tripartite_gateway/core/util" ) type Manager struct { eqRouters map[string]*Router regexRouter map[*regexp.Regexp]*Router } // InitRouterManager 初始化系统代理路由 // 支持完全匹配和正则匹配 func InitRouterManager() (*Manager, error) { redis.DelByCodePattern("other", "reqLimit_tripartite_*") //加载规则 res := db.GateWatMySql.SelectBySql(`SELECT * FROM front_proxy`) if res == nil { return nil, errors.New("未发现可用路由") } // 初始化 routerManager routerManager := &Manager{ eqRouters: make(map[string]*Router), regexRouter: make(map[*regexp.Regexp]*Router), } for _, row := range *res { // 获取路由信息 router := gconv.String(row["url"]) routerRule := &Router{ Id: gconv.Int(row["id"]), Status: gconv.Int(row["status"]), ReqUrl: router, TimeOut: gconv.Int64(row["timeout"]), Remark: gconv.String(row["remark"]), Server: gconv.String(row["server"]), Price: gconv.Int64(row["price"]), } routerRule.ReqLimit = &util.ReqLimit{ Size: gconv.Int(row["pool_size"]), Key: fmt.Sprintf("reqLimit_tripartite_%d", routerRule.Id), } routerRule.ReqLimit.Init() routerRule.IsFree = routerRule.Price <= 0 // 判断路由匹配方式是完全匹配还是正则匹配 (此处逻辑参考x-web框架) if regexp.QuoteMeta(router) == router { routerManager.eqRouters[router] = routerRule } else { reg, err := regexp.Compile(router) if err != nil { log.Println("路由", router, "装载异常", err) continue } routerManager.regexRouter[reg] = routerRule } } return routerManager, nil } // GetRouterRule 获取路由规则 // 根据用户请求地址匹配路由规则,优先绝对匹配后用正则匹配。 func (m *Manager) GetRouterRule(url string) (*Router, error) { routerRule, exists := m.eqRouters[url] if !exists { for reg, thisRouterRule := range m.regexRouter { if reg.MatchString(url) { routerRule = thisRouterRule break } } } if routerRule == nil || routerRule.Status != 1 { return nil, NewErrorWithCode(GLOBAL_ERR_NOTFIND) } return routerRule, nil } // InfusionContext 注入通用结构体gContext func (m *Manager) InfusionContext(r *ghttp.Request) (err error) { _, span := gtrace.NewSpan(r.Context(), "InfusionContext") defer span.End() //r.SetCtx(ctx) var router *Router var GCtx = &GContext{ RouterRule: &Router{}, } router, err = m.GetRouterRule(r.URL.Path) if err != nil { return err } appid := r.GetQuery("appid").String() res := db.GateWatMySql.SelectBySql(`SELECT b.* FROM USER a INNER JOIN user_api b ON (a.appid=? AND b.front_proxy_id=? AND a.id=b.user_id)`, appid, router.Id) if res == nil || len(*res) == 0 { return NewErrorWithCode(GLOBAL_ERR_NOPERMISSION) } router = &Router{ Id: router.Id, Status: router.Status, ReqUrl: router.ReqUrl, TimeOut: router.TimeOut, Price: router.Price, Remark: router.Remark, Server: router.Server, ReqLimit: router.ReqLimit, IsFree: router.IsFree, } if price := gconv.Int64((*res)[0]["price"]); price >= 0 { router.Price = price } rl := &util.ReqLimit{ Size: gconv.Int((*res)[0]["pool_size"]), Key: fmt.Sprintf("reqLimit_tripartite_%d_%d", router.Id, gconv.Int((*res)[0]["user_id"])), } sizeKey := router.ReqLimit.Key + "_size" if rl.Size > 0 { router.ReqLimit = rl //数据库中调整了某个用户的某个接口并发数,重新初始化 if redis.GetInt("other", sizeKey) != router.ReqLimit.Size { redis.PutCKV("other", sizeKey, router.ReqLimit.Size) router.ReqLimit.Clear() router.ReqLimit.Init() } } else { redis.Del("other", sizeKey) rl.Clear() } GCtx.RouterRule = router //获取session /*jySess, _ := InitJySessionContext(r) GCtx.Sess = jySess*/ r.SetCtxVar(GContextKey, GCtx) return }