Files
jh-zz/actions/update.go

222 lines
5.6 KiB
Go
Raw Normal View History

2025-08-05 10:51:35 +08:00
package actions
import (
"fmt"
"log/slog"
"time"
2025-08-05 10:51:35 +08:00
"zzman/clients/jd"
"zzman/model"
u "zzman/util"
"gorm.io/gorm"
2025-08-05 10:51:35 +08:00
)
type UpdateArgs struct {
Mock bool
}
func Update(args ...UpdateArgs) error {
2025-08-05 10:51:35 +08:00
var arg UpdateArgs
if len(args) > 0 {
arg = args[0]
} else {
arg.Mock = false
}
return model.DB.Transaction(func(tx *gorm.DB) error {
return update(tx, arg)
})
}
func update(tx *gorm.DB, arg UpdateArgs) error {
var now = time.Now()
2025-09-10 18:26:59 +08:00
var step = now
2025-09-10 18:26:59 +08:00
// 获取所有网关
2025-08-05 10:51:35 +08:00
gateways, err := FindGateways(tx)
if err != nil {
return fmt.Errorf("获取所有网关失败:%w", err)
}
2025-09-10 18:26:59 +08:00
var findGateway = make(map[string]model.Gateway)
for _, gateway := range gateways {
findGateway[gateway.Macaddr] = gateway
}
println(fmt.Sprintf("获取网关:%v", time.Since(step)))
step = time.Now()
2025-08-05 10:51:35 +08:00
2025-09-10 18:26:59 +08:00
// 获取所有城市
2025-08-05 10:51:35 +08:00
cities, err := FindCitiesWithEdgesCount(tx)
if err != nil {
return fmt.Errorf("获取所有城市失败:%w", err)
}
2025-09-10 18:26:59 +08:00
var findCity = make(map[string]model.City)
for _, city := range cities {
findCity[city.Hash] = city
2025-08-05 10:51:35 +08:00
}
2025-09-10 18:26:59 +08:00
println(fmt.Sprintf("获取城市:%v", time.Since(step)))
step = time.Now()
2025-08-05 10:51:35 +08:00
2025-09-10 18:26:59 +08:00
// 获取所有配置
configs, err := FindConfigs(tx)
if err != nil {
return fmt.Errorf("获取所有配置失败:%w", err)
}
var findConfig = make(map[string]model.Config)
for _, config := range configs {
findConfig[config.Cityhash+":"+config.GatewayMac] = config
2025-08-05 10:51:35 +08:00
}
2025-09-10 18:26:59 +08:00
println(fmt.Sprintf("获取配置:%v", time.Since(step)))
step = time.Now()
// 更新网关配置
var newConfigs = make(map[model.Gateway][]ConfigInfo)
var changes []model.Change
for _, city := range cities {
2025-08-05 10:51:35 +08:00
2025-09-10 18:26:59 +08:00
// 先处理不变更的节点
configsUpdate := make([]model.Config, 0)
2025-08-05 10:51:35 +08:00
for _, gateway := range gateways {
2025-09-10 18:26:59 +08:00
oldConfig, exists := findConfig[city.Hash+":"+gateway.Macaddr]
2025-08-05 10:51:35 +08:00
if exists && oldConfig.IsChange != 1 {
2025-09-10 18:26:59 +08:00
newConfigs[gateway] = append(newConfigs[gateway], ConfigInfo{
Change: false,
Remote: jd.EdgeInfo{
2025-08-05 10:51:35 +08:00
Mac: oldConfig.Macaddr,
City: oldConfig.Cityhash,
},
2025-09-10 18:26:59 +08:00
})
2025-08-05 10:51:35 +08:00
} else {
2025-09-10 18:26:59 +08:00
configsUpdate = append(configsUpdate, oldConfig)
2025-08-05 10:51:35 +08:00
}
}
2025-09-10 18:26:59 +08:00
count := len(configsUpdate)
if len(configsUpdate) == 0 {
2025-08-05 10:51:35 +08:00
continue
}
2025-09-10 18:26:59 +08:00
// 如果有需要变更的节点,获取足量新节点
2025-08-05 10:51:35 +08:00
offset := city.Offset
if count > city.EdgesCount {
slog.Warn(fmt.Sprintf("城市节点数量不足,跳过本次更新,城市:%s节点数%d网关数%d", city.Name, city.EdgesCount, count))
2025-08-05 10:51:35 +08:00
continue
}
edges, err := SliceActiveEdges(tx, city.Id, offset, count)
2025-08-05 10:51:35 +08:00
if err != nil {
return fmt.Errorf("查询城市 %s 可用节点失败:%w", city.Name, err)
}
if len(edges) < count {
slog.Debug(fmt.Sprintf("城市节点不足,将循环使用节点,城市:%s节点数%d网关数%d", city.Name, city.EdgesCount, count))
edges, err = SliceActiveEdges(tx, city.Id, 0, count)
if err != nil {
return fmt.Errorf("查询城市 %s 可用节点失败:%w", city.Name, err)
}
}
2025-08-05 10:51:35 +08:00
2025-09-10 18:26:59 +08:00
city.Offset = edges[len(edges)-1].Id
2025-08-05 10:51:35 +08:00
2025-09-10 18:26:59 +08:00
// 分配新节点
for i, oldConfig := range configsUpdate {
2025-08-05 10:51:35 +08:00
2025-09-10 18:26:59 +08:00
gateway := findGateway[oldConfig.GatewayMac]
edge := edges[i]
2025-08-05 10:51:35 +08:00
2025-09-10 18:26:59 +08:00
slog.Debug(fmt.Sprintf("网关配置变更,网关:%s旧节点%s新节点%s", gateway.Macaddr, oldConfig.Macaddr, edge.Macaddr))
2025-08-05 10:51:35 +08:00
2025-09-10 18:26:59 +08:00
newConfigs[gateway] = append(newConfigs[gateway], ConfigInfo{
Change: true,
Remote: jd.EdgeInfo{
City: city.Hash,
Mac: edge.Macaddr,
},
Config: model.ConfigUpdate{
2025-08-05 10:51:35 +08:00
Id: oldConfig.Id,
2025-09-10 18:26:59 +08:00
Macaddr: u.P(edge.Macaddr),
2025-08-05 10:51:35 +08:00
IsChange: u.P(0),
2025-09-10 18:26:59 +08:00
IsOnline: u.P(1),
},
})
changes = append(changes, model.Change{
Time: now,
CityId: city.Id,
Gateway: gateway.Macaddr,
OldEdge: oldConfig.Macaddr,
NewEdge: edge.Macaddr,
})
}
}
2025-09-10 18:26:59 +08:00
println(fmt.Sprintf("循环分配:%v", time.Since(step)))
step = time.Now()
2025-08-05 10:51:35 +08:00
2025-09-10 18:26:59 +08:00
// 更新城市偏移量
err = UpdateCitiesOffset(tx, cities)
if err != nil {
return fmt.Errorf("更新城市偏移量失败:%w", err)
}
2025-09-10 18:26:59 +08:00
println(fmt.Sprintf("更新城市偏移量:%v", time.Since(step)))
step = time.Now()
2025-08-05 10:51:35 +08:00
2025-09-10 18:26:59 +08:00
// 记录节点变更
err = RecordChanges(tx, changes)
if err != nil {
return fmt.Errorf("记录节点变更失败:%w", err)
2025-08-05 10:51:35 +08:00
}
2025-09-10 18:26:59 +08:00
println(fmt.Sprintf("记录节点变更:%v", time.Since(step)))
step = time.Now()
2025-08-05 10:51:35 +08:00
// 提交所有网关配置到云端
for gateway, infos := range newConfigs {
edges := make([]jd.EdgeInfo, len(infos))
2025-09-10 18:26:59 +08:00
configsUpdate := make([]model.ConfigUpdate, 0)
// 统计变更数
change := 0
2025-08-05 10:51:35 +08:00
for i, info := range infos {
2025-09-10 18:26:59 +08:00
edges[i] = info.Remote
if info.Change {
configsUpdate = append(configsUpdate, info.Config)
2025-08-05 10:51:35 +08:00
change++
}
}
2025-09-10 18:26:59 +08:00
slog.Info(fmt.Sprintf("提交网关配置,网关:%s变更数%d", gateway.Macaddr, change))
// 更新配置版本
err = AppendGatewayConfigVersion(tx, gateway.Id)
if err != nil {
return fmt.Errorf("更新网关 %s 配置版本失败:%w", gateway.Macaddr, err)
}
// 更新本地配置
err = UpdateConfigs(tx, configsUpdate)
if err != nil {
return fmt.Errorf("更新网关 %s 本地配置失败:%w", gateway.Macaddr, err)
}
2025-08-05 10:51:35 +08:00
// 提交配置到云端:配置版本 gateway.ConfigVersion
2025-08-19 17:25:01 +08:00
if !arg.Mock {
2025-08-05 10:51:35 +08:00
err := jd.GatewayConfigSet(gateway.ConfigVersion, gateway.Macaddr, edges)
if err != nil {
return fmt.Errorf("配置网关 %s 失败:%w", gateway.Macaddr, err)
}
}
}
2025-09-10 18:26:59 +08:00
println(fmt.Sprintf("提交配置:%v", time.Since(step)))
println(fmt.Sprintf("总耗时:%v", time.Since(now)))
2025-08-05 10:51:35 +08:00
return nil
}
2025-09-10 18:26:59 +08:00
type ConfigInfo struct {
Change bool
Remote jd.EdgeInfo
Config model.ConfigUpdate
}