Files
jh-zz/actions/update.go

208 lines
5.5 KiB
Go
Raw Normal View History

2025-08-05 10:51:35 +08:00
package actions
import (
"fmt"
"log/slog"
"strconv"
"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 {
2025-08-05 10:51:35 +08:00
gateways, err := FindGateways(tx)
if err != nil {
return fmt.Errorf("获取所有网关失败:%w", err)
}
cities, err := FindCitiesWithEdgesCount(tx)
if err != nil {
return fmt.Errorf("获取所有城市失败:%w", err)
}
// 准备网关查找表,初始化网关配置表
type ConfigInfo struct {
Item jd.EdgeInfo
Type int // 0: 不变, 1: 更新, 2: 新增
}
var oldConfigsMap = make(map[model.Gateway]map[string]model.Config)
var newConfigs = make(map[model.Gateway][]ConfigInfo)
for _, gateway := range gateways {
newConfigs[gateway] = make([]ConfigInfo, len(cities))
oldConfigs, err := FindConfigsByGateway(tx, gateway.Macaddr)
if err != nil {
return fmt.Errorf("获取网关 %s 城市节点失败:%w", gateway.Macaddr, err)
}
oldConfigsMap[gateway] = make(map[string]model.Config)
for _, config := range oldConfigs {
oldConfigsMap[gateway][config.Cityhash] = config
}
}
// 按城市循环,对比并更新网关配置
for iCity, city := range cities {
// 如果每个网关在此城市都有节点且无需改变,就不需要重新分配节点
2025-08-05 10:51:35 +08:00
// 相当于直接重新提交配置,此流程下配置更新是幂等的
var gateways2Update []model.Gateway
for _, gateway := range gateways {
oldConfig, exists := oldConfigsMap[gateway][city.Hash]
if exists && oldConfig.IsChange != 1 {
newConfigs[gateway][iCity] = ConfigInfo{
Type: 0, // 不变
Item: jd.EdgeInfo{
Mac: oldConfig.Macaddr,
City: oldConfig.Cityhash,
},
}
} else {
gateways2Update = append(gateways2Update, gateway)
}
}
if len(gateways2Update) == 0 {
continue
}
// 否则获取足量新节点
2025-08-05 10:51:35 +08:00
offset := city.Offset
count := len(gateways2Update)
2025-08-05 10:51:35 +08:00
if count > city.EdgesCount {
slog.Warn("城市节点数量不足,跳过本次更新", "城市", city.Name, "节点数", city.EdgesCount, "网关数", count)
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("城市节点不足,将循环使用节点", "城市", 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
offset = edges[len(edges)-1].Id
2025-08-05 10:51:35 +08:00
// 更新网关配置
var configs2Create []model.Config
var configs2Update []model.ConfigUpdate
for iGateway, gateway := range gateways2Update {
oldConfig, exists := oldConfigsMap[gateway][city.Hash]
newConfig := edges[iGateway]
if exists {
slog.Debug("网关配置变更", "网关", gateway.Macaddr, "旧节点", oldConfig.Macaddr, "新节点", newConfig.Macaddr)
2025-08-05 10:51:35 +08:00
configs2Update = append(configs2Update, model.ConfigUpdate{
Id: oldConfig.Id,
Macaddr: u.P(oldConfig.Macaddr),
IsChange: u.P(0),
})
newConfigs[gateway][iCity] = ConfigInfo{
Type: 1, // 更新
Item: jd.EdgeInfo{
Mac: oldConfig.Macaddr,
City: city.Hash,
},
}
} else {
slog.Debug("网关配置新增", "网关", gateway.Macaddr, "新节点", newConfig.Macaddr)
2025-08-05 10:51:35 +08:00
configs2Create = append(configs2Create, model.Config{
Cityhash: city.Hash,
CityLabel: city.Label,
GatewayMac: gateway.Macaddr,
Macaddr: newConfig.Macaddr,
Table: strconv.Itoa(iCity + 1),
User: fmt.Sprintf("jdzz%ddt%d", iGateway+1, iCity+1),
Network: fmt.Sprintf("172.30.168.%d", iCity+2),
InnerIp: fmt.Sprintf("172.16.%d.%d", iGateway+1, iCity+2),
})
newConfigs[gateway][iCity] = ConfigInfo{
Type: 2, // 新增
Item: jd.EdgeInfo{
Mac: oldConfig.Macaddr,
City: city.Hash,
},
}
}
}
err = CreateConfigs(tx, configs2Create)
if err != nil {
return fmt.Errorf("创建新配置失败:%w", err)
}
err = UpdateConfigs(tx, configs2Update)
if err != nil {
return fmt.Errorf("更新配置失败:%w", err)
}
err = UpdateCityOffset(tx, city.Id, offset)
2025-08-05 10:51:35 +08:00
if err != nil {
return fmt.Errorf("更新城市 %s 的偏移量失败:%w", city.Name, err)
}
}
// 提交所有网关配置到云端
for gateway, infos := range newConfigs {
change := 0
setup := 0
edges := make([]jd.EdgeInfo, len(infos))
for i, info := range infos {
edges[i] = info.Item
switch info.Type {
case 1:
change++
case 2:
setup++
}
}
slog.Info("提交网关配置", "网关", gateway.Macaddr, "变更", change, "新增", setup)
2025-08-05 10:51:35 +08:00
// 提交配置到云端:配置版本 gateway.ConfigVersion
if arg.Mock {
slog.Info("[MOCK] 配置网关", "网关", gateway.Macaddr, "配置", edges)
2025-08-05 10:51:35 +08:00
} else {
err := jd.GatewayConfigSet(gateway.ConfigVersion, gateway.Macaddr, edges)
if err != nil {
return fmt.Errorf("配置网关 %s 失败:%w", gateway.Macaddr, err)
}
}
// 更新配置版本
err = AppendGatewayConfigVersion(tx, gateway.Id)
if err != nil {
return fmt.Errorf("更新网关 %s 配置版本失败:%w", gateway.Macaddr, err)
}
}
return nil
}