557 lines
14 KiB
Go
557 lines
14 KiB
Go
package service
|
||
|
||
import (
|
||
"context"
|
||
"fmt"
|
||
"time"
|
||
|
||
"go-common/app/admin/main/aegis/model"
|
||
"go-common/app/admin/main/aegis/model/net"
|
||
"go-common/library/ecode"
|
||
"go-common/library/log"
|
||
)
|
||
|
||
//ShowDirection .
|
||
func (s *Service) ShowDirection(c context.Context, id int64) (r *net.ShowDirectionResult, err error) {
|
||
var (
|
||
d *net.Direction
|
||
f *net.Flow
|
||
t *net.Transition
|
||
)
|
||
|
||
if d, err = s.gorm.DirectionByID(c, id); err != nil {
|
||
return
|
||
}
|
||
if f, err = s.gorm.FlowByID(c, d.FlowID); err != nil {
|
||
return
|
||
}
|
||
if t, err = s.gorm.TransitionByID(c, d.TransitionID); err != nil {
|
||
return
|
||
}
|
||
r = &net.ShowDirectionResult{
|
||
Direction: d,
|
||
FlowName: f.ChName,
|
||
TransitionName: t.ChName,
|
||
}
|
||
return
|
||
}
|
||
|
||
//GetDirectionList .
|
||
func (s *Service) GetDirectionList(c context.Context, pm *net.ListDirectionParam) (result *net.ListDirectionRes, err error) {
|
||
var (
|
||
n *net.Net
|
||
flows map[int64]string
|
||
trans map[int64]string
|
||
unames map[int64]string
|
||
fids = []int64{}
|
||
tids = []int64{}
|
||
uid = []int64{}
|
||
)
|
||
if n, err = s.gorm.NetByID(c, pm.NetID); err != nil {
|
||
return
|
||
}
|
||
if result, err = s.gorm.DirectionList(c, pm); err != nil {
|
||
return
|
||
}
|
||
if len(result.Result) == 0 {
|
||
return
|
||
}
|
||
for _, item := range result.Result {
|
||
fids = append(fids, item.FlowID)
|
||
tids = append(tids, item.TransitionID)
|
||
uid = append(uid, item.UID)
|
||
}
|
||
if flows, err = s.gorm.ColumnMapString(c, net.TableFlow, "ch_name", fids, ""); err != nil {
|
||
return
|
||
}
|
||
if trans, err = s.gorm.ColumnMapString(c, net.TableTransition, "ch_name", tids, ""); err != nil {
|
||
return
|
||
}
|
||
if unames, err = s.http.GetUnames(c, uid); err != nil {
|
||
log.Error("GetDirectionList s.http.GetUnames error(%v)", err)
|
||
err = nil
|
||
}
|
||
|
||
for _, item := range result.Result {
|
||
item.NetName = n.ChName
|
||
item.FlowName = flows[item.FlowID]
|
||
item.TransitionName = trans[item.TransitionID]
|
||
item.UserName = unames[item.UID]
|
||
}
|
||
return
|
||
}
|
||
|
||
//SwitchDirection .
|
||
func (s *Service) SwitchDirection(c context.Context, id int64, needDisable bool) (err error, msg string) {
|
||
var (
|
||
old *net.Direction
|
||
action string
|
||
canUpdate bool
|
||
)
|
||
if old, err = s.gorm.DirectionByID(c, id); err != nil {
|
||
log.Error("SwitchDirection s.gorm.DirectionByID(%d) error(%v) needDisable(%v)", id, err, needDisable)
|
||
return
|
||
}
|
||
available := old.IsAvailable()
|
||
if available == !needDisable {
|
||
return
|
||
}
|
||
|
||
if canUpdate, err = s.beforeUpdate(c, old.NetID); err != nil {
|
||
log.Error("SwitchDirection s.beforeUpdate error(%v)", err)
|
||
return
|
||
}
|
||
if !canUpdate {
|
||
log.Error("SwitchDirection can't update id(%d) needdisable(%v)", id, needDisable)
|
||
return
|
||
}
|
||
|
||
if needDisable {
|
||
old.DisableTime = time.Now()
|
||
action = model.LogNetActionDisable
|
||
} else {
|
||
if err = s.checkDirectionBindAvailable(c, old.FlowID, old.TransitionID); err != nil {
|
||
log.Error("SwitchDirection s.checkDirectionBindAvailable(%+v) error(%v) needDisable(%v)", old, err, needDisable)
|
||
return
|
||
}
|
||
if err, msg = s.checkDirConflict(c, old); err != nil {
|
||
log.Error("SwitchDirection s.checkDirConflict(%+v) error(%v) needDisable(%v)", old, err, needDisable)
|
||
return
|
||
}
|
||
old.DisableTime = net.Recovered
|
||
action = model.LogNetActionAvailable
|
||
}
|
||
|
||
tx, err := s.gorm.BeginTx(c)
|
||
if err != nil {
|
||
log.Error("SwitchDirection s.gorm.BeginTx error(%v)", err)
|
||
return
|
||
}
|
||
if err = s.gorm.DisableNet(c, tx, old.NetID); err != nil {
|
||
tx.Rollback()
|
||
return
|
||
}
|
||
if err = s.gorm.UpdateFields(c, tx, net.TableDirection, id, map[string]interface{}{"disable_time": old.DisableTime}); err != nil {
|
||
tx.Rollback()
|
||
return
|
||
}
|
||
if err = tx.Commit().Error; err != nil {
|
||
log.Error("SwitchDirection tx.Commit error(%v)", err)
|
||
return
|
||
}
|
||
s.delDirCache(c, old)
|
||
|
||
//日志
|
||
oper := &model.NetConfOper{
|
||
OID: old.ID,
|
||
Action: action,
|
||
UID: old.UID,
|
||
NetID: old.NetID,
|
||
FlowID: old.FlowID,
|
||
TranID: old.TransitionID,
|
||
}
|
||
s.sendNetConfLog(c, model.LogTypeDirConf, oper)
|
||
return
|
||
}
|
||
|
||
func (s *Service) checkDirectionUnique(c context.Context, netID int64, FlowID int64, transitionID int64, direction int8) (err error, msg string) {
|
||
var exist *net.Direction
|
||
if exist, err = s.gorm.DirectionByUnique(c, netID, FlowID, transitionID, direction); err != nil {
|
||
return
|
||
}
|
||
if exist != nil {
|
||
err = ecode.AegisUniqueAlreadyExist
|
||
msg = fmt.Sprintf(ecode.AegisUniqueAlreadyExist.Message(), "有向线", "")
|
||
}
|
||
return
|
||
}
|
||
|
||
func (s *Service) checkDirectionBindAvailable(c context.Context, flowID, transitionID int64) (err error) {
|
||
var (
|
||
f *net.Flow
|
||
t *net.Transition
|
||
)
|
||
|
||
if flowID > 0 {
|
||
if f, err = s.gorm.FlowByID(c, flowID); err != nil {
|
||
return
|
||
}
|
||
if !f.IsAvailable() {
|
||
err = ecode.AegisFlowDisabled
|
||
return
|
||
|
||
}
|
||
}
|
||
|
||
if transitionID > 0 {
|
||
if t, err = s.gorm.TransitionByID(c, transitionID); err != nil {
|
||
return
|
||
}
|
||
if !t.IsAvailable() {
|
||
err = ecode.AegisTranDisabled
|
||
return
|
||
}
|
||
}
|
||
|
||
return
|
||
}
|
||
|
||
/**
|
||
* 不同order兼容性不同:
|
||
* order=顺序,flow<->tran一对一
|
||
* order=todo
|
||
*/
|
||
func (s *Service) checkDirConflict(c context.Context, d *net.Direction) (err error, msg string) {
|
||
var (
|
||
flowDir, tranDir []*net.Direction
|
||
orderDes, conflictDes string
|
||
)
|
||
if d == nil {
|
||
return
|
||
}
|
||
if flowDir, err = s.gorm.DirectionByFlowID(c, []int64{d.FlowID}, d.Direction); err != nil {
|
||
log.Error("checkDirConflict s.gorm.DirectionByFlowID error(%v) direction(%+v)", err, d)
|
||
return
|
||
}
|
||
flowDirLen := len(flowDir)
|
||
for k, item := range flowDir {
|
||
if item.ID != d.ID {
|
||
continue
|
||
}
|
||
if k < flowDirLen-1 {
|
||
flowDir = append(flowDir[:k], flowDir[k+1:]...)
|
||
} else {
|
||
flowDir = flowDir[:k]
|
||
}
|
||
flowDirLen--
|
||
}
|
||
|
||
if tranDir, err = s.gorm.DirectionByTransitionID(c, []int64{d.TransitionID}, d.Direction, true); err != nil {
|
||
log.Error("checkDirConflict s.gorm.DirectionByTransitionID error(%v) direction(%+v)", err, d)
|
||
return
|
||
}
|
||
tranDirLen := len(tranDir)
|
||
for k, item := range tranDir {
|
||
if item.ID != d.ID {
|
||
continue
|
||
}
|
||
if k < tranDirLen-1 {
|
||
tranDir = append(tranDir[:k], tranDir[k+1:]...)
|
||
} else {
|
||
tranDir = tranDir[:k]
|
||
}
|
||
tranDirLen--
|
||
}
|
||
//无任何已有线
|
||
if flowDirLen == 0 && tranDirLen == 0 {
|
||
return
|
||
}
|
||
|
||
if d.Order == net.DirOrderSequence {
|
||
conflictDes = "节点或变迁已被绑定"
|
||
} else {
|
||
//不支持的顺序报错
|
||
log.Error("checkDirConflict order(%d) is not supported! direction(%+v)", d.Order, d)
|
||
err = ecode.RequestErr
|
||
return
|
||
}
|
||
|
||
//顺序兼容性报错
|
||
log.Error("checkDirConflict direction(%+v) not allowed!", d)
|
||
err = ecode.AegisDirOrderConflict
|
||
orderDes = net.DirOrderDesc[d.Order]
|
||
msg = fmt.Sprintf(ecode.AegisDirOrderConflict.Message(), orderDes, conflictDes)
|
||
return
|
||
}
|
||
|
||
//AddDirection .
|
||
func (s *Service) AddDirection(c context.Context, uid int64, d *net.DirEditParam) (id int64, err error, msg string) {
|
||
var (
|
||
canUpdate bool
|
||
)
|
||
if canUpdate, err = s.beforeUpdate(c, d.NetID); err != nil {
|
||
log.Error("AddDirection s.beforeUpdate error(%v)", err)
|
||
return
|
||
}
|
||
if !canUpdate {
|
||
log.Error("AddDirection can't update param(%+v)", d)
|
||
return
|
||
}
|
||
if err, msg = s.checkDirectionUnique(c, d.NetID, d.FlowID, d.TransitionID, d.Direction); err != nil {
|
||
return
|
||
}
|
||
if err = s.checkDirectionBindAvailable(c, d.FlowID, d.TransitionID); err != nil {
|
||
return
|
||
}
|
||
dir := &net.Direction{
|
||
NetID: d.NetID,
|
||
FlowID: d.FlowID,
|
||
TransitionID: d.TransitionID,
|
||
Direction: d.Direction,
|
||
Order: d.Order,
|
||
Guard: d.Guard,
|
||
Output: d.Output,
|
||
UID: uid,
|
||
}
|
||
if err, msg = s.checkDirConflict(c, dir); err != nil {
|
||
return
|
||
}
|
||
|
||
tx, err := s.gorm.BeginTx(c)
|
||
if err != nil {
|
||
log.Error("AddDirection s.gorm.BeginTx error(%v)", err)
|
||
return
|
||
}
|
||
if err = s.gorm.DisableNet(c, tx, dir.NetID); err != nil {
|
||
tx.Rollback()
|
||
return
|
||
}
|
||
if err = s.gorm.AddItem(c, tx, dir); err != nil {
|
||
tx.Rollback()
|
||
return
|
||
}
|
||
if err = tx.Commit().Error; err != nil {
|
||
log.Error("AddDirection tx.Commit error(%v)", err)
|
||
return
|
||
}
|
||
id = d.ID
|
||
|
||
//日志
|
||
oper := &model.NetConfOper{
|
||
OID: dir.ID,
|
||
Action: model.LogNetActionNew,
|
||
UID: dir.UID,
|
||
NetID: dir.NetID,
|
||
FlowID: dir.FlowID,
|
||
TranID: dir.TransitionID,
|
||
Diff: []string{
|
||
model.LogFieldTemp(model.LogFieldDirection, net.DirDirectionDesc[dir.Direction], "", false),
|
||
model.LogFieldTemp(model.LogFieldOrder, net.DirOrderDesc[dir.Order], "", false),
|
||
model.LogFieldTemp(model.LogFieldGuard, dir.Guard, "", false),
|
||
model.LogFieldTemp(model.LogFieldOutput, dir.Output, "", false),
|
||
},
|
||
}
|
||
s.sendNetConfLog(c, model.LogTypeDirConf, oper)
|
||
return
|
||
}
|
||
|
||
//UpdateDirection .
|
||
func (s *Service) UpdateDirection(c context.Context, uid int64, d *net.DirEditParam) (err error, msg string) {
|
||
var (
|
||
old *net.Direction
|
||
canUpdate, checkUnique, orderChanged bool
|
||
updates = map[string]interface{}{}
|
||
diff = []string{}
|
||
)
|
||
if old, err = s.gorm.DirectionByID(c, d.ID); err != nil {
|
||
log.Error("UpdateDirection s.gorm.DirectionByID(%d) error(%v)", d.ID, err)
|
||
return
|
||
}
|
||
if canUpdate, err = s.beforeUpdate(c, old.NetID); err != nil {
|
||
log.Error("UpdateDirection s.beforeUpdate error(%v)", err)
|
||
return
|
||
}
|
||
if !canUpdate {
|
||
log.Error("UpdateDirection can't update param(%+v)", d)
|
||
return
|
||
}
|
||
|
||
cp := *old
|
||
nw := &cp
|
||
if d.FlowID != old.FlowID {
|
||
if err = s.checkDirectionBindAvailable(c, d.FlowID, 0); err != nil {
|
||
return
|
||
}
|
||
checkUnique = true
|
||
nw.FlowID = d.FlowID
|
||
updates["flow_id"] = d.FlowID
|
||
}
|
||
if d.TransitionID != old.TransitionID {
|
||
if err = s.checkDirectionBindAvailable(c, 0, d.TransitionID); err != nil {
|
||
return
|
||
}
|
||
checkUnique = true
|
||
nw.TransitionID = d.TransitionID
|
||
updates["transition_id"] = d.TransitionID
|
||
}
|
||
if d.Direction != old.Direction {
|
||
checkUnique = true
|
||
diff = append(diff, model.LogFieldTemp(model.LogFieldDirection, net.DirDirectionDesc[nw.Direction], net.DirDirectionDesc[old.Direction], true))
|
||
nw.Direction = d.Direction
|
||
updates["direction"] = d.Direction
|
||
}
|
||
if checkUnique {
|
||
if err, msg = s.checkDirectionUnique(c, nw.NetID, nw.FlowID, nw.TransitionID, nw.Direction); err != nil {
|
||
return
|
||
}
|
||
}
|
||
if d.Order != old.Order {
|
||
diff = append(diff, model.LogFieldTemp(model.LogFieldOrder, net.DirOrderDesc[nw.Order], net.DirOrderDesc[old.Order], true))
|
||
nw.Order = d.Order
|
||
updates["order"] = d.Order
|
||
orderChanged = true
|
||
}
|
||
//todo-- guard,output
|
||
if checkUnique || orderChanged {
|
||
if err, msg = s.checkDirConflict(c, nw); err != nil {
|
||
return
|
||
}
|
||
}
|
||
if len(updates) <= 0 {
|
||
return
|
||
}
|
||
|
||
tx, err := s.gorm.BeginTx(c)
|
||
if err != nil {
|
||
log.Error("UpdateDirection s.gorm.BeginTx error(%v)", err)
|
||
return
|
||
}
|
||
if err = s.gorm.DisableNet(c, tx, old.NetID); err != nil {
|
||
tx.Rollback()
|
||
return
|
||
}
|
||
if err = s.gorm.UpdateFields(c, tx, net.TableDirection, old.ID, updates); err != nil {
|
||
tx.Rollback()
|
||
return
|
||
}
|
||
if err = tx.Commit().Error; err != nil {
|
||
log.Error("UpdateDirection tx.Commit error(%v)", err)
|
||
return
|
||
}
|
||
s.delDirCache(c, old)
|
||
|
||
//日志
|
||
oper := &model.NetConfOper{
|
||
OID: nw.ID,
|
||
Action: model.LogNetActionUpdate,
|
||
UID: nw.UID,
|
||
NetID: nw.NetID,
|
||
FlowID: nw.FlowID,
|
||
TranID: nw.TransitionID,
|
||
Diff: diff,
|
||
}
|
||
s.sendNetConfLog(c, model.LogTypeDirConf, oper)
|
||
return
|
||
}
|
||
|
||
/**
|
||
* isDirEnable 检查到下一步的可能性,由order&guard决定
|
||
*/
|
||
func (s *Service) isDirEnable(dir *net.Direction) (enable bool) {
|
||
if dir == nil {
|
||
return
|
||
}
|
||
if (dir.Order != net.DirOrderOrSplit && dir.Order != net.DirOrderOrResultSplit) ||
|
||
(dir.Order == net.DirOrderOrResultSplit && dir.Guard == "") {
|
||
enable = true
|
||
return
|
||
}
|
||
|
||
//todo--compute guard expression-v2
|
||
|
||
return
|
||
}
|
||
|
||
/**
|
||
* dispatchDirs 方向线是否可达下一步
|
||
* 加入资源维度:若资源没有任何可达性如何办,这是配置错误--后期加入动态检查
|
||
*/
|
||
func (s *Service) dispatchDirs(dirs []*net.Direction) (enableDir []*net.Direction) {
|
||
var (
|
||
enable bool
|
||
)
|
||
|
||
//对每个有向线, 过滤所有资源, 区分哪些资源可达
|
||
enableDir = []*net.Direction{}
|
||
for _, dir := range dirs {
|
||
enable = s.isDirEnable(dir)
|
||
if enable {
|
||
enableDir = append(enableDir, dir)
|
||
continue
|
||
}
|
||
}
|
||
|
||
return
|
||
}
|
||
|
||
/**
|
||
* fetchFlowNextEnableDirs 从flow出发,找到下一步变迁
|
||
* 后期加入资源维度:若资源没有任何可达性如何办,这是配置错误--后期加入动态检查
|
||
* 被应用在:
|
||
* 1. 新节点查看下一步变迁是否需要创建分发任务;
|
||
* 2. 审核提交后,通过flowid找到被触发的是哪个变迁(必须是同一个---后期加入动态检查);
|
||
* 3. 通过flowid获取可用变迁的操作项;
|
||
* todo -- 任务方存储了transitionid后,可以移除2+3逻辑
|
||
*/
|
||
func (s *Service) fetchFlowNextEnableDirs(c context.Context, flowID int64) (enableDir []*net.Direction, err error) {
|
||
var (
|
||
list []*net.Direction
|
||
)
|
||
|
||
//找到以flow为起点的所有方向线
|
||
if list, err = s.dirByFlow(c, []int64{flowID}, net.DirInput); err != nil {
|
||
log.Error("fetchFlowNextEnableDirs s.dirByFlow(%d) error(%v)", flowID, err)
|
||
return
|
||
}
|
||
if len(list) == 0 { //没配置下一步,正常情况
|
||
return
|
||
}
|
||
|
||
if enableDir = s.dispatchDirs(list); len(enableDir) == 0 {
|
||
err = ecode.AegisFlowNoEnableTran
|
||
log.Error("fetchFlowNextEnableDirs s.dispatchDirs flowid(%v) no enable transition", flowID)
|
||
}
|
||
return
|
||
}
|
||
|
||
/**
|
||
* fetchTranNextEnableDirs 从变迁出发,找到下一步flow
|
||
* 后期加入资源维度
|
||
*/
|
||
func (s *Service) fetchTranNextEnableDirs(c context.Context, tranID int64) (resultDir *net.Direction, err error) {
|
||
var (
|
||
list []*net.Direction
|
||
enableDir []*net.Direction
|
||
)
|
||
if list, err = s.dirByTran(c, []int64{tranID}, net.DirOutput, true); err != nil {
|
||
log.Error("fetchTranNextEnableDirs s.dirByTran(%d) error(%v)", tranID, err)
|
||
return
|
||
}
|
||
if len(list) == 0 { //变迁后面没配置flow,为配置错误--后期都需要添加动态检查
|
||
err = ecode.AegisTranNoFlow
|
||
log.Error("fetchTranNextEnableDirs s.gorm.DirectionByTransitionID(%d) no flow", tranID)
|
||
return
|
||
}
|
||
|
||
enableDir = s.dispatchDirs(list)
|
||
if len(enableDir) == 0 { //变迁后面,没有任何可用flow,为配置错误---后期需添加动态检查
|
||
err = ecode.AegisTranNoFlow
|
||
log.Error("fetchTranNextEnableDirs transition(%d) has no enable flow", tranID)
|
||
}
|
||
|
||
//todo--允许变迁和节点的一对多对应吗?
|
||
resultDir = enableDir[0]
|
||
return
|
||
}
|
||
|
||
func (s *Service) beforeUpdate(c context.Context, netID int64) (ok bool, err error) {
|
||
var (
|
||
fr *net.FlowResource
|
||
flowID []int64
|
||
)
|
||
|
||
if flowID, err = s.flowIDByNet(c, netID); err != nil {
|
||
return
|
||
}
|
||
|
||
if len(flowID) > 0 {
|
||
if fr, err = s.gorm.FRByFlow(c, flowID); err != nil {
|
||
log.Error("beforeUpdate s.gorm.FRByFlow error(%v) netid(%d)", err, netID)
|
||
return
|
||
}
|
||
}
|
||
|
||
ok = fr == nil
|
||
return
|
||
}
|