go_dreamfactory/lego/sys/rpcx/selector.go
2023-05-25 18:49:16 +08:00

181 lines
4.8 KiB
Go

package rpcx
import (
"context"
"go_dreamfactory/lego/sys/log"
"regexp"
"strings"
"sync"
"github.com/smallnest/rpcx/share"
"github.com/valyala/fastrand"
)
var rex_nogather = regexp.MustCompile(`\!\[([^)]+)\]`)
var rex_noid = regexp.MustCompile(`\!([^)]+)`)
var rex_gather = regexp.MustCompile(`\[([^)]+)\]`)
func newSelector(log log.ILogger, stag string, fn func(map[string]*ServiceNode)) *Selector {
return &Selector{
log: log,
stag: stag,
updateServerEvent: fn,
servers: make(map[string]*ServiceNode),
serversType: make(map[string][]*ServiceNode),
i: make(map[string]int),
}
}
type ServiceNode struct {
ServiceTag string `json:"stag"` //服务集群标签
ServiceId string `json:"sid"` //服务id
ServiceType string `json:"stype"` //服务类型
Version string `json:"version"` //服务版本
ServiceAddr string `json:"addr"` //服务地址
}
type Selector struct {
log log.ILogger
stag string
updateServerEvent func(map[string]*ServiceNode)
servers map[string]*ServiceNode
serversType map[string][]*ServiceNode
lock sync.Mutex
i map[string]int
}
///servicePath = (worker)/(worker/worker_1)/(worker/!worker_1)/(worker/[worker_1,worker_2])/(worker/![worker_1,worker_2])
func (this *Selector) Select(ctx context.Context, servicePath, serviceMethod string, args interface{}) string {
routrules := ctx.Value(share.ReqMetaDataKey).(map[string]string)[CallRoutRulesKey]
service := strings.Split(routrules, "/")
leng := len(service)
if leng == 1 {
if nodes, ok := this.serversType[service[0]]; ok {
i, ok := this.i[service[0]]
if !ok {
i = 0
}
i = i % len(nodes)
this.lock.Lock()
this.i[service[0]] = i + 1
this.lock.Unlock()
return nodes[i].ServiceAddr
}
} else if leng == 2 {
result := this.ParseRoutRules(service[1])
if len(result) == 0 {
this.log.Error("Select no found any node",
log.Field{Key: "stag", Value: this.stag},
log.Field{Key: "servicePath", Value: servicePath},
log.Field{Key: "serviceMethod", Value: serviceMethod},
log.Field{Key: "routrules", Value: routrules},
)
return ""
}
i := fastrand.Uint32n(uint32(len(result)))
if node, ok := this.servers[result[i]]; ok {
return node.ServiceAddr
}
}
// this.log.Error("Select no found any node", log.Field{"stag", this.stag}, log.Field{"servicePath", servicePath}, log.Field{"serviceMethod", serviceMethod}, log.Field{"routrules", routrules})
return ""
}
//找到同类型节点信息
func (this *Selector) Find(ctx context.Context, servicePath, serviceMethod string, args interface{}) []string {
if nodes, ok := this.serversType[servicePath]; ok {
addrs := make([]string, len(nodes))
for i, v := range nodes {
addrs[i] = v.ServiceAddr
}
return addrs
}
return nil
}
//更新服务列表
func (this *Selector) UpdateServer(servers map[string]string) {
ss := make(map[string]*ServiceNode)
sst := make(map[string][]*ServiceNode)
for _, v := range servers {
if node, err := smetaToServiceNode(v); err != nil {
this.log.Errorf("smetaToServiceNode:%s err:%v", v, err)
continue
} else {
ss[node.ServiceId] = node
if ssts, ok := sst[node.ServiceType]; !ok {
sst[node.ServiceType] = make([]*ServiceNode, 0)
sst[node.ServiceType] = append(sst[node.ServiceType], node)
} else {
ssts = append(ssts, node)
}
}
}
this.servers = ss
this.serversType = sst
if this.updateServerEvent != nil {
go this.updateServerEvent(ss)
}
}
//路由规则解析
func (this *Selector) ParseRoutRules(rules string) (result []string) {
result = make([]string, 0)
//解析 ![sid,sid] 格式规则
if out := rex_nogather.FindAllStringSubmatch(rules, -1); len(out) == 1 && len(out[0]) == 2 {
if nogather := strings.Split(out[0][1], ","); len(nogather) > 0 {
for k, _ := range this.servers {
iskeep := false
for _, v := range nogather {
if k == v {
iskeep = true
break
}
}
if !iskeep {
result = append(result, k)
}
}
return
}
}
//解析 !sid 格式规则
if out := rex_noid.FindAllStringSubmatch(rules, -1); len(out) == 1 && len(out[0]) == 2 {
for k, _ := range this.servers {
iskeep := false
if k == out[0][1] {
iskeep = true
break
}
if !iskeep {
result = append(result, k)
}
}
return
}
//解析 [sid,sid] 格式规则
if out := rex_gather.FindAllStringSubmatch(rules, -1); len(out) == 1 && len(out[0]) == 2 {
if nogather := strings.Split(out[0][1], ","); len(nogather) > 0 {
for k, _ := range this.servers {
iskeep := false
for _, v := range nogather {
if k == v {
iskeep = true
break
}
}
if iskeep {
result = append(result, k)
}
}
return
}
}
if _, ok := this.servers[rules]; ok {
result = append(result, rules)
}
return
}