scd_mgr.go 60 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779
  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": "测量值",
  1202. "CMV": "复数测量值",
  1203. "SAV": "呆样值",
  1204. "WYE": "三相项系统中相对地相关测量值",
  1205. "DEL": "三相项系统中相对相相关测量值",
  1206. "SEQ": "顺序值",
  1207. "INC": "可控整数状态",
  1208. "BSC": "二进制受控步位置信息",
  1209. "ISC": "整数受控步位置信息",
  1210. "APC": "可控模拟过程信息",
  1211. "ENC": "可控枚举状态",
  1212. "HMV": "谐波值",
  1213. "HWYE": "WYE谐波值",
  1214. "HDEL": "DEL谐波值",
  1215. "BAC": "可控的二进制模拟过程值",
  1216. "ING": "整数状态定值",
  1217. }
  1218. var YaoXinMap = map[string]string{
  1219. "SPS": "单点状态信息",
  1220. "DPS": "双点状态信息",
  1221. "ACT": "保护激活信息",
  1222. "ACD": "方向保护激活信息",
  1223. "SPC": "可控的单点",
  1224. "DPC": "可控的双点",
  1225. "ENS": "枚举状态",
  1226. "VSS": "可见字符串状态",
  1227. "HST": "直方图",
  1228. "LPL": "逻辑节点铭牌",
  1229. "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": "可控的单点",
  1244. "DPC": "可控的双点",
  1245. "INC": "可控的整数状态",
  1246. "BSC": "二进制受控步位置信息",
  1247. "ISC": "整数受控步位置信息",
  1248. "APC": "可控模拟过程信息",
  1249. "ENC": "可控枚举状态",
  1250. "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": "整数状态",
  1267. "BCR": "二进制计数器读数",
  1268. "CSD": "曲线形状描述",
  1269. }
  1270. //根据cdc返回对应的数据类型名称
  1271. func (c *ScdMgr) GetCdcDataTypeName(cdccode string) string {
  1272. name := DingZhiMap[cdccode]
  1273. if name == "" {
  1274. name = YaoKongMap[cdccode]
  1275. }
  1276. if name == "" {
  1277. name = YaoXinMap[cdccode]
  1278. }
  1279. if name == "" {
  1280. name = YaoCeMap[cdccode]
  1281. }
  1282. if name == "" {
  1283. name = OtherCdcTypeMap[cdccode]
  1284. }
  1285. return name
  1286. }
  1287. //获取指定scd的数据模板LNodeType集合
  1288. func (c *ScdMgr) GetLNodeType(scdXmlObj *node_attr.SCL) map[string]*node_attr.NLNodeType {
  1289. key := fmt.Sprintf("%d%s", scdXmlObj.NodeId, "lnodetype")
  1290. if v, h := global.GoCahce.Get(key); h {
  1291. return v.(map[string]*node_attr.NLNodeType)
  1292. }
  1293. mapSourceLNodeType := map[string]*node_attr.NLNodeType{}
  1294. for _, lnnodetpye := range scdXmlObj.DataTypeTemplates.LNodeType {
  1295. mapSourceLNodeType[lnnodetpye.Id] = lnnodetpye
  1296. }
  1297. global.GoCahce.Set(key, mapSourceLNodeType, 30*time.Minute)
  1298. return mapSourceLNodeType
  1299. }
  1300. //获取指定scd的数据模板DOType集合
  1301. func (c *ScdMgr) GetDOType(scdXmlObj *node_attr.SCL) map[string]*node_attr.NDOType {
  1302. key := fmt.Sprintf("%d%s", scdXmlObj.NodeId, "dotype")
  1303. if v, h := global.GoCahce.Get(key); h {
  1304. return v.(map[string]*node_attr.NDOType)
  1305. }
  1306. mapSourceDOType := map[string]*node_attr.NDOType{}
  1307. for _, lnnodetpye := range scdXmlObj.DataTypeTemplates.DOType {
  1308. mapSourceDOType[lnnodetpye.Id] = lnnodetpye
  1309. }
  1310. global.GoCahce.Set(key, mapSourceDOType, 30*time.Minute)
  1311. return mapSourceDOType
  1312. }
  1313. //获取遥控DOType集合
  1314. //遥控测点规则:模型模板中,DOType包含cdc为"SPC", "DPC", "INC", "BSC", "ISC", "APC",”ENC”,”BAC”,同时DOType的DA子节点中含有name为Oper元素
  1315. func (c *ScdMgr) GetYaoKongDoTypeMap(scdXmlObj *node_attr.SCL) map[string]*node_attr.NDOType {
  1316. result := map[string]*node_attr.NDOType{}
  1317. for _, lnnodetpye := range scdXmlObj.DataTypeTemplates.DOType {
  1318. if _, h := YaoKongMap[lnnodetpye.Cdc]; h {
  1319. for _, da := range lnnodetpye.DA {
  1320. if da.Name == "Oper" {
  1321. result[lnnodetpye.Id] = lnnodetpye
  1322. break
  1323. }
  1324. }
  1325. }
  1326. }
  1327. return result
  1328. }
  1329. //获取指定IED下的遥控测点DOI实例
  1330. func (c *ScdMgr) GetYaoKongDOIMap(scdXmlObj *node_attr.SCL, iedname string) map[string]*node_attr.NDOI {
  1331. result := map[string]*node_attr.NDOI{}
  1332. yaokongDOType := c.GetYaoKongDoTypeMap(scdXmlObj)
  1333. if len(yaokongDOType) == 0 {
  1334. //集合为空,则全文遥控数据为空
  1335. return nil
  1336. }
  1337. key := fmt.Sprintf("%d%s%s", scdXmlObj.NodeId, iedname, "yaoking")
  1338. if v, h := global.GoCahce.Get(key); h {
  1339. return v.(map[string]*node_attr.NDOI)
  1340. }
  1341. lnnodetype := c.GetLNodeType(scdXmlObj)
  1342. daiTxtKey := map[string]bool{
  1343. "1": true,
  1344. "2": true,
  1345. "3": true,
  1346. "4": true,
  1347. "direct-with-normal-security": true,
  1348. "sbo-with-normal-security": true,
  1349. "direct-with-enhanced-security": true,
  1350. "sbo-with-enhanced-security": true,
  1351. }
  1352. iedObj := new(ScdNode).GetIed(scdXmlObj, "", iedname)
  1353. var getdoicdc = func(lntype, doiname string) string {
  1354. doNames := lnnodetype[lntype]
  1355. if doNames == nil {
  1356. return ""
  1357. }
  1358. for _, do := range doNames.DO {
  1359. if do.Name == doiname && yaokongDOType[do.Type] != nil {
  1360. return yaokongDOType[do.Type].Cdc
  1361. }
  1362. }
  1363. return ""
  1364. }
  1365. //遍历模型实例化中,所有步骤1集合中的DOI实例
  1366. for _, ap := range iedObj.AccessPoint {
  1367. if ap.Server == nil {
  1368. continue
  1369. }
  1370. for _, ld := range ap.Server.LDevice {
  1371. if ld.LN0 != nil {
  1372. for _, doi := range ld.LN0.DOI {
  1373. //获取doi的cdc
  1374. cdc := getdoicdc(ld.LN0.LnType, doi.Name)
  1375. if cdc == "" {
  1376. continue
  1377. }
  1378. key := fmt.Sprintf("%s.%s.%s", ld.Inst, ld.LN0.Inst, doi.Name)
  1379. //检查DOI下是否含有name为ctlModel的DAI,若不含DAI,则默认为遥控,
  1380. //若含有DAI,则判断ctlModel的txt值,当text值为1、2、3、4或”direct-with-normal-security”、“sbo-with-normal-security”、“direct-with-enhanced-security”、“sbo-with-enhanced-security”时,认为该点为遥控
  1381. hasctlModel := false
  1382. for _, dai := range doi.DAI {
  1383. if dai.Name == "ctlModel" {
  1384. hasctlModel = true
  1385. if dai.Val != nil {
  1386. txt := dai.Val.InnerText
  1387. if _, h := daiTxtKey[txt]; h {
  1388. result[key] = doi
  1389. }
  1390. }
  1391. break
  1392. }
  1393. }
  1394. if !hasctlModel {
  1395. result[key] = doi
  1396. }
  1397. }
  1398. }
  1399. for _, ln := range ld.LN {
  1400. for _, doi := range ln.DOI {
  1401. //获取doi的cdc
  1402. cdc := getdoicdc(ld.LN0.LnType, doi.Name)
  1403. if cdc == "" {
  1404. continue
  1405. }
  1406. key := fmt.Sprintf("%s.%s.%s", ld.Inst, ln.Inst, doi.Name)
  1407. hasctlModel := false
  1408. for _, dai := range doi.DAI {
  1409. if dai.Name == "ctlModel" {
  1410. hasctlModel = true
  1411. if dai.Val != nil {
  1412. txt := dai.Val.InnerText
  1413. if _, h := daiTxtKey[txt]; h {
  1414. result[key] = doi
  1415. }
  1416. }
  1417. break
  1418. }
  1419. }
  1420. if !hasctlModel {
  1421. result[key] = doi
  1422. }
  1423. }
  1424. }
  1425. }
  1426. }
  1427. global.GoCahce.Set(key, result, 31*time.Minute)
  1428. return result
  1429. }
  1430. //获取指定IED下的定值测点DOI实例
  1431. func (c *ScdMgr) GetDingZhiDOIMap(scdXmlObj *node_attr.SCL, iedname string) map[string]*node_attr.NDOI {
  1432. result := map[string]*node_attr.NDOI{}
  1433. dingzhiDOType := c.GetDingZhiDoTypeMap(scdXmlObj)
  1434. if len(dingzhiDOType) == 0 {
  1435. //集合为空,则全文定值数据为空
  1436. return nil
  1437. }
  1438. key := fmt.Sprintf("%d%s%s", scdXmlObj.NodeId, iedname, "dingzhi")
  1439. if v, h := global.GoCahce.Get(key); h {
  1440. return v.(map[string]*node_attr.NDOI)
  1441. }
  1442. lnnodetype := c.GetLNodeType(scdXmlObj)
  1443. iedObj := new(ScdNode).GetIed(scdXmlObj, "", iedname)
  1444. ldList := map[string]*node_attr.NLDevice{}
  1445. for _, ap := range iedObj.AccessPoint {
  1446. if ap.Server == nil {
  1447. continue
  1448. }
  1449. for _, ld := range ap.Server.LDevice {
  1450. ldList[ld.Inst] = ld
  1451. }
  1452. }
  1453. var foundFcdaDingZhi = func(dst *node_attr.NDataSet) map[string]*node_attr.NDOI {
  1454. result := map[string]*node_attr.NDOI{}
  1455. for _, fcda := range dst.FCDA {
  1456. if fcda.Fc == "SP" || fcda.Fc == "SG" || fcda.Fc == "SE" {
  1457. ld := ldList[fcda.LdInst]
  1458. if fcda.LnClass == "LLN0" && ld.LN0.LnClass == fcda.LnClass {
  1459. lnodetype := lnnodetype[ld.LN0.LnType]
  1460. if lnodetype == nil {
  1461. continue
  1462. }
  1463. for _, doi := range ld.LN0.DOI {
  1464. if doi.Name == fcda.DoName {
  1465. for _, do := range lnodetype.DO {
  1466. if do.Name == doi.Name && dingzhiDOType[do.Type] != nil {
  1467. key := fmt.Sprintf("%s/%s%s%s.%s/%s", fcda.LdInst, fcda.Prefix, fcda.LnClass, fcda.LnInst, fcda.DoName, fcda.Fc)
  1468. result[key] = doi
  1469. break
  1470. }
  1471. }
  1472. break
  1473. }
  1474. }
  1475. } else {
  1476. for _, ln := range ld.LN {
  1477. lnodetype := lnnodetype[ln.LnType]
  1478. if lnodetype == nil {
  1479. continue
  1480. }
  1481. if ln.LnClass == fcda.LnClass && ln.Inst == fcda.LnInst {
  1482. for _, doi := range ln.DOI {
  1483. if doi.Name == fcda.DoName {
  1484. for _, do := range lnodetype.DO {
  1485. if do.Name == doi.Name && dingzhiDOType[do.Type] != nil {
  1486. key := fmt.Sprintf("%s/%s%s%s.%s/%s", fcda.LdInst, fcda.Prefix, fcda.LnClass, fcda.LnInst, fcda.DoName, fcda.Fc)
  1487. result[key] = doi
  1488. break
  1489. }
  1490. }
  1491. break
  1492. }
  1493. }
  1494. break
  1495. }
  1496. }
  1497. }
  1498. }
  1499. }
  1500. return result
  1501. }
  1502. //遍历模型实例化中,所有步骤1集合中的DOI实例
  1503. for _, ld := range ldList {
  1504. if ld.LN0 != nil && ld.LN0.SettingControl != nil {
  1505. for _, dst := range ld.LN0.DataSet {
  1506. dingzhi := foundFcdaDingZhi(dst)
  1507. for k, v := range dingzhi {
  1508. result[k] = v
  1509. }
  1510. }
  1511. }
  1512. for _, ln := range ld.LN {
  1513. if ln.SettingControl == nil {
  1514. continue
  1515. }
  1516. for _, dst := range ln.DataSet {
  1517. dingzhi := foundFcdaDingZhi(dst)
  1518. for k, v := range dingzhi {
  1519. result[k] = v
  1520. }
  1521. }
  1522. }
  1523. }
  1524. global.GoCahce.Set(key, result, 31*time.Minute)
  1525. return result
  1526. }
  1527. //获取指定IED下的遥测、遥信、遥脉测点
  1528. func (c *ScdMgr) GetYcYkYmMap(scdXmlObj *node_attr.SCL, iedname string) (yc map[string]interface{}, yx map[string]interface{}, ym map[string]interface{}) {
  1529. key := fmt.Sprintf("%d%s%s", scdXmlObj.NodeId, iedname, "YcYkYm")
  1530. if v, h := global.GoCahce.Get(key); h {
  1531. v1 := v.([]interface{})
  1532. return v1[0].(map[string]interface{}), v1[1].(map[string]interface{}), v1[2].(map[string]interface{})
  1533. }
  1534. targetIedObj := new(ScdNode).GetIed(scdXmlObj, "", iedname)
  1535. //IED内的遥信
  1536. targetYaoXin := map[string]interface{}{}
  1537. //IED内的遥测
  1538. targetYaoCe := map[string]interface{}{}
  1539. //IED内的遥脉
  1540. targetYaoMai := map[string]interface{}{}
  1541. mapTargetLNodeType := c.GetLNodeType(scdXmlObj)
  1542. mapTargetLDoType := c.GetDOType(scdXmlObj)
  1543. for _, ap := range targetIedObj.AccessPoint {
  1544. if ap.Server == nil {
  1545. continue
  1546. }
  1547. for _, ld := range ap.Server.LDevice {
  1548. if ld.LN0 == nil {
  1549. break
  1550. }
  1551. for _, rpb := range ld.LN0.ReportControl {
  1552. if rpb.DatSet != "dsLog" {
  1553. //处理遥信、遥测、遥脉数据
  1554. for _, dst := range ld.LN0.DataSet {
  1555. if dst.Name == rpb.DatSet {
  1556. for _, fcda := range dst.FCDA {
  1557. if fcda.Fc == "" {
  1558. //数据集成员的fc为空或为"",跳过
  1559. continue
  1560. }
  1561. key := fmt.Sprintf("%s/%s%s%s.%s.%s", fcda.LdInst, fcda.Prefix, fcda.LnClass, fcda.LnInst, fcda.DoName, fcda.DaName)
  1562. //根据FCDA的prefix、lnClass、lnInst在DataSet所属的LDevice的LN0、LN中找到对应的节点,取到节点的lnType
  1563. lnType := ""
  1564. if ld.LN0.Prefix == fcda.Prefix && ld.LN0.LnClass == fcda.LnClass && ld.LN0.Inst == fcda.LnInst {
  1565. lnType = ld.LN0.LnType
  1566. } else {
  1567. for _, lnitem := range ld.LN {
  1568. if lnitem.Prefix == fcda.Prefix && lnitem.LnClass == fcda.LnClass && lnitem.Inst == fcda.LnInst {
  1569. lnType = lnitem.LnType
  1570. break
  1571. }
  1572. }
  1573. }
  1574. if lnType != "" {
  1575. if lnnodetpye, h := mapTargetLNodeType[lnType]; h {
  1576. for _, doitem := range lnnodetpye.DO {
  1577. if doitem.Name == fcda.DoName {
  1578. dotype := doitem.Type
  1579. if dotypeobj, h := mapTargetLDoType[dotype]; h {
  1580. cdctype := new(ScdMgr).GetDoTypePointType(dotypeobj, fcda)
  1581. switch cdctype {
  1582. case "YC":
  1583. targetYaoCe[key] = fcda
  1584. break
  1585. case "YX":
  1586. targetYaoXin[key] = fcda
  1587. break
  1588. case "YM":
  1589. targetYaoMai[key] = fcda
  1590. break
  1591. }
  1592. }
  1593. break
  1594. }
  1595. }
  1596. }
  1597. }
  1598. }
  1599. break
  1600. }
  1601. }
  1602. }
  1603. }
  1604. }
  1605. }
  1606. global.GoCahce.Set(key, []interface{}{targetYaoCe, targetYaoXin, targetYaoMai}, 30*time.Minute)
  1607. return targetYaoCe, targetYaoXin, targetYaoMai
  1608. }
  1609. //获取指定IED下遥信接收端子
  1610. //return: map对象。key为端子对象地址,value为字符串数组,固定2个元素。第一个元素为端子描述,第二个元素为端子的cdc类型码
  1611. func (c *ScdMgr) GetYxExtref(scdXmlObj *node_attr.SCL, scdid int64, iedname string) map[*node_attr.NExtRef][]string {
  1612. result := map[*node_attr.NExtRef][]string{}
  1613. targetIedObj := new(ScdNode).GetIed(scdXmlObj, "", iedname)
  1614. mapTargetLNodeType := c.GetLNodeType(scdXmlObj)
  1615. mapTargetLDoType := c.GetDOType(scdXmlObj)
  1616. tmpdata, _ := GlobalNodeMap.Load(scdid)
  1617. nodeCacheMap := tmpdata.(map[int64]NodeCacheMap)
  1618. scdNode := new(ScdNodeRule)
  1619. scdNode.scdXmlObject = scdXmlObj
  1620. for _, ap := range targetIedObj.AccessPoint {
  1621. if ap.Server == nil {
  1622. continue
  1623. }
  1624. for _, ld := range ap.Server.LDevice {
  1625. if ld.LN0 != nil && ld.LN0.Inputs != nil {
  1626. for _, extref := range ld.LN0.Inputs.ExtRef {
  1627. doi := scdNode.IedIntAddrExist(iedname, extref.IntAddr)
  1628. if doi == nil {
  1629. continue
  1630. }
  1631. doiObj := doi.(*node_attr.NDOI)
  1632. lnnode := nodeCacheMap[nodeCacheMap[doiObj.NodeId].ParentNodeId]
  1633. lnType := lnnode.ObjAddr.(*node_attr.NLN).LnType
  1634. if lnType != "" {
  1635. if lnnodetpye, h := mapTargetLNodeType[lnType]; h {
  1636. for _, doitem := range lnnodetpye.DO {
  1637. if doitem.Name == doiObj.Name {
  1638. dotype := doitem.Type
  1639. if dotypeobj, h := mapTargetLDoType[dotype]; h {
  1640. cdctype := new(ScdMgr).GetDoTypePointType(dotypeobj, nil)
  1641. if cdctype == "YX" {
  1642. result[extref] = []string{doiObj.Desc, dotypeobj.Cdc}
  1643. }
  1644. }
  1645. break
  1646. }
  1647. }
  1648. }
  1649. }
  1650. }
  1651. break
  1652. }
  1653. }
  1654. }
  1655. return result
  1656. }
  1657. //获取定值DOType集合
  1658. //规则:模型模板中,DOType包含cdc为"SPG", "ING", "ASG", "STG", "ENG", "ORG",”TSG”,”CSG”,”CUG”,”VSG”,”CURVE”
  1659. //同时DOType的DA子节点中含有name为setVal或setMag元素的DOType
  1660. func (c *ScdMgr) GetDingZhiDoTypeMap(scdXmlObj *node_attr.SCL) map[string]*node_attr.NDOType {
  1661. result := map[string]*node_attr.NDOType{}
  1662. for _, lnnodetpye := range scdXmlObj.DataTypeTemplates.DOType {
  1663. if _, h := DingZhiMap[lnnodetpye.Cdc]; h {
  1664. for _, da := range lnnodetpye.DA {
  1665. if da.Name == "setVal" || da.Name == "setMag" {
  1666. result[lnnodetpye.Id] = lnnodetpye
  1667. break
  1668. }
  1669. }
  1670. }
  1671. }
  1672. return result
  1673. }
  1674. //判断cdc对应的测点数据类型。YX:遥信、YC:遥测、YM:遥脉、YK:遥控、DZ:定值
  1675. func (c *ScdMgr) GetDoTypePointType(dotype *node_attr.NDOType, fcda *node_attr.NFCDA) string {
  1676. if dotype == nil {
  1677. return ""
  1678. }
  1679. if _, h := YaoCeMap[dotype.Cdc]; h {
  1680. return "YC"
  1681. }
  1682. if _, h := YaoXinMap[dotype.Cdc]; h {
  1683. return "YX"
  1684. }
  1685. if dotype.Cdc == "INS" && fcda != nil {
  1686. //判断DOType下DA中的name等于FCDA的daName的元素的bType值,如果bType值小写后为enum,分两种情况:
  1687. //1. DOType下DA中含有type,并且type值为fltloop,类型为遥测
  1688. //2. 不满足1为遥信;
  1689. //3. 如果bType值小写后不为enum,类型为遥测
  1690. for _, daitem := range dotype.DA {
  1691. if daitem.Name == fcda.DaName {
  1692. if daitem.BType == "Enum" {
  1693. if daitem.Type == "fltloop" {
  1694. return "YC"
  1695. } else {
  1696. return "YX"
  1697. }
  1698. } else {
  1699. return "YC"
  1700. }
  1701. }
  1702. }
  1703. }
  1704. if dotype.Cdc == "BCR" && fcda != nil {
  1705. //判断LnClass,若LnClass为MMTR,则认为是遥脉,否则认为是遥测
  1706. if fcda.LnClass == "MMTR" {
  1707. return "YM"
  1708. } else {
  1709. return "YC"
  1710. }
  1711. }
  1712. return ""
  1713. }
  1714. //根据doi对象获取对应的cdc代码及名称
  1715. func (c *ScdMgr) GetDoiCdcInfo(scdXmlObj *node_attr.SCL, scdid int64, doiObj *node_attr.NDOI) string {
  1716. mapTargetLNodeType := c.GetLNodeType(scdXmlObj)
  1717. mapTargetLDoType := c.GetDOType(scdXmlObj)
  1718. tmpdata, _ := GlobalNodeMap.Load(scdid)
  1719. nodeCacheMap := tmpdata.(map[int64]NodeCacheMap)
  1720. lnnode := nodeCacheMap[nodeCacheMap[doiObj.NodeId].ParentNodeId]
  1721. lnType := lnnode.ObjAddr.(*node_attr.NLN).LnType
  1722. if lnnodetpye, h := mapTargetLNodeType[lnType]; h {
  1723. for _, doitem := range lnnodetpye.DO {
  1724. if doitem.Name == doiObj.Name {
  1725. dotype := doitem.Type
  1726. if dotypeobj, h := mapTargetLDoType[dotype]; h {
  1727. return dotypeobj.Cdc
  1728. }
  1729. break
  1730. }
  1731. }
  1732. }
  1733. return ""
  1734. }