scd_node_rule.go 128 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704
  1. package bo
  2. import (
  3. "errors"
  4. "fmt"
  5. "log"
  6. "os"
  7. "runtime"
  8. "scd_check_tools/global"
  9. "scd_check_tools/logger"
  10. "scd_check_tools/models/enum"
  11. "scd_check_tools/models/node_attr"
  12. "scd_check_tools/mqtt"
  13. "scd_check_tools/tools"
  14. "strconv"
  15. "strings"
  16. "sync"
  17. "time"
  18. "github.com/astaxie/beego/orm"
  19. )
  20. //节点规则解析管理
  21. //单独启用专用解析进程,与节点入库操作为异步关系。该进程在没有新scd入库时为睡眠状态,当有新scd需要解析时,需要外部将其唤醒
  22. //进程被唤醒后,定时查询节点表中未被解析的节点进行规则有效性验证,如果验证不通过,则将结果写入规则解析结果表
  23. //每个节点状态都将按以下状态进行切换:0 未解析->1 解析中-> 2已解析
  24. type ScdNodeRule struct {
  25. ScdID int64
  26. ScdName string
  27. DeviceBaseModel
  28. doiMap *sync.Map
  29. daMap *sync.Map
  30. lnodeTypeMap *sync.Map // map[string]*node_attr.NLNodeType{}
  31. doTypeMap *sync.Map // map[string]*node_attr.NDOType{}
  32. daTypeMap *sync.Map // map[string]*node_attr.NDOType{}
  33. //当前未通过验证的节点列表
  34. CheckFailList []map[string]interface{}
  35. //等待解析的队列
  36. NodeRuleList map[string]orm.Params
  37. //
  38. NodeRuleFunctionList []orm.Params
  39. //是否正在解析节点。默认为0
  40. isRun int
  41. parseLock sync.RWMutex
  42. checkFailListLock sync.RWMutex
  43. scdXmlObject *node_attr.SCL
  44. }
  45. type t_scd_node_rule_parse struct {
  46. Id int64 `orm:"pk"`
  47. ScdId int64
  48. NodeId int64
  49. RuleId int64
  50. ParseResult string
  51. CreatedBy int
  52. CreatedTime string
  53. }
  54. //语法语义规则模型
  55. type t_scd_scl_check struct {
  56. Id int64 `orm:"pk"`
  57. CheckName string
  58. CheckType string
  59. HintText string
  60. ApplyStandard string
  61. ApplyStandardNo string
  62. ObjectType string
  63. ObjectName string
  64. FuncName string
  65. CheckDesc string
  66. CheckArea string
  67. AlertLevel string
  68. NodePath string
  69. IsExists string
  70. IsRef string
  71. IsNotnull string
  72. DataType string
  73. MinLen string
  74. MaxLen string
  75. MinValue string
  76. MaxValue string
  77. IsuniqueByParent string
  78. IsuniqueByGlobal string
  79. ConstValue string
  80. EmunValue string
  81. RegexpValue string
  82. Enable string
  83. CreatedBy int
  84. CreatedTime string
  85. }
  86. //逻辑规则模型.(已不使用)
  87. type t_scd_node_check struct {
  88. Id int64 `orm:"pk"`
  89. CheckObject string
  90. CheckDesc string
  91. CheckArea string
  92. AlertLevel string
  93. IsExists string
  94. IsRef string
  95. IsUnique string
  96. HintText string
  97. Enable string
  98. CreatedBy int
  99. CreatedTime string
  100. }
  101. func init() {
  102. orm.RegisterModel(new(t_scd_node_rule_parse))
  103. orm.RegisterModel(new(t_scd_node_check))
  104. orm.RegisterModel(new(t_scd_scl_check))
  105. }
  106. var checktopic = "/jujutong/scd_check_tools/ruleparse"
  107. func (c *ScdNodeRule) SetScdXmlObject(obj *node_attr.SCL) {
  108. c.scdXmlObject = obj
  109. }
  110. func (c *ScdNodeRule) TestCheckRule() {
  111. c.scdXmlObject, _ = new(ScdParse).GetScdXmlObjectBySCDID(tools.IsEmpty(c.ScdID))
  112. if c.scdXmlObject == nil {
  113. logger.Logger.Error(errors.New("无效的SCD"))
  114. mqtt.PublishMessage(fmt.Sprintf("%s/%d", checktopic, c.ScdID), `{"code":0,"scdid":"`+tools.IsEmpty(c.ScdID)+`","state":0,"msg":"无效的SCD"}`)
  115. return
  116. }
  117. if _, h := global.CheckingScd.Load(c.ScdID); h {
  118. logger.Logger.Debug(fmt.Sprintf("%d文件正在校验中", c.ScdID))
  119. mqtt.PublishMessage(fmt.Sprintf("%s/%d", checktopic, c.ScdID), `{"code":0,"scdid":"`+tools.IsEmpty(c.ScdID)+`","state":0,"msg":"该SCD正在校验中"}`)
  120. return
  121. }
  122. c.doiMap = &sync.Map{}
  123. c.daMap = &sync.Map{}
  124. c.lnodeTypeMap = &sync.Map{}
  125. c.doTypeMap = &sync.Map{}
  126. c.daTypeMap = &sync.Map{}
  127. c.NodeRuleList = map[string]orm.Params{}
  128. c.NodeRuleFunctionList = []orm.Params{}
  129. db := orm.NewOrm()
  130. lst := []orm.Params{}
  131. db.Raw("select * from t_scd_scl_check where enable=1").Values(&lst)
  132. for _, r := range lst {
  133. //object_name := r["object_name"].(string)
  134. //object_type := r["object_type"].(string)
  135. checkname := tools.IsEmpty(r["check_name"])
  136. if checkname != "" {
  137. c.NodeRuleList[checkname] = r
  138. }
  139. }
  140. mqtt.PublishMessage(fmt.Sprintf("%s/%d", checktopic, c.ScdID), `{"code":1,"scdid":"`+tools.IsEmpty(c.ScdID)+`","state":0,"msg":"SCD正在校验中"}`)
  141. global.CheckingScd.Store(c.ScdID, "1")
  142. c.StartFunctionNodeParse()
  143. }
  144. //查询规则定义列表
  145. func (c *ScdNodeRule) GetDefList(param map[string]interface{}, pageno, pagesize int) ([]orm.Params, int, error) {
  146. db := orm.NewOrm()
  147. rule_type := param["rule_type"]
  148. sqlParams := []interface{}{}
  149. sql := "select t.*,ifnull(c.name,'其它') check_type_name from t_scd_scl_check t left join global_const_code c on t.check_type=c.id and c.parentcode='checkrule_type' where 1=1"
  150. if v1, ok := param["rule_id"]; ok {
  151. v := tools.IsEmpty(v1)
  152. if v != "" {
  153. sql = sql + " and t.id=?"
  154. sqlParams = append(sqlParams, v)
  155. }
  156. }
  157. if v1, ok := param["check_type"]; ok {
  158. v := tools.IsEmpty(v1)
  159. if v != "" {
  160. sql = sql + " and t.check_type=?"
  161. sqlParams = append(sqlParams, v)
  162. }
  163. }
  164. if v1, ok := param["check_name"]; ok {
  165. v := tools.IsEmpty(v1)
  166. if v != "" {
  167. sql = sql + " and t.check_name like ?"
  168. sqlParams = append(sqlParams, "%"+v+"%")
  169. }
  170. }
  171. if v1, ok := param["enable"]; ok {
  172. v := tools.IsEmpty(v1)
  173. if v != "" {
  174. sql = sql + " and t.enable=?"
  175. sqlParams = append(sqlParams, v)
  176. }
  177. }
  178. if v1, ok := param["object_type"]; ok {
  179. v := tools.IsEmpty(v1)
  180. if v != "" {
  181. sql = sql + " and t.object_type=?"
  182. sqlParams = append(sqlParams, v)
  183. }
  184. }
  185. if v1, ok := param["object_name"]; ok {
  186. v := tools.IsEmpty(v1)
  187. if v != "" {
  188. if rule_type == "logic" {
  189. sql = sql + " and t.check_object like ?"
  190. sqlParams = append(sqlParams, v+"%")
  191. } else {
  192. sql = sql + " and t.object_name like ?"
  193. sqlParams = append(sqlParams, v+"%")
  194. }
  195. }
  196. }
  197. if v1, ok := param["apply_standard"]; ok {
  198. v := tools.IsEmpty(v1)
  199. if v != "" {
  200. sql = sql + " and t.apply_standard like ?"
  201. sqlParams = append(sqlParams, "%"+v+"%")
  202. }
  203. }
  204. if v1, ok := param["alert_level"]; ok {
  205. v := tools.IsEmpty(v1)
  206. if v != "" {
  207. sql = sql + " and t.alert_level=?"
  208. sqlParams = append(sqlParams, v)
  209. }
  210. }
  211. limit := fmt.Sprintf(" order by t.check_type desc,t.id limit %d,%d", (pageno-1)*pagesize, pagesize)
  212. rowset := []orm.Params{}
  213. _, err := db.Raw(sql+limit, sqlParams).Values(&rowset)
  214. if err != nil {
  215. logger.Logger.Error(err, fmt.Sprintf("SQL:%s 参数:%+v", sql+limit, sqlParams))
  216. return nil, 0, err
  217. }
  218. totalSql := "select count(1) cnt " + sql[strings.Index(sql, "from "):]
  219. tmpRowset := []orm.Params{}
  220. _, err = db.Raw(totalSql, sqlParams).Values(&tmpRowset)
  221. if err != nil {
  222. logger.Logger.Error(err, fmt.Sprintf("SQL:%s 参数:%+v", totalSql, sqlParams))
  223. return nil, 0, err
  224. }
  225. totalCnt, _ := strconv.Atoi(tools.IsEmpty(tmpRowset[0]["cnt"]))
  226. return rowset, totalCnt, err
  227. }
  228. //删除指定的规则定义
  229. func (c *ScdNodeRule) DeleteRuleDef(id, rule_type string) error {
  230. db := orm.NewOrm()
  231. sql := ""
  232. sql2 := ""
  233. if rule_type == "logic" {
  234. //逻辑规则
  235. sql = "delete from t_scd_node_check t where id=?"
  236. sql2 = "delete from t_scd_node_rule_parse where rule_target='node' and rule_id=?"
  237. } else {
  238. //语法规则
  239. sql = "delete from t_scd_scl_check t where id=?"
  240. sql2 = "delete from t_scd_node_rule_parse where rule_target='attr' and rule_id=?"
  241. }
  242. dblog := new(SystemLog)
  243. dblog.SetUserInfo(c.GetUserInfo())
  244. dblog.Audittype = enum.AuditType_admin_rule
  245. dblog.Logtype = enum.LogType_Delete
  246. dblog.Eventtype = enum.OptEventType_Bus
  247. dblog.Eventlevel = enum.OptEventLevel_Hight
  248. _, err := db.Raw(sql, id).Exec()
  249. if err != nil {
  250. logger.Logger.Error(err)
  251. dblog.Description = fmt.Sprintf("删除scd校验规则(id=%s)失败:%s", id, err.Error())
  252. dblog.Fail2()
  253. return err
  254. }
  255. _, err = db.Raw(sql2, id).Exec()
  256. if err != nil {
  257. logger.Logger.Error(err)
  258. dblog.Description = fmt.Sprintf("删除scd校验规则(id=%s)失败:%s", id, err.Error())
  259. dblog.Fail2()
  260. return err
  261. }
  262. dblog.Description = fmt.Sprintf("删除scd校验规则(id=%s)成功", id)
  263. dblog.Success2()
  264. return nil
  265. }
  266. //添加新的规则定义
  267. func (c *ScdNodeRule) AddRuleDef(param map[string]string, rule_type string) error {
  268. db := orm.NewOrm()
  269. id, _ := strconv.Atoi(param["id"])
  270. dblog := new(SystemLog)
  271. dblog.SetUserInfo(c.GetUserInfo())
  272. dblog.Audittype = enum.AuditType_admin_rule
  273. dblog.Logtype = enum.LogType_Insert
  274. dblog.Eventtype = enum.OptEventType_Bus
  275. dblog.Eventlevel = enum.OptEventLevel_Hight
  276. if rule_type == "logic" {
  277. //逻辑规则
  278. mo := t_scd_node_check{}
  279. mo.CreatedBy, _ = strconv.Atoi(c.GetUserId())
  280. mo.CreatedTime = tools.NowTime()
  281. mo.Enable = param["enable"]
  282. mo.AlertLevel = param["alert_level"]
  283. mo.CheckArea = param["check_area"]
  284. mo.CheckDesc = param["check_desc"]
  285. mo.CheckObject = param["check_object"]
  286. mo.HintText = param["hint_text"]
  287. mo.IsExists = param["is_exists"]
  288. mo.IsRef = param["is_ref"]
  289. mo.IsUnique = param["is_unique"]
  290. if id != 0 {
  291. mo.Id = int64(id)
  292. _, err := db.Update(&mo)
  293. if err != nil {
  294. dblog.Description = fmt.Sprintf("编辑scd逻辑校验规则(id=%d)失败:%s", id, err.Error())
  295. dblog.Fail2()
  296. return err
  297. }
  298. dblog.Description = fmt.Sprintf("编辑scd逻辑校验规则(id=%d)成功", id)
  299. dblog.Success2()
  300. return nil
  301. } else {
  302. _, err := db.Insert(&mo)
  303. if err != nil {
  304. dblog.Description = fmt.Sprintf("新增scd逻辑校验规则(id=%d)失败:%s", id, err.Error())
  305. dblog.Fail2()
  306. return err
  307. }
  308. dblog.Description = fmt.Sprintf("新增scd逻辑校验规则(id=%d)成功", id)
  309. dblog.Success2()
  310. return nil
  311. }
  312. } else {
  313. //语法规则
  314. mo := t_scd_scl_check{}
  315. mo.FuncName = param["func_name"]
  316. mo.CheckType = tools.IsEmpty(param["check_type"], "0")
  317. mo.CheckName = param["check_name"]
  318. mo.CheckArea = param["check_area"]
  319. mo.CheckDesc = param["check_desc"]
  320. mo.HintText = param["hint_text"]
  321. mo.ApplyStandard = tools.IsEmpty(param["apply_standard"], "")
  322. mo.ApplyStandardNo = tools.IsEmpty(param["apply_standard_no"], "")
  323. mo.IsExists = tools.IsEmpty(param["is_exists"], "0")
  324. mo.IsRef = tools.IsEmpty(param["is_ref"], "0")
  325. mo.AlertLevel = param["alert_level"]
  326. mo.ConstValue = param["const_value"]
  327. mo.CreatedBy, _ = strconv.Atoi(c.GetUserId())
  328. mo.CreatedTime = tools.NowTime()
  329. mo.DataType = param["data_type"]
  330. mo.EmunValue = param["emun_value"]
  331. mo.Enable = param["enable"]
  332. mo.IsNotnull = tools.IsEmpty(param["is_notnull"], "0")
  333. mo.IsuniqueByGlobal = tools.IsEmpty(param["isunique_by_global"], "0")
  334. mo.IsuniqueByParent = tools.IsEmpty(param["isunique_by_parent"], "0")
  335. mo.MaxLen = tools.IsEmpty(param["max_len"], "0")
  336. mo.MinLen = tools.IsEmpty(param["min_len"], "0")
  337. mo.MaxValue = tools.IsEmpty(param["max_value"], "")
  338. mo.MinValue = tools.IsEmpty(param["min_value"], "")
  339. mo.NodePath = param["node_path"]
  340. mo.ObjectName = param["object_name"]
  341. mo.ObjectType = param["object_type"]
  342. mo.RegexpValue = param["regexp_value"]
  343. syslog := new(SystemLog)
  344. syslog.SetUserInfo(c.GetUserInfo())
  345. mo.CreatedBy, _ = strconv.Atoi(c.GetUserId())
  346. mo.CreatedTime = tools.NowTime()
  347. if id != 0 {
  348. mo.Id = int64(id)
  349. _, err := db.Update(&mo)
  350. if err != nil {
  351. dblog.Description = fmt.Sprintf("编辑scd语法语义校验规则(id=%d)失败:%s", id, err.Error())
  352. dblog.Fail2()
  353. //syslog.Fail("规则管理", fmt.Sprintf("编辑scd语法语义校验规则(id=%d)失败:%s", id, err.Error()))
  354. //SaveSyslog(fmt.Sprintf("编辑scd语法语义校验规则(id=%d)失败:%s", id, err.Error()), "规则管理", false, tools.IsEmpty(c.UserInfo["name"]))
  355. return err
  356. }
  357. dblog.Description = fmt.Sprintf("编辑scd语法语义校验规则(id=%d)成功", id)
  358. dblog.Fail2()
  359. return nil
  360. } else {
  361. _, err := db.Insert(&mo)
  362. if err != nil {
  363. dblog.Description = fmt.Sprintf("新增scd语法语义校验规则(id=%d)失败:%s", id, err.Error())
  364. dblog.Fail2()
  365. return err
  366. }
  367. dblog.Description = fmt.Sprintf("新增scd语法语义校验规则(id=%d)成功", id)
  368. dblog.Success2()
  369. return nil
  370. }
  371. }
  372. }
  373. //按校验等级统计数量
  374. func (c *ScdNodeRule) ResultStatByLevel(scdname, scdpath, ied_name, node_name, node_id string) ([]orm.Params, error) {
  375. if c.ScdID == 0 {
  376. fline := string(os.PathSeparator)
  377. fileFirstChar := scdpath[0:1]
  378. if fileFirstChar != "." {
  379. if fileFirstChar == fline {
  380. scdpath = "." + scdpath
  381. } else {
  382. scdpath = "." + fline + scdpath
  383. }
  384. }
  385. if scdname == "" && scdpath == "" {
  386. return nil, errors.New("scd名称和路径不能为空")
  387. }
  388. db := orm.NewOrm()
  389. sql := "select id from t_scd_scl where scd_name=? and path=? limit 0,1"
  390. tmpRowset := []orm.Params{}
  391. db.Raw(sql, scdname, scdpath).Values(&tmpRowset)
  392. if len(tmpRowset) == 0 {
  393. return nil, errors.New("无效的scd名称和路径")
  394. }
  395. cScdID, _ := strconv.Atoi(tools.IsEmpty(tmpRowset[0]["id"]))
  396. c.ScdID = int64(cScdID)
  397. }
  398. where := ""
  399. param := []interface{}{}
  400. param = append(param, c.ScdID)
  401. if ied_name != "" {
  402. where += " and t.ied_name=?"
  403. param = append(param, ied_name)
  404. }
  405. if node_name != "" {
  406. if node_name == "area" {
  407. //间隔
  408. where += " and EXISTS(select 1 from t_area_ied_relation a where a.ied_name=t.ied_name and a.area_id=? )"
  409. param = append(param, node_id)
  410. } else if node_name == "voltage_level" {
  411. //电压等级
  412. where += " and EXISTS(select 1 from t_substation_area v1, t_area_ied_relation v2 where v1.id=v2.area_id and v2.ied_name=t.ied_name and v1.voltage_level=? and v1.scd_id=? )"
  413. param = append(param, node_id)
  414. param = append(param, c.ScdID)
  415. } else if node_name == "Communication" {
  416. //通讯类
  417. where += " and t1.object_name=?"
  418. param = append(param, "Communication")
  419. } else if node_name == "DataTypeTemplates" {
  420. //通讯类
  421. where += " and t1.object_name=?"
  422. param = append(param, "DataTypeTemplates")
  423. } else if node_name == "SCLSyntax" {
  424. //语法类
  425. where += " and t1.object_name=?"
  426. param = append(param, "SCLSyntax")
  427. }
  428. }
  429. db := orm.NewOrm()
  430. sql := `select t1.alert_level, count(0) cnt from t_scd_scl_check t1 ,t_scd_node_rule_parse t where t.scd_id=? ` + where + ` and t.rule_id=t1.id GROUP BY alert_level`
  431. rowset := []orm.Params{}
  432. _, err := db.Raw(sql, param).Values(&rowset)
  433. if err != nil {
  434. logger.Logger.Error(err, fmt.Sprintf("SQL:%s 参数:%+v", sql, c.ScdID))
  435. }
  436. return rowset, err
  437. }
  438. //汇总统计校验结果数量
  439. func (c *ScdNodeRule) SumCheckResult() ([]orm.Params, error) {
  440. db := orm.NewOrm()
  441. sql := `SELECT t1.object_name, t1.alert_level ,a.ied_name from t_scd_node_rule_parse a ,t_scd_scl_check t1 where a.rule_id=t1.id and a.scd_id=? GROUP BY t1.object_name,a.ied_name ,t1.alert_level`
  442. rowset := []orm.Params{}
  443. _, err := db.Raw(sql, c.ScdID).Values(&rowset)
  444. if err != nil {
  445. logger.Logger.Error(err, fmt.Sprintf("SQL:%s 参数:%+v", sql, []interface{}{c.ScdID, c.ScdID, c.ScdID}))
  446. return rowset, err
  447. }
  448. return rowset, nil
  449. }
  450. //统计指定站当前scd的正确率
  451. func (c *ScdNodeRule) RightRateStat(stationid string) (orm.Params, error) {
  452. db := orm.NewOrm()
  453. sql := `select a.* from ( select t1.node_cnt nodetotal, max(t2.id) station_id,max(t2.AREA_NAME) station_name,max(t1.id) scd_id, count(t.id) cnt
  454. from t_scd_node_rule_parse t,t_scd_scl t1,t_data_area t2
  455. where t.scd_id=t1.id and t1.station_id=t2.id and t1.station_id=? and t1.version like '在运版%') a `
  456. rowset := []orm.Params{}
  457. _, err := db.Raw(sql, stationid).Values(&rowset)
  458. if err != nil {
  459. logger.Logger.Error(err, fmt.Sprintf("SQL:%s 参数:%+v", sql, stationid))
  460. return nil, err
  461. }
  462. if len(rowset) == 0 {
  463. return nil, nil
  464. }
  465. return rowset[0], nil
  466. }
  467. func (c *ScdNodeRule) ExportData(level, ied_name string) ([]orm.Params, error) {
  468. sql := "select t.*,g.alert_level,g.apply_standard,g.apply_standard_no from t_scd_node_rule_parse t inner join t_scd_scl_check g on t.rule_id=g.id where t.scd_id=? and t.rule_target='attr' "
  469. param := []interface{}{}
  470. param = append(param, c.ScdID)
  471. if level != "" {
  472. sql += " and g.alert_level=? "
  473. param = append(param, level)
  474. }
  475. if ied_name != "" {
  476. sql += " and t.ied_name=?"
  477. param = append(param, ied_name)
  478. }
  479. limit := fmt.Sprintf(" order by id ")
  480. rowset := []orm.Params{}
  481. db := orm.NewOrm()
  482. _, err := db.Raw(sql+limit, param).Values(&rowset)
  483. if err != nil {
  484. logger.Logger.Error(err, fmt.Sprintf("SQL:%s 参数:%+v", sql+limit, param))
  485. }
  486. return rowset, err
  487. }
  488. //查询校验规则列表
  489. //level 规则检查结果级别 为空时查询所有的结果
  490. func (c *ScdNodeRule) ResultList(scdname, scdpath string, level, ied_name, node_name, node_id string, pageno, pagesize int) ([]orm.Params, int, error) {
  491. if c.ScdID == 0 {
  492. fline := string(os.PathSeparator)
  493. fileFirstChar := scdpath[0:1]
  494. if fileFirstChar != "." {
  495. if fileFirstChar == fline {
  496. scdpath = "." + scdpath
  497. } else {
  498. scdpath = "." + fline + scdpath
  499. }
  500. }
  501. if scdname == "" && scdpath == "" {
  502. return nil, 0, errors.New("scd名称和路径不能为空")
  503. }
  504. db := orm.NewOrm()
  505. sql := "select id from t_scd_scl where scd_name=? and path=? limit 0,1"
  506. tmpRowset := []orm.Params{}
  507. db.Raw(sql, scdname, scdpath).Values(&tmpRowset)
  508. if len(tmpRowset) == 0 {
  509. return nil, 0, errors.New("无效的scd名称和路径")
  510. }
  511. cScdID, _ := strconv.Atoi(tools.IsEmpty(tmpRowset[0]["id"]))
  512. c.ScdID = int64(cScdID)
  513. }
  514. sql := "select t.*,g.alert_level,g.apply_standard,g.apply_standard_no from t_scd_node_rule_parse t inner join t_scd_scl_check g on t.rule_id=g.id where t.scd_id=? "
  515. where := ""
  516. param := []interface{}{}
  517. param = append(param, c.ScdID)
  518. if level != "" {
  519. where += " and g.alert_level=? "
  520. param = append(param, level)
  521. }
  522. if ied_name != "" {
  523. where += " and t.ied_name=?"
  524. param = append(param, ied_name)
  525. }
  526. if node_name != "" {
  527. if node_name == "area" {
  528. //间隔
  529. where += " and EXISTS(select 1 from t_area_ied_relation a where a.ied_name=t.ied_name and a.area_id=? )"
  530. param = append(param, node_id)
  531. } else if node_name == "voltage_level" {
  532. //电压等级
  533. where += " and EXISTS(select 1 from t_substation_area v1, t_area_ied_relation v2 where v1.id=v2.area_id and v2.ied_name=t.ied_name and v1.voltage_level=? and v1.scd_id=? )"
  534. param = append(param, node_id)
  535. param = append(param, c.ScdID)
  536. } else if node_name == "Communication" {
  537. //通讯类
  538. where += " and g.object_name=?"
  539. param = append(param, "Communication")
  540. } else if node_name == "DataTypeTemplates" {
  541. //通讯类
  542. where += " and g.object_name=?"
  543. param = append(param, "DataTypeTemplates")
  544. } else if node_name == "SCLSyntax" {
  545. //语法类
  546. where += " and g.object_name=?"
  547. param = append(param, "SCLSyntax")
  548. }
  549. }
  550. sql += where
  551. limit := fmt.Sprintf(" order by g.alert_level limit %d,%d", (pageno-1)*pagesize, pagesize)
  552. rowset := []orm.Params{}
  553. db := orm.NewOrm()
  554. _, err := db.Raw(sql+limit, param).Values(&rowset)
  555. if err != nil {
  556. logger.Logger.Error(err, fmt.Sprintf("SQL:%s 参数:%+v", sql+limit, param))
  557. return rowset, 0, err
  558. }
  559. totalNum := 0
  560. if err == nil {
  561. tmpRowset := []orm.Params{}
  562. _, err = db.Raw(strings.ReplaceAll(sql, "t.*,g.alert_level", "count(1) cnt"), param).Values(&tmpRowset)
  563. if err != nil {
  564. logger.Logger.Error(err, fmt.Sprintf("SQL:%s 参数:%+v", sql, param))
  565. } else if len(tmpRowset) > 0 {
  566. for _, r1 := range tmpRowset {
  567. totalNumi, _ := strconv.Atoi(tools.IsEmpty(r1["cnt"]))
  568. totalNum += totalNumi
  569. }
  570. }
  571. }
  572. return rowset, totalNum, err
  573. }
  574. //启动自定义校验
  575. func (c *ScdNodeRule) StartFunctionNodeParse() {
  576. new(TaskMgr).SetStep(tools.IsEmpty(c.ScdID), enum.TaskStep_SCD_rule_parse.Code(), 1)
  577. c.CheckFunc_header_number(nil)
  578. c.CheckFunc_header_name_structure(nil)
  579. c.CheckFunc_header_toolid(nil)
  580. c.CheckFunc_header_complete(nil)
  581. c.CheckFunc_header_version(nil)
  582. c.CheckFunc_header_hitem_complete(nil)
  583. c.CheckFunc_substation_number(nil)
  584. c.CheckFunc_substation_name(nil)
  585. c.CheckFunc_voltagelevel_complete(nil)
  586. c.CheckFunc_communication_connectedap(nil)
  587. dATypeMap := c.CheckFunc_datatypetemplates(nil)
  588. c.CheckFunc_ied(dATypeMap)
  589. new(TaskMgr).SetStep(tools.IsEmpty(c.ScdID), enum.TaskStep_SCD_rule_parse.Code(), 2)
  590. //在crc校验完成后将所有校验结果写入数据库
  591. go c.CheckFunc_crc()
  592. c.doiMap = nil
  593. c.daMap = nil
  594. }
  595. //----------------------自定义的规则校验方法------------------
  596. func (c *ScdNodeRule) CheckFunc_header_number(para orm.Params) {
  597. ruleid := c.getRuleIdByName("Header元素完备性校验")
  598. if ruleid != "" {
  599. if c.scdXmlObject.Header == nil {
  600. parse_result := fmt.Sprintf("Header元素缺失")
  601. r := map[string]interface{}{"scdid": c.ScdID, "lineno": c.scdXmlObject.Lineno, "ruleid": ruleid, "nodeid": c.scdXmlObject.NodeId, "parse_result": parse_result}
  602. c.AppendPaseResult(r)
  603. }
  604. }
  605. }
  606. func (c *ScdNodeRule) CheckFunc_header_name_structure(para orm.Params) {
  607. ruleid := c.getRuleIdByName("Header元素完备性校验")
  608. if ruleid != "" {
  609. if c.scdXmlObject.Header != nil && c.scdXmlObject.Header.NameStructure != "IEDName" {
  610. parse_result := fmt.Sprintf("Header元素中的属性nameStructure值不正确,其值只能为IEDName")
  611. r := map[string]interface{}{"scdid": c.ScdID, "lineno": c.scdXmlObject.Header.Lineno, "ruleid": ruleid, "nodeid": c.scdXmlObject.Header.NodeId, "parse_result": parse_result}
  612. //唯一性检查未通过
  613. c.AppendPaseResult(r)
  614. }
  615. }
  616. }
  617. func (c *ScdNodeRule) CheckFunc_header_toolid(para orm.Params) {
  618. ruleid := c.getRuleIdByName("toolID属性检查")
  619. if ruleid != "" {
  620. if c.scdXmlObject.Header != nil && c.scdXmlObject.Header.ToolID == "" {
  621. parse_result := fmt.Sprintf("Header元素中的属性toolID配置不规范,其值为空")
  622. r := map[string]interface{}{"scdid": c.ScdID, "lineno": c.scdXmlObject.Header.Lineno, "ruleid": ruleid, "nodeid": c.scdXmlObject.Header.NodeId, "parse_result": parse_result}
  623. //唯一性检查未通过
  624. c.AppendPaseResult(r)
  625. }
  626. if c.scdXmlObject.Header != nil && c.scdXmlObject.Header.ToolID != "" {
  627. ary := strings.Split(c.scdXmlObject.Header.ToolID, "_")
  628. if len(ary) != 3 {
  629. parse_result := fmt.Sprintf("Header元素属性toolID配置不规范,格式应为:厂商编码_配置工具名称_工具软件版本")
  630. r := map[string]interface{}{"scdid": c.ScdID, "lineno": c.scdXmlObject.Header.Lineno, "ruleid": ruleid, "nodeid": c.scdXmlObject.Header.NodeId, "parse_result": parse_result}
  631. //唯一性检查未通过
  632. c.AppendPaseResult(r)
  633. }
  634. }
  635. }
  636. }
  637. //完整性校验
  638. func (c *ScdNodeRule) CheckFunc_header_complete(para orm.Params) {
  639. if c.scdXmlObject.Header == nil {
  640. return
  641. }
  642. ruleid := c.getRuleIdByName("Header元素完备性校验")
  643. if ruleid != "" {
  644. if c.scdXmlObject.Header.Id == "" {
  645. //验证不通过
  646. parse_result := fmt.Sprintf("Header元素中id属性缺失")
  647. r := map[string]interface{}{"scdid": c.ScdID, "lineno": c.scdXmlObject.Lineno, "ruleid": ruleid, "nodeid": c.scdXmlObject.Header.NodeId, "parse_result": parse_result}
  648. //唯一性检查未通过
  649. c.AppendPaseResult(r)
  650. }
  651. if c.scdXmlObject.Header.Version == "" {
  652. //验证不通过
  653. parse_result := fmt.Sprintf("Header元素中version属性缺失")
  654. r := map[string]interface{}{"scdid": c.ScdID, "lineno": c.scdXmlObject.Header.Lineno, "ruleid": ruleid, "nodeid": c.scdXmlObject.Header.NodeId, "parse_result": parse_result}
  655. //唯一性检查未通过
  656. c.AppendPaseResult(r)
  657. }
  658. if c.scdXmlObject.Header.Revision == "" {
  659. //验证不通过
  660. parse_result := fmt.Sprintf("Header元素中revision属性缺失")
  661. r := map[string]interface{}{"scdid": c.ScdID, "lineno": c.scdXmlObject.Header.Lineno, "ruleid": ruleid, "nodeid": c.scdXmlObject.Header.NodeId, "parse_result": parse_result}
  662. //唯一性检查未通过
  663. c.AppendPaseResult(r)
  664. }
  665. }
  666. }
  667. func (c *ScdNodeRule) CheckFunc_header_version(para orm.Params) {
  668. if c.scdXmlObject.Header == nil {
  669. return
  670. }
  671. ruleid := c.getRuleIdByName("Header版本一致性")
  672. if ruleid != "" {
  673. ver := c.scdXmlObject.Header.Version
  674. rever := c.scdXmlObject.Header.Revision
  675. if c.scdXmlObject.Header.History != nil {
  676. hitems := c.scdXmlObject.Header.History.Hitem
  677. if len(hitems) > 0 {
  678. lastHitem := hitems[len(hitems)-1]
  679. if ver != lastHitem.Version && rever != lastHitem.Revision {
  680. //验证不通过
  681. parse_result := fmt.Sprintf("Header中的version=%s、revision=%s与History中的最后一个Item不一致", ver, rever)
  682. r := map[string]interface{}{"scdid": c.ScdID, "lineno": lastHitem.Lineno, "ruleid": ruleid, "nodeid": c.scdXmlObject.Header.NodeId, "parse_result": parse_result}
  683. //唯一性检查未通过
  684. c.AppendPaseResult(r)
  685. }
  686. }
  687. }
  688. }
  689. }
  690. func (c *ScdNodeRule) CheckFunc_header_hitem_complete(para orm.Params) {
  691. if c.scdXmlObject.Header == nil {
  692. return
  693. }
  694. if c.scdXmlObject.Header.History != nil {
  695. hitems := c.scdXmlObject.Header.History.Hitem
  696. if len(hitems) > 0 {
  697. ver := ""
  698. rever := ""
  699. hitemruleid1 := c.getRuleIdByName("Hitem元素完备性校验")
  700. hitemruleid2 := c.getRuleIdByName("History版本连续性")
  701. for _, hitem := range hitems {
  702. if hitemruleid1 != "" {
  703. errattr := []string{}
  704. if hitem.Version == "" {
  705. errattr = append(errattr, "version")
  706. }
  707. if hitem.Revision == "" {
  708. errattr = append(errattr, "revision")
  709. }
  710. if hitem.When == "" {
  711. errattr = append(errattr, "when")
  712. }
  713. if len(errattr) > 0 {
  714. //验证不通过
  715. parse_result := fmt.Sprintf("Hitem元素中%s属性缺失", strings.Join(errattr, ","))
  716. r := map[string]interface{}{"scdid": c.ScdID, "lineno": hitem.Lineno, "ruleid": hitemruleid1, "nodeid": hitem.NodeId, "parse_result": parse_result}
  717. c.AppendPaseResult(r)
  718. }
  719. }
  720. if hitemruleid2 != "" {
  721. //连续性判断
  722. if ver == "" {
  723. ver = hitem.Version
  724. rever = hitem.Revision
  725. } else {
  726. v1, _ := strconv.Atoi(hitem.Version)
  727. v2, _ := strconv.Atoi(hitem.Revision)
  728. v3, _ := strconv.Atoi(ver)
  729. v4, _ := strconv.Atoi(rever)
  730. if v1 == v3 && int(float64(v2)-float64(v4)-0.1) != 0 {
  731. //验证不通过
  732. parse_result := fmt.Sprintf("History版本元素中版本信息不连续:version=%s,revison=%s->version=%s,revison=%s", ver, rever, hitem.Version, hitem.Revision)
  733. r := map[string]interface{}{"scdid": c.ScdID, "lineno": hitem.Lineno, "ruleid": hitemruleid2, "nodeid": hitem.NodeId, "parse_result": parse_result}
  734. c.AppendPaseResult(r)
  735. }
  736. if v1 != v3 && hitem.Revision != "1.0" {
  737. //验证不通过
  738. parse_result := fmt.Sprintf("History版本元素中版本信息不规范:文件版本增加时,文件修订版本应置为1.0")
  739. r := map[string]interface{}{"scdid": c.ScdID, "lineno": hitem.Lineno, "ruleid": hitemruleid2, "nodeid": hitem.NodeId, "parse_result": parse_result}
  740. c.AppendPaseResult(r)
  741. }
  742. ver = hitem.Version
  743. rever = hitem.Revision
  744. }
  745. }
  746. }
  747. }
  748. }
  749. }
  750. func (c *ScdNodeRule) CheckFunc_substation_number(para orm.Params) {
  751. ruleid := c.getRuleIdByName("Substation完备性校验")
  752. if ruleid != "" {
  753. if c.scdXmlObject.Substation == nil {
  754. //验证不通过
  755. parse_result := fmt.Sprintf("Substation元素缺失")
  756. r := map[string]interface{}{"scdid": c.ScdID, "lineno": c.scdXmlObject.Lineno, "ruleid": ruleid, "nodeid": c.scdXmlObject.NodeId, "parse_result": parse_result}
  757. c.AppendPaseResult(r)
  758. return
  759. }
  760. }
  761. ruleid = c.getRuleIdByName("Substation对象缺失CIME-dtype元素")
  762. ruleid2 := c.getRuleIdByName("Substation对象缺失CIME-area元素")
  763. if ruleid != "" || ruleid2 != "" {
  764. if len(c.scdXmlObject.Substation.Private) == 0 {
  765. parse_result := fmt.Sprintf("Substation对象缺失CIME-dtype元素")
  766. r := map[string]interface{}{"scdid": c.ScdID, "lineno": c.scdXmlObject.Substation.Lineno, "ruleid": ruleid, "nodeid": c.scdXmlObject.Substation.NodeId, "parse_result": parse_result}
  767. c.AppendPaseResult(r)
  768. return
  769. }
  770. isFound := false
  771. isFoundCIMEArea := false
  772. for _, pr := range c.scdXmlObject.Substation.Private {
  773. if pr.Type == "CIME-dtype" {
  774. isFound = true
  775. ruleid3 := c.getRuleIdByName("Substation对象对应CIME-dtype中属性缺失")
  776. if ruleid3 != "" && (pr.Desc == "") {
  777. parse_result := fmt.Sprintf("Substation对象对应CIME-dtype中属性(desc)缺失")
  778. r := map[string]interface{}{"scdid": c.ScdID, "lineno": pr.Lineno, "ruleid": ruleid3, "nodeid": c.scdXmlObject.Substation.NodeId, "parse_result": parse_result}
  779. c.AppendPaseResult(r)
  780. }
  781. }
  782. if pr.Type == "CIME-area" {
  783. isFoundCIMEArea = true
  784. ruleid3 := c.getRuleIdByName("Substation对象对应CIME-area中属性缺失")
  785. if ruleid3 != "" && (pr.Name == "" || pr.Desc == "") {
  786. parse_result := fmt.Sprintf("Substation对象对应CIME-area中属性(name或desc)缺失")
  787. r := map[string]interface{}{"scdid": c.ScdID, "lineno": pr.Lineno, "ruleid": ruleid3, "nodeid": c.scdXmlObject.Substation.NodeId, "parse_result": parse_result}
  788. c.AppendPaseResult(r)
  789. }
  790. }
  791. }
  792. if !isFound {
  793. parse_result := fmt.Sprintf("Substation对象缺失CIME-dtype元素")
  794. r := map[string]interface{}{"scdid": c.ScdID, "lineno": c.scdXmlObject.Substation.Lineno, "ruleid": ruleid, "nodeid": c.scdXmlObject.Substation.NodeId, "parse_result": parse_result}
  795. c.AppendPaseResult(r)
  796. }
  797. if !isFoundCIMEArea {
  798. parse_result := fmt.Sprintf("Substation对象缺失CIME-area元素")
  799. r := map[string]interface{}{"scdid": c.ScdID, "lineno": c.scdXmlObject.Substation.Lineno, "ruleid": ruleid2, "nodeid": c.scdXmlObject.Substation.NodeId, "parse_result": parse_result}
  800. c.AppendPaseResult(r)
  801. }
  802. }
  803. }
  804. func (c *ScdNodeRule) CheckFunc_substation_name(para orm.Params) {
  805. if c.scdXmlObject.Substation == nil {
  806. return
  807. }
  808. ruleid := c.getRuleIdByName("变电站名称一致性")
  809. if ruleid != "" {
  810. if c.scdXmlObject.Substation.Name != c.scdXmlObject.Header.Id {
  811. //验证不通过
  812. parse_result := fmt.Sprintf("Substation的name(%s)与Header中的id(%s)不一致", c.scdXmlObject.Substation.Name, c.scdXmlObject.Header.Id)
  813. r := map[string]interface{}{"scdid": c.ScdID, "lineno": c.scdXmlObject.Substation.Lineno, "ruleid": ruleid, "nodeid": c.scdXmlObject.Substation.NodeId, "parse_result": parse_result}
  814. c.AppendPaseResult(r)
  815. }
  816. }
  817. }
  818. //VoltageLevel 对象的命名 name 应按“‘额定电压’ kV”形式命名,如“ 1000kV”“110kV”等,并且全站唯一。 desc 描述参照 name 命名方式
  819. func (c *ScdNodeRule) CheckFunc_voltagelevel_complete(para orm.Params) {
  820. if c.scdXmlObject.Substation == nil {
  821. return
  822. }
  823. ruleid1 := c.getRuleIdByName("VoltageLevel命名错误")
  824. ruleid2 := c.getRuleIdByName("VoltageLevel下Voltage缺失")
  825. ruleid3 := c.getRuleIdByName("Voltage对象的取值/属性错误")
  826. ruleid4 := c.getRuleIdByName("SSD关联关系错误")
  827. if len(c.scdXmlObject.Substation.VoltageLevel) == 0 {
  828. parse_result := fmt.Sprintf("Substation中存在层级关系错误:未定义VoltageLevel")
  829. r := map[string]interface{}{"scdid": c.ScdID, "lineno": c.scdXmlObject.Substation.Lineno, "ruleid": ruleid4, "nodeid": c.scdXmlObject.Substation.NodeId, "parse_result": parse_result}
  830. c.AppendPaseResult(r)
  831. return
  832. }
  833. priMap := map[string]string{}
  834. for _, item := range c.scdXmlObject.Substation.VoltageLevel {
  835. name := item.Name
  836. //desc := item.Desc
  837. if ruleid1 != "" {
  838. if _, h := priMap[name]; h {
  839. //验证不通过
  840. parse_result := fmt.Sprintf("VoltageLevel命名错误:name应该全站唯一")
  841. r := map[string]interface{}{"scdid": c.ScdID, "lineno": item.Lineno, "ruleid": ruleid1, "nodeid": item.NodeId, "parse_result": parse_result}
  842. c.AppendPaseResult(r)
  843. continue
  844. }
  845. priMap[name] = ""
  846. if name == "" || len(name) < 3 || !strings.HasSuffix(name, "kV") {
  847. //验证不通过
  848. parse_result := fmt.Sprintf("VoltageLevel命名错误:name应按“‘额定电压’ kV”形式命名,如“1000kV”“110kV”等,并且全站唯一")
  849. r := map[string]interface{}{"scdid": c.ScdID, "lineno": item.Lineno, "ruleid": ruleid1, "nodeid": item.NodeId, "parse_result": parse_result}
  850. c.AppendPaseResult(r)
  851. }
  852. }
  853. if ruleid2 != "" {
  854. if item.Voltage == nil {
  855. //验证不通过
  856. parse_result := fmt.Sprintf("VoltageLevel(%s)下缺失Voltage对象", item.Name)
  857. r := map[string]interface{}{"scdid": c.ScdID, "lineno": item.Lineno, "ruleid": ruleid2, "nodeid": item.NodeId, "parse_result": parse_result}
  858. c.AppendPaseResult(r)
  859. }
  860. }
  861. if ruleid3 != "" && item.Voltage != nil {
  862. if item.Voltage.InnerText != item.Name[0:len(item.Name)-2] {
  863. //验证不通过
  864. parse_result := fmt.Sprintf("VoltageLevel(%s)下属Voltage对象的取值错误", item.Name)
  865. r := map[string]interface{}{"scdid": c.ScdID, "lineno": item.Voltage.Lineno, "ruleid": ruleid3, "nodeid": item.NodeId, "parse_result": parse_result}
  866. c.AppendPaseResult(r)
  867. }
  868. if item.Voltage.Multiplier != "k" {
  869. //验证不通过
  870. parse_result := fmt.Sprintf("VoltageLevel(%s)下属Voltage对象属性(%s=%s)错误", item.Name, "multiplier", item.Voltage.Multiplier)
  871. r := map[string]interface{}{"scdid": c.ScdID, "lineno": item.Voltage.Lineno, "ruleid": ruleid3, "nodeid": item.NodeId, "parse_result": parse_result}
  872. c.AppendPaseResult(r)
  873. }
  874. if item.Voltage.Unit != "V" {
  875. //验证不通过
  876. parse_result := fmt.Sprintf("VoltageLevel(%s)下属Voltage对象属性(%s=%s)错误", item.Name, "unit", item.Voltage.Unit)
  877. r := map[string]interface{}{"scdid": c.ScdID, "lineno": item.Voltage.Lineno, "ruleid": ruleid3, "nodeid": item.NodeId, "parse_result": parse_result}
  878. c.AppendPaseResult(r)
  879. }
  880. }
  881. //Bay校验
  882. if len(item.Bay) > 0 {
  883. ruleid5 := c.getRuleIdByName("Bay对象缺失CIME-dtype元素")
  884. ruleid6 := c.getRuleIdByName("Bay对象对应CIME-dtype中desc属性值错误")
  885. if ruleid5 != "" {
  886. for _, bayrow := range item.Bay {
  887. if bayrow.Private == nil {
  888. parse_result := fmt.Sprintf("Bay对象缺失CIME-dtype元素")
  889. r := map[string]interface{}{"scdid": c.ScdID, "lineno": bayrow.Lineno, "ruleid": ruleid5, "nodeid": c.scdXmlObject.Substation.NodeId, "parse_result": parse_result}
  890. c.AppendPaseResult(r)
  891. } else {
  892. if ruleid6 != "" && bayrow.Private.Desc == "" {
  893. parse_result := fmt.Sprintf("Bay对象对应CIME-dtype中desc属性值错误")
  894. r := map[string]interface{}{"scdid": c.ScdID, "lineno": bayrow.Lineno, "ruleid": ruleid6, "nodeid": c.scdXmlObject.Substation.NodeId, "parse_result": parse_result}
  895. c.AppendPaseResult(r)
  896. }
  897. }
  898. bayRule1 := c.getRuleIdByName("间隔关联逻辑节点不存在")
  899. if len(bayrow.PowerTransformer) > 0 {
  900. ruleid7 := c.getRuleIdByName("PowerTransformer对象命名错误")
  901. ruleid8 := c.getRuleIdByName("PowerTransformer对象type错误")
  902. for _, tmpr := range bayrow.PowerTransformer {
  903. if ruleid7 != "" && (tmpr.Name == "" || !strings.HasPrefix(tmpr.Name, "PTR")) {
  904. parse_result := fmt.Sprintf("PowerTransformer对象命名(%s)错误", tmpr.Name)
  905. r := map[string]interface{}{"scdid": c.ScdID, "lineno": tmpr.Lineno, "ruleid": ruleid7, "nodeid": c.scdXmlObject.Substation.NodeId, "parse_result": parse_result}
  906. c.AppendPaseResult(r)
  907. }
  908. if ruleid8 != "" && tmpr.Type != "PTR" {
  909. parse_result := fmt.Sprintf("PowerTransformer对象(%s)type(%s)不为PTR", tmpr.Name, tmpr.Type)
  910. r := map[string]interface{}{"scdid": c.ScdID, "lineno": tmpr.Lineno, "ruleid": ruleid8, "nodeid": c.scdXmlObject.Substation.NodeId, "parse_result": parse_result}
  911. c.AppendPaseResult(r)
  912. }
  913. if len(tmpr.TransformerWinding) > 0 {
  914. ruleid9 := c.getRuleIdByName("TransformerWinding对象缺失:CIME-voltageLevel")
  915. ruleid10 := c.getRuleIdByName("TransformerWinding对象中CIME-voltageLevel属性错误或缺失")
  916. for _, rw := range tmpr.TransformerWinding {
  917. if ruleid9 != "" && (rw.Private != nil || rw.Private.Type != "CIME-voltageLevel") {
  918. parse_result := fmt.Sprintf("TransformerWinding对象(%s)缺失:CIME-voltageLevel", rw.Name)
  919. r := map[string]interface{}{"scdid": c.ScdID, "lineno": rw.Lineno, "ruleid": ruleid9, "nodeid": c.scdXmlObject.Substation.NodeId, "parse_result": parse_result}
  920. c.AppendPaseResult(r)
  921. }
  922. if ruleid10 != "" && rw.Private != nil && rw.Private.Desc == "" {
  923. parse_result := fmt.Sprintf("TransformerWinding对象(%s)中的CIME-voltageLevel的desc属性缺失", rw.Desc)
  924. r := map[string]interface{}{"scdid": c.ScdID, "lineno": rw.Lineno, "ruleid": ruleid10, "nodeid": c.scdXmlObject.Substation.NodeId, "parse_result": parse_result}
  925. c.AppendPaseResult(r)
  926. }
  927. if ruleid10 != "" && rw.Private != nil && rw.Private.Name == "" {
  928. parse_result := fmt.Sprintf("TransformerWinding对象(%s)中的CIME-voltageLevel的name属性缺失", rw.Name)
  929. r := map[string]interface{}{"scdid": c.ScdID, "lineno": rw.Lineno, "ruleid": ruleid10, "nodeid": c.scdXmlObject.Substation.NodeId, "parse_result": parse_result}
  930. c.AppendPaseResult(r)
  931. }
  932. if ruleid10 != "" && rw.Private != nil && rw.Private.Name != item.Name {
  933. parse_result := fmt.Sprintf("TransformerWinding对象(%s)中的CIME-voltageLevel的name属性(%s)与已有电压等级(%s)不一致", rw.Name, rw.Private.Name, item.Name)
  934. r := map[string]interface{}{"scdid": c.ScdID, "lineno": rw.Lineno, "ruleid": ruleid10, "nodeid": c.scdXmlObject.Substation.NodeId, "parse_result": parse_result}
  935. c.AppendPaseResult(r)
  936. }
  937. }
  938. }
  939. if bayRule1 != "" && len(tmpr.LNode) > 0 {
  940. scdnode := new(ScdNode)
  941. for _, i1 := range tmpr.LNode {
  942. if scdnode.GetIed(c.scdXmlObject, tools.IsEmpty(c.ScdID), i1.IedName) == nil {
  943. parse_result := fmt.Sprintf("间隔(%s)关联逻辑节点(%s)不存在", bayrow.Name, i1.IedName)
  944. r := map[string]interface{}{"scdid": c.ScdID, "lineno": i1.Lineno, "ruleid": bayRule1, "nodeid": c.scdXmlObject.Substation.NodeId, "parse_result": parse_result}
  945. c.AppendPaseResult(r)
  946. }
  947. }
  948. }
  949. }
  950. }
  951. if len(bayrow.ConductingEquipment) > 0 {
  952. ruleid7 := c.getRuleIdByName("ConductingEquipment命名错误")
  953. condmap := map[string]int{}
  954. for _, r := range bayrow.ConductingEquipment {
  955. if ruleid7 != "" {
  956. if r.Name == "" {
  957. parse_result := fmt.Sprintf("ConductingEquipment命名错误:name不能为空")
  958. rt := map[string]interface{}{"scdid": c.ScdID, "lineno": r.Lineno, "ruleid": ruleid7, "nodeid": c.scdXmlObject.Substation.NodeId, "parse_result": parse_result}
  959. c.AppendPaseResult(rt)
  960. continue
  961. }
  962. if condmap[r.Name] == 1 {
  963. parse_result := fmt.Sprintf("在同一Bay内不应有两个同名的ConductingEquipment(%s)元素", r.Name)
  964. rt := map[string]interface{}{"scdid": c.ScdID, "lineno": r.Lineno, "ruleid": ruleid7, "nodeid": c.scdXmlObject.Substation.NodeId, "parse_result": parse_result}
  965. c.AppendPaseResult(rt)
  966. continue
  967. }
  968. condmap[r.Name] = 1
  969. }
  970. ruleid8 := c.getRuleIdByName("ConductingEquipment对象缺失CIME-dtype元素")
  971. if ruleid8 != "" && (r.Private == nil || r.Private.Type != "CIME-dtype") {
  972. parse_result := fmt.Sprintf("ConductingEquipment对象(%s)缺失CIME-dtype元素", r.Name)
  973. rt := map[string]interface{}{"scdid": c.ScdID, "lineno": r.Private.Lineno, "ruleid": ruleid8, "nodeid": c.scdXmlObject.Substation.NodeId, "parse_result": parse_result}
  974. c.AppendPaseResult(rt)
  975. }
  976. ruleid9 := c.getRuleIdByName("ConductingEquipment对象对应CIME-dtype中desc属性值错误")
  977. if ruleid9 != "" && r.Private != nil && r.Private.Type == "CIME-dtype" {
  978. if r.Private.Desc == "" {
  979. parse_result := fmt.Sprintf("ConductingEquipment对象(%s)对应CIME-dtype元素中desc属性值错误", r.Name)
  980. rt := map[string]interface{}{"scdid": c.ScdID, "lineno": r.Private.Lineno, "ruleid": ruleid9, "nodeid": c.scdXmlObject.Substation.NodeId, "parse_result": parse_result}
  981. c.AppendPaseResult(rt)
  982. }
  983. }
  984. if bayRule1 != "" && len(r.LNode) > 0 {
  985. scdnode := new(ScdNode)
  986. for _, i1 := range r.LNode {
  987. if scdnode.GetIed(c.scdXmlObject, tools.IsEmpty(c.ScdID), i1.IedName) == nil {
  988. parse_result := fmt.Sprintf("间隔(%s)关联逻辑节点(%s)不存在", bayrow.Name, i1.IedName)
  989. rt := map[string]interface{}{"scdid": c.ScdID, "lineno": i1.Lineno, "ruleid": bayRule1, "nodeid": c.scdXmlObject.Substation.NodeId, "parse_result": parse_result}
  990. c.AppendPaseResult(rt)
  991. }
  992. }
  993. }
  994. }
  995. }
  996. if len(bayrow.ConnectivityNode) > 0 {
  997. ruleid10 := c.getRuleIdByName("ConnectivityNode对象命名错误")
  998. if ruleid10 != "" {
  999. for _, r := range bayrow.ConnectivityNode {
  1000. if r.Name == "" {
  1001. parse_result := fmt.Sprintf("ConnectivityNode对象命名错误:不能为空")
  1002. rt := map[string]interface{}{"scdid": c.ScdID, "lineno": r.Lineno, "ruleid": ruleid10, "nodeid": c.scdXmlObject.Substation.NodeId, "parse_result": parse_result}
  1003. c.AppendPaseResult(rt)
  1004. continue
  1005. }
  1006. if r.Name[0:1] != "C" {
  1007. parse_result := fmt.Sprintf("ConnectivityNode对象(%s)命名不符合规范:Cn进行命名(n)为间隔内ConnectivityNode实例的序号", r.Name)
  1008. rt := map[string]interface{}{"scdid": c.ScdID, "lineno": r.Lineno, "ruleid": ruleid10, "nodeid": c.scdXmlObject.Substation.NodeId, "parse_result": parse_result}
  1009. c.AppendPaseResult(rt)
  1010. } else {
  1011. no := r.Name[1:]
  1012. _, er := strconv.Atoi(no)
  1013. if er != nil {
  1014. parse_result := fmt.Sprintf("ConnectivityNode对象(%s)命名不符合规范:Cn进行命名(n)为间隔内ConnectivityNode实例的序号", r.Name)
  1015. rt := map[string]interface{}{"scdid": c.ScdID, "lineno": r.Lineno, "ruleid": ruleid10, "nodeid": c.scdXmlObject.Substation.NodeId, "parse_result": parse_result}
  1016. c.AppendPaseResult(rt)
  1017. }
  1018. }
  1019. }
  1020. }
  1021. }
  1022. }
  1023. }
  1024. }
  1025. }
  1026. }
  1027. //主要校验以下规则
  1028. //访问点命名一致性校验:〈Communication)下<ConnectedAP>的apName届性值是否指向已存在的TED访问点
  1029. //IED命名一致性校验:〈Communication)下(ConnectedAP>的iedName属性值是否指向己存在的IED
  1030. //GSE命名一致性校验:〈Communication)下<GSE>的cbName、Idlnst属性值是否指向已存在的GOOSE控制块
  1031. //SMV命名一致性校验:〈Communication)下<SMV>的cbName、Idlnst属性值是否指向已存在的SMV控制块
  1032. //ConnectedAP唯一性校验:ConnectedAP 不应重复配置
  1033. //
  1034. func (c *ScdNodeRule) CheckFunc_communication_connectedap(para orm.Params) {
  1035. logger.Logger.Debug(fmt.Sprintf("校验SCD %d的通信节点", c.ScdID))
  1036. if c.scdXmlObject.Communication == nil {
  1037. //验证不通过
  1038. parse_result := fmt.Sprintf("Communication未定义")
  1039. r := map[string]interface{}{"scdid": c.ScdID, "lineno": c.scdXmlObject.Lineno, "ruleid": c.getRuleIdByName("Communication元素完备性校验"), "nodeid": c.scdXmlObject.NodeId, "parse_result": parse_result}
  1040. c.AppendPaseResult(r)
  1041. return
  1042. }
  1043. if len(c.scdXmlObject.Communication.SubNetwork) == 0 {
  1044. //验证不通过
  1045. parse_result := fmt.Sprintf("SubNetwork未定义")
  1046. r := map[string]interface{}{"scdid": c.ScdID, "lineno": c.scdXmlObject.Communication.Lineno, "ruleid": c.getRuleIdByName("SubNetwork元素完备性校验"), "nodeid": c.scdXmlObject.NodeId, "parse_result": parse_result}
  1047. c.AppendPaseResult(r)
  1048. return
  1049. }
  1050. gseP := map[string]string{}
  1051. smvP := map[string]string{}
  1052. ipAddressIp := map[string]string{}
  1053. gseAppidMap := map[string]string{}
  1054. for _, subnet := range c.scdXmlObject.Communication.SubNetwork {
  1055. apPri := map[string]int{}
  1056. for _, apitem := range subnet.ConnectedAP {
  1057. if apPri[apitem.ApName+apitem.IedName] == 1 {
  1058. parse_result := fmt.Sprintf("%s子网下ConnectedAP(apName=%s,iedName=%s)重复配置", subnet.Name, apitem.ApName, apitem.IedName)
  1059. r := map[string]interface{}{"scdid": c.ScdID, "lineno": apitem.Lineno, "ruleid": c.getRuleIdByName("ConnectedAP唯一性校验"), "nodeid": apitem.NodeId, "parse_result": parse_result}
  1060. c.AppendPaseResult(r)
  1061. continue
  1062. }
  1063. apPri[apitem.ApName+apitem.IedName] = 1
  1064. ied := new(ScdNode).GetIed(c.scdXmlObject, "", apitem.IedName)
  1065. if ied == nil {
  1066. parse_result := fmt.Sprintf("%s子网下ConnectedAP(%s)的iedName(%s)未指向已存在的IED", subnet.Name, apitem.ApName, apitem.IedName)
  1067. r := map[string]interface{}{"scdid": c.ScdID, "lineno": apitem.Lineno, "ruleid": c.getRuleIdByName("IED命名一致性校验"), "nodeid": apitem.NodeId, "parse_result": parse_result}
  1068. c.AppendPaseResult(r)
  1069. continue
  1070. }
  1071. apHas := false
  1072. if ied.AccessPoint != nil {
  1073. for _, iedap := range ied.AccessPoint {
  1074. if iedap.Name == apitem.ApName {
  1075. apHas = true
  1076. break
  1077. }
  1078. }
  1079. }
  1080. if !apHas {
  1081. parse_result := fmt.Sprintf("%s子网下ConnectedAP(%s)的apName未指向已存在的IED访问点", subnet.Name, apitem.ApName)
  1082. r := map[string]interface{}{"scdid": c.ScdID, "lineno": apitem.Lineno, "ruleid": c.getRuleIdByName("访问点命名一致性校验"), "nodeid": apitem.NodeId, "parse_result": parse_result}
  1083. c.AppendPaseResult(r)
  1084. }
  1085. if len(apitem.SMV) > 0 {
  1086. for _, apsmvitem := range apitem.SMV {
  1087. foundLdInst := false
  1088. foundCbname := false
  1089. if ied.AccessPoint != nil {
  1090. for _, iedap := range ied.AccessPoint {
  1091. if iedap.Server == nil {
  1092. continue
  1093. }
  1094. for _, iedld := range iedap.Server.LDevice {
  1095. if iedld.Inst == apsmvitem.LdInst {
  1096. //查找控制块
  1097. if iedld.LN0 != nil {
  1098. for _, iedSmvCb := range iedld.LN0.SampledValueControl {
  1099. if iedSmvCb.Name == apsmvitem.CbName {
  1100. foundCbname = true
  1101. if iedSmvCb.SmvID == "" {
  1102. parse_result := fmt.Sprintf("IED(%s)在%s子网下的控制块(%s)的通信参数(svmID)缺失", apitem.IedName, subnet.Name, iedSmvCb.Name)
  1103. r := map[string]interface{}{"scdid": c.ScdID, "lineno": iedSmvCb.Lineno, "ruleid": c.getRuleIdByName("SV通信参数缺失"), "nodeid": apitem.NodeId, "parse_result": parse_result}
  1104. c.AppendPaseResult(r, ied)
  1105. } else {
  1106. if v, h := gseAppidMap[iedSmvCb.SmvID]; h {
  1107. parse_result := fmt.Sprintf("IED(%s)在%s子网下的控制块(%s)的smvID(%s)与IED(%s)重复", apitem.IedName, subnet.Name, iedSmvCb.Name, iedSmvCb.SmvID, v)
  1108. r := map[string]interface{}{"scdid": c.ScdID, "lineno": iedSmvCb.Lineno, "ruleid": c.getRuleIdByName("SV通信参数唯一性"), "nodeid": apitem.NodeId, "parse_result": parse_result}
  1109. c.AppendPaseResult(r, ied)
  1110. }
  1111. gseAppidMap[iedSmvCb.SmvID] = ied.Name
  1112. }
  1113. if iedSmvCb.ConfRev == "" {
  1114. parse_result := fmt.Sprintf("IED(%s)在%s子网下的控制块(%s)的通信参数(confRev)缺失", apitem.IedName, subnet.Name, iedSmvCb.Name)
  1115. r := map[string]interface{}{"scdid": c.ScdID, "lineno": iedSmvCb.Lineno, "ruleid": c.getRuleIdByName("SV通信参数缺失"), "nodeid": apitem.NodeId, "parse_result": parse_result}
  1116. c.AppendPaseResult(r, ied)
  1117. }
  1118. break
  1119. }
  1120. }
  1121. }
  1122. foundLdInst = true
  1123. break
  1124. }
  1125. }
  1126. if foundLdInst {
  1127. break
  1128. }
  1129. }
  1130. }
  1131. if !foundLdInst {
  1132. parse_result := fmt.Sprintf("%s子网下ConnectedAP(%s,%s)的SMV(cbName=%s,ldInst=%s)中的ldInst未指向已存在的IED逻辑设备inst", subnet.Name, apitem.ApName, apitem.IedName, apsmvitem.CbName, apsmvitem.LdInst)
  1133. r := map[string]interface{}{"scdid": c.ScdID, "lineno": apsmvitem.Lineno, "ruleid": c.getRuleIdByName("SMV命名一致性校验"), "nodeid": apitem.NodeId, "parse_result": parse_result}
  1134. c.AppendPaseResult(r, ied)
  1135. } else {
  1136. if !foundCbname {
  1137. parse_result := fmt.Sprintf("%s子网下ConnectedAP(%s,%s)的SMV(cbName=%s,ldInst=%s)中的cbName未指向已存在的IED SMV控制块", subnet.Name, apitem.ApName, apitem.IedName, apsmvitem.CbName, apsmvitem.LdInst)
  1138. r := map[string]interface{}{"scdid": c.ScdID, "lineno": apsmvitem.Lineno, "ruleid": c.getRuleIdByName("SMV命名一致性校验"), "nodeid": apitem.NodeId, "parse_result": parse_result}
  1139. c.AppendPaseResult(r, ied)
  1140. }
  1141. }
  1142. if apsmvitem.Address != nil {
  1143. mACAddress := ""
  1144. for _, tmpP := range apsmvitem.Address.P {
  1145. if tmpP.InnerText == "" {
  1146. parse_result := fmt.Sprintf("IED(%s)下的LD(%s)在%s子网下的控制块(%s)的通信参数(%s)缺失", apitem.IedName, apsmvitem.LdInst, subnet.Name, apsmvitem.CbName, tmpP.Type)
  1147. r := map[string]interface{}{"scdid": c.ScdID, "lineno": tmpP.Lineno, "ruleid": c.getRuleIdByName("SV通信参数缺失"), "nodeid": apitem.NodeId, "parse_result": parse_result}
  1148. c.AppendPaseResult(r, ied)
  1149. continue
  1150. }
  1151. key := tmpP.Type + tmpP.InnerText
  1152. tmpIednameV := smvP[key]
  1153. switch tmpP.Type {
  1154. case "MAC-Address":
  1155. if tmpIednameV != "" {
  1156. parse_result := fmt.Sprintf("IED(%s)在%s子网(%s)下的控制块(cbName=%s,ldInst=%s)的MAC地址(%s)与IED(%s)重复", apitem.IedName, subnet.Name, apsmvitem.CbName, apsmvitem.LdInst, tmpP.InnerText, tmpIednameV)
  1157. r := map[string]interface{}{"scdid": c.ScdID, "lineno": tmpP.Lineno, "ruleid": c.getRuleIdByName("SV通信参数唯一性"), "nodeid": apitem.NodeId, "parse_result": parse_result}
  1158. c.AppendPaseResult(r, ied)
  1159. break
  1160. }
  1161. ary := strings.Split(tmpP.InnerText, "-")
  1162. if len(ary) == 6 && strings.HasPrefix(tmpP.InnerText, "01-0C-CD-04-") {
  1163. //校验是否越界
  1164. p1, er1 := strconv.ParseUint(ary[4], 16, 32) //16进制转10进制
  1165. p2, er2 := strconv.ParseUint(ary[5], 16, 32) //16进制转10进制
  1166. if er1 != nil || er2 != nil {
  1167. parse_result := fmt.Sprintf("IED(%s)在%s子网下的控制块(cbName=%s,ldInst=%s)的MAC地址(%s)配置不规范", apitem.IedName, subnet.Name, apsmvitem.CbName, apsmvitem.LdInst, tmpP.InnerText)
  1168. r := map[string]interface{}{"scdid": c.ScdID, "lineno": tmpP.Lineno, "ruleid": c.getRuleIdByName("SV通信参数Mac地址越界"), "nodeid": apitem.NodeId, "parse_result": parse_result}
  1169. c.AppendPaseResult(r)
  1170. } else {
  1171. p00, _ := strconv.ParseUint("00", 16, 32)
  1172. pff, _ := strconv.ParseUint("FF", 16, 32)
  1173. if p1 < p00 || p1 > pff || p2 < p00 || p2 > pff {
  1174. parse_result := fmt.Sprintf("IED(%s)在%s子网下的控制块(cbName=%s,ldInst=%s)的MAC地址(%s)越界", apitem.IedName, subnet.Name, apsmvitem.CbName, apsmvitem.LdInst, tmpP.InnerText)
  1175. r := map[string]interface{}{"scdid": c.ScdID, "lineno": tmpP.Lineno, "ruleid": c.getRuleIdByName("SV通信参数Mac地址越界"), "nodeid": apitem.NodeId, "parse_result": parse_result}
  1176. c.AppendPaseResult(r)
  1177. } else {
  1178. mACAddress = tmpP.InnerText
  1179. }
  1180. }
  1181. } else {
  1182. parse_result := fmt.Sprintf("IED(%s)在%s子网下的控制块(cbName=%s,ldInst=%s)的MAC地址(%s)配置不规范", apitem.IedName, subnet.Name, apsmvitem.CbName, apsmvitem.LdInst, tmpP.InnerText)
  1183. r := map[string]interface{}{"scdid": c.ScdID, "lineno": tmpP.Lineno, "ruleid": c.getRuleIdByName("SV通信参数Mac地址越界"), "nodeid": apitem.NodeId, "parse_result": parse_result}
  1184. c.AppendPaseResult(r, ied)
  1185. }
  1186. break
  1187. case "APPID":
  1188. if tmpIednameV != "" {
  1189. parse_result := fmt.Sprintf("IED(%s)在%s子网(%s)下的控制块(cbName=%s,ldInst=%s)的APPID(%s)与IED(%s)重复", apitem.IedName, subnet.Name, apsmvitem.CbName, apsmvitem.LdInst, tmpP.InnerText, tmpIednameV)
  1190. r := map[string]interface{}{"scdid": c.ScdID, "lineno": tmpP.Lineno, "ruleid": c.getRuleIdByName("SV通信参数唯一性"), "nodeid": apitem.NodeId, "parse_result": parse_result}
  1191. c.AppendPaseResult(r, ied)
  1192. } else {
  1193. //校验APPID是否越界
  1194. p16, er := strconv.ParseUint(tmpP.InnerText, 16, 32)
  1195. if len(tmpP.InnerText) != 4 || er != nil {
  1196. parse_result := fmt.Sprintf("IED(%s)在%s子网下的控制块(cbName=%s,ldInst=%s)的APPID(%s)配置不规范,应为4位16进制值", apitem.IedName, subnet.Name, apsmvitem.CbName, apsmvitem.LdInst, tmpP.InnerText)
  1197. r := map[string]interface{}{"scdid": c.ScdID, "lineno": tmpP.Lineno, "ruleid": c.getRuleIdByName("SV通信参数APPID越界"), "nodeid": apitem.NodeId, "parse_result": parse_result}
  1198. c.AppendPaseResult(r, ied)
  1199. } else {
  1200. p1000, _ := strconv.ParseUint("4000", 16, 32)
  1201. p1fff, _ := strconv.ParseUint("4FFF", 16, 32)
  1202. if p16 < p1000 || p16 > p1fff {
  1203. parse_result := fmt.Sprintf("IED(%s)在%s子网下的控制块(cbName=%s,ldInst=%s)的APPID(%s)越界,其范围为0x4000~0x4FFF", apitem.IedName, subnet.Name, apsmvitem.CbName, apsmvitem.LdInst, tmpP.InnerText)
  1204. r := map[string]interface{}{"scdid": c.ScdID, "lineno": tmpP.Lineno, "ruleid": c.getRuleIdByName("SV通信参数APPID越界"), "nodeid": apitem.NodeId, "parse_result": parse_result}
  1205. c.AppendPaseResult(r, ied)
  1206. }
  1207. if mACAddress != "" {
  1208. //校验appid生成是否正确
  1209. macAry := strings.Split(mACAddress, "-")
  1210. tmpAppid := macAry[3][1:] + macAry[4][1:] + macAry[5]
  1211. if tmpP.InnerText != tmpAppid {
  1212. parse_result := fmt.Sprintf("IED(%s)在%s子网下的控制块(cbName=%s,ldInst=%s)的APPID(%s)与mac地址不匹配", apitem.IedName, subnet.Name, apsmvitem.CbName, apsmvitem.LdInst, tmpP.InnerText)
  1213. r := map[string]interface{}{"scdid": c.ScdID, "lineno": tmpP.Lineno, "ruleid": c.getRuleIdByName("SV通信参数APPID与Mac地址不匹配"), "nodeid": apitem.NodeId, "parse_result": parse_result}
  1214. c.AppendPaseResult(r, ied)
  1215. }
  1216. }
  1217. }
  1218. }
  1219. break
  1220. case "VLAN-ID":
  1221. p16, er := strconv.ParseUint(tmpP.InnerText, 16, 32)
  1222. if er != nil || len(tmpP.InnerText) < 3 {
  1223. parse_result := fmt.Sprintf("IED(%s)在%s子网下的控制块(cbName=%s,ldInst=%s)的VLAN-ID(%s)配置不规范,应为3位16进制值", apitem.IedName, subnet.Name, apsmvitem.CbName, apsmvitem.LdInst, tmpP.InnerText)
  1224. r := map[string]interface{}{"scdid": c.ScdID, "lineno": tmpP.Lineno, "ruleid": c.getRuleIdByName("SV通信参数VLAN-ID越界"), "nodeid": apitem.NodeId, "parse_result": parse_result}
  1225. c.AppendPaseResult(r, ied)
  1226. } else {
  1227. p1000, _ := strconv.ParseUint("000", 16, 32)
  1228. p1fff, _ := strconv.ParseUint("FFF", 16, 32)
  1229. if p16 < p1000 || p16 > p1fff {
  1230. parse_result := fmt.Sprintf("IED(%s)在%s子网下的控制块(cbName=%s,ldInst=%s)的VLAN-ID(%s)越界,其范围为0x000~0xFFF", apitem.IedName, subnet.Name, apsmvitem.CbName, apsmvitem.LdInst, tmpP.InnerText)
  1231. r := map[string]interface{}{"scdid": c.ScdID, "lineno": tmpP.Lineno, "ruleid": c.getRuleIdByName("SV通信参数VLAN-ID越界"), "nodeid": apitem.NodeId, "parse_result": parse_result}
  1232. c.AppendPaseResult(r, ied)
  1233. }
  1234. }
  1235. break
  1236. case "VLAN-Priority":
  1237. p16, er := strconv.ParseUint(tmpP.InnerText, 16, 32)
  1238. if len(tmpP.InnerText) != 1 || er != nil {
  1239. parse_result := fmt.Sprintf("IED(%s)在%s子网下的控制块(cbName=%s,ldInst=%s)的VLAN-Priority(%s)配置不规范,应为1位16进制值", apitem.IedName, subnet.Name, apsmvitem.CbName, apsmvitem.LdInst, tmpP.InnerText)
  1240. r := map[string]interface{}{"scdid": c.ScdID, "lineno": tmpP.Lineno, "ruleid": c.getRuleIdByName("SV通信参数VLAN-Priority越界"), "nodeid": apitem.NodeId, "parse_result": parse_result}
  1241. c.AppendPaseResult(r, ied)
  1242. } else {
  1243. if p16 < 0 || p16 > 7 {
  1244. parse_result := fmt.Sprintf("IED(%s)在%s子网下的控制块(cbName=%s,ldInst=%s)的VLAN-Priority(%s)越界,其范围为0~7", apitem.IedName, subnet.Name, apsmvitem.CbName, apsmvitem.LdInst, tmpP.InnerText)
  1245. r := map[string]interface{}{"scdid": c.ScdID, "lineno": tmpP.Lineno, "ruleid": c.getRuleIdByName("SV通信参数VLAN-Priority越界"), "nodeid": apitem.NodeId, "parse_result": parse_result}
  1246. c.AppendPaseResult(r, ied)
  1247. }
  1248. }
  1249. break
  1250. }
  1251. smvP[key] = apitem.IedName
  1252. }
  1253. }
  1254. }
  1255. }
  1256. if len(apitem.GSE) > 0 {
  1257. for _, apsmvitem := range apitem.GSE {
  1258. foundLdInst := false
  1259. foundCbname := false
  1260. if ied.AccessPoint != nil {
  1261. for _, iedap := range ied.AccessPoint {
  1262. if iedap.Server == nil {
  1263. continue
  1264. }
  1265. for _, iedld := range iedap.Server.LDevice {
  1266. if iedld.Inst == apsmvitem.LdInst {
  1267. //查找控制块
  1268. if iedld.LN0 != nil {
  1269. for _, iedCb := range iedld.LN0.GSEControl {
  1270. if iedCb.Name == apsmvitem.CbName {
  1271. foundCbname = true
  1272. if iedCb.AppID == "" {
  1273. parse_result := fmt.Sprintf("IED(%s)在%s子网下的控制块(%s)的通信参数(appID)缺失", apitem.IedName, subnet.Name, iedCb.Name)
  1274. r := map[string]interface{}{"scdid": c.ScdID, "lineno": iedCb.Lineno, "ruleid": c.getRuleIdByName("GOOSE通信参数缺失"), "nodeid": apitem.NodeId, "parse_result": parse_result}
  1275. c.AppendPaseResult(r, ied)
  1276. } else {
  1277. if v, h := gseAppidMap[iedCb.AppID]; h {
  1278. parse_result := fmt.Sprintf("IED(%s)在%s子网下的控制块(%s)的appID(%s)与IED(%s)重复", apitem.IedName, subnet.Name, iedCb.Name, iedCb.AppID, v)
  1279. r := map[string]interface{}{"scdid": c.ScdID, "lineno": iedCb.Lineno, "ruleid": c.getRuleIdByName("GOOSE通信参数唯一性"), "nodeid": apitem.NodeId, "parse_result": parse_result}
  1280. c.AppendPaseResult(r, ied)
  1281. }
  1282. gseAppidMap[iedCb.AppID] = ied.Name
  1283. }
  1284. if iedCb.ConfRev == "" {
  1285. parse_result := fmt.Sprintf("IED(%s)在%s子网下的控制块(%s)的通信参数(confRev)缺失", apitem.IedName, subnet.Name, iedCb.Name)
  1286. r := map[string]interface{}{"scdid": c.ScdID, "lineno": iedCb.Lineno, "ruleid": c.getRuleIdByName("GOOSE通信参数缺失"), "nodeid": apitem.NodeId, "parse_result": parse_result}
  1287. c.AppendPaseResult(r, ied)
  1288. }
  1289. break
  1290. }
  1291. }
  1292. }
  1293. foundLdInst = true
  1294. break
  1295. }
  1296. }
  1297. if foundLdInst {
  1298. break
  1299. }
  1300. }
  1301. }
  1302. if !foundLdInst {
  1303. parse_result := fmt.Sprintf("%s子网下ConnectedAP(%s,%s)的GSE(cbName=%s,ldInst=%s)中的ldInst未指向已存在的IED逻辑设备inst", subnet.Name, apitem.ApName, apitem.IedName, apsmvitem.CbName, apsmvitem.LdInst)
  1304. r := map[string]interface{}{"scdid": c.ScdID, "lineno": apsmvitem.Lineno, "ruleid": c.getRuleIdByName("GSE命名一致性校验"), "nodeid": apitem.NodeId, "parse_result": parse_result}
  1305. c.AppendPaseResult(r, ied)
  1306. } else {
  1307. if !foundCbname {
  1308. parse_result := fmt.Sprintf("%s子网下ConnectedAP(%s,%s)的GSE(cbName=%s,ldInst=%s)中的cbName未指向已存在的IED GOOSE控制块", subnet.Name, apitem.ApName, apitem.IedName, apsmvitem.CbName, apsmvitem.LdInst)
  1309. r := map[string]interface{}{"scdid": c.ScdID, "lineno": apsmvitem.Lineno, "ruleid": c.getRuleIdByName("GSE命名一致性校验"), "nodeid": apitem.NodeId, "parse_result": parse_result}
  1310. c.AppendPaseResult(r, ied)
  1311. }
  1312. }
  1313. //GOOSE通信参数校验:GOOSE通信参数唯一性、GOOSE通信参数Mac地址越界、GOOSE通信参数APPID越界、GOOSE通信参数APPID与Mac地址不匹配、GOOSE通信参数VLAN-ID越界、GOOSE通信参数VLAN-Priority越界、GOOSE通信参数MinTime 和 MaxTime 不为推荐值、GOOSE通信参数缺失
  1314. if apsmvitem.Address != nil {
  1315. mACAddress := ""
  1316. for _, tmpP := range apsmvitem.Address.P {
  1317. if tmpP.InnerText == "" {
  1318. parse_result := fmt.Sprintf("IED(%s)下的LD(%s)在%s子网控制块(%s)的通信参数(%s)缺失", apitem.IedName, apsmvitem.LdInst, subnet.Name, apsmvitem.CbName, tmpP.Type)
  1319. r := map[string]interface{}{"scdid": c.ScdID, "lineno": tmpP.Lineno, "ruleid": c.getRuleIdByName("GOOSE通信参数缺失"), "nodeid": apitem.NodeId, "parse_result": parse_result}
  1320. c.AppendPaseResult(r, ied)
  1321. continue
  1322. }
  1323. key := tmpP.Type + tmpP.InnerText
  1324. tmpIednameV := gseP[key]
  1325. switch tmpP.Type {
  1326. case "MAC-Address":
  1327. if tmpIednameV != "" {
  1328. parse_result := fmt.Sprintf("IED(%s)在%s子网下的控制块(cbName=%s,ldInst=%s)的MAC地址(%s)与IED(%s)重复", apitem.IedName, subnet.Name, apsmvitem.CbName, apsmvitem.LdInst, tmpP.InnerText, tmpIednameV)
  1329. r := map[string]interface{}{"scdid": c.ScdID, "lineno": tmpP.Lineno, "ruleid": c.getRuleIdByName("GOOSE通信参数唯一性"), "nodeid": apitem.NodeId, "parse_result": parse_result}
  1330. c.AppendPaseResult(r, ied)
  1331. break
  1332. }
  1333. ary := strings.Split(tmpP.InnerText, "-")
  1334. if len(ary) == 6 && strings.HasPrefix(tmpP.InnerText, "01-0C-CD-01-") {
  1335. //校验是否越界
  1336. p1, er1 := strconv.ParseUint(ary[4], 16, 32) //16进制转10进制
  1337. p2, er2 := strconv.ParseUint(ary[5], 16, 32) //16进制转10进制
  1338. if er1 != nil || er2 != nil {
  1339. parse_result := fmt.Sprintf("IED(%s)在%s子网下的控制块(cbName=%s,ldInst=%s)的MAC地址(%s)配置不规范", apitem.IedName, subnet.Name, apsmvitem.CbName, apsmvitem.LdInst, tmpP.InnerText)
  1340. r := map[string]interface{}{"scdid": c.ScdID, "lineno": tmpP.Lineno, "ruleid": c.getRuleIdByName("GOOSE通信参数Mac地址越界"), "nodeid": apitem.NodeId, "parse_result": parse_result}
  1341. c.AppendPaseResult(r)
  1342. } else {
  1343. p00, _ := strconv.ParseUint("00", 16, 32)
  1344. pff, _ := strconv.ParseUint("FF", 16, 32)
  1345. if p1 < p00 || p1 > pff || p2 < p00 || p2 > pff {
  1346. parse_result := fmt.Sprintf("IED(%s)在%s子网下的控制块(cbName=%s,ldInst=%s)的MAC地址(%s)越界", apitem.IedName, subnet.Name, apsmvitem.CbName, apsmvitem.LdInst, tmpP.InnerText)
  1347. r := map[string]interface{}{"scdid": c.ScdID, "lineno": tmpP.Lineno, "ruleid": c.getRuleIdByName("GOOSE通信参数Mac地址越界"), "nodeid": apitem.NodeId, "parse_result": parse_result}
  1348. c.AppendPaseResult(r)
  1349. } else {
  1350. mACAddress = tmpP.InnerText
  1351. }
  1352. }
  1353. } else {
  1354. parse_result := fmt.Sprintf("IED(%s)在%s子网下的控制块(cbName=%s,ldInst=%s)的MAC地址(%s)配置不规范", apitem.IedName, subnet.Name, apsmvitem.CbName, apsmvitem.LdInst, tmpP.InnerText)
  1355. r := map[string]interface{}{"scdid": c.ScdID, "lineno": tmpP.Lineno, "ruleid": c.getRuleIdByName("GOOSE通信参数Mac地址越界"), "nodeid": apitem.NodeId, "parse_result": parse_result}
  1356. c.AppendPaseResult(r, ied)
  1357. }
  1358. break
  1359. case "APPID":
  1360. if tmpIednameV != "" {
  1361. parse_result := fmt.Sprintf("IED(%s)在%s子网下的控制块(cbName=%s,ldInst=%s)的APPID(%s)与IED(%s)重复", apitem.IedName, subnet.Name, apsmvitem.CbName, apsmvitem.LdInst, tmpP.InnerText, tmpIednameV)
  1362. r := map[string]interface{}{"scdid": c.ScdID, "lineno": tmpP.Lineno, "ruleid": c.getRuleIdByName("GOOSE通信参数唯一性"), "nodeid": apitem.NodeId, "parse_result": parse_result}
  1363. c.AppendPaseResult(r, ied)
  1364. } else {
  1365. //校验APPID是否越界
  1366. p16, er := strconv.ParseUint(tmpP.InnerText, 16, 32)
  1367. if len(tmpP.InnerText) != 4 || er != nil {
  1368. parse_result := fmt.Sprintf("IED(%s)在%s子网下的控制块(cbName=%s,ldInst=%s)的APPID(%s)配置不规范,应为4位16进制值", apitem.IedName, subnet.Name, apsmvitem.CbName, apsmvitem.LdInst, tmpP.InnerText)
  1369. r := map[string]interface{}{"scdid": c.ScdID, "lineno": tmpP.Lineno, "ruleid": c.getRuleIdByName("GOOSE通信参数APPID越界"), "nodeid": apitem.NodeId, "parse_result": parse_result}
  1370. c.AppendPaseResult(r, ied)
  1371. } else {
  1372. p1000, _ := strconv.ParseUint("1000", 16, 32)
  1373. p1fff, _ := strconv.ParseUint("1FFF", 16, 32)
  1374. if p16 < p1000 || p16 > p1fff {
  1375. parse_result := fmt.Sprintf("IED(%s)在%s子网下的控制块(cbName=%s,ldInst=%s)的APPID(%s)越界,其范围为0x1000~0x1FFF", apitem.IedName, subnet.Name, apsmvitem.CbName, apsmvitem.LdInst, tmpP.InnerText)
  1376. r := map[string]interface{}{"scdid": c.ScdID, "lineno": tmpP.Lineno, "ruleid": c.getRuleIdByName("GOOSE通信参数APPID越界"), "nodeid": apitem.NodeId, "parse_result": parse_result}
  1377. c.AppendPaseResult(r, ied)
  1378. }
  1379. if mACAddress != "" {
  1380. //校验appid生成是否正确
  1381. macAry := strings.Split(mACAddress, "-")
  1382. tmpAppid := macAry[3][1:] + macAry[4][1:] + macAry[5]
  1383. if tmpP.InnerText != tmpAppid {
  1384. parse_result := fmt.Sprintf("IED(%s)在%s子网下的控制块(cbName=%s,ldInst=%s)的APPID(%s)与mac地址不匹配", apitem.IedName, subnet.Name, apsmvitem.CbName, apsmvitem.LdInst, tmpP.InnerText)
  1385. r := map[string]interface{}{"scdid": c.ScdID, "lineno": tmpP.Lineno, "ruleid": c.getRuleIdByName("GOOSE通信参数APPID与Mac地址不匹配"), "nodeid": apitem.NodeId, "parse_result": parse_result}
  1386. c.AppendPaseResult(r, ied)
  1387. }
  1388. }
  1389. }
  1390. }
  1391. break
  1392. case "VLAN-ID":
  1393. p16, er := strconv.ParseUint(tmpP.InnerText, 16, 32)
  1394. if er != nil || len(tmpP.InnerText) < 3 {
  1395. parse_result := fmt.Sprintf("IED(%s)在%s子网下的控制块(cbName=%s,ldInst=%s)的VLAN-ID(%s)配置不规范,应为3位16进制值", apitem.IedName, subnet.Name, apsmvitem.CbName, apsmvitem.LdInst, tmpP.InnerText)
  1396. r := map[string]interface{}{"scdid": c.ScdID, "lineno": tmpP.Lineno, "ruleid": c.getRuleIdByName("GOOSE通信参数VLAN-ID越界"), "nodeid": apitem.NodeId, "parse_result": parse_result}
  1397. c.AppendPaseResult(r, ied)
  1398. } else {
  1399. p1000, _ := strconv.ParseUint("000", 16, 32)
  1400. p1fff, _ := strconv.ParseUint("FFF", 16, 32)
  1401. if p16 < p1000 || p16 > p1fff {
  1402. parse_result := fmt.Sprintf("IED(%s)在%s子网下的控制块(cbName=%s,ldInst=%s)的VLAN-ID(%s)越界,其范围为0x000~0xFFF", apitem.IedName, subnet.Name, apsmvitem.CbName, apsmvitem.LdInst, tmpP.InnerText)
  1403. r := map[string]interface{}{"scdid": c.ScdID, "lineno": tmpP.Lineno, "ruleid": c.getRuleIdByName("GOOSE通信参数VLAN-ID越界"), "nodeid": apitem.NodeId, "parse_result": parse_result}
  1404. c.AppendPaseResult(r, ied)
  1405. }
  1406. }
  1407. break
  1408. case "VLAN-Priority":
  1409. p16, er := strconv.ParseUint(tmpP.InnerText, 16, 32)
  1410. if len(tmpP.InnerText) != 1 || er != nil {
  1411. parse_result := fmt.Sprintf("IED(%s)在%s子网下的控制块(cbName=%s,ldInst=%s)的VLAN-Priority(%s)配置不规范,应为1位16进制值", apitem.IedName, subnet.Name, apsmvitem.CbName, apsmvitem.LdInst, tmpP.InnerText)
  1412. r := map[string]interface{}{"scdid": c.ScdID, "lineno": tmpP.Lineno, "ruleid": c.getRuleIdByName("GOOSE通信参数VLAN-Priority越界"), "nodeid": apitem.NodeId, "parse_result": parse_result}
  1413. c.AppendPaseResult(r, ied)
  1414. } else {
  1415. if p16 < 0 || p16 > 7 {
  1416. parse_result := fmt.Sprintf("IED(%s)在%s子网下的控制块(cbName=%s,ldInst=%s)的VLAN-Priority(%s)越界,其范围为0~7", apitem.IedName, subnet.Name, apsmvitem.CbName, apsmvitem.LdInst, tmpP.InnerText)
  1417. r := map[string]interface{}{"scdid": c.ScdID, "lineno": tmpP.Lineno, "ruleid": c.getRuleIdByName("GOOSE通信参数VLAN-Priority越界"), "nodeid": apitem.NodeId, "parse_result": parse_result}
  1418. c.AppendPaseResult(r, ied)
  1419. }
  1420. }
  1421. break
  1422. }
  1423. gseP[key] = apitem.IedName
  1424. }
  1425. }
  1426. if apsmvitem.MaxTime == nil {
  1427. parse_result := fmt.Sprintf("IED(%s)在%s子网下的控制块(%s)的通信参数(MaxTime)缺失", apitem.IedName, subnet.Name, apsmvitem.CbName)
  1428. r := map[string]interface{}{"scdid": c.ScdID, "lineno": apsmvitem.Lineno, "ruleid": c.getRuleIdByName("GOOSE通信参数缺失"), "nodeid": apitem.NodeId, "parse_result": parse_result}
  1429. c.AppendPaseResult(r, ied)
  1430. } else {
  1431. if apsmvitem.MaxTime.InnerText != "5000" {
  1432. parse_result := fmt.Sprintf("IED(%s)在%s子网下的控制块(%s)的通信参数MaxTime(%s)不为标准值5000", apitem.IedName, subnet.Name, apsmvitem.CbName, apsmvitem.MaxTime.InnerText)
  1433. r := map[string]interface{}{"scdid": c.ScdID, "lineno": apsmvitem.Lineno, "ruleid": c.getRuleIdByName("GOOSE通信参数MinTime和MaxTime不为推荐值"), "nodeid": apitem.NodeId, "parse_result": parse_result}
  1434. c.AppendPaseResult(r, ied)
  1435. }
  1436. }
  1437. if apsmvitem.MinTime == nil {
  1438. parse_result := fmt.Sprintf("IED(%s)在%s子网下的控制块(%s)的通信参数(MinTime)缺失", apitem.IedName, subnet.Name, apsmvitem.CbName)
  1439. r := map[string]interface{}{"scdid": c.ScdID, "lineno": apsmvitem.Lineno, "ruleid": c.getRuleIdByName("GOOSE通信参数缺失"), "nodeid": apitem.NodeId, "parse_result": parse_result}
  1440. c.AppendPaseResult(r, ied)
  1441. } else {
  1442. if apsmvitem.MinTime.InnerText != "2" {
  1443. parse_result := fmt.Sprintf("IED(%s)在%s子网下的控制块(%s)的通信参数MinTime(%s)不为标准值2", apitem.IedName, subnet.Name, apsmvitem.CbName, apsmvitem.MinTime.InnerText)
  1444. r := map[string]interface{}{"scdid": c.ScdID, "lineno": apsmvitem.Lineno, "ruleid": c.getRuleIdByName("GOOSE通信参数MinTime和MaxTime不为推荐值"), "nodeid": apitem.NodeId, "parse_result": parse_result}
  1445. c.AppendPaseResult(r, ied)
  1446. }
  1447. }
  1448. }
  1449. }
  1450. //检查站控层通信参数校验
  1451. //1、IP地址同一子网内唯一性
  1452. if apitem.Address != nil {
  1453. for _, ips := range apitem.Address.P {
  1454. if ips.Type == "IP" {
  1455. if ips.InnerText == "" {
  1456. parse_result := fmt.Sprintf("IED(%s)在%s子网下未配置IP地址", apitem.ApName, subnet.Name, subnet.Desc)
  1457. r := map[string]interface{}{"scdid": c.ScdID, "lineno": ips.Lineno, "ruleid": c.getRuleIdByName("IP地址未配置"), "nodeid": apitem.NodeId, "parse_result": parse_result}
  1458. c.AppendPaseResult(r, ied)
  1459. } else {
  1460. //判断IP是否越界
  1461. ipparts := strings.Split(ips.InnerText, ".")
  1462. if len(ipparts) != 4 {
  1463. parse_result := fmt.Sprintf("IED(%s)在%s子网下IP地址(%s)无效", apitem.ApName, subnet.Name, ips.InnerText)
  1464. r := map[string]interface{}{"scdid": c.ScdID, "lineno": ips.Lineno, "ruleid": c.getRuleIdByName("IP地址配置不规范"), "nodeid": apitem.NodeId, "parse_result": parse_result}
  1465. c.AppendPaseResult(r, ied)
  1466. } else {
  1467. ip1, _ := strconv.Atoi(ipparts[0])
  1468. ip2, _ := strconv.Atoi(ipparts[1])
  1469. ip3, _ := strconv.Atoi(ipparts[2])
  1470. ip4, _ := strconv.Atoi(ipparts[3])
  1471. if (ip1 < 0 && ip1 > 255) || (ip2 < 0 && ip2 > 255) || (ip3 < 0 && ip3 > 255) || (ip4 < 0 && ip4 > 255) {
  1472. parse_result := fmt.Sprintf("IED(%s)在%s子网下IP地址(%s)越界", apitem.ApName, subnet.Name, ips.InnerText)
  1473. r := map[string]interface{}{"scdid": c.ScdID, "lineno": ips.Lineno, "ruleid": c.getRuleIdByName("IP地址越界"), "nodeid": apitem.NodeId, "parse_result": parse_result}
  1474. c.AppendPaseResult(r, ied)
  1475. }
  1476. }
  1477. }
  1478. if tmpIednameV, h := ipAddressIp[ips.InnerText]; h {
  1479. parse_result := fmt.Sprintf("IED(%s)在%s子网下的IP地址与IED(%s)重复", apitem.ApName, subnet.Name, tmpIednameV)
  1480. r := map[string]interface{}{"scdid": c.ScdID, "lineno": ips.Lineno, "ruleid": c.getRuleIdByName("IP地址唯一性"), "nodeid": apitem.NodeId, "parse_result": parse_result}
  1481. c.AppendPaseResult(r, ied)
  1482. }
  1483. ipAddressIp[ips.InnerText] = apitem.IedName
  1484. }
  1485. if ips.Type == "IP-SUBNET" {
  1486. if ips.InnerText == "" {
  1487. parse_result := fmt.Sprintf("IED(%s)在%s子网下未配置IP-SUBNET地址", apitem.ApName, subnet.Name, subnet.Desc)
  1488. r := map[string]interface{}{"scdid": c.ScdID, "lineno": ips.Lineno, "ruleid": c.getRuleIdByName("IP-SUBNET地址未配置"), "nodeid": apitem.NodeId, "parse_result": parse_result}
  1489. c.AppendPaseResult(r, ied)
  1490. } else {
  1491. ipparts := strings.Split(ips.InnerText, ".")
  1492. if len(ipparts) != 4 {
  1493. parse_result := fmt.Sprintf("IED(%s)在%s子网下IP-SUBNET地址(%s)无效", apitem.ApName, subnet.Name, ips.InnerText)
  1494. r := map[string]interface{}{"scdid": c.ScdID, "lineno": ips.Lineno, "ruleid": c.getRuleIdByName("IP-SUBNET地址配置不规范"), "nodeid": apitem.NodeId, "parse_result": parse_result}
  1495. c.AppendPaseResult(r, ied)
  1496. } else {
  1497. ip1, _ := strconv.Atoi(ipparts[0])
  1498. ip2, _ := strconv.Atoi(ipparts[1])
  1499. ip3, _ := strconv.Atoi(ipparts[2])
  1500. ip4, _ := strconv.Atoi(ipparts[3])
  1501. if (ip1 < 0 && ip1 > 255) || (ip2 < 0 && ip2 > 255) || (ip3 < 0 && ip3 > 255) || (ip4 < 0 && ip4 > 255) {
  1502. parse_result := fmt.Sprintf("IED(%s)在%s子网下IP-SUBNET地址(%s)越界", apitem.ApName, subnet.Name, ips.InnerText)
  1503. r := map[string]interface{}{"scdid": c.ScdID, "lineno": ips.Lineno, "ruleid": c.getRuleIdByName("IP-SUBNET地址越界"), "nodeid": apitem.NodeId, "parse_result": parse_result}
  1504. c.AppendPaseResult(r, ied)
  1505. }
  1506. }
  1507. }
  1508. }
  1509. }
  1510. }
  1511. }
  1512. }
  1513. }
  1514. //IED校验
  1515. //.IED(XXX)中Server对象缺失
  1516. //.IED(XXX)中访问点***中的Server缺失LD对象
  1517. //.IED(XXX)中LD***中缺失LLN0
  1518. //.IED(XXX)中LD***中缺失LPHD
  1519. //.IED(XXX)中LD***中缺失非LPHD外其他LN
  1520. func (c *ScdNodeRule) CheckFunc_ied(dATypeMap map[string]*node_attr.NDAType) {
  1521. logger.Logger.Debug(fmt.Sprintf("校验SCD %d的IED节点", c.ScdID))
  1522. if c.scdXmlObject == nil {
  1523. return
  1524. }
  1525. //fcdaMap := map[string]string{}
  1526. gooseAppidMap := sync.Map{} // map[string]*node_attr.NIED{}
  1527. smvAppidMap := sync.Map{} // map[string]*node_attr.NIED{}
  1528. reportRptIDMap := sync.Map{}
  1529. var confDataSet *node_attr.NConfDataSet
  1530. for _, iedObj := range c.scdXmlObject.IED {
  1531. //判断ccd校验码 需要在生成crc校验码后进行
  1532. ccdCrc := ""
  1533. for _, iedPrivate := range iedObj.Priavate {
  1534. if iedPrivate.Type == "IED virtual terminal conection CRC" {
  1535. ccdCrc = iedPrivate.InnerText
  1536. break
  1537. }
  1538. }
  1539. if ccdCrc == "" {
  1540. parse_result := fmt.Sprintf("IED(%s)不存在ICD文件CRC校验码", iedObj.Name)
  1541. r := map[string]interface{}{"scdid": c.ScdID, "lineno": iedObj.Lineno, "ruleid": c.getRuleIdByName("ICD文件校验码存在性"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
  1542. c.AppendPaseResult(r, iedObj)
  1543. }
  1544. if iedObj.Services != nil {
  1545. confDataSet = iedObj.Services.ConfDataSet
  1546. }
  1547. signalMapFound := false
  1548. for _, iedPrivate := range iedObj.Priavate {
  1549. if iedPrivate.Type == "Signal Map" {
  1550. signalMapFound = true
  1551. break
  1552. }
  1553. }
  1554. if !signalMapFound {
  1555. parse_result := fmt.Sprintf("IED(%s)定义关联关系的信号或软压板不存在", iedObj.Name)
  1556. r := map[string]interface{}{"scdid": c.ScdID, "lineno": iedObj.Lineno, "ruleid": c.getRuleIdByName("信号关联关系格式检查"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
  1557. c.AppendPaseResult(r, iedObj)
  1558. }
  1559. if len(iedObj.Name) < 5 || len(iedObj.Name) > 8 {
  1560. //IED 的 name 由 5 部分共 8 位合法可视字符组成,分别代表: IED 类型、归属设备类型、电压等级、归属设备编号、 IED 编号,具体要求如附录 B 所示
  1561. parse_result := fmt.Sprintf("IED(%s)名称不符合规范要求", iedObj.Name)
  1562. r := map[string]interface{}{"scdid": c.ScdID, "lineno": iedObj.Lineno, "ruleid": c.getRuleIdByName("IEDName合法性校验"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
  1563. c.AppendPaseResult(r, iedObj)
  1564. }
  1565. if len(iedObj.AccessPoint) == 0 {
  1566. parse_result := fmt.Sprintf("IED(%s)中AccessPoint对象缺失", iedObj.Name)
  1567. r := map[string]interface{}{"scdid": c.ScdID, "lineno": iedObj.Lineno, "ruleid": c.getRuleIdByName("访问点(AccessPoint)名称校验"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
  1568. c.AppendPaseResult(r, iedObj)
  1569. continue
  1570. }
  1571. for _, ap := range iedObj.AccessPoint {
  1572. if ap.Server == nil {
  1573. parse_result := fmt.Sprintf("IED(%s)中Server对象缺失", iedObj.Name)
  1574. r := map[string]interface{}{"scdid": c.ScdID, "lineno": ap.Lineno, "ruleid": c.getRuleIdByName("逻辑设备建模正确性"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
  1575. c.AppendPaseResult(r, iedObj)
  1576. continue
  1577. }
  1578. if len(ap.Server.LDevice) == 0 {
  1579. parse_result := fmt.Sprintf("IED(%s)中访问点(%s:%s)缺失LD对象", iedObj.Name, ap.Name, ap.Desc)
  1580. r := map[string]interface{}{"scdid": c.ScdID, "lineno": ap.Server.Lineno, "ruleid": c.getRuleIdByName("逻辑设备建模正确性"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
  1581. c.AppendPaseResult(r, iedObj)
  1582. continue
  1583. }
  1584. for _, ld := range ap.Server.LDevice {
  1585. //校验DOI/SDI引用模板不一致、DAI引用模板不一致
  1586. c.check_ln_doidai(iedObj, dATypeMap, ld)
  1587. if ld.LN0 == nil {
  1588. parse_result := fmt.Sprintf("IED(%s)中访问点(%s:%s)下的LD(%s)缺失对象LLN0", iedObj.Name, ap.Name, ap.Desc, ld.Desc)
  1589. r := map[string]interface{}{"scdid": c.ScdID, "lineno": ld.Lineno, "ruleid": c.getRuleIdByName("逻辑设备建模正确性"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
  1590. c.AppendPaseResult(r, iedObj)
  1591. continue
  1592. } else {
  1593. if _, h := c.lnodeTypeMap.Load(ld.LN0.LnType); !h {
  1594. parse_result := fmt.Sprintf("IED(%s)中访问点(%s:%s)下的LD(%s)下的LN0(%s)引用的LNodeType(%s)在模板中不存在", iedObj.Name, ap.Name, ap.Desc, ld.Inst, ld.LN0.Desc, ld.LN0.LnType)
  1595. r := map[string]interface{}{"scdid": c.ScdID, "lineno": ld.LN0.Lineno, "ruleid": c.getRuleIdByName("LN引用LNodeType不存在"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
  1596. c.AppendPaseResult(r, iedObj)
  1597. }
  1598. if confDataSet != nil {
  1599. max, _ := strconv.Atoi(confDataSet.Max)
  1600. if len(ld.LN0.DataSet) > max {
  1601. parse_result := fmt.Sprintf("IED(%s)中访问点(%s:%s)下的LD(%s)数据集个数超过允许的最大值(当前数=%d, 最大值=%s)", iedObj.Name, ap.Name, ap.Desc, ld.Inst, len(ld.LN0.DataSet), confDataSet.Max)
  1602. r := map[string]interface{}{"scdid": c.ScdID, "lineno": ld.LN0.Lineno, "ruleid": c.getRuleIdByName("数据集数目校验"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
  1603. c.AppendPaseResult(r, iedObj)
  1604. }
  1605. }
  1606. datsetList := map[string]*node_attr.NDataSet{}
  1607. //校验FCDA唯一性
  1608. for _, datset := range ld.LN0.DataSet {
  1609. datsetList[datset.Name] = datset
  1610. if confDataSet != nil {
  1611. max, _ := strconv.Atoi(confDataSet.MaxAttributes)
  1612. if len(datset.FCDA) > max {
  1613. parse_result := fmt.Sprintf("IED(%s)中访问点(%s:%s)下的LD(%s)数据集(%s)成员FCDA个数超过允许的最大值(当前数=%d, 最大值=%s)", iedObj.Name, ap.Name, ap.Desc, ld.Inst, datset.Name, len(datset.FCDA), confDataSet.MaxAttributes)
  1614. r := map[string]interface{}{"scdid": c.ScdID, "lineno": datset.Lineno, "ruleid": c.getRuleIdByName("数据集成员数目校验"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
  1615. c.AppendPaseResult(r, iedObj)
  1616. }
  1617. }
  1618. //dsGOOSE 数据集成员总数不应超过256个
  1619. if strings.HasPrefix(datset.Name, "dsGOOSE") && len(datset.FCDA) > 256 {
  1620. parse_result := fmt.Sprintf("IED(%s)中访问点(%s:%s)下的LD(%s)数据集(%s)成员FCDA个数%d不能超过256", iedObj.Name, ap.Name, ap.Desc, ld.Inst, datset.Name, len(datset.FCDA))
  1621. r := map[string]interface{}{"scdid": c.ScdID, "lineno": datset.Lineno, "ruleid": c.getRuleIdByName("校验数据集成员构成"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
  1622. c.AppendPaseResult(r, iedObj)
  1623. }
  1624. for _, fcdaitem := range datset.FCDA {
  1625. key := fmt.Sprintf("%s/%s%s%s.%s", fcdaitem.LdInst, fcdaitem.Prefix, fcdaitem.LnClass, fcdaitem.LnInst, fcdaitem.DoName)
  1626. if fcdaitem.DaName != "" {
  1627. key = key + "." + fcdaitem.DaName
  1628. }
  1629. if fcdaitem.LdInst != ld.Inst {
  1630. parse_result := fmt.Sprintf("IED(%s)中访问点(%s:%s)下的LD(%s)数据集(%s)FCDA成员(%s)不允许跨LD", iedObj.Name, ap.Name, ap.Desc, ld.Inst, datset.Name, key)
  1631. r := map[string]interface{}{"scdid": c.ScdID, "lineno": fcdaitem.Lineno, "ruleid": c.getRuleIdByName("数据集成员跨LD校验"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
  1632. c.AppendPaseResult(r, iedObj)
  1633. continue
  1634. }
  1635. //成员有效性
  1636. has1, _ := c.IedFcdaExist(iedObj.Name, fcdaitem.LdInst, fcdaitem.LnClass, fcdaitem.LnInst, fcdaitem.Prefix, fcdaitem.DoName, fcdaitem.DaName)
  1637. if has1 == nil {
  1638. parse_result := fmt.Sprintf("IED(%s)中访问点(%s:%s)下的LD(%s)数据集(%s)FCDA成员(%s)不存在", iedObj.Name, ap.Name, ap.Desc, ld.Inst, datset.Name, key)
  1639. r := map[string]interface{}{"scdid": c.ScdID, "lineno": fcdaitem.Lineno, "ruleid": c.getRuleIdByName("数据集成员有效性校验"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
  1640. c.AppendPaseResult(r, iedObj)
  1641. }
  1642. //dsGOOSE 数据集的所有成员都应采用FCDA构成方式,其它数据集成员都应采用FCD构成方式。
  1643. if strings.HasPrefix(datset.Name, "dsGOOSE") && fcdaitem.DaName == "" {
  1644. parse_result := fmt.Sprintf("IED(%s)中访问点(%s:%s)下的LD(%s)数据集(%s)成员(%s)不是FCDA格式", iedObj.Name, ap.Name, ap.Desc, ld.Inst, datset.Name, key)
  1645. r := map[string]interface{}{"scdid": c.ScdID, "lineno": fcdaitem.Lineno, "ruleid": c.getRuleIdByName("校验数据集成员构成"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
  1646. c.AppendPaseResult(r, iedObj)
  1647. }
  1648. if !strings.HasPrefix(datset.Name, "dsGOOSE") && fcdaitem.DaName != "" {
  1649. //parse_result := fmt.Sprintf("IED(%s)中访问点(%s:%s)下的LD(%s)数据集(%s)成员(%s)不是FCD格式", iedObj.Name, ap.Name, ap.Desc, ld.Inst, datset.Name, key)
  1650. //r := map[string]interface{}{"scdid": c.ScdID, "ruleid": c.getRuleIdByName("校验数据集成员构成"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
  1651. //c.AppendPaseResult(r, iedObj)
  1652. }
  1653. }
  1654. }
  1655. //虚回路校验
  1656. if ld.LN0.Inputs != nil {
  1657. for _, extref := range ld.LN0.Inputs.ExtRef {
  1658. //检查端子2端模型是否相同:DO对应DO,DA对应DA
  1659. hasinsideda := extref.DaName != ""
  1660. hasoutsideda := strings.Count(extref.IntAddr, ".") > 1
  1661. if hasinsideda != hasoutsideda {
  1662. extrefstr := fmt.Sprintf("IED=%s,addr=%s/%s%s%s.%s", extref.IedName, extref.LdInst, extref.Prefix, extref.LnClass, extref.LnInst, extref.DoName)
  1663. if extref.DaName != "" {
  1664. extrefstr = extrefstr + "." + extref.DaName
  1665. }
  1666. parse_result := fmt.Sprintf("IED(%s)中访问点(%s:%s)中LD(%s)的关联内(%s)外部虚端子(%s)类型不一致", iedObj.Name, ap.Name, ap.Desc, ld.Inst, extref.IntAddr, extrefstr)
  1667. r := map[string]interface{}{"scdid": c.ScdID, "lineno": extref.Lineno, "ruleid": c.getRuleIdByName("连线两端数据不匹配"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
  1668. c.AppendPaseResult(r, iedObj)
  1669. }
  1670. has1, cdc1 := c.IedFcdaExist(extref.IedName, extref.LdInst, extref.LnClass, extref.LnInst, extref.Prefix, extref.DoName, extref.DaName)
  1671. if has1 == nil {
  1672. extrefstr := fmt.Sprintf("IED=%s,addr=%s/%s%s%s.%s", extref.IedName, extref.LdInst, extref.Prefix, extref.LnClass, extref.LnInst, extref.DoName)
  1673. if extref.DaName != "" {
  1674. extrefstr = extrefstr + "." + extref.DaName
  1675. }
  1676. parse_result := fmt.Sprintf("IED(%s)中访问点(%s:%s)中LD(%s)的关联外部虚端子(%s)不存在", iedObj.Name, ap.Name, ap.Desc, ld.Inst, extrefstr)
  1677. r := map[string]interface{}{"scdid": c.ScdID, "lineno": extref.Lineno, "ruleid": c.getRuleIdByName("连线外部虚端子合法性"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
  1678. c.AppendPaseResult(r, iedObj)
  1679. }
  1680. //内部地址对应的定义是否存在校验
  1681. /*
  1682. has2 := c.iedIntAddrExist(iedObj.Name, extref.IntAddr)
  1683. if has2 == nil {
  1684. parse_result := fmt.Sprintf("IED(%s)中访问点(%s:%s)中LD(%s)的虚回路关联内部虚端子(%s)不存在", iedObj.Name, ap.Name, ap.Desc, ld.Inst, extref.IntAddr)
  1685. r := map[string]interface{}{"scdid": c.ScdID, "lineno": extref.Lineno, "ruleid": c.getRuleIdByName("连线内部参引对应数据不存在"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
  1686. c.AppendPaseResult(r, iedObj)
  1687. }
  1688. */
  1689. //da或do实例化校验
  1690. has2, cdc2 := c.iedIntAddrDoiOrDaiExist(iedObj.Name, extref.IntAddr)
  1691. if has2 == nil {
  1692. //parse_result := fmt.Sprintf("IED(%s)中访问点(%s:%s)中LD(%s)的虚回路关联内部虚端子(%s)属性值与实例化不匹配", iedObj.Name, ap.Name, ap.Desc, ld.Inst, extref.IntAddr)
  1693. //r := map[string]interface{}{"scdid": c.ScdID, "lineno": extref.Lineno, "ruleid": c.getRuleIdByName("连线内部参引对应数据不存在"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
  1694. //c.AppendPaseResult(r, iedObj)
  1695. }
  1696. //连接2端端子数据类型匹配检查。即DO数据模板的cdc属性值以及Da的bType
  1697. if has1 != nil && has2 != nil && cdc1 != cdc2 {
  1698. tmpTypeName := "CDC"
  1699. if extref.DaName != "" {
  1700. tmpTypeName = "bType"
  1701. }
  1702. parse_result := fmt.Sprintf("IED(%s)中访问点(%s:%s)中LD(%s)的虚端子(%s)%s类型(%s)与关联外部虚端子(%s %s/%s%s%s.%s)的类型(%s)不匹配", iedObj.Name, ap.Name, ap.Desc, ld.Inst, extref.IntAddr, tmpTypeName, cdc2, extref.IedName, extref.LdInst, extref.Prefix, extref.LnClass, extref.LnInst, extref.DoName, cdc1)
  1703. r := map[string]interface{}{"scdid": c.ScdID, "lineno": extref.Lineno, "ruleid": c.getRuleIdByName("连线两端数据不匹配"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
  1704. c.AppendPaseResult(r, iedObj)
  1705. }
  1706. }
  1707. }
  1708. //GOOSE控制块校验
  1709. gooseitemMap := map[string]int{}
  1710. if iedObj.Services.GOOSE != nil {
  1711. max, _ := strconv.Atoi(iedObj.Services.GOOSE.Max)
  1712. if len(ld.LN0.GSEControl) > max {
  1713. parse_result := fmt.Sprintf("IED(%s)中访问点(%s:%s)下的LD(%s)GOOSE控制块个数%d超出声明的最大值(%d)", iedObj.Name, ap.Name, ap.Desc, ld.Inst, len(ld.LN0.GSEControl), max)
  1714. r := map[string]interface{}{"scdid": c.ScdID, "lineno": iedObj.Services.GOOSE.Lineno, "ruleid": c.getRuleIdByName("GOOSE控制块的个数超出声明的最大值"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
  1715. c.AppendPaseResult(r, iedObj)
  1716. }
  1717. }
  1718. for _, gooseitem := range ld.LN0.GSEControl {
  1719. if gooseitemMap[gooseitem.Name] == 1 {
  1720. parse_result := fmt.Sprintf("IED(%s)中访问点(%s:%s)下的LD(%s)GOOSE控制块(%s)name属性值在LN内重复配置", iedObj.Name, ap.Name, ap.Desc, ld.Inst, gooseitem.Name)
  1721. r := map[string]interface{}{"scdid": c.ScdID, "lineno": gooseitem.Lineno, "ruleid": c.getRuleIdByName("GOOSE控制块的name属性值在LN内重复配置"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
  1722. c.AppendPaseResult(r)
  1723. continue
  1724. }
  1725. gooseitemMap[gooseitem.Name] = 1
  1726. if datsetList[gooseitem.DatSet] == nil {
  1727. parse_result := fmt.Sprintf("IED(%s)中访问点(%s:%s)下的LD(%s)GOOSE控制块(%s)引用的数据集(%s)不存在", iedObj.Name, ap.Name, ap.Desc, ld.Inst, gooseitem.Name, gooseitem.DatSet)
  1728. r := map[string]interface{}{"scdid": c.ScdID, "lineno": gooseitem.Lineno, "ruleid": c.getRuleIdByName("GOOSE控制块引用的数据集不存在"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
  1729. c.AppendPaseResult(r, iedObj)
  1730. }
  1731. if gooseitem.AppID == "" {
  1732. parse_result := fmt.Sprintf("IED(%s)中访问点(%s:%s)下的LD(%s)GOOSE控制块(%s)appID属性配置错误", iedObj.Name, ap.Name, ap.Desc, ld.Inst, gooseitem.Name)
  1733. r := map[string]interface{}{"scdid": c.ScdID, "lineno": gooseitem.Lineno, "ruleid": c.getRuleIdByName("GOOSE控制块的appID属性配置错误(缺失、值为空)"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
  1734. c.AppendPaseResult(r, iedObj)
  1735. } else {
  1736. if tmpIED, h := gooseAppidMap.Load(gooseitem.AppID); h {
  1737. iedPointer := tmpIED.(*node_attr.NIED)
  1738. parse_result := fmt.Sprintf("IED(%s)中访问点(%s:%s)下的LD(%s)GOOSE控制块(%s)的appID(%s)与IED(%s)中重复定义", iedObj.Name, ap.Name, ap.Desc, ld.Inst, gooseitem.Name, gooseitem.AppID, iedPointer.Name)
  1739. r := map[string]interface{}{"scdid": c.ScdID, "lineno": gooseitem.Lineno, "ruleid": c.getRuleIdByName("GOOSE控制块的appID唯一性"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
  1740. c.AppendPaseResult(r, iedObj)
  1741. }
  1742. //格式校验
  1743. newGooseAppid := fmt.Sprintf("%s%s/LLN0.%s", iedObj.Name, ld.Inst, gooseitem.Name)
  1744. if gooseitem.AppID != newGooseAppid {
  1745. parse_result := fmt.Sprintf("IED(%s)中访问点(%s:%s)下的LD(%s)GOOSE控制块(%s)的appID(%s)格式不符合规范", iedObj.Name, ap.Name, ap.Desc, ld.Inst, gooseitem.Name, gooseitem.AppID)
  1746. r := map[string]interface{}{"scdid": c.ScdID, "lineno": gooseitem.Lineno, "ruleid": c.getRuleIdByName("GOOSE控制块appID格式校验"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
  1747. c.AppendPaseResult(r, iedObj)
  1748. }
  1749. gooseAppidMap.Store(gooseitem.AppID, iedObj)
  1750. if gooseitem.ConfRev == "" {
  1751. parse_result := fmt.Sprintf("IED(%s)中访问点(%s:%s)下的LD(%s)GOOSE控制块(%s)的confRev属性配置错误", iedObj.Name, ap.Name, ap.Desc, ld.Inst, gooseitem.Name)
  1752. r := map[string]interface{}{"scdid": c.ScdID, "lineno": gooseitem.Lineno, "ruleid": c.getRuleIdByName("GOOSE控制块的confRev属性配置错误(缺失、值为空)"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
  1753. c.AppendPaseResult(r, iedObj)
  1754. }
  1755. //是否配置网络参数
  1756. gseNetFound := false
  1757. for _, net := range c.scdXmlObject.Communication.SubNetwork {
  1758. if net.Type != gooseitem.Type && net.Type != "IECGOOSE" {
  1759. continue
  1760. }
  1761. for _, connAp := range net.ConnectedAP {
  1762. if connAp.IedName == iedObj.Name {
  1763. for _, gseNet := range connAp.GSE {
  1764. if gseNet.CbName == gooseitem.Name && gseNet.LdInst == ld.Inst {
  1765. gseNetFound = true
  1766. }
  1767. }
  1768. }
  1769. }
  1770. }
  1771. if !gseNetFound {
  1772. parse_result := fmt.Sprintf("IED(%s)中访问点(%s:%s)下的LD(%s)GOOSE控制块(%s)未配置网络参数", iedObj.Name, ap.Name, ap.Desc, ld.Inst, gooseitem.Name)
  1773. r := map[string]interface{}{"scdid": c.ScdID, "lineno": gooseitem.Lineno, "ruleid": c.getRuleIdByName("GOOSE控制块未配置网络参数"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
  1774. c.AppendPaseResult(r, iedObj)
  1775. }
  1776. }
  1777. }
  1778. //SV控制块
  1779. smvitemMap := map[string]int{}
  1780. for _, gooseitem := range ld.LN0.SampledValueControl {
  1781. if smvitemMap[gooseitem.Name] == 1 {
  1782. parse_result := fmt.Sprintf("IED(%s)中访问点(%s:%s)下的LD(%s)SV控制块(%s)name属性值在LN内重复配置", iedObj.Name, ap.Name, ap.Desc, ld.Inst, gooseitem.Name)
  1783. r := map[string]interface{}{"scdid": c.ScdID, "lineno": gooseitem.Lineno, "ruleid": c.getRuleIdByName("SV控制块的name属性值在LN内重复配置"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
  1784. c.AppendPaseResult(r, iedObj)
  1785. continue
  1786. }
  1787. smvitemMap[gooseitem.Name] = 1
  1788. if datsetList[gooseitem.DatSet] == nil {
  1789. parse_result := fmt.Sprintf("IED(%s)中访问点(%s:%s)下的LD(%s)SV控制块(%s)引用的数据集(%s)不存在", iedObj.Name, ap.Name, ap.Desc, ld.Inst, gooseitem.Name, gooseitem.DatSet)
  1790. r := map[string]interface{}{"scdid": c.ScdID, "lineno": gooseitem.Lineno, "ruleid": c.getRuleIdByName("SV控制块引用的数据集不存在"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
  1791. c.AppendPaseResult(r, iedObj)
  1792. }
  1793. if gooseitem.SmvID == "" {
  1794. parse_result := fmt.Sprintf("IED(%s)中访问点(%s:%s)下的LD(%s)SV控制块(%s)smvID属性配置错误", iedObj.Name, ap.Name, ap.Desc, ld.Inst, gooseitem.Name)
  1795. r := map[string]interface{}{"scdid": c.ScdID, "lineno": gooseitem.Lineno, "ruleid": c.getRuleIdByName("SV控制块的smvID属性配置错误(缺失、值为空)"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
  1796. c.AppendPaseResult(r, iedObj)
  1797. } else {
  1798. if tmpIED, h := smvAppidMap.Load(gooseitem.SmvID); h {
  1799. iedPointer := tmpIED.(*node_attr.NIED)
  1800. parse_result := fmt.Sprintf("IED(%s)中访问点(%s:%s)下的LD(%s)SV控制块(%s)的smvID(%s)与IED(%s)中重复定义", iedObj.Name, ap.Name, ap.Desc, ld.Inst, gooseitem.Name, gooseitem.SmvID, iedPointer.Name)
  1801. r := map[string]interface{}{"scdid": c.ScdID, "lineno": gooseitem.Lineno, "ruleid": c.getRuleIdByName("SV控制块的smvID唯一性"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
  1802. c.AppendPaseResult(r, iedObj)
  1803. }
  1804. //格式校验
  1805. newGooseAppid := fmt.Sprintf("%s%s/LLN0.%s", iedObj.Name, ld.Inst, gooseitem.Name)
  1806. if gooseitem.SmvID != newGooseAppid {
  1807. parse_result := fmt.Sprintf("IED(%s)中访问点(%s:%s)下的LD(%s)SV控制块(%s)的appID(%s)格式不符合规范", iedObj.Name, ap.Name, ap.Desc, ld.Inst, gooseitem.Name, gooseitem.SmvID)
  1808. r := map[string]interface{}{"scdid": c.ScdID, "lineno": gooseitem.Lineno, "ruleid": c.getRuleIdByName("SV控制块appID格式校验"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
  1809. c.AppendPaseResult(r, iedObj)
  1810. }
  1811. smvAppidMap.Store(gooseitem.SmvID, iedObj)
  1812. if gooseitem.ConfRev == "" {
  1813. parse_result := fmt.Sprintf("IED(%s)中访问点(%s:%s)下的LD(%s)SV控制块(%s)的confRev属性配置错误", iedObj.Name, ap.Name, ap.Desc, ld.Inst, gooseitem.Name)
  1814. r := map[string]interface{}{"scdid": c.ScdID, "lineno": gooseitem.Lineno, "ruleid": c.getRuleIdByName("SV控制块的confRev属性配置错误(缺失、值为空)"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
  1815. c.AppendPaseResult(r, iedObj)
  1816. }
  1817. if gooseitem.SmpRate == "" {
  1818. parse_result := fmt.Sprintf("IED(%s)中访问点(%s:%s)下的LD(%s)SV控制块(%s)的smpRate属性配置错误", iedObj.Name, ap.Name, ap.Desc, ld.Inst, gooseitem.Name)
  1819. r := map[string]interface{}{"scdid": c.ScdID, "lineno": gooseitem.Lineno, "ruleid": c.getRuleIdByName("SV控制块的smpRate属性配置错误(缺失、值为空)"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
  1820. c.AppendPaseResult(r, iedObj)
  1821. }
  1822. if gooseitem.NofASDU == "" {
  1823. parse_result := fmt.Sprintf("IED(%s)中访问点(%s:%s)下的LD(%s)SV控制块(%s)的nofASDU属性配置错误", iedObj.Name, ap.Name, ap.Desc, ld.Inst, gooseitem.Name)
  1824. r := map[string]interface{}{"scdid": c.ScdID, "lineno": gooseitem.Lineno, "ruleid": c.getRuleIdByName("SV控制块的nofASDU属性配置错误(缺失、值为空)"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
  1825. c.AppendPaseResult(r, iedObj)
  1826. }
  1827. //是否配置网络参数
  1828. gseNetFound := false
  1829. for _, net := range c.scdXmlObject.Communication.SubNetwork {
  1830. if net.Type != "SMV" {
  1831. continue
  1832. }
  1833. for _, connAp := range net.ConnectedAP {
  1834. if connAp.IedName == iedObj.Name {
  1835. for _, gseNet := range connAp.SMV {
  1836. if gseNet.CbName == gooseitem.Name && gseNet.LdInst == ld.Inst {
  1837. gseNetFound = true
  1838. }
  1839. }
  1840. }
  1841. }
  1842. }
  1843. if !gseNetFound {
  1844. parse_result := fmt.Sprintf("IED(%s)中访问点(%s:%s)下的LD(%s)SV控制块(%s)未配置网络参数", iedObj.Name, ap.Name, ap.Desc, ld.Inst, gooseitem.Name)
  1845. r := map[string]interface{}{"scdid": c.ScdID, "lineno": gooseitem.Lineno, "ruleid": c.getRuleIdByName("SV控制块未配置网络参数"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
  1846. c.AppendPaseResult(r, iedObj)
  1847. }
  1848. }
  1849. }
  1850. //日志控制块校验
  1851. logNameMap := map[string]int{}
  1852. for _, logItem := range ld.LN0.LogControl {
  1853. if logItem.DatSet == "" {
  1854. parse_result := fmt.Sprintf("IED(%s)中访问点(%s:%s)下的LD(%s)日志控制块(%s)datSet属性配置错误(缺失、值为空)", iedObj.Name, ap.Name, ap.Desc, ld.Inst, logItem.Name)
  1855. r := map[string]interface{}{"scdid": c.ScdID, "lineno": logItem.Lineno, "ruleid": c.getRuleIdByName("日志控制块的datSet属性配置错误(缺失、值为空)"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
  1856. c.AppendPaseResult(r, iedObj)
  1857. } else {
  1858. logDatsetFound := false
  1859. for _, dsitem := range ld.LN0.DataSet {
  1860. if dsitem.Name == logItem.DatSet {
  1861. logDatsetFound = true
  1862. break
  1863. }
  1864. }
  1865. if !logDatsetFound {
  1866. parse_result := fmt.Sprintf("IED(%s)中访问点(%s:%s)下的LD(%s)日志控制块(%s)引用的数据集(%s)不存在", iedObj.Name, ap.Name, ap.Desc, ld.Inst, logItem.Name, logItem.DatSet)
  1867. r := map[string]interface{}{"scdid": c.ScdID, "lineno": logItem.Lineno, "ruleid": c.getRuleIdByName("日志控制块引用的数据集不存在"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
  1868. c.AppendPaseResult(r, iedObj)
  1869. }
  1870. }
  1871. if logItem.IntgPd == "" {
  1872. parse_result := fmt.Sprintf("IED(%s)中访问点(%s:%s)下的LD(%s)日志控制块(%s)intgPd属性配置错误(缺失、值为空)", iedObj.Name, ap.Name, ap.Desc, ld.Inst, logItem.Name)
  1873. r := map[string]interface{}{"scdid": c.ScdID, "lineno": logItem.Lineno, "ruleid": c.getRuleIdByName("日志控制块的intgPd属性配置错误(缺失、值为空)"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
  1874. c.AppendPaseResult(r, iedObj)
  1875. }
  1876. logLdnameFound := false
  1877. for _, logLd := range ap.Server.LDevice {
  1878. if logLd.Inst == logItem.LogName {
  1879. logLdnameFound = true
  1880. break
  1881. }
  1882. }
  1883. if !logLdnameFound {
  1884. parse_result := fmt.Sprintf("IED(%s)中访问点(%s:%s)下的LD(%s)日志控制块(%s)对应的日志名(%s)不存在", iedObj.Name, ap.Name, ap.Desc, ld.Inst, logItem.Name, logItem.LogName)
  1885. r := map[string]interface{}{"scdid": c.ScdID, "lineno": logItem.Lineno, "ruleid": c.getRuleIdByName("日志控制块对应的日志名不存在"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
  1886. c.AppendPaseResult(r, iedObj)
  1887. }
  1888. if _, h := logNameMap[logItem.Name]; h {
  1889. parse_result := fmt.Sprintf("IED(%s)中访问点(%s:%s)下的LD(%s)日志控制块的name(%s)属性在LN下配置重复", iedObj.Name, ap.Name, ap.Desc, ld.Inst, logItem.Name)
  1890. r := map[string]interface{}{"scdid": c.ScdID, "lineno": logItem.Lineno, "ruleid": c.getRuleIdByName("日志控制块的name属性在LN下配置重复"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
  1891. c.AppendPaseResult(r, iedObj)
  1892. }
  1893. logNameMap[logItem.Name] = 1
  1894. }
  1895. //报告控制块校验
  1896. reportNameMap := map[string]int{}
  1897. for _, reportItem := range ld.LN0.ReportControl {
  1898. if reportItem.DatSet != "" {
  1899. datsetFound := false
  1900. for _, dsitem := range ld.LN0.DataSet {
  1901. if dsitem.Name == reportItem.DatSet {
  1902. datsetFound = true
  1903. break
  1904. }
  1905. }
  1906. if !datsetFound {
  1907. parse_result := fmt.Sprintf("IED(%s)中访问点(%s:%s)下的LD(%s)报告控制块(%s)引用的数据集(%s)不存在", iedObj.Name, ap.Name, ap.Desc, ld.Inst, reportItem.Name, reportItem.DatSet)
  1908. r := map[string]interface{}{"scdid": c.ScdID, "lineno": reportItem.Lineno, "ruleid": c.getRuleIdByName("报告控制块引用的数据集不存在"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
  1909. c.AppendPaseResult(r, iedObj)
  1910. }
  1911. }
  1912. if reportItem.RptID == "" {
  1913. parse_result := fmt.Sprintf("IED(%s)中访问点(%s:%s)下的LD(%s)报告控制块(%s)中的rptID属性配置错误(缺失、值为空)", iedObj.Name, ap.Name, ap.Desc, ld.Inst, reportItem.Name)
  1914. r := map[string]interface{}{"scdid": c.ScdID, "lineno": reportItem.Lineno, "ruleid": c.getRuleIdByName("报告控制块的rptID属性配置错误(缺失、值为空)"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
  1915. c.AppendPaseResult(r, iedObj)
  1916. } else {
  1917. if v, h := reportRptIDMap.Load(iedObj.Name + reportItem.RptID); h {
  1918. v1 := v.(map[string]interface{})
  1919. parse_result := fmt.Sprintf("IED(%s)中访问点(%s:%s)下的LD(%s)报告控制块(%s)属性rptID(%s)与IED(%s)中报告控制块(%s)rptID重复", iedObj.Name, ap.Name, ap.Desc, ld.Inst, reportItem.Name, reportItem.RptID, tools.IsEmpty(v1["iedname"]), tools.IsEmpty(v1["reportcontrol"]))
  1920. r := map[string]interface{}{"scdid": c.ScdID, "lineno": reportItem.Lineno, "ruleid": c.getRuleIdByName("报告控制块的rptID重复"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
  1921. c.AppendPaseResult(r, iedObj)
  1922. }
  1923. reportRptIDMap.Store(iedObj.Name+reportItem.RptID, map[string]interface{}{"iedname": iedObj.Name, "reportcontrol": reportItem.Name})
  1924. }
  1925. if reportItem.ConfRev == "" {
  1926. parse_result := fmt.Sprintf("IED(%s)中访问点(%s:%s)下的LD(%s)报告控制块(%s)中的confRev属性配置错误(缺失、值为空)", iedObj.Name, ap.Name, ap.Desc, ld.Inst, reportItem.Name)
  1927. r := map[string]interface{}{"scdid": c.ScdID, "lineno": reportItem.Lineno, "ruleid": c.getRuleIdByName("报告控制块的confRev属性配置错误(缺失、值为空)"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
  1928. c.AppendPaseResult(r, iedObj)
  1929. }
  1930. if _, h := reportNameMap[iedObj.Name+reportItem.Name]; h {
  1931. parse_result := fmt.Sprintf("IED(%s)中访问点(%s:%s)下的LD(%s)报告控制块的name(%s)属性在LN下配置重复", iedObj.Name, ap.Name, ap.Desc, ld.Inst, reportItem.Name)
  1932. r := map[string]interface{}{"scdid": c.ScdID, "lineno": reportItem.Lineno, "ruleid": c.getRuleIdByName("报告控制块的name属性在LN下配置重复"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
  1933. c.AppendPaseResult(r, iedObj)
  1934. }
  1935. reportNameMap[iedObj.Name+reportItem.Name] = 1
  1936. if len(reportItem.Name) >= 4 && (reportItem.Name[0:4] == "brcb" || reportItem.Name[0:4] == "urcb") {
  1937. //名称符合规范
  1938. } else {
  1939. parse_result := fmt.Sprintf("IED(%s)中访问点(%s:%s)下的LD(%s)报告控制块的name(%s)属性未按规范命名", iedObj.Name, ap.Name, ap.Desc, ld.Inst, reportItem.Name)
  1940. r := map[string]interface{}{"scdid": c.ScdID, "lineno": reportItem.Lineno, "ruleid": c.getRuleIdByName("报告控制块属性正确性及规范性检查"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
  1941. c.AppendPaseResult(r, iedObj)
  1942. }
  1943. }
  1944. //定值控制块校验
  1945. if ld.LN0.SettingControl != nil {
  1946. if ld.LN0.SettingControl.ActSG == "" {
  1947. parse_result := fmt.Sprintf("IED(%s)中访问点(%s:%s)下的LD(%s)定值控制块actSG属性配置值不正确", iedObj.Name, ap.Name, ap.Desc, ld.Inst)
  1948. r := map[string]interface{}{"scdid": c.ScdID, "lineno": ld.LN0.SettingControl.Lineno, "ruleid": c.getRuleIdByName("定值控制块的actSG属性配置错误(值不正确)"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
  1949. c.AppendPaseResult(r, iedObj)
  1950. }
  1951. if ld.LN0.SettingControl.NumOfSGs == "" {
  1952. parse_result := fmt.Sprintf("IED(%s)中访问点(%s:%s)下的LD(%s)定值控制块numOfSGs属性配置值不正确", iedObj.Name, ap.Name, ap.Desc, ld.Inst)
  1953. r := map[string]interface{}{"scdid": c.ScdID, "lineno": ld.LN0.SettingControl.Lineno, "ruleid": c.getRuleIdByName("定值控制块的numOfSGs属性配置错误(值不正确)"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
  1954. c.AppendPaseResult(r, iedObj)
  1955. }
  1956. }
  1957. }
  1958. lphdFound := false
  1959. otherLnFound := false
  1960. for _, lns := range ld.LN {
  1961. if _, h := c.lnodeTypeMap.Load(lns.LnType); !h {
  1962. parse_result := fmt.Sprintf("IED(%s)中访问点(%s:%s)中LD(%s)下的LN(%s)引用的LNodeType(%s)在模板中不存在", iedObj.Name, ap.Name, ap.Desc, ld.Inst, lns.Desc, lns.LnType)
  1963. r := map[string]interface{}{"scdid": c.ScdID, "lineno": lns.Lineno, "ruleid": c.getRuleIdByName("LN引用LNodeType不存在"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
  1964. c.AppendPaseResult(r, iedObj)
  1965. }
  1966. if lns.LnClass == "LPHD" {
  1967. lphdFound = true
  1968. } else {
  1969. otherLnFound = true
  1970. }
  1971. }
  1972. if !lphdFound {
  1973. parse_result := fmt.Sprintf("IED(%s)中访问点(%s:%s)中LD(%s)的缺失对象LPHD", iedObj.Name, ap.Name, ap.Desc, ld.Inst)
  1974. r := map[string]interface{}{"scdid": c.ScdID, "lineno": ld.Lineno, "ruleid": c.getRuleIdByName("逻辑设备建模正确性"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
  1975. c.AppendPaseResult(r, iedObj)
  1976. }
  1977. if !otherLnFound {
  1978. parse_result := fmt.Sprintf("IED(%s)中访问点(%s:%s)中LD(%s)的缺失非LPHD外其他LN", iedObj.Name, ap.Name, ap.Desc, ld.Inst)
  1979. r := map[string]interface{}{"scdid": c.ScdID, "lineno": ld.Lineno, "ruleid": c.getRuleIdByName("逻辑设备建模正确性"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
  1980. c.AppendPaseResult(r, iedObj)
  1981. }
  1982. }
  1983. }
  1984. }
  1985. }
  1986. //校验IED crc一致性
  1987. func (c *ScdNodeRule) CheckFunc_crc() {
  1988. defer func() {
  1989. c.isRun = 2 //校验完成标识
  1990. c.Flush() //将校验结果写数据库
  1991. }()
  1992. logger.Logger.Debug(fmt.Sprintf("校验SCD %d的IED Crc", c.ScdID))
  1993. if c.scdXmlObject == nil {
  1994. return
  1995. }
  1996. checkcnt := 1
  1997. timeoutTotal := len(c.scdXmlObject.IED) * 3
  1998. for {
  1999. //检查crc提取是否完成
  2000. if v, h := global.IedCrcMakeState.Load(fmt.Sprintf("crc_%d", c.ScdID)); h {
  2001. v1 := tools.IsEmpty(v)
  2002. if v1 == "0" || v1 == "2" {
  2003. //提取失败0或者已完成2
  2004. break
  2005. }
  2006. }
  2007. time.Sleep(500 * time.Millisecond)
  2008. checkcnt = checkcnt + 1
  2009. if checkcnt > timeoutTotal {
  2010. //crc提取超时
  2011. logger.Logger.Error(errors.New(fmt.Sprintf("SCD %d的IED Crc提取超时", c.ScdID)))
  2012. break
  2013. }
  2014. }
  2015. crclist, _ := global.CachedScdCrc.Load(fmt.Sprintf("crc_%d", c.ScdID))
  2016. if crclist == nil {
  2017. logger.Logger.Debug(fmt.Sprintf("未找到SCD %d的IED Crc提取结果数据", c.ScdID))
  2018. return
  2019. }
  2020. crcmap := crclist.(map[string]string)
  2021. for _, iedObj := range c.scdXmlObject.IED {
  2022. crc := ""
  2023. p := new(node_attr.NPrivate)
  2024. for _, p = range iedObj.Priavate {
  2025. if p.Type == "IED virtual terminal conection CRC" {
  2026. crc = p.InnerText
  2027. break
  2028. }
  2029. }
  2030. iedcrc2 := crcmap[iedObj.Name]
  2031. if crc != "" && iedcrc2 != crc {
  2032. parse_result := fmt.Sprintf("IED(%s)中存储的CCD校验码(%s)与实际校验码(%s)不一致", iedObj.Name, crc, iedcrc2)
  2033. r := map[string]interface{}{"scdid": c.ScdID, "lineno": p.Lineno, "ruleid": c.getRuleIdByName("CCD校验码校验"), "nodeid": c.scdXmlObject.DataTypeTemplates.NodeId, "parse_result": parse_result}
  2034. c.AppendPaseResult(r, iedObj)
  2035. }
  2036. }
  2037. }
  2038. func (c *ScdNodeRule) check_ln_doidai(iedObj *node_attr.NIED, dATypeMap map[string]*node_attr.NDAType, ld *node_attr.NLDevice) {
  2039. if c.daMap == nil {
  2040. c.daMap = &sync.Map{}
  2041. }
  2042. if c.doiMap == nil {
  2043. c.doiMap = &sync.Map{}
  2044. }
  2045. if ld.LN0 != nil {
  2046. vlnnode, _ := c.lnodeTypeMap.Load(ld.LN0.LnType)
  2047. if vlnnode == nil {
  2048. parse_result := fmt.Sprintf("IED(%s)中LD(%s%s)下的LN(%s%s)引用的LNodeType(%s)在模板中不存在", iedObj.Name, ld.Desc, ld.Inst, ld.LN0.Desc, ld.LN0.Inst, ld.LN0.LnType)
  2049. r := map[string]interface{}{"scdid": c.ScdID, "lineno": ld.LN0.Lineno, "ruleid": c.getRuleIdByName("LN引用LNodeType不存在"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
  2050. c.AppendPaseResult(r, iedObj)
  2051. } else {
  2052. lnnode := vlnnode.(*node_attr.NLNodeType)
  2053. lnchilderdoi := map[string]string{}
  2054. v_lnchilderdoi, _ := c.doiMap.Load(ld.LN0.LnType)
  2055. if v_lnchilderdoi == nil {
  2056. for _, do := range lnnode.DO {
  2057. lnchilderdoi[do.Name] = do.Type
  2058. }
  2059. c.doiMap.Store(ld.LN0.LnType, lnchilderdoi)
  2060. } else {
  2061. lnchilderdoi = v_lnchilderdoi.(map[string]string)
  2062. }
  2063. for _, doi := range ld.LN0.DOI {
  2064. if lnchilderdoi[doi.Name] == "" {
  2065. //fmt.Println(fmt.Sprintf("ied:%s LN0.LnType:%s doi.Name:%s %+v", iedObj.Name, ld.LN0.LnType, doi.Name, lnchilderdoi))
  2066. parse_result := fmt.Sprintf("IED(%s)中LD(%s%s)下的LN(%s%s)引用的DOI/SDI(%s)在模板中不存在", iedObj.Name, ld.Desc, ld.Inst, ld.LN0.Desc, ld.LN0.Inst, doi.Name)
  2067. r := map[string]interface{}{"scdid": c.ScdID, "lineno": doi.Lineno, "ruleid": c.getRuleIdByName("DOI/SDI引用模板不一致"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
  2068. c.AppendPaseResult(r, iedObj)
  2069. }
  2070. }
  2071. }
  2072. }
  2073. for _, ln := range ld.LN {
  2074. vlnnode, _ := c.lnodeTypeMap.Load(ln.LnType)
  2075. if vlnnode == nil {
  2076. parse_result := fmt.Sprintf("IED(%s)中LD(%s%s)下的LN(%s%s)引用的LNodeType(%s)在模板中不存在", iedObj.Name, ld.Desc, ld.Inst, ln.Desc, ln.Inst, ln.LnType)
  2077. r := map[string]interface{}{"scdid": c.ScdID, "lineno": ln.Lineno, "ruleid": c.getRuleIdByName("LN引用LNodeType不存在"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
  2078. c.AppendPaseResult(r, iedObj)
  2079. } else {
  2080. lnnode := vlnnode.(*node_attr.NLNodeType)
  2081. lnchilderdoi := map[string]string{}
  2082. v_lnchilderdoi, _ := c.doiMap.Load(ln.LnType)
  2083. if v_lnchilderdoi == nil {
  2084. for _, do := range lnnode.DO {
  2085. lnchilderdoi[do.Name] = do.Type
  2086. }
  2087. c.doiMap.Store(ln.LnType, lnchilderdoi)
  2088. } else {
  2089. lnchilderdoi = v_lnchilderdoi.(map[string]string)
  2090. }
  2091. for _, doi := range ln.DOI {
  2092. if lnchilderdoi[doi.Name] == "" {
  2093. //fmt.Println(fmt.Sprintf("ied:%s LN.LnType:%s doi.Name:%s %+v", iedObj.Name, ln.LnType, doi.Name, lnchilderdoi))
  2094. parse_result := fmt.Sprintf("IED(%s)中LD(%s%s)下的LN(%s%s)引用的DOI/SDI(%s)在模板中不存在", iedObj.Name, ld.Desc, ld.Inst, ln.Desc, ln.Inst, doi.Name)
  2095. r := map[string]interface{}{"scdid": c.ScdID, "lineno": doi.Lineno, "ruleid": c.getRuleIdByName("DOI/SDI引用模板不一致"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
  2096. c.AppendPaseResult(r)
  2097. continue
  2098. }
  2099. dotype := lnchilderdoi[doi.Name]
  2100. dalist := map[string]string{}
  2101. v_dalist, _ := c.daMap.Load(dotype)
  2102. if v_dalist == nil {
  2103. v, _ := c.doTypeMap.Load(dotype)
  2104. if v == nil {
  2105. //do模板不存在
  2106. continue
  2107. }
  2108. for _, daitem := range v.(*node_attr.NDOType).DA {
  2109. dalist[daitem.Name] = "1"
  2110. }
  2111. c.daMap.Store(dotype, dalist)
  2112. } else {
  2113. dalist = v_dalist.(map[string]string)
  2114. }
  2115. for _, da := range doi.DAI {
  2116. if dalist[da.Name] == "" {
  2117. //fmt.Println(fmt.Sprintf("IED(%s)中LD(%s%s)下的LN(%s%s)引用的DAI(%s) %+v", iedObj.Name, ld.Desc, ld.Inst, ln.Desc, ln.Inst, da.Name, daMap[dotype]))
  2118. parse_result := fmt.Sprintf("IED(%s)中LD(%s%s)下的LN(%s%s)引用的DAI(%s)在模板中不存在", iedObj.Name, ld.Desc, ld.Inst, ln.Desc, ln.Inst, da.Name)
  2119. r := map[string]interface{}{"scdid": c.ScdID, "lineno": da.Lineno, "ruleid": c.getRuleIdByName("DAI引用模板不一致"), "nodeid": iedObj.NodeId, "parse_result": parse_result}
  2120. c.AppendPaseResult(r, iedObj)
  2121. }
  2122. }
  2123. }
  2124. }
  2125. }
  2126. }
  2127. //DataTypeTemplates校验
  2128. //数据实例引用模板正确性检查
  2129. //数据类型模板引用正确性检查
  2130. //模板重复定义校验
  2131. //冗余模板校验
  2132. func (c *ScdNodeRule) CheckFunc_datatypetemplates(para orm.Params) (a3 map[string]*node_attr.NDAType) {
  2133. logger.Logger.Debug(fmt.Sprintf("校验SCD %d的数据模板节点", c.ScdID))
  2134. if c.scdXmlObject == nil {
  2135. return
  2136. }
  2137. usedLNodeTypeMap := map[string]int{}
  2138. for _, iedObj := range c.scdXmlObject.IED {
  2139. for _, acc := range iedObj.AccessPoint {
  2140. if acc.Server == nil {
  2141. continue
  2142. }
  2143. for _, ld := range acc.Server.LDevice {
  2144. usedLNodeTypeMap[ld.LN0.LnType] = 1
  2145. for _, ln := range ld.LN {
  2146. usedLNodeTypeMap[ln.LnType] = 1
  2147. }
  2148. }
  2149. }
  2150. }
  2151. usedDoTypeMap := map[string]int{}
  2152. daTypeMap := map[string]*node_attr.NDAType{}
  2153. usedDaTypeMap := map[string]int{}
  2154. enumTypeMap := map[string]*node_attr.NEnumType{}
  2155. usedEnumTypeMap := map[string]int{}
  2156. for _, enumtype := range c.scdXmlObject.DataTypeTemplates.EnumType {
  2157. if enumTypeMap[enumtype.Id] != nil {
  2158. parse_result := fmt.Sprintf("EnumType(%s)定义重复", enumtype.Id)
  2159. r := map[string]interface{}{"scdid": c.ScdID, "lineno": enumtype.Lineno, "ruleid": c.getRuleIdByName("模板重复定义校验"), "nodeid": c.scdXmlObject.DataTypeTemplates.NodeId, "parse_result": parse_result}
  2160. c.AppendPaseResult(r)
  2161. continue
  2162. }
  2163. enumTypeMap[enumtype.Id] = enumtype
  2164. }
  2165. for _, datype := range c.scdXmlObject.DataTypeTemplates.DAType {
  2166. if daTypeMap[datype.Id] != nil {
  2167. parse_result := fmt.Sprintf("DAType(%s)定义重复", datype.Id)
  2168. r := map[string]interface{}{"scdid": c.ScdID, "lineno": datype.Lineno, "ruleid": c.getRuleIdByName("模板重复定义校验"), "nodeid": c.scdXmlObject.DataTypeTemplates.NodeId, "parse_result": parse_result}
  2169. c.AppendPaseResult(r)
  2170. continue
  2171. }
  2172. daTypeMap[datype.Id] = datype
  2173. c.daTypeMap.Store(datype.Id, datype)
  2174. for _, enum := range datype.BDA {
  2175. if enum.Type == "" {
  2176. continue
  2177. }
  2178. if enum.BType == "Enum" {
  2179. usedEnumTypeMap[enum.Type] = 1 //使用的模板
  2180. if enumTypeMap[enum.Type] == nil {
  2181. parse_result := fmt.Sprintf("DAType(%s)中引用的EnumType(%s)不存在", datype.Id, enum.Type)
  2182. r := map[string]interface{}{"scdid": c.ScdID, "lineno": enum.Lineno, "ruleid": c.getRuleIdByName("EnumType模板引用合法性校验"), "nodeid": c.scdXmlObject.DataTypeTemplates.NodeId, "parse_result": parse_result}
  2183. c.AppendPaseResult(r)
  2184. }
  2185. }
  2186. }
  2187. }
  2188. for _, dotype := range c.scdXmlObject.DataTypeTemplates.DOType {
  2189. if v, _ := c.doTypeMap.Load(dotype.Id); v != nil {
  2190. parse_result := fmt.Sprintf("DOType(%s)定义重复", dotype.Id)
  2191. r := map[string]interface{}{"scdid": c.ScdID, "lineno": dotype.Lineno, "ruleid": c.getRuleIdByName("模板重复定义校验"), "nodeid": c.scdXmlObject.DataTypeTemplates.NodeId, "parse_result": parse_result}
  2192. c.AppendPaseResult(r)
  2193. continue
  2194. }
  2195. c.doTypeMap.Store(dotype.Id, dotype)
  2196. for _, da := range dotype.DA {
  2197. if da.Type == "" {
  2198. continue
  2199. }
  2200. if da.BType == "Enum" {
  2201. usedEnumTypeMap[da.Type] = 1 //使用的模板
  2202. if enumTypeMap[da.Type] == nil {
  2203. parse_result := fmt.Sprintf("DOType(%s)中引用的btype为Enum的DAType(%s)不存在", dotype.Id, da.Type)
  2204. r := map[string]interface{}{"scdid": c.ScdID, "lineno": da.Lineno, "ruleid": c.getRuleIdByName("EnumType模板引用合法性校验"), "nodeid": c.scdXmlObject.DataTypeTemplates.NodeId, "parse_result": parse_result}
  2205. c.AppendPaseResult(r)
  2206. }
  2207. } else {
  2208. usedDaTypeMap[da.Type] = 1
  2209. if daTypeMap[da.Type] == nil {
  2210. parse_result := fmt.Sprintf("DOType(%s)中引用的DAType(%s)不存在", dotype.Id, da.Type)
  2211. r := map[string]interface{}{"scdid": c.ScdID, "lineno": da.Lineno, "ruleid": c.getRuleIdByName("DaType模板引用合法性校验"), "nodeid": c.scdXmlObject.DataTypeTemplates.NodeId, "parse_result": parse_result}
  2212. c.AppendPaseResult(r)
  2213. }
  2214. }
  2215. }
  2216. }
  2217. //查找未被引用的enum模板
  2218. for enumtype, obj := range enumTypeMap {
  2219. if _, h := usedEnumTypeMap[enumtype]; !h {
  2220. parse_result := fmt.Sprintf("EnumType(%s)未被引用", enumtype)
  2221. r := map[string]interface{}{"scdid": c.ScdID, "lineno": obj.Lineno, "ruleid": c.getRuleIdByName("冗余模板校验"), "nodeid": c.scdXmlObject.DataTypeTemplates.NodeId, "parse_result": parse_result}
  2222. c.AppendPaseResult(r)
  2223. }
  2224. }
  2225. //查找未被引用的da模板
  2226. //fmt.Println(fmt.Sprintf("%+v", daTypeMap))
  2227. for datype, obj := range daTypeMap {
  2228. if _, h := usedDaTypeMap[datype]; !h {
  2229. parse_result := fmt.Sprintf("DAType(%s)未被引用", datype)
  2230. r := map[string]interface{}{"scdid": c.ScdID, "lineno": obj.Lineno, "ruleid": c.getRuleIdByName("冗余模板校验"), "nodeid": c.scdXmlObject.DataTypeTemplates.NodeId, "parse_result": parse_result}
  2231. c.AppendPaseResult(r)
  2232. }
  2233. }
  2234. for _, lntype := range c.scdXmlObject.DataTypeTemplates.LNodeType {
  2235. if v, _ := c.lnodeTypeMap.Load(lntype.Id); v != nil {
  2236. parse_result := fmt.Sprintf("LNodeType(%s)定义重复", lntype.Id)
  2237. r := map[string]interface{}{"scdid": c.ScdID, "lineno": lntype.Lineno, "ruleid": c.getRuleIdByName("模板重复定义校验"), "nodeid": c.scdXmlObject.DataTypeTemplates.NodeId, "parse_result": parse_result}
  2238. c.AppendPaseResult(r)
  2239. continue
  2240. }
  2241. //查找未被引用的LNodeType模板
  2242. if _, h := usedLNodeTypeMap[lntype.Id]; !h {
  2243. parse_result := fmt.Sprintf("LNodeType(%s)未被引用", lntype.Id)
  2244. r := map[string]interface{}{"scdid": c.ScdID, "lineno": lntype.Lineno, "ruleid": c.getRuleIdByName("冗余模板校验"), "nodeid": c.scdXmlObject.DataTypeTemplates.NodeId, "parse_result": parse_result}
  2245. c.AppendPaseResult(r)
  2246. continue
  2247. }
  2248. c.lnodeTypeMap.Store(lntype.Id, lntype)
  2249. for _, do := range lntype.DO {
  2250. if do.Type == "" {
  2251. continue
  2252. }
  2253. usedDoTypeMap[do.Type] = 1
  2254. if v, _ := c.doTypeMap.Load(do.Type); v == nil {
  2255. parse_result := fmt.Sprintf("LNodeType(%s)中引用的DoType(%s)不存在", lntype.Id, do.Type)
  2256. r := map[string]interface{}{"scdid": c.ScdID, "lineno": do.Lineno, "ruleid": c.getRuleIdByName("DoType模板引用合法性校验"), "nodeid": c.scdXmlObject.DataTypeTemplates.NodeId, "parse_result": parse_result}
  2257. c.AppendPaseResult(r)
  2258. }
  2259. }
  2260. }
  2261. //查找未被引用的DOtype模板
  2262. c.doTypeMap.Range(func(k, v any) bool {
  2263. dotype := tools.IsEmpty(k)
  2264. if _, h := usedDoTypeMap[dotype]; !h {
  2265. parse_result := fmt.Sprintf("DOType(%s)未被引用", dotype)
  2266. r := map[string]interface{}{"scdid": c.ScdID, "lineno": v.(*node_attr.NDOType).Lineno, "ruleid": c.getRuleIdByName("冗余模板校验"), "nodeid": c.scdXmlObject.DataTypeTemplates.NodeId, "parse_result": parse_result}
  2267. c.AppendPaseResult(r)
  2268. }
  2269. return true
  2270. })
  2271. return daTypeMap
  2272. }
  2273. //发送端虚端子检查
  2274. //存在性检查
  2275. //cdc检查
  2276. //
  2277. func (c *ScdNodeRule) IedFcdaExist(iedname, ldinst, lnclass, lninst, prefix, doname, daname string) (obj interface{}, cdc string) {
  2278. if c.scdXmlObject == nil {
  2279. return nil, ""
  2280. }
  2281. donames := strings.Split(doname, ".") //检查是否是sdi定义
  2282. doname = donames[0]
  2283. sdiname := ""
  2284. if len(donames) > 1 {
  2285. sdiname = donames[1]
  2286. }
  2287. for _, iedObj := range c.scdXmlObject.IED {
  2288. if iedObj.Name != iedname {
  2289. continue
  2290. }
  2291. for _, ap := range iedObj.AccessPoint {
  2292. if ap.Server == nil {
  2293. continue
  2294. }
  2295. for _, ld := range ap.Server.LDevice {
  2296. if ld.Inst != ldinst {
  2297. continue
  2298. }
  2299. if ld.LN0 != nil && lnclass == ld.LN0.LnClass && lninst == ld.LN0.Inst && prefix == ld.LN0.Prefix {
  2300. for _, doi := range ld.LN0.DOI {
  2301. if doi.Name == doname {
  2302. if sdiname != "" {
  2303. foundsdi := false
  2304. for _, sdi := range doi.SDI {
  2305. if sdi.Name == sdiname {
  2306. foundsdi = true
  2307. }
  2308. }
  2309. if !foundsdi {
  2310. return nil, ""
  2311. }
  2312. }
  2313. cdc := c.getDoICdc(ld.LN0.LnType, doname, daname)
  2314. return doi, cdc
  2315. }
  2316. }
  2317. }
  2318. for _, ln := range ld.LN {
  2319. if lnclass == ln.LnClass && lninst == ln.Inst && prefix == ln.Prefix {
  2320. for _, doi := range ln.DOI {
  2321. if doi.Name == doname {
  2322. if sdiname != "" {
  2323. foundsdi := false
  2324. for _, sdi := range doi.SDI {
  2325. if sdi.Name == sdiname {
  2326. foundsdi = true
  2327. }
  2328. }
  2329. if !foundsdi {
  2330. return nil, ""
  2331. }
  2332. }
  2333. cdc := c.getDoICdc(ln.LnType, doname, daname)
  2334. return doi, cdc
  2335. }
  2336. }
  2337. }
  2338. }
  2339. }
  2340. }
  2341. }
  2342. return nil, ""
  2343. }
  2344. func (c *ScdNodeRule) IedIntAddrExist(iedname, intAddr string) (obj interface{}) {
  2345. if c.scdXmlObject == nil {
  2346. return nil
  2347. }
  2348. //intaddr格式:2-B:PIGO1/GOINGGIO1.SPCSO8.stVal
  2349. addrs := strings.Split(intAddr, ":")
  2350. if len(addrs) == 2 {
  2351. intAddr = addrs[1]
  2352. }
  2353. intAddrs := strings.Split(intAddr, "/")
  2354. if len(intAddrs) == 1 {
  2355. logger.Logger.Error(errors.New(fmt.Sprintf("装置%s发现无效的intAddr:%s", iedname, intAddr)))
  2356. return nil
  2357. }
  2358. ldinst := intAddrs[0]
  2359. lnstr := intAddrs[1]
  2360. v_tmpAry := strings.Split(lnstr, ".")
  2361. if len(v_tmpAry) < 2 {
  2362. logger.Logger.Error(errors.New(fmt.Sprintf("装置%s发现无效的intAddr:%s", iedname, intAddr)))
  2363. return nil
  2364. }
  2365. doda := v_tmpAry[1:]
  2366. doname := ""
  2367. //daname := ""
  2368. if len(doda) == 1 {
  2369. //只有do
  2370. doname = doda[0]
  2371. } else {
  2372. doname = doda[0]
  2373. //daname = strings.Join(doda[1:], ".") //还原da
  2374. }
  2375. for _, iedObj := range c.scdXmlObject.IED {
  2376. if iedObj.Name != iedname {
  2377. continue
  2378. }
  2379. for _, ap := range iedObj.AccessPoint {
  2380. if ap.Server != nil {
  2381. for _, ld := range ap.Server.LDevice {
  2382. if ld.Inst == ldinst {
  2383. if ld.LN0 != nil {
  2384. if strings.HasPrefix(lnstr, fmt.Sprintf("%s%s%s", ld.LN0.Prefix, ld.LN0.LnClass, ld.LN0.Inst)) {
  2385. for _, item := range ld.LN0.DOI {
  2386. if item.Name == doname {
  2387. return item
  2388. }
  2389. }
  2390. }
  2391. }
  2392. for _, item := range ld.LN {
  2393. if strings.HasPrefix(lnstr, fmt.Sprintf("%s%s%s", item.Prefix, item.LnClass, item.Inst)) {
  2394. for _, item := range item.DOI {
  2395. if item.Name == doname {
  2396. return item
  2397. }
  2398. }
  2399. }
  2400. }
  2401. }
  2402. }
  2403. }
  2404. }
  2405. }
  2406. return nil
  2407. }
  2408. //校验内部端子的DO或DA实例是否存在
  2409. func (c *ScdNodeRule) iedIntAddrDoiOrDaiExist(iedname, intAddr string) (obj interface{}, cdc string) {
  2410. if c.scdXmlObject == nil {
  2411. return nil, ""
  2412. }
  2413. //intaddr格式:2-B:PIGO1/GOINGGIO1.SPCSO8.stVal
  2414. addrs := strings.Split(intAddr, ":")
  2415. if len(addrs) == 2 {
  2416. intAddr = addrs[1]
  2417. }
  2418. intAddrs := strings.Split(intAddr, "/")
  2419. if len(intAddrs) == 1 {
  2420. logger.Logger.Error(errors.New(fmt.Sprintf("装置%s发现无效的intAddr:%s", iedname, intAddr)))
  2421. return nil, ""
  2422. }
  2423. ldinst := intAddrs[0]
  2424. lnstr := intAddrs[1]
  2425. for _, iedObj := range c.scdXmlObject.IED {
  2426. if iedObj.Name != iedname {
  2427. continue
  2428. }
  2429. for _, ap := range iedObj.AccessPoint {
  2430. if ap.Server != nil {
  2431. for _, ld := range ap.Server.LDevice {
  2432. if ld.Inst == ldinst {
  2433. for _, ln := range ld.LN {
  2434. str := fmt.Sprintf("%s%s%s", ln.Prefix, ln.LnClass, ln.Inst)
  2435. v_tmpAry := strings.Split(lnstr, ".")
  2436. if v_tmpAry[0] == str {
  2437. doda := v_tmpAry[1:]
  2438. doname := ""
  2439. daname := ""
  2440. if len(doda) == 1 {
  2441. //只有do
  2442. doname = doda[0]
  2443. } else {
  2444. doname = doda[0]
  2445. daname = strings.Join(doda[1:], ".") //还原da
  2446. }
  2447. for _, doi := range ln.DOI {
  2448. if doi.Name == doname {
  2449. cdc := c.getDoICdc(ln.LnType, doi.Name, daname)
  2450. if daname == "" {
  2451. return doi, cdc
  2452. }
  2453. for _, dai := range doi.DAI {
  2454. if dai.Name == daname {
  2455. return dai, cdc
  2456. }
  2457. }
  2458. das := strings.Split(daname, ".")
  2459. if len(das) > 1 {
  2460. for _, sdi := range doi.SDI {
  2461. if sdi.Name == das[0] {
  2462. for _, dai := range sdi.DAI {
  2463. if dai.Name == das[1] {
  2464. return dai, cdc
  2465. }
  2466. }
  2467. for _, sdi2 := range sdi.SDI {
  2468. for _, dai := range sdi2.DAI {
  2469. if dai.Name == das[1] {
  2470. return dai, cdc
  2471. }
  2472. }
  2473. }
  2474. return nil, cdc
  2475. }
  2476. }
  2477. }
  2478. return nil, cdc
  2479. }
  2480. }
  2481. return nil, ""
  2482. }
  2483. }
  2484. return nil, ""
  2485. }
  2486. }
  2487. }
  2488. }
  2489. }
  2490. return nil, ""
  2491. }
  2492. //根据LNtype和doi名称返回其cdc属性值
  2493. func (c *ScdNodeRule) getDoICdc(lntype, doiname, daname string) string {
  2494. if c.lnodeTypeMap == nil {
  2495. return ""
  2496. }
  2497. v, _ := c.lnodeTypeMap.Load(lntype)
  2498. if v == nil {
  2499. return ""
  2500. }
  2501. for _, do := range v.(*node_attr.NLNodeType).DO {
  2502. if do.Name == doiname {
  2503. if do.Type == "" {
  2504. return ""
  2505. }
  2506. d1, _ := c.doTypeMap.Load(do.Type)
  2507. if d1 == nil {
  2508. return ""
  2509. }
  2510. if daname == "" {
  2511. return d1.(*node_attr.NDOType).Cdc
  2512. }
  2513. das := strings.Split(daname, ".") //多层da
  2514. for _, daitem := range d1.(*node_attr.NDOType).DA {
  2515. if daitem.Name == das[0] {
  2516. if len(das) == 1 {
  2517. return daitem.BType
  2518. } else {
  2519. bdatype := daitem.Type
  2520. da1, _ := c.daTypeMap.Load(bdatype)
  2521. if da1 == nil {
  2522. return ""
  2523. }
  2524. for _, dbaitem := range da1.(*node_attr.NDAType).BDA {
  2525. if dbaitem.Name == das[1] {
  2526. return dbaitem.BType
  2527. }
  2528. }
  2529. }
  2530. return ""
  2531. }
  2532. }
  2533. }
  2534. }
  2535. return ""
  2536. }
  2537. //---------------------------------------------------------
  2538. func (c *ScdNodeRule) AppendPaseResult(r map[string]interface{}, ied ...*node_attr.NIED) {
  2539. var iedobj *node_attr.NIED
  2540. if len(ied) > 0 && ied[0] != nil {
  2541. iedobj = ied[0]
  2542. r["ied_name"] = iedobj.Name
  2543. r["ied_desc"] = iedobj.Desc
  2544. }
  2545. c.checkFailListLock.Lock()
  2546. c.CheckFailList = append(c.CheckFailList, r)
  2547. c.checkFailListLock.Unlock()
  2548. //logger.Logger.Info(fmt.Sprintf("========校验结果:%v", r))
  2549. //实时将结果通过mqtt发送解析结果
  2550. //结果处理客户端需要订阅/jujutong/scd_check_tools/ruleparse/{scdid}
  2551. //go mqtt.PublishMessage("/jujutong/scd_check_tools/ruleparse/"+fmt.Sprintf("%d", c.ScdID), r["parse_result"].(string))
  2552. }
  2553. //添加端子检查结果
  2554. //需要数据:ied_name,ied_desc,fcda_desc,fcda_addr,out_ied_name,out_ied_desc,out_fcda_desc,out_fcda_addr,error_type
  2555. //其中error_type值为以下之一:1 多余端子 2 错误端子 3 缺失
  2556. func (c *ScdNodeRule) AppendFcdaCheckResult(r map[string]interface{}) {
  2557. r["check_type"] = "fcda"
  2558. c.checkFailListLock.Lock()
  2559. c.CheckFailList = append(c.CheckFailList, r)
  2560. c.checkFailListLock.Unlock()
  2561. }
  2562. func (c *ScdNodeRule) CheckFinish() {
  2563. c.isRun = 2
  2564. }
  2565. //节点规则验证完成
  2566. func (c *ScdNodeRule) Flush() {
  2567. //判断等待验证队列中的数据是否已处理完,没有处理完则一直等待
  2568. if c.isRun != 2 {
  2569. for {
  2570. time.Sleep(100 * time.Millisecond)
  2571. if c.isRun == 2 {
  2572. break
  2573. }
  2574. }
  2575. }
  2576. logger.Logger.Debug(fmt.Sprintln("规则校验结果,共%d条!", len(c.CheckFailList)))
  2577. c.writeNodeDB()
  2578. }
  2579. //根据规则名称获取规则ID.返回为""时表示还未定义该规则名称
  2580. func (c *ScdNodeRule) getRuleIdByName(name string) string {
  2581. row := c.NodeRuleList[name]
  2582. if row == nil {
  2583. return "0"
  2584. }
  2585. return tools.IsEmpty(row["id"])
  2586. }
  2587. //将验证结果写入数据库。仅写入验证不通过的结果
  2588. //每5000条写入一次
  2589. func (c *ScdNodeRule) writeNodeDB() {
  2590. if len(c.CheckFailList) == 0 {
  2591. return
  2592. }
  2593. db := orm.NewOrm()
  2594. s1 := time.Now().Unix()
  2595. nodeCols := "(scd_id,node_id,line_no,rule_target,rule_id,parse_result,ied_name,ied_desc)"
  2596. fcdaCols := "(scd_id,ied_name,ied_desc,fcda_desc,fcda_addr,out_ied_name,out_ied_desc,out_fcda_desc,out_fcda_addr,rule_id,parse_result,error_type)"
  2597. loadedRec := 0
  2598. nodeSqlValuesAry := []string{}
  2599. fcdaSqlValuesAry := []string{}
  2600. for _, m := range c.CheckFailList {
  2601. check_type := tools.IsEmpty(m["check_type"]) // fcda检查结果写入t_scd_fcda_check_result
  2602. if check_type == "fcda" {
  2603. fcdaSqlValuesAry = append(fcdaSqlValuesAry, "("+tools.IsEmpty(m["scdid"])+",'"+tools.IsEmpty(m["ied_name"])+"','"+tools.IsEmpty(m["ied_desc"])+"','"+tools.IsEmpty(m["fcda_desc"])+"','"+tools.IsEmpty(m["fcda_addr"])+"','"+tools.IsEmpty(m["out_ied_name"])+"','"+tools.IsEmpty(m["out_ied_desc"])+"','"+tools.IsEmpty(m["out_fcda_desc"])+"','"+tools.IsEmpty(m["out_fcda_addr"])+"',"+tools.IsEmpty(m["ruleid"], "0")+",'"+tools.IsEmpty(m["parse_result"])+"',"+tools.IsEmpty(m["error_type"], "0")+")")
  2604. } else {
  2605. nodeSqlValuesAry = append(nodeSqlValuesAry, "("+tools.IsEmpty(m["scdid"])+","+tools.IsEmpty(m["nodeid"], "0")+","+tools.IsEmpty(m["lineno"], "0")+",'"+tools.IsEmpty(m["rule_target"])+"',"+tools.IsEmpty(m["ruleid"], "0")+",'"+tools.IsEmpty(m["parse_result"])+"','"+tools.IsEmpty(m["ied_name"])+"','"+tools.IsEmpty(m["ied_desc"])+"')")
  2606. }
  2607. if len(nodeSqlValuesAry) == 1000 {
  2608. sql := "insert into t_scd_node_rule_parse" + nodeCols + "values" + strings.Join(nodeSqlValuesAry, ",")
  2609. _, err := db.Raw(sql).Exec()
  2610. if err != nil {
  2611. log.Println(err)
  2612. }
  2613. loadedRec = loadedRec + 1000
  2614. nodeSqlValuesAry = nil
  2615. nodeSqlValuesAry = []string{}
  2616. }
  2617. if len(fcdaSqlValuesAry) == 1000 {
  2618. sql := "insert into t_scd_fcda_check_result" + fcdaCols + "values" + strings.Join(fcdaSqlValuesAry, ",")
  2619. _, err := db.Raw(sql).Exec()
  2620. if err != nil {
  2621. log.Println(err)
  2622. }
  2623. loadedRec = loadedRec + 1000
  2624. fcdaSqlValuesAry = nil
  2625. fcdaSqlValuesAry = []string{}
  2626. }
  2627. }
  2628. if len(nodeSqlValuesAry) > 0 {
  2629. sql := "insert into t_scd_node_rule_parse" + nodeCols + "values" + strings.Join(nodeSqlValuesAry, ",")
  2630. _, err := db.Raw(sql).Exec()
  2631. if err != nil {
  2632. log.Println(err)
  2633. }
  2634. nodeSqlValuesAry = nil
  2635. }
  2636. if len(fcdaSqlValuesAry) > 0 {
  2637. sql := "insert into t_scd_fcda_check_result" + fcdaCols + "values" + strings.Join(fcdaSqlValuesAry, ",")
  2638. _, err := db.Raw(sql).Exec()
  2639. if err != nil {
  2640. log.Println(err)
  2641. }
  2642. fcdaSqlValuesAry = nil
  2643. }
  2644. c.CheckFailList = nil
  2645. runtime.GC()
  2646. s2 := time.Now().Unix()
  2647. fmt.Println(fmt.Sprintf("===================Flush NodeAttrParse 完成!。耗时:%d秒", s2-s1))
  2648. fmt.Println("===========节点属性验证完成")
  2649. mqtt.PublishMessage(fmt.Sprintf("%s/%d", checktopic, c.ScdID), `{"code":1,"scdid":"`+tools.IsEmpty(c.ScdID)+`","state":1,"msg":"该SCD校验完成"}`)
  2650. global.CheckingScd.Delete(c.ScdID)
  2651. }