scd_mgr.go 59 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778
  1. package bo
  2. import (
  3. "encoding/json"
  4. "encoding/xml"
  5. "errors"
  6. "fmt"
  7. "io/fs"
  8. "log"
  9. "os"
  10. "os/exec"
  11. "regexp"
  12. "runtime"
  13. "scd_check_tools/conf"
  14. "scd_check_tools/global"
  15. "scd_check_tools/logger"
  16. "scd_check_tools/models/enum"
  17. "scd_check_tools/models/node_attr"
  18. "scd_check_tools/mqtt"
  19. "scd_check_tools/tools"
  20. "strconv"
  21. "strings"
  22. "sync"
  23. "time"
  24. "github.com/astaxie/beego/orm"
  25. )
  26. //SCD管理
  27. type ScdMgr struct {
  28. DeviceBaseModel
  29. //设置删除scd数据时是否是同步模式,同步模式下会等待数据删除完成时才返回结果;反之为后台删除模式.默认为异步删除模式
  30. SyncDeleteMod bool
  31. }
  32. func (c *ScdMgr) IedTotal(stationid string) (int, error) {
  33. dblog := new(SystemLog)
  34. dblog.SetUserInfo(c.GetUserInfo())
  35. dblog.Audittype = enum.AuditType_scd_show
  36. dblog.Logtype = enum.LogType_datastat
  37. dblog.Eventtype = enum.OptEventType_Bus
  38. dblog.Eventlevel = enum.OptEventLevel_Low
  39. db := orm.NewOrm()
  40. sql := "select count(0) cnt from t_scd_node_scl t,(select max(id) scd_id from t_scd_scl where enable=1 and station_id=?) t1 where t.scd_id=t1.scd_id and t.node_name='IED'"
  41. rowset := []orm.Params{}
  42. _, err := db.Raw(sql, stationid).Values(&rowset)
  43. dblog.Description = fmt.Sprintf("SQL:%s,参数:%+v", sql, stationid)
  44. if err != nil {
  45. logger.Logger.Error(err, dblog.Description)
  46. dblog.Fail2()
  47. return 0, err
  48. }
  49. dblog.Success2()
  50. if len(rowset) == 0 {
  51. return 0, nil
  52. }
  53. cnt, _ := strconv.Atoi(tools.IsEmpty(rowset[0]["cnt"]))
  54. return cnt, nil
  55. }
  56. func (c *ScdMgr) IedStat(param map[string]interface{}) (map[string]interface{}, error) {
  57. var result = map[string]interface{}{}
  58. result["data"] = []orm.Params{}
  59. constCode := new(Global)
  60. list, _ := constCode.GetChildrenGlobalCode("device_type")
  61. result["comments"] = list
  62. db := orm.NewOrm()
  63. sqlParams := []interface{}{}
  64. uaObj := new(UserAreaRelationObject)
  65. uaObj.SetUserInfo(c.GetUserInfo())
  66. areaFilerWhere := uaObj.MakeAreaFilerIds("station_id", "and")
  67. scdSql := "select max(id) scd_id from t_scd_scl where enable=1 " + areaFilerWhere + " group by station_id"
  68. station_id := tools.IsEmpty(param["station_id"])
  69. if station_id != "" {
  70. scdSql = "select max(id) scd_id from t_scd_scl where enable=1 and station_id=?"
  71. sqlParams = append(sqlParams, station_id)
  72. }
  73. sql := `
  74. select t.ied_type,count(0) cnt from t_area_ied_relation t ,
  75. (` + scdSql + `) t1
  76. where t.scd_id=t1.scd_id GROUP BY t.ied_type`
  77. rowset := []orm.Params{}
  78. _, err := db.Raw(sql, sqlParams).Values(&rowset)
  79. dblog := new(SystemLog)
  80. dblog.SetUserInfo(c.GetUserInfo())
  81. dblog.Audittype = enum.AuditType_scd_show
  82. dblog.Logtype = enum.LogType_datastat
  83. dblog.Eventtype = enum.OptEventType_Bus
  84. dblog.Eventlevel = enum.OptEventLevel_Low
  85. dblog.Description = fmt.Sprintf("SQL:%s,参数:%+v", sql, sqlParams)
  86. if err != nil {
  87. logger.Logger.Error(err, dblog.Description)
  88. dblog.Fail2()
  89. return nil, err
  90. }
  91. dblog.Success2()
  92. result["data"] = rowset
  93. return result, nil
  94. }
  95. func (c *ScdMgr) GetLastScd(stationid string) (orm.Params, error) {
  96. dblog := new(SystemLog)
  97. dblog.SetUserInfo(c.GetUserInfo())
  98. dblog.Audittype = enum.AuditType_scd_show
  99. dblog.Logtype = enum.LogType_Query
  100. dblog.Eventtype = enum.OptEventType_Bus
  101. dblog.Eventlevel = enum.OptEventLevel_Low
  102. db := orm.NewOrm()
  103. lst := []orm.Params{}
  104. sql := "select * from t_scd_scl where station_id=? order by id desc limit 0,1"
  105. _, err := db.Raw(sql, stationid).Values(&lst)
  106. dblog.Description = fmt.Sprintf("SQL:%s,参数:%+v", sql, stationid)
  107. if err != nil {
  108. logger.Logger.Error(err, dblog.Description)
  109. dblog.Fail2()
  110. return nil, err
  111. }
  112. dblog.Success2()
  113. if len(lst) == 0 {
  114. return nil, nil
  115. }
  116. return lst[0], err
  117. }
  118. //指定scd解析完成
  119. //isdefaultRun:是否立即启用为在运版本。1 立即启用 0 不启用
  120. func (c *ScdMgr) ParseFinish(scdid int64, isdefaultRun ...int) {
  121. scdidStr := tools.IsEmpty(scdid)
  122. c.SetParseStateByID(scdidStr, 1)
  123. v_isdefaultRun := 0
  124. if len(isdefaultRun) > 0 {
  125. v_isdefaultRun = isdefaultRun[0]
  126. }
  127. if v_isdefaultRun == 1 {
  128. //解除当前站下的所有scd锁定状态
  129. c.SetLock("", scdidStr, 0)
  130. c.SetStateByID(scdidStr, 1)
  131. c.UpdateScdVersion(scdid, "", "", "")
  132. c.UpdateRtCrc(scdid)
  133. }
  134. go c.CrcCheck(scdidStr)
  135. }
  136. //获取并更新唯一校验码
  137. func (c *ScdMgr) UpdateRtCrc(scdid int64) {
  138. scdobj, h := global.GoCahce.Get(tools.IsEmpty(scdid))
  139. if !h {
  140. logger.Logger.Error(errors.New("未找到scd解析结果缓存!"))
  141. return
  142. }
  143. crc := ""
  144. for _, item := range scdobj.(*node_attr.SCL).Private {
  145. if item.Type == global.SCD_CheckoutCrcKey {
  146. crc = item.InnerText
  147. break
  148. }
  149. }
  150. if crc == "" {
  151. return
  152. }
  153. //更新scl的签入crc,该crc为通过本系统签出的scd才有
  154. sql := "update t_scd_scl set in_rt_crc=? where scd_id=? "
  155. _, err := orm.NewOrm().Raw(sql, crc, scdid).Exec()
  156. if err != nil {
  157. logger.Logger.Error(err, fmt.Sprintf("SQL:%s 参数:%+v", sql, []interface{}{crc, scdid}))
  158. }
  159. }
  160. func (c *ScdMgr) SetStateByID(scdid string, isenable int) error {
  161. db := orm.NewOrm()
  162. _, err := db.Raw("update t_scd_scl set enable=? where id=?", isenable, scdid).Exec()
  163. return err
  164. }
  165. func (c *ScdMgr) SetParseStateByID(scdid string, isenable int) error {
  166. db := orm.NewOrm()
  167. _, err := db.Raw("update t_scd_scl set is_parse=? where id=?", isenable, scdid).Exec()
  168. return err
  169. }
  170. //锁定/解锁指定scd
  171. func (c *ScdMgr) SetLock(stationid, scdid string, islock int) error {
  172. dblog := new(SystemLog)
  173. dblog.SetUserInfo(c.GetUserInfo())
  174. dblog.Audittype = enum.AuditType_scd_parse
  175. dblog.Logtype = enum.LogType_lock
  176. dblog.Eventtype = enum.OptEventType_Bus
  177. dblog.Eventlevel = enum.OptEventLevel_Hight
  178. db := orm.NewOrm()
  179. var err error
  180. sql := ""
  181. sqlParameters := []interface{}{}
  182. if scdid == "" {
  183. sql = "update t_scd_scl set checkout_lock=? where station_id=?"
  184. sqlParameters = []interface{}{islock, stationid}
  185. _, err = db.Raw(sql, sqlParameters).Exec()
  186. } else {
  187. sql = "update t_scd_scl set checkout_lock=? where station_id=? and id=?"
  188. sqlParameters = []interface{}{islock, stationid, scdid}
  189. _, err = db.Raw(sql, sqlParameters).Exec()
  190. }
  191. dblog.Description = fmt.Sprintf("SQL:%s,参数:%+v", sql, sqlParameters)
  192. if err != nil {
  193. logger.Logger.Error(err, dblog.Description)
  194. dblog.Fail2()
  195. return err
  196. }
  197. dblog.Success2()
  198. return nil
  199. }
  200. //锁定/解锁指定scd
  201. func (c *ScdMgr) IsDispose(scdid string) error {
  202. dblog := new(SystemLog)
  203. dblog.SetUserInfo(c.GetUserInfo())
  204. dblog.Audittype = enum.AuditType_scd_parse
  205. dblog.Logtype = enum.LogType_unlock
  206. dblog.Eventtype = enum.OptEventType_Bus
  207. dblog.Eventlevel = enum.OptEventLevel_Hight
  208. db := orm.NewOrm()
  209. sql := "update t_scd_scl set checkout_lock=0 where id=?"
  210. _, err := db.Raw(sql, scdid).Exec()
  211. dblog.Description = fmt.Sprintf("SQL:%s,参数:%s", sql, scdid)
  212. if err != nil {
  213. logger.Logger.Error(err, dblog.Description)
  214. dblog.Fail2()
  215. return err
  216. }
  217. dblog.Success2()
  218. return err
  219. }
  220. //获取指定站下的已做签出锁定的scd信息
  221. func (c *ScdMgr) GetCheckoutLockScd(stationid string) ([]orm.Params, error) {
  222. db := orm.NewOrm()
  223. sql := "select * from t_scd_scl where station_id=? and checkout_lock=1"
  224. rowset := []orm.Params{}
  225. _, err := db.Raw(sql, stationid).Values(&rowset)
  226. if err != nil {
  227. log.Println(err)
  228. return nil, err
  229. }
  230. return rowset, nil
  231. }
  232. //更新指定scd的版本号
  233. func (c *ScdMgr) UpdateScdVersion(scdid int64, stationid, scdname, scdpath string) error {
  234. db := orm.NewOrm()
  235. var err error
  236. var err2 error
  237. db.Begin()
  238. if scdid > 0 {
  239. _, err = db.Raw("update t_scd_scl set checkout_lock=0,enable=0, version=replace(version,'在运版','历史版') where id=?", scdid).Exec()
  240. _, err2 = db.Raw("update t_scd_scl a set a.enable=1,a.version='在运版' where a.id=?", scdid).Exec()
  241. } else {
  242. fileFirstChar := scdpath[0:1]
  243. fline := string(os.PathSeparator)
  244. if fileFirstChar != "." {
  245. if fileFirstChar == fline {
  246. scdpath = "." + scdpath
  247. } else {
  248. scdpath = "." + fline + scdpath
  249. }
  250. }
  251. _, err = db.Raw("update t_scd_scl set checkout_lock=0,enable=0, version=replace(version,'在运版','历史版') where station_id=? and version like '在运版%'", stationid).Exec()
  252. _, err2 = db.Raw("update t_scd_scl a set a.enable=1, a.version='在运版' where a.station_id=? and a.scd_name=? and a.path=?", stationid, scdname, scdpath).Exec()
  253. }
  254. if err != nil || err2 != nil {
  255. db.Rollback()
  256. if err != nil {
  257. return err
  258. }
  259. if err2 != nil {
  260. return err2
  261. }
  262. }
  263. db.Commit()
  264. return nil
  265. }
  266. func (c *ScdMgr) SetStateByNamePath(scdname, scdpath string, isenable int) error {
  267. fileFirstChar := scdpath[0:1]
  268. fline := string(os.PathSeparator)
  269. if fileFirstChar != "." {
  270. if fileFirstChar == fline {
  271. scdpath = "." + scdpath
  272. } else {
  273. scdpath = "." + fline + scdpath
  274. }
  275. }
  276. db := orm.NewOrm()
  277. _, err := db.Raw("update t_scd_scl set enable=? where scd_name=? and path=?", isenable, scdname, scdpath).Exec()
  278. return err
  279. }
  280. func (c *ScdMgr) List(param map[string]interface{}) ([]orm.Params, int, error) {
  281. c.ModelTableName = "t_scd_scl"
  282. db := orm.NewOrm()
  283. sql := "select t.*,u.name user_name,s.area_name station_name from " + c.ModelTableName + " t left join t_data_user u on t.CREATED_BY=u.id left join t_data_area s on t.station_id=s.id where 1=1 "
  284. where := []string{}
  285. sqlParas := []interface{}{}
  286. //状态默认查询
  287. if v, ok := param["enable"]; ok {
  288. v1 := tools.IsEmpty(v)
  289. if v1 != "" {
  290. sqlParas = append(sqlParas, v1)
  291. where = append(where, "t.enable=?")
  292. }
  293. }
  294. if v, ok := param["ischeckinscd"]; ok {
  295. v1 := tools.IsEmpty(v)
  296. if v1 != "" {
  297. sqlParas = append(sqlParas, v1)
  298. where = append(where, "t.is_checkin_scd=?")
  299. }
  300. }
  301. if v, ok := param["stationid"]; ok {
  302. v1 := tools.IsEmpty(v)
  303. if v1 != "" {
  304. where = append(where, "t.station_id=?")
  305. sqlParas = append(sqlParas, v)
  306. } else {
  307. usObj := new(UserAreaRelationObject)
  308. usObj.SetUserInfo(c.GetUserInfo())
  309. usScope := usObj.MakeAreaFilerWhere("t.station_id", "and")
  310. if usScope != "" {
  311. where = append(where, usScope)
  312. }
  313. }
  314. }
  315. if v, ok := param["id"]; ok {
  316. v1 := tools.IsEmpty(v)
  317. if v1 != "" {
  318. where = append(where, "t.id=?")
  319. sqlParas = append(sqlParas, v)
  320. }
  321. }
  322. if v, ok := param["name"]; ok {
  323. v1 := tools.IsEmpty(v)
  324. if v1 != "" {
  325. where = append(where, "t.name like ?")
  326. sqlParas = append(sqlParas, "%"+tools.IsEmpty(v)+"%")
  327. }
  328. }
  329. rowset := []orm.Params{}
  330. if len(where) > 0 {
  331. where = append([]string{""}, where...)
  332. }
  333. pageno, _ := strconv.Atoi(tools.IsEmpty(param["pageno"], "1"))
  334. pagesize, _ := strconv.Atoi(tools.IsEmpty(param["pagesize"], "100"))
  335. limit := fmt.Sprintf(" order by t.CREATED_TIME desc limit %d,%d", (pageno-1)*pagesize, pagesize)
  336. _, err := db.Raw(sql+strings.Join(where, " and ")+limit, sqlParas).Values(&rowset)
  337. totalCnt := 0
  338. if err != nil {
  339. log.Println(err)
  340. } else {
  341. totalSql := "select count(1) cnt from " + c.ModelTableName + " t where 1=1 " + strings.Join(where, " and ")
  342. tmpRowset := []orm.Params{}
  343. _, err = db.Raw(totalSql, sqlParas).Values(&tmpRowset)
  344. if err != nil {
  345. logger.Logger.Error(err, fmt.Sprintf("SQL:%s 参数:%+v", totalSql, sqlParas))
  346. return nil, 0, err
  347. }
  348. totalCnt, _ = strconv.Atoi(tools.IsEmpty(tmpRowset[0]["cnt"]))
  349. }
  350. return rowset, totalCnt, err
  351. }
  352. //获取指定scd的间隔信息
  353. func (c *ScdMgr) GetAreaList(scdid string) ([]orm.Params, error) {
  354. db := orm.NewOrm()
  355. sql := "select * from t_substation_area where scdid=? order by voltage_level, id"
  356. rowset := []orm.Params{}
  357. _, err := db.Raw(sql, scdid).Values(&rowset)
  358. if err != nil {
  359. log.Println(err)
  360. return nil, err
  361. }
  362. return rowset, nil
  363. }
  364. func (c *ScdMgr) One(id string) (orm.Params, error) {
  365. key := fmt.Sprintf("scd_info_%s", id)
  366. if v, h := global.GoCahce.Get(key); h {
  367. return v.(orm.Params), nil
  368. }
  369. para := map[string]interface{}{"id": id}
  370. rowset, _, err := c.List(para)
  371. if err == nil && len(rowset) > 0 {
  372. global.GoCahce.Set(key, rowset[0], -1)
  373. return rowset[0], nil
  374. }
  375. return nil, err
  376. }
  377. //检查当前正在解析中的scd是否超过并发解析限制
  378. //返回true表示当前并发数已满,系统不能接收新的解析请求;false表示允许进行解析新的scd
  379. //从2方面进行限制:一是设置的最大并发解析数 二是当前服务器性能指标大于80%时不接收新的解析
  380. func (c *ScdMgr) CheckParseMaxLimit() (bool, string) {
  381. cpuHC, _ := strconv.Atoi(tools.IsEmpty(conf.GlobalConfig["alarm_cpu_value"], "90")) //cpu高耗用率
  382. memHC, _ := strconv.Atoi(tools.IsEmpty(conf.GlobalConfig["alarm_mem_value"], "90")) //内存高耗用率
  383. diskHCC, _ := strconv.Atoi(tools.IsEmpty(conf.GlobalConfig["alarm_disk_value"], "90")) //C磁盘高耗用率
  384. //内存检查
  385. if ishc, h := global.PerformanceRuntimeMonitorResult.Load("mem"); h {
  386. if ishc.(int) > memHC {
  387. return true, fmt.Sprintf("内存耗用率%d", ishc.(int))
  388. }
  389. }
  390. if ishc, h := global.PerformanceRuntimeMonitorResult.Load("cpu"); h {
  391. if ishc.(int) > cpuHC {
  392. return true, fmt.Sprintf("CPU耗用率%d", ishc.(int))
  393. }
  394. }
  395. if ishc, h := global.PerformanceRuntimeMonitorResult.Load("disk"); h {
  396. if ishc.(int) > diskHCC {
  397. return true, fmt.Sprintf("磁盘空间耗用率%d", ishc.(int))
  398. }
  399. }
  400. scdparse_max_count, _ := GetSysParamValue("scdparse_max_count", "5")
  401. db := orm.NewOrm()
  402. sql := "select 'cnt' cnt, count(1) value from t_scd_scl where is_parse=0 and CREATED_TIME<date_sub(now(),interval 30 MINUTE)"
  403. result := orm.Params{}
  404. _, err := db.Raw(sql).RowsToMap(&result, "cnt", "value")
  405. if err != nil {
  406. logger.Logger.Error(err)
  407. return true, err.Error()
  408. }
  409. if result == nil {
  410. return false, ""
  411. }
  412. if tools.IsEmpty(result["value"]) >= scdparse_max_count {
  413. return true, fmt.Sprintf("正在解析SCD数为%d", tools.IsEmpty(result["value"]))
  414. }
  415. return false, ""
  416. }
  417. //根据scd名称和path返回scd信息
  418. func (c *ScdMgr) OneByName(scdname, scdpath string) (orm.Params, error) {
  419. if scdpath == "" || scdname == "" {
  420. return nil, errors.New("无效的参数!")
  421. }
  422. fileFirstChar := scdpath[0:1]
  423. fline := string(os.PathSeparator)
  424. if fileFirstChar != "." {
  425. if fileFirstChar == fline {
  426. scdpath = "." + scdpath
  427. } else {
  428. scdpath = "." + fline + scdpath
  429. }
  430. }
  431. db := orm.NewOrm()
  432. rowset := []orm.Params{}
  433. _, err := db.Raw("select t.*,s.area_name station_id from t_scd_scl t,t_data_area s where t.station_id=s.id and t.scd_name=? and t.path=?", scdname, scdpath).Values(&rowset)
  434. if err == nil && len(rowset) > 0 {
  435. return rowset[0], nil
  436. }
  437. if err != nil {
  438. logger.Logger.Error(err)
  439. }
  440. return nil, err
  441. }
  442. //重新解析指定SCD
  443. func (c *ScdMgr) AginParse(scdid string) error {
  444. if scdid == "" {
  445. return errors.New("SCD编号不能为空")
  446. }
  447. if h, msg := c.CheckParseMaxLimit(); h {
  448. return errors.New("系统繁忙:" + msg + ",请稍候(约5分钟)再试")
  449. }
  450. //获取scd基本信息
  451. db := orm.NewOrm()
  452. sql := "select * from t_scd_scl where id=? "
  453. rowset := []orm.Params{}
  454. db.Raw(sql, scdid).Values(&rowset)
  455. if len(rowset) == 0 {
  456. return errors.New("无效的SCD编号")
  457. }
  458. go func(row orm.Params) {
  459. db.Raw("update t_scd_scl set is_parse=0 where id=?", scdid).Exec()
  460. //先清除旧数据
  461. c.SyncDeleteMod = true
  462. c.DeleteScd(scdid, false)
  463. //log.Println("====================清理完成")
  464. scdObj := GetScdParseInstance()
  465. ischeckinscd, _ := strconv.Atoi(tools.IsEmpty(row["is_checkin_scd"], "1"))
  466. scdObj.IsCheckinScd = ischeckinscd
  467. scdObj.Idseq, _ = strconv.ParseInt(scdid, 10, 64)
  468. scdObj.Idseq = scdObj.Idseq - 1 //新生成 的SCD ID是在该变量基础上加1,为了保持原ID不变,所以先减1
  469. //log.Println(fmt.Sprintf("%v", rowset[0]))
  470. err := scdObj.XmlParse(tools.IsEmpty(row["station_id"]), tools.IsEmpty(row["path"]), tools.IsEmpty(row["scd_name"]), 0)
  471. if err != nil {
  472. log.Println(err)
  473. }
  474. if ischeckinscd == 1 {
  475. db.Raw("update t_scd_scl set version=?,enable=?,checkout_lock=? where id=?",
  476. tools.IsEmpty(row["version"]),
  477. tools.IsEmpty(row["enable"]),
  478. tools.IsEmpty(row["checkout_lock"]),
  479. scdid).Exec()
  480. }
  481. new(SystemLog).Success(enum.AuditType_scd_resetparse,
  482. enum.LogType_Execute,
  483. enum.OptEventType_System,
  484. enum.OptEventLevel_Hight,
  485. fmt.Sprintf("对变电站[id=%s]scd文件%s重新进行了解析", tools.IsEmpty(row["station_id"]), tools.IsEmpty(row["scd_name"])),
  486. c.GetUserInfo(),
  487. )
  488. //SaveSyslog(, "SCD管理", true, tools.IsEmpty(c.UserInfo["name"]), tools.IsEmpty(c.UserInfo["ip"]))
  489. }(rowset[0])
  490. return nil
  491. }
  492. //删除指定scd的所有数据
  493. //isall:true 包含流转数据、签入时的其他上传文件等 false:只清除scd本身数据
  494. func (c *ScdMgr) DeleteScd(scdid string, isall ...bool) error {
  495. scdidInt64, _ := strconv.ParseInt(scdid, 10, 64)
  496. db := orm.NewOrm()
  497. sql := "select t.*,a.area_name station_name,s1.check_flag from t_scd_scl t left join t_data_area a on t.station_id=a.id left JOIN t_sys_attachment s1 on t.id=s1.scd_id and s1.file_suffix='scd' where t.id=? "
  498. rowset0 := []orm.Params{}
  499. db.Raw(sql, scdidInt64).Values(&rowset0)
  500. if len(rowset0) == 0 {
  501. new(SystemLog).Fail(enum.AuditType_scd_show,
  502. enum.LogType_Delete,
  503. enum.OptEventType_Bus,
  504. enum.OptEventLevel_Hight,
  505. fmt.Sprintf("SQL:%s,参数:%s", sql, scdid),
  506. c.GetUserInfo(),
  507. )
  508. return errors.New("无效的SCD编号")
  509. }
  510. //如果当前scd是签入的,需要解锁该scd所属变电站的签入锁定
  511. if tools.IsEmpty(rowset0[0]["check_flag"]) == "1" {
  512. checkinLockKey := fmt.Sprintf("%s%s", tools.IsEmpty(rowset0[0]["station_id"]), "scdin")
  513. global.CheckingInInfo.Delete(checkinLockKey)
  514. }
  515. scd_name := tools.IsEmpty(rowset0[0]["scd_name"])
  516. scd_path := tools.IsEmpty(rowset0[0]["path"])
  517. //获取scd属性表
  518. sql = "select table_name , table_comment from information_schema.tables where table_schema = (select database()) and table_name like 't_scd_%' "
  519. rowset := []orm.Params{}
  520. _, err := db.Raw(sql).Values(&rowset)
  521. if err != nil {
  522. logger.Logger.Error(err)
  523. new(SystemLog).Fail(enum.AuditType_scd_show,
  524. enum.LogType_Delete,
  525. enum.OptEventType_Bus,
  526. enum.OptEventLevel_Hight,
  527. fmt.Sprintf("SQL:%s", sql),
  528. c.GetUserInfo(),
  529. )
  530. return err
  531. }
  532. go new(ScdParse).RemoveScdCache(scdid)
  533. go mqtt.PublishMessage("/jujutong/scd_check_tools/delete/"+scdid, `{"state":0,"scd_name":"`+tools.IsEmpty(rowset0[0]["scd_name"])+`","user":"`+c.GetUserName()+`"}`)
  534. deleteAll := true
  535. if len(isall) > 0 {
  536. deleteAll = isall[0]
  537. }
  538. var wg = sync.WaitGroup{}
  539. if c.SyncDeleteMod {
  540. wg.Add(1)
  541. }
  542. go func() {
  543. if c.SyncDeleteMod {
  544. defer func() {
  545. wg.Done()
  546. }()
  547. }
  548. dirChar := string(os.PathSeparator)
  549. for _, row := range rowset {
  550. tb := tools.IsEmpty(row["TABLE_NAME"]) + tools.IsEmpty(row["table_name"])
  551. if tb == "t_scd_scl" {
  552. continue
  553. }
  554. for {
  555. sql = "delete from " + tb + " where scd_id=? limit 10000"
  556. r, _ := db.Raw(sql, scdidInt64).Exec()
  557. if r != nil {
  558. cnt, _ := r.RowsAffected()
  559. if cnt == 0 || cnt < 10000 {
  560. break
  561. }
  562. } else {
  563. break
  564. }
  565. }
  566. }
  567. db.Raw("delete from t_ied_relation where scd_id=?", scdidInt64).Exec()
  568. db.Raw("delete from t_ied_ctrl_relation where scd_id=?", scdidInt64).Exec()
  569. db.Raw("delete from t_area_ied_relation where area_id in(select id from t_substation_area where scd_id=?)", scdidInt64).Exec()
  570. db.Raw("delete from t_substation_area where scd_id=?", scdidInt64).Exec()
  571. db.Raw("delete from t_scd_diff_compare_detail where compare_id=(select id from t_scd_diff_compare where source_id=?)", scdidInt64).Exec()
  572. db.Raw("delete from t_scd_node_rule_parse where scd_id=?", scdidInt64).Exec()
  573. os.Remove(scd_path + ".parsed.xml")
  574. os.Remove(strings.Join([]string{".", "static", "upload", scdid + ".scd.crc"}, dirChar))
  575. os.Remove(strings.Join([]string{".", "static", "upload", scdid + ".schema_valid"}, dirChar))
  576. if deleteAll {
  577. db.Raw("delete from t_scd_diff_compare where source_id=? or target_id=?", scdidInt64, scdidInt64).Exec()
  578. db.Raw("delete from t_scd_scl where id=?", scdidInt64).Exec()
  579. os.Remove(scd_path)
  580. attachmentlist := []orm.Params{}
  581. //清除相关附件
  582. db.Raw("select save_path from t_sys_attachment where scd_id=?", scdidInt64).Values(&attachmentlist)
  583. for _, fr := range attachmentlist {
  584. savepath := tools.IsEmpty(fr["save_path"])
  585. if savepath != "" {
  586. savepath = "." + strings.ReplaceAll(savepath, "\\", dirChar)
  587. os.Remove(savepath)
  588. }
  589. }
  590. db.Raw("delete from t_sys_attachment where scd_id=?", scdidInt64).Exec()
  591. if len(scd_path) > 0 && scd_path[0:1] == "." {
  592. scd_path = scd_path[1:]
  593. }
  594. db.Raw("delete from t_sys_flow_run_detail where flow_run_id in(select t.id from t_sys_flow_run t where t.scd_name=? and t.scd_path=?)", scd_name, scd_path).Exec()
  595. db.Raw("delete from t_sys_flow_run where scd_name=? and scd_path=?", scd_name, scd_path).Exec()
  596. }
  597. db.Raw("delete from t_sys_attachment where check_flag=2 and scd_id=?", scdidInt64).Exec() //删除裁剪文件记录
  598. db.Raw("update t_sys_attachment set scd_id=0 where scd_id=?", scdidInt64).Exec()
  599. //删除该scd相关文件,包括每个装置配置ied、crc等文件
  600. tmpPart := []string{".", "static", "upload", "ied", scdid}
  601. iedpath := strings.Join(tmpPart, dirChar)
  602. os.RemoveAll(iedpath)
  603. new(SystemLog).Success(enum.AuditType_scd_show,
  604. enum.LogType_Delete,
  605. enum.OptEventType_Bus,
  606. enum.OptEventLevel_Hight,
  607. fmt.Sprintf("清除了变电站[id=%s]scd文件%s的所有数据", tools.IsEmpty(rowset0[0]["station_name"]), tools.IsEmpty(rowset0[0]["scd_name"])),
  608. c.GetUserInfo(),
  609. )
  610. go mqtt.PublishMessage("/jujutong/scd_check_tools/delete/"+scdid, `{"state":1,"station_name":"`+tools.IsEmpty(rowset0[0]["station_name"])+`","scd_name":"`+tools.IsEmpty(rowset0[0]["scd_name"])+`","user":"`+c.GetUserName()+`"}`)
  611. }()
  612. if c.SyncDeleteMod {
  613. wg.Wait()
  614. }
  615. //如果当前删除的是签入SCD,则需要把当前站最后签出记录的签出锁定状态更改为1,否则该站将无法再次签入了
  616. if deleteAll && tools.IsEmpty(rowset0[0]["is_checkin_scd"]) == "1" {
  617. station_id := tools.IsEmpty(rowset0[0]["station_id"])
  618. //判断该站有没有签出记录
  619. rowset0 = []orm.Params{}
  620. sql = "select id from t_scd_scl where station_id=? order by id desc limit 1"
  621. db.Raw(sql, station_id).Values(&rowset0)
  622. if len(rowset0) > 0 {
  623. db.Raw("update t_scd_scl set checkout_lock=1 where id=?", tools.IsEmpty(rowset0[0]["id"])).Exec()
  624. }
  625. }
  626. return nil
  627. }
  628. //获取指定scd中装置网络地址
  629. func (c *ScdMgr) GetIedNetAddr(scdid string) ([]orm.Params, error) {
  630. key := fmt.Sprintf("scd_netinfo_%d", scdid)
  631. if v, h := global.GoCahce.Get(key); h {
  632. return v.([]orm.Params), nil
  633. }
  634. scdXmlObj, serr := new(ScdParse).GetScdXmlObjectBySCDID(scdid)
  635. if serr != nil {
  636. return nil, serr
  637. }
  638. if scdXmlObj == nil {
  639. return nil, errors.New("无效的SCD")
  640. }
  641. rowset := []orm.Params{}
  642. for _, item := range scdXmlObj.Communication.SubNetwork {
  643. for _, c1 := range item.ConnectedAP {
  644. if c1.Address != nil {
  645. for _, p1 := range c1.Address.P {
  646. if p1.Type == "IP" || p1.Type == "MAC-Address" {
  647. p1type := "ip"
  648. if p1.Type == "MAC-Address" {
  649. p1type = "mac"
  650. }
  651. rowobj := orm.Params{
  652. "id": p1.NodeId,
  653. "node_name": "P",
  654. "node_value": p1.InnerText,
  655. "parent_node_id": c1.NodeId,
  656. "addrtype": p1type,
  657. "attr_ied_name": c1.IedName,
  658. "attr_ap_name": c1.ApName,
  659. }
  660. rowset = append(rowset, rowobj)
  661. }
  662. }
  663. }
  664. }
  665. }
  666. global.GoCahce.Set(key, rowset, -1)
  667. return rowset, nil
  668. }
  669. //对scd进行crc校验
  670. func (c *ScdMgr) CrcCheck(scdid string) (bool, error) {
  671. crcFilePath := fmt.Sprintf(strings.Join([]string{".", "static", "upload", ""}, string(os.PathSeparator))+"%s.scd.crc", scdid)
  672. f, _ := os.Stat(crcFilePath)
  673. if f != nil {
  674. crcmap := map[string]string{}
  675. txt, _ := os.ReadFile(crcFilePath)
  676. err := json.Unmarshal(txt, &crcmap)
  677. if err == nil {
  678. global.CachedScdCrc.Store(fmt.Sprintf("crc_%s", scdid), crcmap)
  679. //crc提取完成
  680. global.IedCrcMakeState.Store(fmt.Sprintf("crc_%s", scdid), "2")
  681. new(TaskMgr).SetStep(scdid, enum.TaskStep_SCD_crc_extract.Code(), 2)
  682. new(TaskMgr).SetStep(scdid, enum.TaskStep_SCD_ccd_extract.Code(), 2)
  683. new(TaskMgr).SetStep(scdid, enum.TaskStep_SCD_cid_extract.Code(), 2)
  684. new(TaskMgr).SetStep(scdid, enum.TaskStep_SCD_icd_extract.Code(), 2)
  685. return true, nil
  686. }
  687. }
  688. scdInfo, err := c.One(scdid)
  689. if err != nil {
  690. //crc提取失败
  691. global.IedCrcMakeState.Store(fmt.Sprintf("crc_%s", scdid), "0")
  692. new(TaskMgr).SetStep(scdid, enum.TaskStep_SCD_crc_extract.Code(), 3, err.Error())
  693. new(TaskMgr).SetStep(scdid, enum.TaskStep_SCD_ccd_extract.Code(), 3, err.Error())
  694. new(TaskMgr).SetStep(scdid, enum.TaskStep_SCD_cid_extract.Code(), 3, err.Error())
  695. new(TaskMgr).SetStep(scdid, enum.TaskStep_SCD_icd_extract.Code(), 3, err.Error())
  696. return false, err
  697. }
  698. if scdInfo == nil {
  699. //crc提取失败
  700. global.IedCrcMakeState.Store(fmt.Sprintf("crc_%s", scdid), "0")
  701. new(TaskMgr).SetStep(scdid, enum.TaskStep_SCD_crc_extract.Code(), 3, "无效的scd名称和路径")
  702. new(TaskMgr).SetStep(scdid, enum.TaskStep_SCD_ccd_extract.Code(), 3, "无效的scd名称和路径")
  703. new(TaskMgr).SetStep(scdid, enum.TaskStep_SCD_cid_extract.Code(), 3, "无效的scd名称和路径")
  704. new(TaskMgr).SetStep(scdid, enum.TaskStep_SCD_icd_extract.Code(), 3, "无效的scd名称和路径")
  705. return false, errors.New("无效的scd名称和路径")
  706. }
  707. scdpath := scdInfo["path"].(string)
  708. scdname := scdInfo["scd_name"].(string)
  709. station_id := tools.IsEmpty(scdInfo["station_id"])
  710. data := map[string]string{"name": scdname, "stationid": station_id, "rootid": scdid, "state": "0", "node": "crc-file", "msg": ""}
  711. dataMsg, _ := json.Marshal(data)
  712. mqtt.PublishMessage(fmt.Sprintf("/jujutong/scd_check_tools/parse/%s/%s", station_id, scdid), string(dataMsg))
  713. //crc提取开始
  714. new(TaskMgr).SetStep(scdid, enum.TaskStep_SCD_crc_extract.Code(), 1)
  715. global.IedCrcMakeState.Store(fmt.Sprintf("crc_%s", scdid), "1")
  716. osname := string(runtime.GOOS)
  717. var subProcess *exec.Cmd
  718. if osname == "windows" {
  719. subProcess = exec.Command("cmd", "/c", "crclibtest.exe")
  720. } else {
  721. subProcess = exec.Command("bash", "-c", "./crctestdemo")
  722. }
  723. stdin, err := subProcess.StdinPipe()
  724. if err != nil {
  725. logger.Logger.Error(err)
  726. //crc提取失败
  727. global.IedCrcMakeState.Store(fmt.Sprintf("crc_%s", scdid), "0")
  728. new(TaskMgr).SetStep(scdid, enum.TaskStep_SCD_crc_extract.Code(), 3, err.Error())
  729. new(TaskMgr).SetStep(scdid, enum.TaskStep_SCD_ccd_extract.Code(), 3, err.Error())
  730. new(TaskMgr).SetStep(scdid, enum.TaskStep_SCD_cid_extract.Code(), 3, err.Error())
  731. new(TaskMgr).SetStep(scdid, enum.TaskStep_SCD_icd_extract.Code(), 3, err.Error())
  732. return false, err
  733. }
  734. defer stdin.Close()
  735. stdout, _ := subProcess.StdoutPipe()
  736. //subProcess.Stdout = os.Stdout
  737. //subProcess.Stderr = os.Stderr
  738. logger.Logger.Debug("====正在提取IED校验码!")
  739. if err = subProcess.Start(); err != nil {
  740. logger.Logger.Error(err)
  741. //crc提取失败
  742. global.IedCrcMakeState.Store(fmt.Sprintf("crc_%s", scdid), "0")
  743. new(TaskMgr).SetStep(scdid, enum.TaskStep_SCD_crc_extract.Code(), 3, err.Error())
  744. new(TaskMgr).SetStep(scdid, enum.TaskStep_SCD_ccd_extract.Code(), 3, err.Error())
  745. new(TaskMgr).SetStep(scdid, enum.TaskStep_SCD_cid_extract.Code(), 3, err.Error())
  746. new(TaskMgr).SetStep(scdid, enum.TaskStep_SCD_icd_extract.Code(), 3, err.Error())
  747. return false, err
  748. }
  749. txt := make([]byte, 1024)
  750. for {
  751. time.Sleep(100 * time.Millisecond)
  752. n, _ := stdout.Read(txt)
  753. str := string(txt[0:n])
  754. if strings.Index(str, "number(1-3)") > 1 {
  755. break
  756. }
  757. }
  758. _, err = stdin.Write([]byte("1\n"))
  759. if err != nil {
  760. logger.Logger.Error(err)
  761. //crc提取失败
  762. global.IedCrcMakeState.Store(fmt.Sprintf("crc_%s", scdid), "0")
  763. new(TaskMgr).SetStep(scdid, enum.TaskStep_SCD_crc_extract.Code(), 3, err.Error())
  764. new(TaskMgr).SetStep(scdid, enum.TaskStep_SCD_ccd_extract.Code(), 3, err.Error())
  765. new(TaskMgr).SetStep(scdid, enum.TaskStep_SCD_cid_extract.Code(), 3, err.Error())
  766. new(TaskMgr).SetStep(scdid, enum.TaskStep_SCD_icd_extract.Code(), 3, err.Error())
  767. return false, err
  768. }
  769. txt = make([]byte, 1024)
  770. for {
  771. time.Sleep(100 * time.Millisecond)
  772. n, _ := stdout.Read(txt)
  773. if n == 0 {
  774. break
  775. }
  776. str := string(txt[0:n])
  777. if strings.Index(str, "SCD file") > -1 {
  778. break
  779. }
  780. }
  781. stdin.Write([]byte(scdpath + "\n"))
  782. //io.WriteString(stdin, scdpath+"\n") //输入scd路径
  783. outContent := ""
  784. for {
  785. time.Sleep(1 * time.Second)
  786. n, _ := stdout.Read(txt)
  787. str := tools.ConvertByte2String(txt[0:n], "GB18030")
  788. outContent = outContent + str
  789. if strings.Index(str, "The CRC of SCD is") > -1 {
  790. break
  791. }
  792. }
  793. stdin.Write([]byte("\n"))
  794. stdin.Close()
  795. logger.Logger.Debug("====IED校验码提取完成!")
  796. crclist := strings.Split(outContent, "\n")
  797. logger.Logger.Debug(fmt.Sprintf("%+v", crclist))
  798. crcmap := map[string]string{}
  799. for _, crc := range crclist {
  800. if crc == "" {
  801. continue
  802. }
  803. if crc[0:6] == "Please" {
  804. continue
  805. }
  806. if strings.Index(crc, "The CRC of SCD is") > -1 {
  807. crcmap["scdcrc"] = strings.Trim(strings.Split(crc, ":")[1], "\r") //根据所有IED生成的scd校验码
  808. continue
  809. }
  810. v_crc := strings.Split(crc, ":")
  811. if len(v_crc) > 1 {
  812. if len(v_crc[0]) > 2 && v_crc[0][0:3] == "SCD" {
  813. continue
  814. }
  815. crcmap[v_crc[0]] = strings.Trim(v_crc[1], "\r")
  816. }
  817. }
  818. global.CachedScdCrc.Store(fmt.Sprintf("crc_%s", scdid), crcmap)
  819. //crc提取完成
  820. global.IedCrcMakeState.Store(fmt.Sprintf("crc_%s", scdid), "2")
  821. crcdata, _ := json.Marshal(crcmap)
  822. err = os.WriteFile(crcFilePath, crcdata, fs.ModePerm)
  823. if err != nil {
  824. logger.Logger.Error(err)
  825. }
  826. data = map[string]string{"name": scdname, "stationid": station_id, "rootid": scdid, "state": "1", "node": "crc-file", "msg": ""}
  827. dataMsg, _ = json.Marshal(data)
  828. mqtt.PublishMessage(fmt.Sprintf("/jujutong/scd_check_tools/parse/%s/%s", station_id, scdid), string(dataMsg))
  829. new(TaskMgr).SetStep(scdid, enum.TaskStep_SCD_crc_extract.Code(), 2)
  830. dirChar := string(os.PathSeparator)
  831. tmpPart := []string{".", "static", "upload", "ied", scdid}
  832. ccdpath := strings.Join(tmpPart, dirChar)
  833. os.MkdirAll(ccdpath, fs.ModePerm)
  834. go func(scdid, scdname, station_id, scdpath, ccdpath string) {
  835. //提取CCD文件
  836. new(TaskMgr).SetStep(scdid, enum.TaskStep_SCD_ccd_extract.Code(), 1)
  837. logger.Logger.Debug("====开始提取IED装置CCD文件...")
  838. ccdFileSqls := []string{}
  839. for iedname, _ := range crcmap {
  840. if iedname == "scdcrc" {
  841. continue
  842. }
  843. var subProcess *exec.Cmd
  844. logger.Logger.Debug("====正在提取IED装置" + iedname + "的CCD文件到" + ccdpath)
  845. if osname == "windows" {
  846. subProcess = exec.Command("cmd", "/c", "crclibtest.exe")
  847. } else {
  848. subProcess = exec.Command("bash", "-c", "./crctestdemo")
  849. }
  850. stdin, err := subProcess.StdinPipe()
  851. if err != nil {
  852. logger.Logger.Error(err)
  853. continue
  854. }
  855. stdout, _ := subProcess.StdoutPipe()
  856. if err = subProcess.Start(); err != nil {
  857. logger.Logger.Error(err)
  858. stdin.Close()
  859. continue
  860. }
  861. txt := make([]byte, 1024)
  862. for {
  863. time.Sleep(10 * time.Millisecond)
  864. n, _ := stdout.Read(txt)
  865. str := string(txt[0:n])
  866. if n > 0 {
  867. logger.Logger.Debug(str)
  868. }
  869. if strings.Index(str, "number(1-3)") > 1 {
  870. break
  871. }
  872. }
  873. _, err = stdin.Write([]byte("3\n"))
  874. if err != nil {
  875. logger.Logger.Error(err)
  876. stdin.Close()
  877. continue
  878. }
  879. txt = make([]byte, 1024)
  880. for {
  881. time.Sleep(10 * time.Millisecond)
  882. n, _ := stdout.Read(txt)
  883. str := string(txt[0:n])
  884. if n > 0 {
  885. logger.Logger.Debug(str)
  886. }
  887. if strings.Index(str, "SCD file") > 0 {
  888. break
  889. }
  890. }
  891. _, err = stdin.Write([]byte(scdpath + "\n"))
  892. if err != nil {
  893. logger.Logger.Error(err)
  894. stdin.Close()
  895. continue
  896. }
  897. txt = make([]byte, 1024)
  898. for {
  899. time.Sleep(10 * time.Millisecond)
  900. n, _ := stdout.Read(txt)
  901. str := string(txt[0:n])
  902. if n > 0 {
  903. logger.Logger.Debug(str)
  904. }
  905. if strings.Index(str, "IED:") > 0 {
  906. break
  907. }
  908. }
  909. _, err = stdin.Write([]byte(iedname + "\n"))
  910. if err != nil {
  911. logger.Logger.Error(err)
  912. stdin.Close()
  913. continue
  914. }
  915. txt = make([]byte, 1024)
  916. for {
  917. time.Sleep(10 * time.Millisecond)
  918. n, _ := stdout.Read(txt)
  919. str := string(txt[0:n])
  920. if n > 0 {
  921. logger.Logger.Debug(str)
  922. }
  923. if strings.Index(str, "directory:") > 0 {
  924. break
  925. }
  926. }
  927. _, err = stdin.Write([]byte(ccdpath + "\n"))
  928. if err != nil {
  929. logger.Logger.Error(err)
  930. stdin.Close()
  931. continue
  932. }
  933. txt = make([]byte, 1024)
  934. for i := 0; i < 10; i++ {
  935. time.Sleep(10 * time.Millisecond)
  936. n, _ := stdout.Read(txt)
  937. if n > 0 {
  938. logger.Logger.Debug(string(txt[0:n]))
  939. break
  940. }
  941. }
  942. stdin.Write([]byte(" \n"))
  943. logger.Logger.Debug("====IED装置" + iedname + "的CCD文件提取完成!")
  944. stdin.Close()
  945. tmpF, e := os.Stat(ccdpath + dirChar + iedname + ".ccd")
  946. if e != nil {
  947. logger.Logger.Error(e)
  948. } else {
  949. ccdFileType, _ := global.GoCahce.Get("global_code_file_typesfile_ccd") //ccd文件类型的字典id
  950. //(station_id,scd_id,ied_name,file_name,file_size,save_path,file_type,file_suffix,check_flag)
  951. ccdFileSqls = append(ccdFileSqls, fmt.Sprintf("(%s,%s,'%s','%s','%s','%s','%s','%s',%d,now())",
  952. station_id, scdid, iedname, iedname+".ccd",
  953. tools.FormatFileSize(tmpF.Size()),
  954. strings.ReplaceAll(ccdpath+dirChar+iedname+".ccd", "\\", "/")[1:],
  955. tools.IsEmpty(ccdFileType.(orm.Params)["id"]), "ccd", 2))
  956. }
  957. }
  958. if len(ccdFileSqls) > 0 {
  959. odb := orm.NewOrm()
  960. odb.Raw("insert into t_sys_attachment(station_id,scd_id,ied_name,file_name,file_size,save_path,file_type,file_suffix,check_flag,created_time)values" + strings.Join(ccdFileSqls, ",")).Exec()
  961. ccdFileSqls = nil
  962. }
  963. new(TaskMgr).SetStep(scdid, enum.TaskStep_SCD_ccd_extract.Code(), 2)
  964. logger.Logger.Debug("====IED装置CCD文件提取完成!")
  965. data := map[string]string{"name": scdname, "stationid": station_id, "rootid": scdid, "state": "1", "node": "ccd-file", "msg": ""}
  966. dataMsg, _ := json.Marshal(data)
  967. mqtt.PublishMessage(fmt.Sprintf("/jujutong/scd_check_tools/parse/%s/%s", station_id, scdid), string(dataMsg))
  968. }(scdid, scdname, station_id, scdpath, ccdpath)
  969. //icd,cid提取
  970. go func(scdid, savepath string) {
  971. new(TaskMgr).SetStep(scdid, enum.TaskStep_SCD_cid_extract.Code(), 1)
  972. new(TaskMgr).SetStep(scdid, enum.TaskStep_SCD_icd_extract.Code(), 1)
  973. logger.Logger.Debug("====开始提取SCD【" + scdid + "】的IED装置ICD、CID文件...")
  974. scdXmlObj, serr := new(ScdParse).GetScdXmlObjectBySCDID(scdid)
  975. if serr != nil {
  976. logger.Logger.Error(serr)
  977. return
  978. }
  979. if scdXmlObj == nil {
  980. return
  981. }
  982. lnodetypes := c.GetLNodeType(scdXmlObj)
  983. dotypes := c.GetDOType(scdXmlObj)
  984. dirChar := string(os.PathSeparator)
  985. xxxFileSqls := []string{}
  986. icdFileType, _ := global.GoCahce.Get("global_code_file_typesfile_icd") //icd文件类型的字典id
  987. cidFileType, _ := global.GoCahce.Get("global_code_file_typesfile_cid") //cid文件类型的字典id
  988. for iedname, _ := range crcmap {
  989. if iedname == "scdcrc" {
  990. continue
  991. }
  992. iedObj := new(ScdNode).GetIed(scdXmlObj, scdid, iedname)
  993. if iedObj == nil {
  994. logger.Logger.Error(errors.New(fmt.Sprintf("scd【%s】中未发现装置%s", scdid, iedname)))
  995. continue
  996. }
  997. xmllines := []string{`<?xml version="1.0" encoding="UTF-8"?>` + "\r\n"}
  998. xmllines = append(xmllines, `<SCL xmlns="http://www.iec.ch/61850/2003/SCL" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">`+"\r\n")
  999. //icd提取
  1000. xmlbytes, err := xml.MarshalIndent(iedObj, "", " ")
  1001. if err == nil {
  1002. xmlStr := string(xmlbytes)
  1003. pattern := `( lineno="\d{1,}" nodeid="\d{1,}")|(&#xA;)|( ix="")|(<ext:eOption.*?>.*?</ext:eOption>)` //替换其中的lineno和nodeid属性
  1004. reg := regexp.MustCompile(pattern)
  1005. xmlStr = reg.ReplaceAllString(xmlStr, "")
  1006. xmlStr = "<IED" + xmlStr[5:]
  1007. xmlStr = xmlStr[0:len(xmlStr)-7] + "</IED>\r\n"
  1008. xmlStr = xmlStr + "<DataTypeTemplates>\r\n"
  1009. //提取LNodeType
  1010. isSub := map[string]bool{}
  1011. for _, apt := range iedObj.AccessPoint {
  1012. if apt.Server == nil {
  1013. continue
  1014. }
  1015. for _, ld := range apt.Server.LDevice {
  1016. lnnode := lnodetypes[ld.LN0.LnType]
  1017. if lnnode != nil && isSub[ld.LN0.LnType] == false {
  1018. xmlbytes, _ = xml.MarshalIndent(lnnode, "", " ")
  1019. lnnodeXmlStr := string(xmlbytes)
  1020. lnnodeXmlStr = "<" + lnnodeXmlStr[2:]
  1021. lnnodeXmlStr = lnnodeXmlStr[0:len(lnnodeXmlStr)-13] + "</LNodeType>\r\n"
  1022. xmlStr += reg.ReplaceAllString(lnnodeXmlStr, "")
  1023. isSub[ld.LN0.LnType] = true
  1024. for _, do := range lnnode.DO {
  1025. if isSub[do.Type] == false {
  1026. dotype := dotypes[do.Type]
  1027. xmlbytes, _ = xml.MarshalIndent(dotype, "", " ")
  1028. lnnodeXmlStr := string(xmlbytes)
  1029. lnnodeXmlStr = "<" + lnnodeXmlStr[2:]
  1030. lnnodeXmlStr = lnnodeXmlStr[0:len(lnnodeXmlStr)-10] + "</DOType>\r\n"
  1031. xmlStr += reg.ReplaceAllString(lnnodeXmlStr, "")
  1032. isSub[do.Type] = true
  1033. }
  1034. }
  1035. }
  1036. for _, ln := range ld.LN {
  1037. lnnode = lnodetypes[ln.LnType]
  1038. if lnnode != nil && isSub[ln.LnType] == false {
  1039. xmlbytes, _ = xml.MarshalIndent(lnnode, "", " ")
  1040. lnnodeXmlStr := string(xmlbytes)
  1041. lnnodeXmlStr = "<" + lnnodeXmlStr[2:]
  1042. lnnodeXmlStr = lnnodeXmlStr[0:len(lnnodeXmlStr)-13] + "</LNodeType>\r\n"
  1043. xmlStr += reg.ReplaceAllString(lnnodeXmlStr, "")
  1044. isSub[ln.LnType] = true
  1045. for _, do := range lnnode.DO {
  1046. if isSub[do.Type] == false {
  1047. dotype := dotypes[do.Type]
  1048. xmlbytes, _ = xml.MarshalIndent(dotype, "", " ")
  1049. lnnodeXmlStr := string(xmlbytes)
  1050. lnnodeXmlStr = "<" + lnnodeXmlStr[2:]
  1051. lnnodeXmlStr = lnnodeXmlStr[0:len(lnnodeXmlStr)-10] + "</DOType>\r\n"
  1052. xmlStr += reg.ReplaceAllString(lnnodeXmlStr, "")
  1053. isSub[do.Type] = true
  1054. }
  1055. }
  1056. }
  1057. }
  1058. }
  1059. }
  1060. xmlStr = xmlStr + "</DataTypeTemplates>\r\n</SCL>"
  1061. //生成解析完成结果副本文件
  1062. os.WriteFile(savepath+dirChar+iedname+".icd", []byte(strings.Join(xmllines, "")+xmlStr), fs.ModePerm)
  1063. tmpF, e := os.Stat(savepath + dirChar + iedname + ".icd")
  1064. if e != nil {
  1065. logger.Logger.Error(e)
  1066. } else {
  1067. xxxFileSqls = append(xxxFileSqls, fmt.Sprintf("(%s,%s,'%s','%s','%s','%s','%s','%s',%d,now())",
  1068. station_id, scdid, iedname, iedname+".icd",
  1069. tools.FormatFileSize(tmpF.Size()),
  1070. strings.ReplaceAll(savepath+dirChar+iedname+".icd", "\\", "/")[1:],
  1071. tools.IsEmpty(icdFileType.(orm.Params)["id"]), "icd", 2))
  1072. }
  1073. xmlStr = ""
  1074. } else {
  1075. logger.Logger.Error(err)
  1076. }
  1077. //cid提取
  1078. xmlbytes, err = xml.MarshalIndent(iedObj, "", " ")
  1079. if err == nil {
  1080. //生成解析完成结果副本文件
  1081. xmlStr := string(xmlbytes)
  1082. pattern := `( lineno="\d{1,}" nodeid="\d{1,}")|(&#xA;)|( ix="")|(<ext:eOption.*?>.*?</ext:eOption>)` //替换其中的lineno和nodeid属性
  1083. reg := regexp.MustCompile(pattern)
  1084. //提取通讯参数
  1085. commXml := "<Communication>\r\n"
  1086. subnetworkXml := []string{}
  1087. for _, comm := range scdXmlObj.Communication.SubNetwork {
  1088. apXml := []string{}
  1089. for _, ap := range comm.ConnectedAP {
  1090. if ap.IedName == iedname {
  1091. apxmlbytes, _ := xml.MarshalIndent(ap, "", " ")
  1092. lnnodeXmlStr := string(apxmlbytes)
  1093. lnnodeXmlStr = "<" + lnnodeXmlStr[2:]
  1094. lnnodeXmlStr = lnnodeXmlStr[0:len(lnnodeXmlStr)-15] + "</ConnectedAP>\r\n"
  1095. apXml = append(apXml, lnnodeXmlStr)
  1096. }
  1097. }
  1098. if len(apXml) > 0 {
  1099. subnetworkXml = append(subnetworkXml, fmt.Sprintf("<SubNetwork name=\"%s\" type=\"%s\">\r\n", comm.Name, comm.Type))
  1100. if comm.BitRate != nil {
  1101. subnetworkXml = append(subnetworkXml, fmt.Sprintf("<BitRate unit=\"%s\" multiplier=\"%s\">%s</BitRate>\r\n", comm.BitRate.Unit, comm.BitRate.Multiplier, comm.BitRate.InnerText))
  1102. }
  1103. subnetworkXml = append(subnetworkXml, reg.ReplaceAllString(strings.Join(apXml, ""), "")+"\r\n")
  1104. subnetworkXml = append(subnetworkXml, "</SubNetwork>\r\n")
  1105. }
  1106. }
  1107. if len(subnetworkXml) > 0 {
  1108. commXml += strings.Join(subnetworkXml, "")
  1109. commXml += "</Communication>\r\n"
  1110. } else {
  1111. commXml = ""
  1112. }
  1113. xmlStr = reg.ReplaceAllString(xmlStr, "")
  1114. xmlStr = reg.ReplaceAllString(xmlStr, "")
  1115. xmlStr = commXml + "<IED" + xmlStr[5:]
  1116. xmlStr = xmlStr[0:len(xmlStr)-7] + "</IED>\r\n"
  1117. xmlStr = xmlStr + "<DataTypeTemplates>\r\n"
  1118. //提取LNodeType
  1119. isSub := map[string]bool{}
  1120. for _, apt := range iedObj.AccessPoint {
  1121. if apt.Server == nil {
  1122. continue
  1123. }
  1124. for _, ld := range apt.Server.LDevice {
  1125. lnnode := lnodetypes[ld.LN0.LnType]
  1126. if lnnode != nil && isSub[ld.LN0.LnType] == false {
  1127. xmlbytes, _ = xml.MarshalIndent(lnnode, "", " ")
  1128. lnnodeXmlStr := string(xmlbytes)
  1129. lnnodeXmlStr = "<" + lnnodeXmlStr[2:]
  1130. lnnodeXmlStr = lnnodeXmlStr[0:len(lnnodeXmlStr)-13] + "</LNodeType>\r\n"
  1131. xmlStr += reg.ReplaceAllString(lnnodeXmlStr, "")
  1132. isSub[ld.LN0.LnType] = true
  1133. for _, do := range lnnode.DO {
  1134. if isSub[do.Type] == false {
  1135. dotype := dotypes[do.Type]
  1136. xmlbytes, _ = xml.MarshalIndent(dotype, "", " ")
  1137. lnnodeXmlStr := string(xmlbytes)
  1138. lnnodeXmlStr = "<" + lnnodeXmlStr[2:]
  1139. lnnodeXmlStr = lnnodeXmlStr[0:len(lnnodeXmlStr)-10] + "</DOType>\r\n"
  1140. xmlStr += reg.ReplaceAllString(lnnodeXmlStr, "")
  1141. isSub[do.Type] = true
  1142. }
  1143. }
  1144. }
  1145. for _, ln := range ld.LN {
  1146. lnnode = lnodetypes[ln.LnType]
  1147. if lnnode != nil && isSub[ln.LnType] == false {
  1148. xmlbytes, _ = xml.MarshalIndent(lnnode, "", " ")
  1149. lnnodeXmlStr := string(xmlbytes)
  1150. lnnodeXmlStr = "<" + lnnodeXmlStr[2:]
  1151. lnnodeXmlStr = lnnodeXmlStr[0:len(lnnodeXmlStr)-13] + "</LNodeType>\r\n"
  1152. xmlStr += reg.ReplaceAllString(lnnodeXmlStr, "")
  1153. isSub[ln.LnType] = true
  1154. for _, do := range lnnode.DO {
  1155. if isSub[do.Type] == false {
  1156. dotype := dotypes[do.Type]
  1157. xmlbytes, _ = xml.MarshalIndent(dotype, "", " ")
  1158. lnnodeXmlStr := string(xmlbytes)
  1159. lnnodeXmlStr = "<" + lnnodeXmlStr[2:]
  1160. lnnodeXmlStr = lnnodeXmlStr[0:len(lnnodeXmlStr)-10] + "</DOType>\r\n"
  1161. xmlStr += reg.ReplaceAllString(lnnodeXmlStr, "")
  1162. isSub[do.Type] = true
  1163. }
  1164. }
  1165. }
  1166. }
  1167. }
  1168. }
  1169. xmlStr = xmlStr + "</DataTypeTemplates>\r\n</SCL>"
  1170. os.WriteFile(savepath+dirChar+iedname+".cid", []byte(strings.Join(xmllines, "")+xmlStr), fs.ModePerm)
  1171. tmpF, e := os.Stat(savepath + dirChar + iedname + ".cid")
  1172. if e != nil {
  1173. logger.Logger.Error(e)
  1174. } else {
  1175. xxxFileSqls = append(xxxFileSqls, fmt.Sprintf("(%s,%s,'%s','%s','%s','%s','%s','%s',%d,now())",
  1176. station_id, scdid, iedname, iedname+".cid",
  1177. tools.FormatFileSize(tmpF.Size()),
  1178. strings.ReplaceAll(savepath+dirChar+iedname+".cid", "\\", "/")[1:],
  1179. tools.IsEmpty(cidFileType.(orm.Params)["id"]), "cid", 2))
  1180. }
  1181. xmlStr = ""
  1182. } else {
  1183. logger.Logger.Error(err)
  1184. continue
  1185. }
  1186. }
  1187. if len(xxxFileSqls) > 0 {
  1188. odb := orm.NewOrm()
  1189. odb.Raw("insert into t_sys_attachment(station_id,scd_id,ied_name,file_name,file_size,save_path,file_type,file_suffix,check_flag,created_time)values" + strings.Join(xxxFileSqls, ",")).Exec()
  1190. xxxFileSqls = nil
  1191. }
  1192. new(TaskMgr).SetStep(scdid, enum.TaskStep_SCD_cid_extract.Code(), 2)
  1193. new(TaskMgr).SetStep(scdid, enum.TaskStep_SCD_icd_extract.Code(), 2)
  1194. data := map[string]string{"name": scdname, "stationid": station_id, "rootid": scdid, "state": "1", "node": "cid-file", "msg": ""}
  1195. dataMsg, _ := json.Marshal(data)
  1196. mqtt.PublishMessage(fmt.Sprintf("/jujutong/scd_check_tools/parse/%s/%s", station_id, scdid), string(dataMsg))
  1197. }(scdid, ccdpath)
  1198. return true, nil
  1199. }
  1200. var YaoCeMap = map[string]string{
  1201. "MV": "MV",
  1202. "CMV": "CMV",
  1203. "SAV": "SAV",
  1204. "WYE": "WYE",
  1205. "DEL": "DEL",
  1206. "SEQ": "SEQ",
  1207. "INC": "INC",
  1208. "BSC": "BSC",
  1209. "ISC": "ISC",
  1210. "APC": "APC",
  1211. "ENC": "ENC",
  1212. "HMV": "HMV",
  1213. "HWYE": "HWYE",
  1214. "HDEL": "HDEL",
  1215. "BAC": "BAC",
  1216. "ING": "整数状态定值",
  1217. }
  1218. var YaoXinMap = map[string]string{
  1219. "SPS": "SPS",
  1220. "DPS": "DPS",
  1221. "ACT": "ACT",
  1222. "ACD": "ACD",
  1223. "SPC": "SPC",
  1224. "DPC": "DPC",
  1225. "ENS": "ENS",
  1226. "VSS": "VSS",
  1227. "HST": "直方图",
  1228. "LPL": "LPL",
  1229. "DPL": "DPL",
  1230. "SEC": "安全违例计数",
  1231. }
  1232. //双点遥信类型
  1233. var YaoXinDBType = map[string]bool{
  1234. "DPS": true,
  1235. "DPC": true,
  1236. }
  1237. //单点遥信类型
  1238. var YaoXinSiType = map[string]bool{
  1239. "SPS": true,
  1240. "SPC": true,
  1241. }
  1242. var YaoKongMap = map[string]string{
  1243. "SPC": "SPC",
  1244. "DPC": "DPC",
  1245. "INC": "INC",
  1246. "BSC": "BSC",
  1247. "ISC": "ISC",
  1248. "APC": "APC",
  1249. "ENC": "ENC",
  1250. "BAC": "BAC",
  1251. }
  1252. var DingZhiMap = map[string]string{
  1253. "SPG": "单点定值",
  1254. "ING": "整数状态定值",
  1255. "ASG": "模拟定值",
  1256. "STG": "STG",
  1257. "ENG": "枚举状态定值",
  1258. "ORG": "对象引用定值",
  1259. "TSG": "时间定值",
  1260. "CSG": "曲线形状定值",
  1261. "CUG": "可见字符串定值",
  1262. "VSG": "VSG",
  1263. "CURVE": "定值曲线",
  1264. }
  1265. var OtherCdcTypeMap = map[string]string{
  1266. "INS": "INS",
  1267. "BCR": "BCR",
  1268. }
  1269. //根据cdc返回对应的数据类型名称
  1270. func (c *ScdMgr) GetCdcDataTypeName(cdccode string) string {
  1271. name := DingZhiMap[cdccode]
  1272. if name == "" {
  1273. name = YaoKongMap[cdccode]
  1274. }
  1275. if name == "" {
  1276. name = YaoXinMap[cdccode]
  1277. }
  1278. if name == "" {
  1279. name = YaoCeMap[cdccode]
  1280. }
  1281. if name == "" {
  1282. name = OtherCdcTypeMap[cdccode]
  1283. }
  1284. return name
  1285. }
  1286. //获取指定scd的数据模板LNodeType集合
  1287. func (c *ScdMgr) GetLNodeType(scdXmlObj *node_attr.SCL) map[string]*node_attr.NLNodeType {
  1288. key := fmt.Sprintf("%d%s", scdXmlObj.NodeId, "lnodetype")
  1289. if v, h := global.GoCahce.Get(key); h {
  1290. return v.(map[string]*node_attr.NLNodeType)
  1291. }
  1292. mapSourceLNodeType := map[string]*node_attr.NLNodeType{}
  1293. for _, lnnodetpye := range scdXmlObj.DataTypeTemplates.LNodeType {
  1294. mapSourceLNodeType[lnnodetpye.Id] = lnnodetpye
  1295. }
  1296. global.GoCahce.Set(key, mapSourceLNodeType, 30*time.Minute)
  1297. return mapSourceLNodeType
  1298. }
  1299. //获取指定scd的数据模板DOType集合
  1300. func (c *ScdMgr) GetDOType(scdXmlObj *node_attr.SCL) map[string]*node_attr.NDOType {
  1301. key := fmt.Sprintf("%d%s", scdXmlObj.NodeId, "dotype")
  1302. if v, h := global.GoCahce.Get(key); h {
  1303. return v.(map[string]*node_attr.NDOType)
  1304. }
  1305. mapSourceDOType := map[string]*node_attr.NDOType{}
  1306. for _, lnnodetpye := range scdXmlObj.DataTypeTemplates.DOType {
  1307. mapSourceDOType[lnnodetpye.Id] = lnnodetpye
  1308. }
  1309. global.GoCahce.Set(key, mapSourceDOType, 30*time.Minute)
  1310. return mapSourceDOType
  1311. }
  1312. //获取遥控DOType集合
  1313. //遥控测点规则:模型模板中,DOType包含cdc为"SPC", "DPC", "INC", "BSC", "ISC", "APC",”ENC”,”BAC”,同时DOType的DA子节点中含有name为Oper元素
  1314. func (c *ScdMgr) GetYaoKongDoTypeMap(scdXmlObj *node_attr.SCL) map[string]*node_attr.NDOType {
  1315. result := map[string]*node_attr.NDOType{}
  1316. for _, lnnodetpye := range scdXmlObj.DataTypeTemplates.DOType {
  1317. if _, h := YaoKongMap[lnnodetpye.Cdc]; h {
  1318. for _, da := range lnnodetpye.DA {
  1319. if da.Name == "Oper" {
  1320. result[lnnodetpye.Id] = lnnodetpye
  1321. break
  1322. }
  1323. }
  1324. }
  1325. }
  1326. return result
  1327. }
  1328. //获取指定IED下的遥控测点DOI实例
  1329. func (c *ScdMgr) GetYaoKongDOIMap(scdXmlObj *node_attr.SCL, iedname string) map[string]*node_attr.NDOI {
  1330. result := map[string]*node_attr.NDOI{}
  1331. yaokongDOType := c.GetYaoKongDoTypeMap(scdXmlObj)
  1332. if len(yaokongDOType) == 0 {
  1333. //集合为空,则全文遥控数据为空
  1334. return nil
  1335. }
  1336. key := fmt.Sprintf("%d%s%s", scdXmlObj.NodeId, iedname, "yaoking")
  1337. if v, h := global.GoCahce.Get(key); h {
  1338. return v.(map[string]*node_attr.NDOI)
  1339. }
  1340. lnnodetype := c.GetLNodeType(scdXmlObj)
  1341. daiTxtKey := map[string]bool{
  1342. "1": true,
  1343. "2": true,
  1344. "3": true,
  1345. "4": true,
  1346. "direct-with-normal-security": true,
  1347. "sbo-with-normal-security": true,
  1348. "direct-with-enhanced-security": true,
  1349. "sbo-with-enhanced-security": true,
  1350. }
  1351. iedObj := new(ScdNode).GetIed(scdXmlObj, "", iedname)
  1352. var getdoicdc = func(lntype, doiname string) string {
  1353. doNames := lnnodetype[lntype]
  1354. if doNames == nil {
  1355. return ""
  1356. }
  1357. for _, do := range doNames.DO {
  1358. if do.Name == doiname && yaokongDOType[do.Type] != nil {
  1359. return yaokongDOType[do.Type].Cdc
  1360. }
  1361. }
  1362. return ""
  1363. }
  1364. //遍历模型实例化中,所有步骤1集合中的DOI实例
  1365. for _, ap := range iedObj.AccessPoint {
  1366. if ap.Server == nil {
  1367. continue
  1368. }
  1369. for _, ld := range ap.Server.LDevice {
  1370. if ld.LN0 != nil {
  1371. for _, doi := range ld.LN0.DOI {
  1372. //获取doi的cdc
  1373. cdc := getdoicdc(ld.LN0.LnType, doi.Name)
  1374. if cdc == "" {
  1375. continue
  1376. }
  1377. key := fmt.Sprintf("%s.%s.%s", ld.Inst, ld.LN0.Inst, doi.Name)
  1378. //检查DOI下是否含有name为ctlModel的DAI,若不含DAI,则默认为遥控,
  1379. //若含有DAI,则判断ctlModel的txt值,当text值为1、2、3、4或”direct-with-normal-security”、“sbo-with-normal-security”、“direct-with-enhanced-security”、“sbo-with-enhanced-security”时,认为该点为遥控
  1380. hasctlModel := false
  1381. for _, dai := range doi.DAI {
  1382. if dai.Name == "ctlModel" {
  1383. hasctlModel = true
  1384. if dai.Val != nil {
  1385. txt := dai.Val.InnerText
  1386. if _, h := daiTxtKey[txt]; h {
  1387. result[key] = doi
  1388. }
  1389. }
  1390. break
  1391. }
  1392. }
  1393. if !hasctlModel {
  1394. result[key] = doi
  1395. }
  1396. }
  1397. }
  1398. for _, ln := range ld.LN {
  1399. for _, doi := range ln.DOI {
  1400. //获取doi的cdc
  1401. cdc := getdoicdc(ld.LN0.LnType, doi.Name)
  1402. if cdc == "" {
  1403. continue
  1404. }
  1405. key := fmt.Sprintf("%s.%s.%s", ld.Inst, ln.Inst, doi.Name)
  1406. hasctlModel := false
  1407. for _, dai := range doi.DAI {
  1408. if dai.Name == "ctlModel" {
  1409. hasctlModel = true
  1410. if dai.Val != nil {
  1411. txt := dai.Val.InnerText
  1412. if _, h := daiTxtKey[txt]; h {
  1413. result[key] = doi
  1414. }
  1415. }
  1416. break
  1417. }
  1418. }
  1419. if !hasctlModel {
  1420. result[key] = doi
  1421. }
  1422. }
  1423. }
  1424. }
  1425. }
  1426. global.GoCahce.Set(key, result, 31*time.Minute)
  1427. return result
  1428. }
  1429. //获取指定IED下的定值测点DOI实例
  1430. func (c *ScdMgr) GetDingZhiDOIMap(scdXmlObj *node_attr.SCL, iedname string) map[string]*node_attr.NDOI {
  1431. result := map[string]*node_attr.NDOI{}
  1432. dingzhiDOType := c.GetDingZhiDoTypeMap(scdXmlObj)
  1433. if len(dingzhiDOType) == 0 {
  1434. //集合为空,则全文定值数据为空
  1435. return nil
  1436. }
  1437. key := fmt.Sprintf("%d%s%s", scdXmlObj.NodeId, iedname, "dingzhi")
  1438. if v, h := global.GoCahce.Get(key); h {
  1439. return v.(map[string]*node_attr.NDOI)
  1440. }
  1441. lnnodetype := c.GetLNodeType(scdXmlObj)
  1442. iedObj := new(ScdNode).GetIed(scdXmlObj, "", iedname)
  1443. ldList := map[string]*node_attr.NLDevice{}
  1444. for _, ap := range iedObj.AccessPoint {
  1445. if ap.Server == nil {
  1446. continue
  1447. }
  1448. for _, ld := range ap.Server.LDevice {
  1449. ldList[ld.Inst] = ld
  1450. }
  1451. }
  1452. var foundFcdaDingZhi = func(dst *node_attr.NDataSet) map[string]*node_attr.NDOI {
  1453. result := map[string]*node_attr.NDOI{}
  1454. for _, fcda := range dst.FCDA {
  1455. if fcda.Fc == "SP" || fcda.Fc == "SG" || fcda.Fc == "SE" {
  1456. ld := ldList[fcda.LdInst]
  1457. if fcda.LnClass == "LLN0" && ld.LN0.LnClass == fcda.LnClass {
  1458. lnodetype := lnnodetype[ld.LN0.LnType]
  1459. if lnodetype == nil {
  1460. continue
  1461. }
  1462. for _, doi := range ld.LN0.DOI {
  1463. if doi.Name == fcda.DoName {
  1464. for _, do := range lnodetype.DO {
  1465. if do.Name == doi.Name && dingzhiDOType[do.Type] != nil {
  1466. key := fmt.Sprintf("%s/%s%s%s.%s/%s", fcda.LdInst, fcda.Prefix, fcda.LnClass, fcda.LnInst, fcda.DoName, fcda.Fc)
  1467. result[key] = doi
  1468. break
  1469. }
  1470. }
  1471. break
  1472. }
  1473. }
  1474. } else {
  1475. for _, ln := range ld.LN {
  1476. lnodetype := lnnodetype[ln.LnType]
  1477. if lnodetype == nil {
  1478. continue
  1479. }
  1480. if ln.LnClass == fcda.LnClass && ln.Inst == fcda.LnInst {
  1481. for _, doi := range ln.DOI {
  1482. if doi.Name == fcda.DoName {
  1483. for _, do := range lnodetype.DO {
  1484. if do.Name == doi.Name && dingzhiDOType[do.Type] != nil {
  1485. key := fmt.Sprintf("%s/%s%s%s.%s/%s", fcda.LdInst, fcda.Prefix, fcda.LnClass, fcda.LnInst, fcda.DoName, fcda.Fc)
  1486. result[key] = doi
  1487. break
  1488. }
  1489. }
  1490. break
  1491. }
  1492. }
  1493. break
  1494. }
  1495. }
  1496. }
  1497. }
  1498. }
  1499. return result
  1500. }
  1501. //遍历模型实例化中,所有步骤1集合中的DOI实例
  1502. for _, ld := range ldList {
  1503. if ld.LN0 != nil && ld.LN0.SettingControl != nil {
  1504. for _, dst := range ld.LN0.DataSet {
  1505. dingzhi := foundFcdaDingZhi(dst)
  1506. for k, v := range dingzhi {
  1507. result[k] = v
  1508. }
  1509. }
  1510. }
  1511. for _, ln := range ld.LN {
  1512. if ln.SettingControl == nil {
  1513. continue
  1514. }
  1515. for _, dst := range ln.DataSet {
  1516. dingzhi := foundFcdaDingZhi(dst)
  1517. for k, v := range dingzhi {
  1518. result[k] = v
  1519. }
  1520. }
  1521. }
  1522. }
  1523. global.GoCahce.Set(key, result, 31*time.Minute)
  1524. return result
  1525. }
  1526. //获取指定IED下的遥测、遥信、遥脉测点
  1527. func (c *ScdMgr) GetYcYkYmMap(scdXmlObj *node_attr.SCL, iedname string) (yc map[string]interface{}, yx map[string]interface{}, ym map[string]interface{}) {
  1528. key := fmt.Sprintf("%d%s%s", scdXmlObj.NodeId, iedname, "YcYkYm")
  1529. if v, h := global.GoCahce.Get(key); h {
  1530. v1 := v.([]interface{})
  1531. return v1[0].(map[string]interface{}), v1[1].(map[string]interface{}), v1[2].(map[string]interface{})
  1532. }
  1533. targetIedObj := new(ScdNode).GetIed(scdXmlObj, "", iedname)
  1534. //IED内的遥信
  1535. targetYaoXin := map[string]interface{}{}
  1536. //IED内的遥测
  1537. targetYaoCe := map[string]interface{}{}
  1538. //IED内的遥脉
  1539. targetYaoMai := map[string]interface{}{}
  1540. mapTargetLNodeType := c.GetLNodeType(scdXmlObj)
  1541. mapTargetLDoType := c.GetDOType(scdXmlObj)
  1542. for _, ap := range targetIedObj.AccessPoint {
  1543. if ap.Server == nil {
  1544. continue
  1545. }
  1546. for _, ld := range ap.Server.LDevice {
  1547. if ld.LN0 == nil {
  1548. break
  1549. }
  1550. for _, rpb := range ld.LN0.ReportControl {
  1551. if rpb.DatSet != "dsLog" {
  1552. //处理遥信、遥测、遥脉数据
  1553. for _, dst := range ld.LN0.DataSet {
  1554. if dst.Name == rpb.DatSet {
  1555. for _, fcda := range dst.FCDA {
  1556. if fcda.Fc == "" {
  1557. //数据集成员的fc为空或为"",跳过
  1558. continue
  1559. }
  1560. key := fmt.Sprintf("%s/%s%s%s.%s.%s", fcda.LdInst, fcda.Prefix, fcda.LnClass, fcda.LnInst, fcda.DoName, fcda.DaName)
  1561. //根据FCDA的prefix、lnClass、lnInst在DataSet所属的LDevice的LN0、LN中找到对应的节点,取到节点的lnType
  1562. lnType := ""
  1563. if ld.LN0.Prefix == fcda.Prefix && ld.LN0.LnClass == fcda.LnClass && ld.LN0.Inst == fcda.LnInst {
  1564. lnType = ld.LN0.LnType
  1565. } else {
  1566. for _, lnitem := range ld.LN {
  1567. if lnitem.Prefix == fcda.Prefix && lnitem.LnClass == fcda.LnClass && lnitem.Inst == fcda.LnInst {
  1568. lnType = lnitem.LnType
  1569. break
  1570. }
  1571. }
  1572. }
  1573. if lnType != "" {
  1574. if lnnodetpye, h := mapTargetLNodeType[lnType]; h {
  1575. for _, doitem := range lnnodetpye.DO {
  1576. if doitem.Name == fcda.DoName {
  1577. dotype := doitem.Type
  1578. if dotypeobj, h := mapTargetLDoType[dotype]; h {
  1579. cdctype := new(ScdMgr).GetDoTypePointType(dotypeobj, fcda)
  1580. switch cdctype {
  1581. case "YC":
  1582. targetYaoCe[key] = fcda
  1583. break
  1584. case "YX":
  1585. targetYaoXin[key] = fcda
  1586. break
  1587. case "YM":
  1588. targetYaoMai[key] = fcda
  1589. break
  1590. }
  1591. }
  1592. break
  1593. }
  1594. }
  1595. }
  1596. }
  1597. }
  1598. break
  1599. }
  1600. }
  1601. }
  1602. }
  1603. }
  1604. }
  1605. global.GoCahce.Set(key, []interface{}{targetYaoCe, targetYaoXin, targetYaoMai}, 30*time.Minute)
  1606. return targetYaoCe, targetYaoXin, targetYaoMai
  1607. }
  1608. //获取指定IED下遥信接收端子
  1609. //return: map对象。key为端子对象地址,value为字符串数组,固定2个元素。第一个元素为端子描述,第二个元素为端子的cdc类型码
  1610. func (c *ScdMgr) GetYxExtref(scdXmlObj *node_attr.SCL, scdid int64, iedname string) map[*node_attr.NExtRef][]string {
  1611. result := map[*node_attr.NExtRef][]string{}
  1612. targetIedObj := new(ScdNode).GetIed(scdXmlObj, "", iedname)
  1613. mapTargetLNodeType := c.GetLNodeType(scdXmlObj)
  1614. mapTargetLDoType := c.GetDOType(scdXmlObj)
  1615. tmpdata, _ := GlobalNodeMap.Load(scdid)
  1616. nodeCacheMap := tmpdata.(map[int64]NodeCacheMap)
  1617. scdNode := new(ScdNodeRule)
  1618. scdNode.scdXmlObject = scdXmlObj
  1619. for _, ap := range targetIedObj.AccessPoint {
  1620. if ap.Server == nil {
  1621. continue
  1622. }
  1623. for _, ld := range ap.Server.LDevice {
  1624. if ld.LN0 != nil && ld.LN0.Inputs != nil {
  1625. for _, extref := range ld.LN0.Inputs.ExtRef {
  1626. doi := scdNode.IedIntAddrExist(iedname, extref.IntAddr)
  1627. if doi == nil {
  1628. continue
  1629. }
  1630. doiObj := doi.(*node_attr.NDOI)
  1631. lnnode := nodeCacheMap[nodeCacheMap[doiObj.NodeId].ParentNodeId]
  1632. lnType := lnnode.ObjAddr.(*node_attr.NLN).LnType
  1633. if lnType != "" {
  1634. if lnnodetpye, h := mapTargetLNodeType[lnType]; h {
  1635. for _, doitem := range lnnodetpye.DO {
  1636. if doitem.Name == doiObj.Name {
  1637. dotype := doitem.Type
  1638. if dotypeobj, h := mapTargetLDoType[dotype]; h {
  1639. cdctype := new(ScdMgr).GetDoTypePointType(dotypeobj, nil)
  1640. if cdctype == "YX" {
  1641. result[extref] = []string{doiObj.Desc, dotypeobj.Cdc}
  1642. }
  1643. }
  1644. break
  1645. }
  1646. }
  1647. }
  1648. }
  1649. }
  1650. break
  1651. }
  1652. }
  1653. }
  1654. return result
  1655. }
  1656. //获取定值DOType集合
  1657. //规则:模型模板中,DOType包含cdc为"SPG", "ING", "ASG", "STG", "ENG", "ORG",”TSG”,”CSG”,”CUG”,”VSG”,”CURVE”
  1658. //同时DOType的DA子节点中含有name为setVal或setMag元素的DOType
  1659. func (c *ScdMgr) GetDingZhiDoTypeMap(scdXmlObj *node_attr.SCL) map[string]*node_attr.NDOType {
  1660. result := map[string]*node_attr.NDOType{}
  1661. for _, lnnodetpye := range scdXmlObj.DataTypeTemplates.DOType {
  1662. if _, h := DingZhiMap[lnnodetpye.Cdc]; h {
  1663. for _, da := range lnnodetpye.DA {
  1664. if da.Name == "setVal" || da.Name == "setMag" {
  1665. result[lnnodetpye.Id] = lnnodetpye
  1666. break
  1667. }
  1668. }
  1669. }
  1670. }
  1671. return result
  1672. }
  1673. //判断cdc对应的测点数据类型。YX:遥信、YC:遥测、YM:遥脉、YK:遥控、DZ:定值
  1674. func (c *ScdMgr) GetDoTypePointType(dotype *node_attr.NDOType, fcda *node_attr.NFCDA) string {
  1675. if dotype == nil {
  1676. return ""
  1677. }
  1678. if _, h := YaoCeMap[dotype.Cdc]; h {
  1679. return "YC"
  1680. }
  1681. if _, h := YaoXinMap[dotype.Cdc]; h {
  1682. return "YX"
  1683. }
  1684. if dotype.Cdc == "INS" && fcda != nil {
  1685. //判断DOType下DA中的name等于FCDA的daName的元素的bType值,如果bType值小写后为enum,分两种情况:
  1686. //1. DOType下DA中含有type,并且type值为fltloop,类型为遥测
  1687. //2. 不满足1为遥信;
  1688. //3. 如果bType值小写后不为enum,类型为遥测
  1689. for _, daitem := range dotype.DA {
  1690. if daitem.Name == fcda.DaName {
  1691. if daitem.BType == "Enum" {
  1692. if daitem.Type == "fltloop" {
  1693. return "YC"
  1694. } else {
  1695. return "YX"
  1696. }
  1697. } else {
  1698. return "YC"
  1699. }
  1700. }
  1701. }
  1702. }
  1703. if dotype.Cdc == "BCR" && fcda != nil {
  1704. //判断LnClass,若LnClass为MMTR,则认为是遥脉,否则认为是遥测
  1705. if fcda.LnClass == "MMTR" {
  1706. return "YM"
  1707. } else {
  1708. return "YC"
  1709. }
  1710. }
  1711. return ""
  1712. }
  1713. //根据doi对象获取对应的cdc代码及名称
  1714. func (c *ScdMgr) GetDoiCdcInfo(scdXmlObj *node_attr.SCL, scdid int64, doiObj *node_attr.NDOI) string {
  1715. mapTargetLNodeType := c.GetLNodeType(scdXmlObj)
  1716. mapTargetLDoType := c.GetDOType(scdXmlObj)
  1717. tmpdata, _ := GlobalNodeMap.Load(scdid)
  1718. nodeCacheMap := tmpdata.(map[int64]NodeCacheMap)
  1719. lnnode := nodeCacheMap[nodeCacheMap[doiObj.NodeId].ParentNodeId]
  1720. lnType := lnnode.ObjAddr.(*node_attr.NLN).LnType
  1721. if lnnodetpye, h := mapTargetLNodeType[lnType]; h {
  1722. for _, doitem := range lnnodetpye.DO {
  1723. if doitem.Name == doiObj.Name {
  1724. dotype := doitem.Type
  1725. if dotypeobj, h := mapTargetLDoType[dotype]; h {
  1726. return dotypeobj.Cdc
  1727. }
  1728. break
  1729. }
  1730. }
  1731. }
  1732. return ""
  1733. }