go-common/app/admin/main/aegis/service/net_control.go
2019-04-22 18:49:16 +08:00

892 lines
29 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package service
import (
"context"
"fmt"
"sort"
"strconv"
"strings"
"github.com/jinzhu/gorm"
"go-common/app/admin/main/aegis/model"
"go-common/app/admin/main/aegis/model/net"
"go-common/library/ecode"
"go-common/library/log"
"go-common/library/xstr"
)
//启动流程网之前的检查
func (s *Service) startNet(c context.Context, businessID int64, netID int64) (result *net.TriggerResult, err error) {
var (
n *net.Net
resultTokenPackage *net.TokenPackage
)
//网可用性
if n, err = s.netByID(c, netID); err != nil {
log.Error("startNet s.netByID(%d) error(%v)", netID, err)
return
}
if n == nil || !n.IsAvailable() || n.StartFlowID <= 0 {
log.Error("startNet s.netByID(%d) not found/disabled/start_flow_id=0", netID)
err = ecode.RequestErr
return
}
if n.BusinessID != businessID {
log.Error("startNet s.netByID(%d) business(%d) != param business(%d)", netID, n.BusinessID, businessID)
err = ecode.RequestErr
return
}
//初始节点的token集合
if resultTokenPackage, err = s.computeNewFlowPackage(c, n.StartFlowID, nil, nil, true); err != nil {
log.Error("startNet s.computeNewFlowPackage(%d) error(%+v) netid(%d)", n.StartFlowID, err, netID)
return
}
result = &net.TriggerResult{
NetID: netID,
ResultToken: resultTokenPackage,
NewFlowID: n.StartFlowID,
From: model.LogFromStart,
}
return
}
/*FetchJumpFlowInfo ..
* 跳流程详情页, 跳流程是单独db层面的更新
* 参数flowid(可选)
* 获取网下所有flow和变迁的所有操作项
*/
func (s *Service) FetchJumpFlowInfo(c context.Context, flowID int64) (res *net.JumpInfo, err error) {
var (
flow *net.Flow
runningNet int64
flowList []*net.Flow
)
res = &net.JumpInfo{
Flows: []*net.SimpleInfo{},
Operations: []*net.TranOperation{},
}
if flow, err = s.flowByID(c, flowID); err != nil {
log.Error("FetchJumpFlowInfo s.flowByID(%d) error(%v)", flowID, err)
return
}
if flow == nil {
log.Error("FetchJumpFlowInfo flow(%d) not found", flowID)
err = ecode.AegisFlowNotFound
return
}
runningNet = flow.NetID
if flowList, err = s.flowsByNet(c, runningNet); err != nil {
log.Error("FetchJumpFlowInfo s.flowsByNet(%d) error(%v) flowid(%d)", runningNet, err, flowID)
return
}
flowInfo := []*net.SimpleInfo{}
for _, item := range flowList {
flowInfo = append(flowInfo, &net.SimpleInfo{
ID: item.ID,
ChName: item.ChName,
})
}
//网下的所有变迁可操作项
if res.Operations, err = s.tranOpersByNet(c, []int64{runningNet}, []int8{net.BindTypeTransition}); err != nil {
log.Error("FetchJumpFlowInfo s.tranOpersByNet(%d) error(%v) flowid(%d)", runningNet, err, flowID)
return
}
res.Flows = flowInfo
return
}
/**
* 跳流程提交rid, oldflowid, newflowid, binds
* 可以单独提供flowid,单独提供binds
* 单独提供flowid时不做流程流转
*/
func (s *Service) jumpFlow(c context.Context, tx *gorm.DB, rid int64, oldFlowID int64, newFlowID int64, binds []int64) (result *net.JumpFlowResult, err error) {
var (
frs []*net.FlowResource
oldFlow, newFlow *net.Flow
triggerResult *net.TriggerResult
bindList []*net.TokenBind
submitPackage *net.TokenPackage
)
log.Info("jumpFlow before rid(%d) oldflowid(%d) newflowid(%d) binds(%v)", rid, oldFlowID, newFlowID, binds)
if rid <= 0 || oldFlowID <= 0 || (len(binds) == 0 && newFlowID <= 0) {
err = ecode.RequestErr
return
}
//检查资源是否运行在该节点
if frs, err = s.gorm.FRByUniques(c, []int64{rid}, []int64{oldFlowID}, true); err != nil {
log.Error("jumpFlow s.gorm.FRByUniques(%d,%d) error(%v)", rid, oldFlowID, err)
return
}
if len(frs) == 0 {
log.Error("jumpFlow rid(%d) not running at oldflowid(%d)", rid, oldFlowID)
err = ecode.AegisNotRunInFlow
return
}
if oldFlow, err = s.flowByID(c, oldFlowID); err != nil {
log.Error("jumpFlow s.flowByID(%d) error(%v) rid(%d)", oldFlowID, err, rid)
return
}
if oldFlow == nil {
log.Error("jumpFlow oldflowid(%d) not found, rid(%d)", oldFlowID, rid)
err = ecode.AegisFlowNotFound
return
}
/**
* jumpFlow 指定一批资源,更新为相同现状
* 不需要前端指定现状flowid
* 资源现状从单线跳到多线程的某个节点时----由运营决定是到sync-split节点还是并发分支上的某个节点------fr数目从1变成1/还是1变成n
* 资源现状从多线程跳到某个节点时----节点在并发分支上如何确定现状flow和新节点都在并发分支上----fr数目从1变成1
* ----节点在单线上,结束所有运行中都并发现状,加一个单线分支---fr数目从n变成1
*/
if len(binds) > 0 {
if bindList, err = s.tokenBinds(c, binds, true); err != nil {
log.Error("jumpFlow s.tokenBinds(%v) error(%v) rid(%d)", binds, err, rid)
return
}
if len(bindList) == 0 {
log.Error("jumpFlow binds(%v) not found, rid(%d)", binds, rid)
err = ecode.RequestErr
return
}
if submitPackage, err = s.newTokenPackage(c, bindList, true); err != nil {
log.Error("jumpFlow s.newTokenPackage(%v) error(%v) rid(%d)", binds, err, rid)
return
}
}
if newFlowID > 0 && newFlowID != oldFlowID {
if newFlow, err = s.flowByID(c, newFlowID); err != nil {
log.Error("jumpFlow newflow(%d) error(%v) rid(%d)", newFlowID, err, rid)
return
}
if newFlow == nil {
log.Error("jumpFlow newflow(%d) not found, rid(%d)", newFlowID, rid)
err = ecode.AegisFlowNotFound
return
}
if oldFlow.NetID != newFlow.NetID {
log.Error("jumpFlow rid(%d) run at oldflowid(%d)/net(%d), can't jump to newflowid(%d)/net(%d)", rid, oldFlowID, oldFlow.NetID, newFlowID, newFlow.NetID)
err = ecode.RequestErr
return
}
triggerResult = &net.TriggerResult{
RID: rid,
NetID: oldFlow.NetID,
NewFlowID: newFlowID,
OldFlowID: strconv.FormatInt(oldFlowID, 10),
SubmitToken: submitPackage,
ResultToken: submitPackage,
}
if err = s.reachNewFlowDB(c, tx, triggerResult); err != nil {
log.Error("jumpFlow s.reachNewFlowDB error(%v) triggerresult(%+v)", err, triggerResult)
return
}
} else {
newFlowID = oldFlowID
}
result = &net.JumpFlowResult{
RID: rid,
NetID: oldFlow.NetID,
SubmitToken: submitPackage,
ResultToken: submitPackage,
NewFlowID: newFlowID,
OldFlowID: strconv.FormatInt(oldFlowID, 10),
}
return
}
func (s *Service) afterJumpFlow(c context.Context, res *net.JumpFlowResult, bizid int64) (err error) {
trigger := &net.TriggerResult{
RID: res.RID,
NetID: res.NetID,
SubmitToken: res.SubmitToken,
ResultToken: res.ResultToken,
NewFlowID: res.NewFlowID,
OldFlowID: res.OldFlowID,
From: model.LogFromJump,
}
s.afterReachNewFlow(c, trigger, bizid)
return
}
/**
* 批量审核提交--单个遍历处理
* 参数business, rid, binds
* flowid(由rid反查现状)
* transition_id由flow_id查到的下游transition & token_bind集合 与 token_id的交集决定非叶子节点若找不到则报错
* 找到了,则计算新flow & result_token
* 计算result_token规则
* 变迁trigger=人工必须提供binds;
* 变迁trigger=其他binds可以为空 & 新flow要么有绑定token要么有向线上output不为空
*/
func (s *Service) computeBatchTriggerResult(c context.Context, businessID int64, rid int64, bindID []int64) (result *net.TriggerResult, err error) {
var (
oldFlow *net.Flow
)
log.Info("computeBatchTriggerResult start business(%d) rid(%d) bindID(%+v)", businessID, rid, bindID)
//反查指定资源所运行的节点
if oldFlow, _, err = s.flowsByRunning(c, rid, businessID, 0, true); err != nil {
return
}
if result, err = s.computeResult(c, rid, oldFlow, bindID, true); err != nil {
log.Error("computeBatchTriggerResult s.computeResult error(%v) rid(%d) businessid(%d) bindID(%v) oldflow(%+v)", err, rid, businessID, bindID, oldFlow)
return
}
result.From = model.LogFromBatch
log.Info("computeBatchTriggerResult end business(%d) rid(%d) bindID(%+v) result(%+v)", businessID, rid, bindID, result)
return
}
/**
* 详情页审核提交
* 参数rid, flowid, binds
* 当flowid=最后一个,不流转--binds可能为多个; 其余情况均正常流转到下一个flow--binds只有一个
* 计算result_token规则
* 变迁trigger=人工必须提供binds;
* 变迁trigger=其他binds可以为空 & 新flow要么有绑定token要么有向线上output不为空
*/
func (s *Service) computeTriggerResult(c context.Context, rid int64, oldFlowID int64, binds []int64) (result *net.TriggerResult, err error) {
var (
oldFlow *net.Flow
frs []*net.FlowResource
)
log.Info("computeTriggerResult start rid(%d) oldflow(%d) binds(%+v)", rid, oldFlowID, binds)
if rid <= 0 || oldFlowID <= 0 || len(binds) == 0 {
err = ecode.RequestErr
return
}
if frs, err = s.gorm.FRByUniques(c, []int64{rid}, []int64{oldFlowID}, true); err != nil {
log.Error("computeTriggerResult s.gorm.FRByUniques(%d) error(%v) rid(%d) binds(%v)", oldFlowID, err, rid, binds)
return
}
if len(frs) == 0 {
log.Error("computeTriggerResult rid(%d) not running at oldflow(%d) binds(%v)", rid, oldFlowID, binds)
err = ecode.AegisNotRunInFlow
return
}
if oldFlow, err = s.flowByID(c, oldFlowID); err != nil {
log.Error("computeTriggerResult s.flowByID(%d) error(%v) rid(%d) binds(%v)", oldFlowID, err, rid, binds)
return
}
if oldFlow == nil {
err = ecode.AegisFlowNotFound
return
}
if result, err = s.computeResult(c, rid, oldFlow, binds, false); err != nil {
log.Error("computeTriggerResult s.computeResult error(%v) binds(%v) flow(%+v) rid(%d)", err, binds, oldFlow, rid)
return
}
result.From = model.LogFromSingle
log.Info("computeTriggerResult end rid(%d) oldflow(%d) binds(%+v) result(%+v)", rid, oldFlowID, binds, result)
return
}
func (s *Service) computeResult(c context.Context, rid int64, flow *net.Flow, bindID []int64, fromBatch bool) (result *net.TriggerResult, err error) {
var (
hitAudit, hitHelper bool //审核流转和非流转操作是互斥的,不能同时提交
dirs []*net.Direction
isLast bool
triggerBind = []*net.TokenBind{}
binds []*net.TokenBind
trans []*net.Transition
triggerTranID, newFlowID int64
submitTokenPackage, resultTokenPackage *net.TokenPackage
resultDir *net.Direction
)
//非叶子节点只能有一个bind
if rid == 0 || flow == nil {
log.Error("computeResult rid(%d)=0/flow(%+v)=ni", rid, flow)
err = ecode.RequestErr
return
}
if binds, err = s.tokenBinds(c, bindID, true); err != nil {
log.Error("computeBatchTriggerResult s.tokenBinds(%+v) error(%v)", bindID, err)
return
}
tranID := []int64{}
for _, item := range binds {
if item.IsBatch() != fromBatch {
continue
}
tranID = append(tranID, item.ElementID)
if (fromBatch && item.Type == net.BindTypeTranBatch) || (!fromBatch && item.Type == net.BindTypeTransition) {
hitAudit = true
}
if (fromBatch && item.Type == net.BindTypeTranHelpBatch) || (!fromBatch && item.Type == net.BindTypeTranHelp) {
hitHelper = true
}
}
if len(binds) == 0 || (hitAudit && hitHelper) {
log.Error("computeBatchTriggerResult binds(%v) not found/both hit audit && helper are not allowed", binds)
err = ecode.RequestErr
return
}
if hitAudit {
//同网下、同flow下游的变迁过滤, 非叶子节点必须命中一个变迁
if dirs, err = s.dirByFlow(c, []int64{flow.ID}, net.DirInput); err != nil {
log.Error("computeResult s.dirByFlow(%d) error(%v)", flow.ID, err)
return
}
isLast = len(dirs) == 0 //是否为叶子节点
if !isLast {
tranID = []int64{}
for _, item := range dirs {
tranID = append(tranID, item.TransitionID)
}
}
}
if trans, err = s.transitions(c, tranID, true); err != nil {
log.Error("computeResult s.transitions(%v) error(%v) rid(%d) flow(%v)", tranID, err, rid, flow)
return
}
tranMap := map[int64]*net.Transition{}
for _, item := range trans {
tranMap[item.ID] = item
}
triggerBindID := []int64{}
triggerTrans := []int64{}
for _, item := range binds {
if tranMap[item.ElementID] == nil || tranMap[item.ElementID].Trigger != net.TriggerManual {
continue
}
//叶子节点=同网过滤|非叶子节点=同flow下游变迁过滤
if (isLast && tranMap[item.ElementID].NetID == flow.NetID) || !isLast {
triggerBind = append(triggerBind, item)
triggerTrans = append(triggerTrans, item.ElementID)
triggerBindID = append(triggerBindID, item.ID)
}
}
if len(triggerBind) == 0 || (!isLast && len(triggerBind) > 1) {
log.Error("computeResult no triggered(%+v)/non-leaf-flow triggered >2, rid(%d) flow(%+v)", triggerBindID, rid, flow)
err = ecode.AegisNotTriggerFlow
return
}
//计算提交的变迁 & 提交令牌集合
if submitTokenPackage, err = s.newTokenPackage(c, triggerBind, true); err != nil {
log.Error("computeResult s.newTokenPackage error(%v)", err)
return
}
if hitHelper || isLast {
//不流转的情况
newFlowID = flow.ID
resultTokenPackage = submitTokenPackage
} else {
//中间节点找到下游新节点
triggerTranID = triggerTrans[0]
if resultDir, err = s.fetchTranNextEnableDirs(c, triggerTranID); err != nil {
log.Error("computeResult s.fetchTranNextEnableDirs(%d) error(%v)", triggerTranID, err)
return
}
newFlowID = resultDir.FlowID
if resultTokenPackage, err = s.computeNewFlowPackage(c, newFlowID, resultDir, submitTokenPackage, false); err != nil {
log.Error("computeResult s.computeNewFlowPackage error(%v)", err)
return
}
}
log.Info("submitpk(%+v) result(%+v)", submitTokenPackage, resultTokenPackage)
result = &net.TriggerResult{
RID: rid,
NetID: flow.NetID,
SubmitToken: submitTokenPackage,
ResultToken: resultTokenPackage,
NewFlowID: newFlowID,
OldFlowID: strconv.FormatInt(flow.ID, 10),
TransitionID: triggerTrans,
}
log.Info("computeResult end islast(%v) frombatch(%v) result(%+v)", isLast, fromBatch, result)
return
}
/**
* 资源审核详情页,获取运行资源所在网的节点下的所有可允许下游可操作项,去掉批量可操作项:
* 若为网中的最后一个flow, 获取网中所有变迁的可操作项(bind级别去重)--提交时只改token不改flow
* 若为中间节点:只有一个(非并发),直接获取变迁的可操作项; 并发,需指定哪个变迁(先抛错)
* 前提同一rid只在同一业务下的一个net下运行
* 任务列表进入详情页参数rid,businessid,netid(可选)
*/
func (s *Service) fetchResourceTranInfo(c context.Context, rid int64, businessID int64, netID int64) (result *net.TransitionInfo, err error) {
var (
runningFlow *net.Flow
runningNet int64
)
if rid <= 0 || businessID <= 0 {
err = ecode.RequestErr
return
}
if runningFlow, runningNet, err = s.flowsByRunning(c, rid, businessID, netID, false); err != nil {
return
}
flowID := runningFlow.ID
if result, err = s.fetchTaskTranInfo(c, rid, flowID, runningNet); err != nil {
log.Error("fetchResourceTranInfo s.fetchTaskTranInfo error(%v) rid(%d) businessid(%d) netid(%d) runningnet(%d)", err, rid, businessID, netID, runningNet)
}
return
}
/**
* 任务详情页获取flowid下的所有可允许变迁的可操作项去掉批量可操作项:
* 若为网中的最后一个flow, 获取网中所有变迁的可操作项(bind级别去重)--提交时只改token不改flow
* 若为中间节点:只有一个(非并发),直接获取变迁的可操作项;并发,需指定哪个变迁(先抛错)
* 前提同一rid只在同一业务下的一个net下运行
* 资源列表进入详情页参数rid, flowid, netid(可选)
*/
func (s *Service) fetchTaskTranInfo(c context.Context, rid int64, flowID int64, netID int64) (result *net.TransitionInfo, err error) {
var (
transitionID []int64
flow *net.Flow
enableDir []*net.Direction
trans []*net.Transition
)
if rid <= 0 || flowID <= 0 {
err = ecode.RequestErr
return
}
if enableDir, err = s.fetchFlowNextEnableDirs(c, flowID); err != nil {
log.Error("fetchTaskTranInfo s.fetchFlowNextEnableDirs(%d) error(%v)", flowID, err)
return
}
//作为分支的叶子节点,获取整个网的所有可操作项
if len(enableDir) == 0 {
if netID <= 0 {
if flow, err = s.flowByID(c, flowID); err != nil {
log.Error("fetchTaskTranInfo s.flowByID error(%v) rid(%d) flowid(%d)", err, rid, flowID)
return
}
if flow == nil {
log.Error("fetchTaskTranInfo flow(%d) not found rid(%d) ", flowID, rid)
err = ecode.AegisFlowNotFound
return
}
netID = flow.NetID
}
if transitionID, err = s.tranIDByNet(c, []int64{netID}, true, true); err != nil {
log.Error("fetchTaskTranInfo s.tranIDByNet(%d) error(%v) rid(%d) flowid(%d)", netID, err, rid, flowID)
return
}
} else {
transitionID = []int64{}
for _, item := range enableDir {
transitionID = append(transitionID, item.TransitionID)
}
if trans, err = s.transitions(c, transitionID, false); err != nil {
log.Error("fetchTaskTranInfo s.transitions(%v) error(%v) rid(%d) flowid(%d)", transitionID, err, rid, flowID)
return
}
transitionID = []int64{}
for _, item := range trans {
if item.Trigger == net.TriggerManual {
transitionID = append(transitionID, item.ID)
}
}
}
result = &net.TransitionInfo{
RID: rid,
FlowID: flowID,
}
if len(transitionID) == 0 {
return
}
if result.Operations, err = s.tranOpers(c, transitionID, []int8{net.BindTypeTransition, net.BindTypeTranHelp}); err != nil {
log.Error("fetchTaskTranInfo s.tranOpers(%v) error(%v) rid(%d) flowid(%d)", transitionID, err, rid, flowID)
return
}
return
}
/**
* 全部资源列表页,获取所有变迁的所有批量操作项
* 参数businessid,netid(选填)
*/
func (s *Service) fetchBatchOperations(c context.Context, businessID int64, netID int64) (operations []*net.TranOperation, err error) {
var (
netIDList []int64
)
operations = []*net.TranOperation{}
if netID > 0 {
netIDList = []int64{netID}
} else {
//查询business_id下的所有net
if netIDList, err = s.netIDByBusiness(c, businessID); err != nil {
log.Error("fetchBatchOperations s.netIDByBusiness error(%v) businessid(%d) netid(%d)", err, businessID, netID)
return
}
if len(netIDList) == 0 {
log.Error("fetchBatchOperations business(%d) no net", businessID)
return
}
}
//查询所有net下的所有变迁可操作项
if operations, err = s.tranOpersByNet(c, netIDList, []int8{net.BindTypeTranBatch, net.BindTypeTranHelpBatch}); err != nil {
log.Error("fetchBatchOperations s.tranOpersByNet(%v) error(%v) businessid(%d) netid(%d)", netIDList, err, businessID, netID)
}
return
}
func (s *Service) tranOpersByNet(c context.Context, netIDs []int64, bindTp []int8) (opers []*net.TranOperation, err error) {
var (
transitionID = []int64{}
)
opers = []*net.TranOperation{}
if len(netIDs) == 0 {
return
}
if transitionID, err = s.tranIDByNet(c, netIDs, true, true); err != nil {
log.Error("tranOpersByNet s.tranIDByNet(%v) error(%v) isBatch(%v)", netIDs, err, bindTp)
return
}
if len(transitionID) == 0 {
return
}
if opers, err = s.tranOpers(c, transitionID, bindTp); err != nil {
log.Error("tranOpersByNet s.tranOpers(%v) error(%v) netid(%v) bindtp(%v)", transitionID, err, netIDs, bindTp)
}
return
}
func (s *Service) tranOpers(c context.Context, tranID []int64, bindTp []int8) (opers []*net.TranOperation, err error) {
var (
binds = []*net.TokenBind{}
)
opers = []*net.TranOperation{}
if binds, err = s.tokenBindByElement(c, tranID, bindTp); err != nil {
log.Error("tranOpers s.tokenBindByElement error(%v) tranid(%v) bindtp(%v)", err, tranID, bindTp)
return
}
//bind.token_id维度去重 + bind.id维度排序
tokenIDBind := map[string][]int64{}
unique := map[string]*net.TranOperation{}
for _, item := range binds {
if _, exist := tokenIDBind[item.TokenID]; !exist {
tokenIDBind[item.TokenID] = []int64{item.ID}
unique[item.TokenID] = &net.TranOperation{
ChName: item.ChName,
}
continue
}
tokenIDBind[item.TokenID] = append(tokenIDBind[item.TokenID], item.ID)
}
for uniqueTokenID, item := range unique {
item.BindIDList = xstr.JoinInts(tokenIDBind[uniqueTokenID])
opers = append(opers, item)
}
sort.Sort(net.TranOperationArr(opers))
return
}
/**
* 计算新节点的token集合
* 启动流程节点只提供newflowID, 找绑定的token
* 流转过程中根据bindIDs + 触发变迁的可允许有向线(变迁id + newflowid)计算新flow的结果
* 1. 若有静态绑定token,返回绑定的
* 2. 若没静态绑定且output="",返回bindID
* 3. 若没静态绑定且output!="",解析output计算---计算可能涉及到触发变迁/上一个flowid
* 4. 其他情况,为配置错误,应该在配置时避免---todo
* 5. start临时支持无令牌绑定情况
*/
func (s *Service) computeNewFlowPackage(c context.Context, newFlowID int64, fromDir *net.Direction, submitPackage *net.TokenPackage, start bool) (resultTokens *net.TokenPackage, err error) {
var (
binds []*net.TokenBind
)
//flow绑定了tokens,直接返回
if binds, err = s.tokenBindByElement(c, []int64{newFlowID}, []int8{net.BindTypeFlow}); err != nil {
log.Error("computeNewFlowPackage s.tokenBindByElement error(%v) newflowid(%d) fromdir(%v) submit(%+v)", err, newFlowID, fromDir, submitPackage)
return
}
if len(binds) > 0 {
if resultTokens, err = s.newTokenPackage(c, binds, false); err != nil {
log.Error("computeNewFlowPackage s.newTokenPackage error(%v) newflowid(%d) fromdir(%v) submit(%+v)", err, newFlowID, fromDir, submitPackage)
}
return
}
if start {
return
}
//没绑定的通过有向线的output计算
if fromDir == nil {
err = ecode.AegisFlowNoFromDir
log.Error("computeNewFlowPackage newflowid(%d) has no tokens & fromdir, submit(%+v)", newFlowID, submitPackage)
return
}
//output为空根据提交内容
if fromDir.Output == "" {
resultTokens = submitPackage
return
}
//todo--compute output解析与prevFlowID + rid + submitTokens相关,return {{"rids":[],"tokens":[]}} --version2
return
}
/**
* 计算指定令牌关联的打包形式,包括:各类型的值+关联中文名+关联对应的令牌
* sametokenid=true需检查binds对应的tokenid是否一致
*/
func (s *Service) newTokenPackage(c context.Context, binds []*net.TokenBind, sameTokenID bool) (res *net.TokenPackage, err error) {
var (
tokenIDList []int64
tokens []*net.Token
value interface{}
sameTokenName string
hitAudit bool
)
tokenIDStr := ""
tokenID := ""
if sameTokenID {
tokenID = binds[0].TokenID
sameTokenName = binds[0].ChName
}
for _, item := range binds {
if sameTokenID && tokenID != item.TokenID {
err = ecode.RequestErr
log.Error("newTokenPackage binds diff token(%s!=%s) sameTokenID(%v)", tokenID, item.TokenID, sameTokenID)
return
}
if item.Type == net.BindTypeTransition || item.Type == net.BindTypeTranBatch {
hitAudit = true
}
tokenIDStr = tokenIDStr + "," + item.TokenID
}
tokenIDStr = strings.TrimLeft(tokenIDStr, ",")
if tokenIDList, err = xstr.SplitInts(tokenIDStr); err != nil {
log.Error("newTokenPackage xstr.SplitInts(%s) error(%v) sameTokenID(%v)", tokenIDStr, err, sameTokenID)
return
}
if tokens, err = s.tokens(c, tokenIDList); err != nil {
log.Error("newTokenPackage s.tokens(%v) error(%v) sameTokenID(%v)", tokenIDStr, err, sameTokenID)
return
}
if len(tokens) == 0 {
log.Error("newTokenPackage tokens(%s) not found sameTokenID(%v)", tokenIDStr, sameTokenID)
err = ecode.AegisTokenNotFound
return
}
values := map[string]interface{}{}
chName := sameTokenName
for _, item := range tokens {
if value, err = item.FormatValue(); err != nil {
log.Error("NewTokenPackage item.FormatValue(%+v) error(%v) sameTokenID(%v)", item, err, sameTokenID)
return
}
values[item.Name] = value
if sameTokenName == "" {
chName = chName + item.ChName
}
}
res = &net.TokenPackage{
Values: values,
TokenIDList: tokenIDList,
ChName: chName,
HitAudit: hitAudit,
}
return
}
/**
* flowsByRunning 指定业务或netid获取资源的运行节点, 只在一个节点上运行
* rid反查现状得到flows,netid或businessid做过滤
* businessID可选netID可选2者必须提供一个
* onlyRunning 只过滤正常运行的资源现状
*/
func (s *Service) flowsByRunning(c context.Context, rid int64, businessID int64, netID int64, onlyRunning bool) (runningFlow *net.Flow, runningNetID int64, err error) {
var (
n *net.Net
nets []int64
frs []*net.FlowResource
)
if rid <= 0 || (businessID <= 0 && netID == 0) {
err = ecode.RequestErr
log.Error("flowsByRunning rid(%d)/businessid(%d)+netid(%d) are empty, onlyrunning(%v)", rid, businessID, netID, onlyRunning)
return
}
if netID > 0 {
if n, err = s.netByID(c, netID); err != nil {
log.Error("flowsByRunning s.netByID(%d) error(%v) rid(%d) businessid(%d) onlyrunning(%v)", netID, err, rid, businessID, onlyRunning)
return
}
if n == nil || n.BusinessID != businessID {
log.Error("flowsByRunning net(%d) in business(%d) not found, rid(%d) onlyrunning(%v)", netID, businessID, rid, onlyRunning)
err = ecode.RequestErr
return
}
nets = []int64{netID}
} else {
if nets, err = s.netIDByBusiness(c, businessID); err != nil {
log.Error("flowsByRunning s.netIDByBusiness(%d) error(%v) rid(%d) onlyrunning(%v)", businessID, err, rid, onlyRunning)
return
}
}
if frs, err = s.gorm.FRByNetRID(c, nets, []int64{rid}, onlyRunning); err != nil {
log.Error("flowsByRunning s.gorm.FRByNetRID(%d) error(%v) businessid(%d) netid(%d)", rid, err, businessID, netID)
return
}
if len(frs) == 0 {
log.Error("flowsByRunning rid(%d) not running in business(%d)/netid(%d) onlyrunning(%v)", rid, businessID, netID, onlyRunning)
err = ecode.AegisNotRunInRange
return
}
flowID := []int64{}
for _, item := range frs {
if runningNetID == 0 {
runningNetID = item.NetID
} else if item.NetID != runningNetID {
log.Error("flowsByRunning rid(%d) running is both net(%d) & net(%d), business(%d), onlyrunning(%v)", rid, runningNetID, item.NetID, businessID, onlyRunning)
err = ecode.AegisRunInDiffNet
return
}
flowID = append(flowID, item.FlowID)
}
if len(flowID) > 1 {
log.Error("flowsByRunning rid(%d) running in flows(%+v)>=2, businessid(%d)/netid(%d) runningnet(%d), onlyrunning(%v)", rid, flowID, businessID, netID, runningNetID, onlyRunning)
err = ecode.AegisNotRunInFlow
return
}
if runningFlow, err = s.flowByID(c, flowID[0]); err != nil {
log.Error("flowsByRunning s.flowByID(%d) error(%v), rid(%d) businessid(%d) netid(%d), onlyrunning(%v)", flowID[0], err, rid, businessID, netID, onlyRunning)
return
}
if runningFlow == nil {
log.Error("flowsByRunning rid(%d) running in flows(%d) not found, businessid(%d) netid(%d) onlyrunnning(%v)", rid, flowID[0], businessID, netID, onlyRunning)
err = ecode.AegisFlowNotFound
return
}
return
}
/**
* 流转到新节点且已更新现状表后,所需做的处理
* 1. 现状流转日志
* 2. 下游变迁处理,比如:人工变迁是否需要分发
*/
func (s *Service) afterReachNewFlow(c context.Context, pm *net.TriggerResult, bizid int64) (err error) {
s.sendNetTriggerLog(c, pm)
err = s.prepareBeforeTrigger(c, []int64{pm.RID}, pm.NewFlowID, bizid)
return
}
/**
* 流转到达新节点更新db操作需在新节点计算token之后执行
* 1. 现状表更新
*/
func (s *Service) reachNewFlowDB(c context.Context, tx *gorm.DB, pm *net.TriggerResult) (err error) {
var (
flow *net.Flow
)
if pm.NetID <= 0 || pm.RID <= 0 || pm.NewFlowID <= 0 {
log.Error("reachNewFlowDB params error(%+v)", pm)
err = ecode.RequestErr
return
}
//新节点与netid的同网检查
if flow, err = s.flowByID(c, pm.NewFlowID); err != nil {
log.Error("reachNewFlowDB s.flowByID error(%v) params(%+v)", err, pm)
return
}
if flow == nil || flow.NetID != pm.NetID {
log.Error("reachNewFlowDB s.flowByID not found/not same net, params(%+v), flow(%+v)", pm, flow)
err = ecode.RequestErr
return
}
if err = s.updateFlowResources(c, tx, pm.NetID, pm.RID, pm.NewFlowID); err != nil {
log.Error("reachNewFlowDB s.changeFlowResource error(%v) params(%+v)", err, pm)
return
}
//todo--更新现状token情况
return
}
//取消指定资源的所有运行中流程
func (s *Service) cancelNet(c context.Context, tx *gorm.DB, rids []int64) (res map[int64]string, err error) {
var (
frs []*net.FlowResource
)
if len(rids) == 0 {
return
}
res = map[int64]string{}
if frs, err = s.gorm.FRByUniques(c, rids, nil, true); err != nil {
log.Error("cancelNet s.gorm.FRByUniques error(%v) rids(%+v)", err, rids)
return
}
if len(frs) == 0 {
return
}
if err = s.gorm.CancelFlowResource(c, tx, rids); err != nil {
log.Error("cancelNet s.gorm.CancelFlowResource error(%+v) rids(%+v)", err, rids)
return
}
//添加日志
trigger := &net.TriggerResult{
From: model.LogFromCancle,
}
for _, item := range frs {
pref := res[item.RID]
if pref != "" {
pref = "," + pref
}
res[item.RID] = fmt.Sprintf("%s%d", pref, item.FlowID)
trigger.RID = item.RID
trigger.NetID = item.NetID
trigger.OldFlowID = strconv.FormatInt(item.FlowID, 10)
trigger.NewFlowID = item.FlowID
s.sendNetTriggerLog(c, trigger)
}
return
}