direction.go 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556
  1. package service
  2. import (
  3. "context"
  4. "fmt"
  5. "time"
  6. "go-common/app/admin/main/aegis/model"
  7. "go-common/app/admin/main/aegis/model/net"
  8. "go-common/library/ecode"
  9. "go-common/library/log"
  10. )
  11. //ShowDirection .
  12. func (s *Service) ShowDirection(c context.Context, id int64) (r *net.ShowDirectionResult, err error) {
  13. var (
  14. d *net.Direction
  15. f *net.Flow
  16. t *net.Transition
  17. )
  18. if d, err = s.gorm.DirectionByID(c, id); err != nil {
  19. return
  20. }
  21. if f, err = s.gorm.FlowByID(c, d.FlowID); err != nil {
  22. return
  23. }
  24. if t, err = s.gorm.TransitionByID(c, d.TransitionID); err != nil {
  25. return
  26. }
  27. r = &net.ShowDirectionResult{
  28. Direction: d,
  29. FlowName: f.ChName,
  30. TransitionName: t.ChName,
  31. }
  32. return
  33. }
  34. //GetDirectionList .
  35. func (s *Service) GetDirectionList(c context.Context, pm *net.ListDirectionParam) (result *net.ListDirectionRes, err error) {
  36. var (
  37. n *net.Net
  38. flows map[int64]string
  39. trans map[int64]string
  40. unames map[int64]string
  41. fids = []int64{}
  42. tids = []int64{}
  43. uid = []int64{}
  44. )
  45. if n, err = s.gorm.NetByID(c, pm.NetID); err != nil {
  46. return
  47. }
  48. if result, err = s.gorm.DirectionList(c, pm); err != nil {
  49. return
  50. }
  51. if len(result.Result) == 0 {
  52. return
  53. }
  54. for _, item := range result.Result {
  55. fids = append(fids, item.FlowID)
  56. tids = append(tids, item.TransitionID)
  57. uid = append(uid, item.UID)
  58. }
  59. if flows, err = s.gorm.ColumnMapString(c, net.TableFlow, "ch_name", fids, ""); err != nil {
  60. return
  61. }
  62. if trans, err = s.gorm.ColumnMapString(c, net.TableTransition, "ch_name", tids, ""); err != nil {
  63. return
  64. }
  65. if unames, err = s.http.GetUnames(c, uid); err != nil {
  66. log.Error("GetDirectionList s.http.GetUnames error(%v)", err)
  67. err = nil
  68. }
  69. for _, item := range result.Result {
  70. item.NetName = n.ChName
  71. item.FlowName = flows[item.FlowID]
  72. item.TransitionName = trans[item.TransitionID]
  73. item.UserName = unames[item.UID]
  74. }
  75. return
  76. }
  77. //SwitchDirection .
  78. func (s *Service) SwitchDirection(c context.Context, id int64, needDisable bool) (err error, msg string) {
  79. var (
  80. old *net.Direction
  81. action string
  82. canUpdate bool
  83. )
  84. if old, err = s.gorm.DirectionByID(c, id); err != nil {
  85. log.Error("SwitchDirection s.gorm.DirectionByID(%d) error(%v) needDisable(%v)", id, err, needDisable)
  86. return
  87. }
  88. available := old.IsAvailable()
  89. if available == !needDisable {
  90. return
  91. }
  92. if canUpdate, err = s.beforeUpdate(c, old.NetID); err != nil {
  93. log.Error("SwitchDirection s.beforeUpdate error(%v)", err)
  94. return
  95. }
  96. if !canUpdate {
  97. log.Error("SwitchDirection can't update id(%d) needdisable(%v)", id, needDisable)
  98. return
  99. }
  100. if needDisable {
  101. old.DisableTime = time.Now()
  102. action = model.LogNetActionDisable
  103. } else {
  104. if err = s.checkDirectionBindAvailable(c, old.FlowID, old.TransitionID); err != nil {
  105. log.Error("SwitchDirection s.checkDirectionBindAvailable(%+v) error(%v) needDisable(%v)", old, err, needDisable)
  106. return
  107. }
  108. if err, msg = s.checkDirConflict(c, old); err != nil {
  109. log.Error("SwitchDirection s.checkDirConflict(%+v) error(%v) needDisable(%v)", old, err, needDisable)
  110. return
  111. }
  112. old.DisableTime = net.Recovered
  113. action = model.LogNetActionAvailable
  114. }
  115. tx, err := s.gorm.BeginTx(c)
  116. if err != nil {
  117. log.Error("SwitchDirection s.gorm.BeginTx error(%v)", err)
  118. return
  119. }
  120. if err = s.gorm.DisableNet(c, tx, old.NetID); err != nil {
  121. tx.Rollback()
  122. return
  123. }
  124. if err = s.gorm.UpdateFields(c, tx, net.TableDirection, id, map[string]interface{}{"disable_time": old.DisableTime}); err != nil {
  125. tx.Rollback()
  126. return
  127. }
  128. if err = tx.Commit().Error; err != nil {
  129. log.Error("SwitchDirection tx.Commit error(%v)", err)
  130. return
  131. }
  132. s.delDirCache(c, old)
  133. //日志
  134. oper := &model.NetConfOper{
  135. OID: old.ID,
  136. Action: action,
  137. UID: old.UID,
  138. NetID: old.NetID,
  139. FlowID: old.FlowID,
  140. TranID: old.TransitionID,
  141. }
  142. s.sendNetConfLog(c, model.LogTypeDirConf, oper)
  143. return
  144. }
  145. func (s *Service) checkDirectionUnique(c context.Context, netID int64, FlowID int64, transitionID int64, direction int8) (err error, msg string) {
  146. var exist *net.Direction
  147. if exist, err = s.gorm.DirectionByUnique(c, netID, FlowID, transitionID, direction); err != nil {
  148. return
  149. }
  150. if exist != nil {
  151. err = ecode.AegisUniqueAlreadyExist
  152. msg = fmt.Sprintf(ecode.AegisUniqueAlreadyExist.Message(), "有向线", "")
  153. }
  154. return
  155. }
  156. func (s *Service) checkDirectionBindAvailable(c context.Context, flowID, transitionID int64) (err error) {
  157. var (
  158. f *net.Flow
  159. t *net.Transition
  160. )
  161. if flowID > 0 {
  162. if f, err = s.gorm.FlowByID(c, flowID); err != nil {
  163. return
  164. }
  165. if !f.IsAvailable() {
  166. err = ecode.AegisFlowDisabled
  167. return
  168. }
  169. }
  170. if transitionID > 0 {
  171. if t, err = s.gorm.TransitionByID(c, transitionID); err != nil {
  172. return
  173. }
  174. if !t.IsAvailable() {
  175. err = ecode.AegisTranDisabled
  176. return
  177. }
  178. }
  179. return
  180. }
  181. /**
  182. * 不同order兼容性不同:
  183. * order=顺序,flow<->tran一对一
  184. * order=todo
  185. */
  186. func (s *Service) checkDirConflict(c context.Context, d *net.Direction) (err error, msg string) {
  187. var (
  188. flowDir, tranDir []*net.Direction
  189. orderDes, conflictDes string
  190. )
  191. if d == nil {
  192. return
  193. }
  194. if flowDir, err = s.gorm.DirectionByFlowID(c, []int64{d.FlowID}, d.Direction); err != nil {
  195. log.Error("checkDirConflict s.gorm.DirectionByFlowID error(%v) direction(%+v)", err, d)
  196. return
  197. }
  198. flowDirLen := len(flowDir)
  199. for k, item := range flowDir {
  200. if item.ID != d.ID {
  201. continue
  202. }
  203. if k < flowDirLen-1 {
  204. flowDir = append(flowDir[:k], flowDir[k+1:]...)
  205. } else {
  206. flowDir = flowDir[:k]
  207. }
  208. flowDirLen--
  209. }
  210. if tranDir, err = s.gorm.DirectionByTransitionID(c, []int64{d.TransitionID}, d.Direction, true); err != nil {
  211. log.Error("checkDirConflict s.gorm.DirectionByTransitionID error(%v) direction(%+v)", err, d)
  212. return
  213. }
  214. tranDirLen := len(tranDir)
  215. for k, item := range tranDir {
  216. if item.ID != d.ID {
  217. continue
  218. }
  219. if k < tranDirLen-1 {
  220. tranDir = append(tranDir[:k], tranDir[k+1:]...)
  221. } else {
  222. tranDir = tranDir[:k]
  223. }
  224. tranDirLen--
  225. }
  226. //无任何已有线
  227. if flowDirLen == 0 && tranDirLen == 0 {
  228. return
  229. }
  230. if d.Order == net.DirOrderSequence {
  231. conflictDes = "节点或变迁已被绑定"
  232. } else {
  233. //不支持的顺序报错
  234. log.Error("checkDirConflict order(%d) is not supported! direction(%+v)", d.Order, d)
  235. err = ecode.RequestErr
  236. return
  237. }
  238. //顺序兼容性报错
  239. log.Error("checkDirConflict direction(%+v) not allowed!", d)
  240. err = ecode.AegisDirOrderConflict
  241. orderDes = net.DirOrderDesc[d.Order]
  242. msg = fmt.Sprintf(ecode.AegisDirOrderConflict.Message(), orderDes, conflictDes)
  243. return
  244. }
  245. //AddDirection .
  246. func (s *Service) AddDirection(c context.Context, uid int64, d *net.DirEditParam) (id int64, err error, msg string) {
  247. var (
  248. canUpdate bool
  249. )
  250. if canUpdate, err = s.beforeUpdate(c, d.NetID); err != nil {
  251. log.Error("AddDirection s.beforeUpdate error(%v)", err)
  252. return
  253. }
  254. if !canUpdate {
  255. log.Error("AddDirection can't update param(%+v)", d)
  256. return
  257. }
  258. if err, msg = s.checkDirectionUnique(c, d.NetID, d.FlowID, d.TransitionID, d.Direction); err != nil {
  259. return
  260. }
  261. if err = s.checkDirectionBindAvailable(c, d.FlowID, d.TransitionID); err != nil {
  262. return
  263. }
  264. dir := &net.Direction{
  265. NetID: d.NetID,
  266. FlowID: d.FlowID,
  267. TransitionID: d.TransitionID,
  268. Direction: d.Direction,
  269. Order: d.Order,
  270. Guard: d.Guard,
  271. Output: d.Output,
  272. UID: uid,
  273. }
  274. if err, msg = s.checkDirConflict(c, dir); err != nil {
  275. return
  276. }
  277. tx, err := s.gorm.BeginTx(c)
  278. if err != nil {
  279. log.Error("AddDirection s.gorm.BeginTx error(%v)", err)
  280. return
  281. }
  282. if err = s.gorm.DisableNet(c, tx, dir.NetID); err != nil {
  283. tx.Rollback()
  284. return
  285. }
  286. if err = s.gorm.AddItem(c, tx, dir); err != nil {
  287. tx.Rollback()
  288. return
  289. }
  290. if err = tx.Commit().Error; err != nil {
  291. log.Error("AddDirection tx.Commit error(%v)", err)
  292. return
  293. }
  294. id = d.ID
  295. //日志
  296. oper := &model.NetConfOper{
  297. OID: dir.ID,
  298. Action: model.LogNetActionNew,
  299. UID: dir.UID,
  300. NetID: dir.NetID,
  301. FlowID: dir.FlowID,
  302. TranID: dir.TransitionID,
  303. Diff: []string{
  304. model.LogFieldTemp(model.LogFieldDirection, net.DirDirectionDesc[dir.Direction], "", false),
  305. model.LogFieldTemp(model.LogFieldOrder, net.DirOrderDesc[dir.Order], "", false),
  306. model.LogFieldTemp(model.LogFieldGuard, dir.Guard, "", false),
  307. model.LogFieldTemp(model.LogFieldOutput, dir.Output, "", false),
  308. },
  309. }
  310. s.sendNetConfLog(c, model.LogTypeDirConf, oper)
  311. return
  312. }
  313. //UpdateDirection .
  314. func (s *Service) UpdateDirection(c context.Context, uid int64, d *net.DirEditParam) (err error, msg string) {
  315. var (
  316. old *net.Direction
  317. canUpdate, checkUnique, orderChanged bool
  318. updates = map[string]interface{}{}
  319. diff = []string{}
  320. )
  321. if old, err = s.gorm.DirectionByID(c, d.ID); err != nil {
  322. log.Error("UpdateDirection s.gorm.DirectionByID(%d) error(%v)", d.ID, err)
  323. return
  324. }
  325. if canUpdate, err = s.beforeUpdate(c, old.NetID); err != nil {
  326. log.Error("UpdateDirection s.beforeUpdate error(%v)", err)
  327. return
  328. }
  329. if !canUpdate {
  330. log.Error("UpdateDirection can't update param(%+v)", d)
  331. return
  332. }
  333. cp := *old
  334. nw := &cp
  335. if d.FlowID != old.FlowID {
  336. if err = s.checkDirectionBindAvailable(c, d.FlowID, 0); err != nil {
  337. return
  338. }
  339. checkUnique = true
  340. nw.FlowID = d.FlowID
  341. updates["flow_id"] = d.FlowID
  342. }
  343. if d.TransitionID != old.TransitionID {
  344. if err = s.checkDirectionBindAvailable(c, 0, d.TransitionID); err != nil {
  345. return
  346. }
  347. checkUnique = true
  348. nw.TransitionID = d.TransitionID
  349. updates["transition_id"] = d.TransitionID
  350. }
  351. if d.Direction != old.Direction {
  352. checkUnique = true
  353. diff = append(diff, model.LogFieldTemp(model.LogFieldDirection, net.DirDirectionDesc[nw.Direction], net.DirDirectionDesc[old.Direction], true))
  354. nw.Direction = d.Direction
  355. updates["direction"] = d.Direction
  356. }
  357. if checkUnique {
  358. if err, msg = s.checkDirectionUnique(c, nw.NetID, nw.FlowID, nw.TransitionID, nw.Direction); err != nil {
  359. return
  360. }
  361. }
  362. if d.Order != old.Order {
  363. diff = append(diff, model.LogFieldTemp(model.LogFieldOrder, net.DirOrderDesc[nw.Order], net.DirOrderDesc[old.Order], true))
  364. nw.Order = d.Order
  365. updates["order"] = d.Order
  366. orderChanged = true
  367. }
  368. //todo-- guard,output
  369. if checkUnique || orderChanged {
  370. if err, msg = s.checkDirConflict(c, nw); err != nil {
  371. return
  372. }
  373. }
  374. if len(updates) <= 0 {
  375. return
  376. }
  377. tx, err := s.gorm.BeginTx(c)
  378. if err != nil {
  379. log.Error("UpdateDirection s.gorm.BeginTx error(%v)", err)
  380. return
  381. }
  382. if err = s.gorm.DisableNet(c, tx, old.NetID); err != nil {
  383. tx.Rollback()
  384. return
  385. }
  386. if err = s.gorm.UpdateFields(c, tx, net.TableDirection, old.ID, updates); err != nil {
  387. tx.Rollback()
  388. return
  389. }
  390. if err = tx.Commit().Error; err != nil {
  391. log.Error("UpdateDirection tx.Commit error(%v)", err)
  392. return
  393. }
  394. s.delDirCache(c, old)
  395. //日志
  396. oper := &model.NetConfOper{
  397. OID: nw.ID,
  398. Action: model.LogNetActionUpdate,
  399. UID: nw.UID,
  400. NetID: nw.NetID,
  401. FlowID: nw.FlowID,
  402. TranID: nw.TransitionID,
  403. Diff: diff,
  404. }
  405. s.sendNetConfLog(c, model.LogTypeDirConf, oper)
  406. return
  407. }
  408. /**
  409. * isDirEnable 检查到下一步的可能性,由order&guard决定
  410. */
  411. func (s *Service) isDirEnable(dir *net.Direction) (enable bool) {
  412. if dir == nil {
  413. return
  414. }
  415. if (dir.Order != net.DirOrderOrSplit && dir.Order != net.DirOrderOrResultSplit) ||
  416. (dir.Order == net.DirOrderOrResultSplit && dir.Guard == "") {
  417. enable = true
  418. return
  419. }
  420. //todo--compute guard expression-v2
  421. return
  422. }
  423. /**
  424. * dispatchDirs 方向线是否可达下一步
  425. * 加入资源维度:若资源没有任何可达性如何办,这是配置错误--后期加入动态检查
  426. */
  427. func (s *Service) dispatchDirs(dirs []*net.Direction) (enableDir []*net.Direction) {
  428. var (
  429. enable bool
  430. )
  431. //对每个有向线, 过滤所有资源, 区分哪些资源可达
  432. enableDir = []*net.Direction{}
  433. for _, dir := range dirs {
  434. enable = s.isDirEnable(dir)
  435. if enable {
  436. enableDir = append(enableDir, dir)
  437. continue
  438. }
  439. }
  440. return
  441. }
  442. /**
  443. * fetchFlowNextEnableDirs 从flow出发,找到下一步变迁
  444. * 后期加入资源维度:若资源没有任何可达性如何办,这是配置错误--后期加入动态检查
  445. * 被应用在:
  446. * 1. 新节点查看下一步变迁是否需要创建分发任务;
  447. * 2. 审核提交后,通过flowid找到被触发的是哪个变迁(必须是同一个---后期加入动态检查);
  448. * 3. 通过flowid获取可用变迁的操作项;
  449. * todo -- 任务方存储了transitionid后,可以移除2+3逻辑
  450. */
  451. func (s *Service) fetchFlowNextEnableDirs(c context.Context, flowID int64) (enableDir []*net.Direction, err error) {
  452. var (
  453. list []*net.Direction
  454. )
  455. //找到以flow为起点的所有方向线
  456. if list, err = s.dirByFlow(c, []int64{flowID}, net.DirInput); err != nil {
  457. log.Error("fetchFlowNextEnableDirs s.dirByFlow(%d) error(%v)", flowID, err)
  458. return
  459. }
  460. if len(list) == 0 { //没配置下一步,正常情况
  461. return
  462. }
  463. if enableDir = s.dispatchDirs(list); len(enableDir) == 0 {
  464. err = ecode.AegisFlowNoEnableTran
  465. log.Error("fetchFlowNextEnableDirs s.dispatchDirs flowid(%v) no enable transition", flowID)
  466. }
  467. return
  468. }
  469. /**
  470. * fetchTranNextEnableDirs 从变迁出发,找到下一步flow
  471. * 后期加入资源维度
  472. */
  473. func (s *Service) fetchTranNextEnableDirs(c context.Context, tranID int64) (resultDir *net.Direction, err error) {
  474. var (
  475. list []*net.Direction
  476. enableDir []*net.Direction
  477. )
  478. if list, err = s.dirByTran(c, []int64{tranID}, net.DirOutput, true); err != nil {
  479. log.Error("fetchTranNextEnableDirs s.dirByTran(%d) error(%v)", tranID, err)
  480. return
  481. }
  482. if len(list) == 0 { //变迁后面没配置flow,为配置错误--后期都需要添加动态检查
  483. err = ecode.AegisTranNoFlow
  484. log.Error("fetchTranNextEnableDirs s.gorm.DirectionByTransitionID(%d) no flow", tranID)
  485. return
  486. }
  487. enableDir = s.dispatchDirs(list)
  488. if len(enableDir) == 0 { //变迁后面,没有任何可用flow,为配置错误---后期需添加动态检查
  489. err = ecode.AegisTranNoFlow
  490. log.Error("fetchTranNextEnableDirs transition(%d) has no enable flow", tranID)
  491. }
  492. //todo--允许变迁和节点的一对多对应吗?
  493. resultDir = enableDir[0]
  494. return
  495. }
  496. func (s *Service) beforeUpdate(c context.Context, netID int64) (ok bool, err error) {
  497. var (
  498. fr *net.FlowResource
  499. flowID []int64
  500. )
  501. if flowID, err = s.flowIDByNet(c, netID); err != nil {
  502. return
  503. }
  504. if len(flowID) > 0 {
  505. if fr, err = s.gorm.FRByFlow(c, flowID); err != nil {
  506. log.Error("beforeUpdate s.gorm.FRByFlow error(%v) netid(%d)", err, netID)
  507. return
  508. }
  509. }
  510. ok = fr == nil
  511. return
  512. }