package bo import ( "bufio" "encoding/json" "errors" "fmt" "io" "log" "os" "runtime" "scd_check_tools/global" "scd_check_tools/logger" "scd_check_tools/models/enum" "scd_check_tools/models/node_attr" "scd_check_tools/mqtt" "scd_check_tools/tools" "strconv" "strings" "time" "github.com/astaxie/beego/orm" ) type ScdNode struct { RootID int64 ScdName string ScdPath string Name string DeviceBaseModel //未结束的XML标签列表 NotEndNodeIdList []int64 //节点队列 NodeQue map[int64]*t_scd_node_scl //节点属性入库队列 NodeAttrQue []interface{} //节点验证规则定义 NodeRuleList map[string][]orm.Params //节点属性验证规则定义 NodeAttrRuleList map[string][]orm.Params //节点属性唯一性验证规则定义 NodeAttrUniqueRuleList []orm.Params //节点验证规则列表:内置验证程序实现 NodeRuleFunctionList []orm.Params //间隔管理对象 AreaMgr *ScdAreaMgr //解析完后自动比对的scdID,如果未设置 ,则解析后不做比对 AutoCompScdID int64 StationID int //是否默认为在运版。当签入流程只有一个节点时,需要设备该属性为1,此时在解析完文件后将该scd设置为在运版本 IsDefaultRunVersion int //间隔解析方式.分为Bay方式和自定义解析方式(根据name和des进行分词解析),默认为自定义解析方式解析 IsBay bool } type t_scd_node_scl struct { Id int64 `orm:"pk"` ScdId int64 ParentNodeId int64 NodeName string NodeValue string LineNo int64 CreatedBy int CreatedTime string } type t_scd_scl struct { Id int64 `orm:"pk"` ScdName string Path string Version string Enable int StationId int //签出锁定 CheckoutLock int //是否是管控SCD,true为管控SCD,false为非管控SCD IsCheckinScd int CreatedBy int CreatedTime string } type t_ied_ctrl_relation struct { Id int `orm:"pk"` ScdId int64 MasterIedId int64 MasterIedName string RefType int SourceIedId int64 SourceIedName string TargetIedId int64 TargetIedName string OutLdId int64 OutLdInst string OutLdDesc string LdId int64 LdInst string LdDesc string CtrlId int64 CtrlType string CtrlName string DatsetId int64 DatsetName string DatsetDesc string Cnt int } func init() { orm.RegisterModel(new(t_scd_scl)) orm.RegisterModel(new(t_scd_node_scl)) orm.RegisterModel(new(t_ied_ctrl_relation)) } func (c *ScdNode) GetCheckToolsTreeRoot(id, pid int64, datatype string) ([]orm.Params, error) { sclObj, serr := new(ScdParse).GetScdXmlObjectBySCDID(tools.IsEmpty(c.RootID)) if serr != nil { return nil, serr } if sclObj == nil { return nil, errors.New("无效的SCD编号") } alertDef := map[string]int{ "": 0, "hint": 1, "waring": 2, "error": 3, } noderuleObj := new(ScdNodeRule) noderuleObj.ScdID = c.RootID ruleHintLevel, _ := noderuleObj.SumCheckResult() alertlevelMap := map[string]string{} for _, levelrow := range ruleHintLevel { key := fmt.Sprintf("%s%s", levelrow["object_name"], levelrow["ied_name"]) if v, h := alertlevelMap[key]; h { level := tools.IsEmpty(levelrow["alert_level"]) if alertDef[level] > alertDef[v] { alertlevelMap[key] = level } } else { alertlevelMap[key] = tools.IsEmpty(levelrow["alert_level"]) } } db := orm.NewOrm() reuslt := []orm.Params{} areaMgr := new(ScdAreaMgr) if id == 0 { sclAlertLevel := "" if alertDef[alertlevelMap["Header"]] > alertDef[sclAlertLevel] { sclAlertLevel = alertlevelMap["Header"] } if alertDef[alertlevelMap["Substation"]] > alertDef[sclAlertLevel] { sclAlertLevel = alertlevelMap["Substation"] } reuslt = append(reuslt, orm.Params{ "id": "9999", "title": "基本语法校验结果", "pid": sclObj.NodeId, "isParent": "false", "datatype": "SCLSyntax", "alert_level": alertlevelMap["SCLSyntax"], }) sclAlertLevel = alertlevelMap["SCLSyntax"] //添加通信节点 reuslt = append(reuslt, orm.Params{ "id": sclObj.Communication.NodeId, "title": "Communication", "pid": sclObj.NodeId, "isParent": "false", "datatype": "Communication", "alert_level": alertlevelMap["Communication"], }) if alertDef[alertlevelMap["Communication"]] > alertDef[sclAlertLevel] { sclAlertLevel = alertlevelMap["Communication"] } //添加数据模板节点 reuslt = append(reuslt, orm.Params{ "id": sclObj.DataTypeTemplates.NodeId, "title": "DataTypeTemplates", "pid": sclObj.NodeId, "isParent": "false", "datatype": "DataTypeTemplates", "alert_level": alertlevelMap["DataTypeTemplates"], }) if alertDef[alertlevelMap["DataTypeTemplates"]] > alertDef[sclAlertLevel] { sclAlertLevel = alertlevelMap["DataTypeTemplates"] } //获取间隔列表 areaList, err := areaMgr.GetAreaList(c.RootID) if err != nil { return reuslt, err } voltageLevel := map[string]string{} //电压等级的告警级别 //获取该电压等级下的间隔列表 for _, ararow := range areaList { ararow["title"] = ararow["name"] ararow["datatype"] = "area" ararow["isParent"] = "true" ararow["alert_level"] = "" ararow["pid"] = tools.IsEmpty(ararow["voltage_level"]) areaid, _ := strconv.Atoi(tools.IsEmpty(ararow["id"])) iedList, err := areaMgr.GetIedList(c.RootID, 0, int32(areaid), "") if err != nil { continue } //获取间隔下的IED alertLevel := "" for _, row := range iedList { row["isParent"] = "false" row["pid"] = ararow["id"] row["id"] = row["node_id"] row["title"] = "[" + tools.IsEmpty(row["attr_name"]) + "]" + strings.Replace(tools.IsEmpty(row["attr_desc"]), tools.IsEmpty(row["name"]), "..", 1) iedAlart := alertlevelMap["IED"+tools.IsEmpty(row["attr_name"])] row["alert_level"] = iedAlart reuslt = append(reuslt, row) if alertDef[iedAlart] > alertDef[alertLevel] { alertLevel = iedAlart } } ararow["alert_level"] = alertLevel //间隔的告警级别 reuslt = append(reuslt, ararow) vol := tools.IsEmpty(ararow["voltage_level"]) if v, h := voltageLevel[vol]; h { if alertDef[alertLevel] > alertDef[v] { voltageLevel[vol] = alertLevel } } else { voltageLevel[vol] = alertLevel } } //添加电压等级子节点 sql := "select voltage_level id,t1.name title,0 pid ,'true' isParent,'voltage_level' datatype from t_substation_area t,global_const_code t1 where t.voltage_level=t1.id and scd_id=? GROUP BY voltage_level ORDER BY voltage_level" voltagelevelRowset := []orm.Params{} db.Raw(sql, c.RootID).Values(&voltagelevelRowset) for _, row2 := range voltagelevelRowset { row2["pid"] = sclObj.NodeId vollevel := voltageLevel[tools.IsEmpty(row2["id"])] row2["alert_level"] = vollevel reuslt = append(reuslt, row2) if alertDef[vollevel] > alertDef[sclAlertLevel] { sclAlertLevel = vollevel } } //添加SCL节点 reuslt = append(reuslt, orm.Params{ "id": sclObj.NodeId, "title": "SCL", "pid": 0, "isParent": "true", "datatype": "SCL", "alert_level": sclAlertLevel, }) } else { if datatype == "area" { //当前为间隔时,则返回该间隔下的IED iedList, err := areaMgr.GetIedList(c.RootID, 0, int32(id), "") if err != nil { return nil, err } for _, row := range iedList { row["isParent"] = "false" row["pid"] = id row["id"] = row["node_id"] row["title"] = strings.Replace(tools.IsEmpty(row["attr_desc"]), tools.IsEmpty(row["name"]), "..", 1) } reuslt = iedList } } new(SystemLog).Success(enum.AuditType_scd_show, enum.LogType_Query, enum.OptEventType_Bus, enum.OptEventLevel_Low, "查询IED结构树", c.GetUserInfo()) return reuslt, nil } //查询指定scd的节点列表 func (c *ScdNode) List(param map[string]interface{}) ([]orm.Params, int, error) { scdid := tools.IsEmpty(param["scd_id"]) scdXmlObj, serr := new(ScdParse).GetScdXmlObjectBySCDID(scdid) if serr != nil { return nil, 0, serr } if scdXmlObj == nil { return nil, 0, errors.New("无效的SCD文件") } iedname := tools.IsEmpty(param["ied_name"]) rowset := []orm.Params{} if v, ok := param["name"]; ok { name := tools.IsEmpty(v) switch name { case "SubNetwork": for _, item := range scdXmlObj.Communication.SubNetwork { rowobj := orm.Params{ "node_id": item.NodeId, "node_name": "SubNetwork", "node_value": "", "parent_node_id": scdXmlObj.Communication.NodeId, "attr_desc": item.Desc, "attr_name": item.Name, "attr_type": item.Type, } rowset = append(rowset, rowobj) } break case "ConnectedAP": for _, item := range scdXmlObj.Communication.SubNetwork { for _, c1 := range item.ConnectedAP { rowobj := orm.Params{ "node_id": c1.NodeId, "node_name": "ConnectedAP", "node_value": "", "parent_node_id": item.NodeId, "attr_desc": c1.Desc, "attr_ied_name": c1.IedName, "attr_ap_name": c1.ApName, } rowset = append(rowset, rowobj) } } break case "AccessPoint": if iedname == "" { return nil, 0, errors.New("IED Name不能为空") } iedObj := new(ScdNode).GetIed(scdXmlObj, scdid, iedname) if iedObj == nil { return nil, 0, errors.New("无效的IED Name") } for _, item := range iedObj.AccessPoint { rowobj := orm.Params{ "node_id": item.NodeId, "node_name": "AccessPoint", "node_value": "", "parent_node_id": iedObj.NodeId, "attr_desc": item.Desc, "ied_name": iedObj.Name, "attr_name": item.Name, "attr_clock": item.Clock, "attr_router": item.Router, } rowset = append(rowset, rowobj) } break case "DataSet": if iedname == "" { return nil, 0, errors.New("IED Name不能为空") } iedObj := new(ScdNode).GetIed(scdXmlObj, scdid, iedname) if iedObj == nil { return nil, 0, errors.New("无效的IED Name") } for _, item := range iedObj.AccessPoint { if item.Server == nil { continue } for _, c1 := range item.Server.LDevice { for _, ds := range c1.LN0.DataSet { rowobj := orm.Params{ "node_id": ds.NodeId, "node_name": "DataSet", "node_value": "", "parent_node_id": c1.NodeId, "attr_desc": ds.Desc, "ied_name": iedObj.Name, "attr_name": ds.Name, } rowset = append(rowset, rowobj) } } } break case "LN0": parent_node_id, _ := strconv.ParseInt(tools.IsEmpty(param["parent_node_id"]), 10, 64) scdidint64, _ := strconv.ParseInt(scdid, 10, 64) v_scdcache, _ := GlobalNodeMap.Load(scdidint64) if v_scdcache == nil { break } scdcache := v_scdcache.(map[int64]NodeCacheMap) ldevice := scdcache[parent_node_id].ObjAddr.(*node_attr.NLDevice) rowobj := orm.Params{ "node_id": ldevice.LN0.NodeId, "node_name": "LN0", "node_value": "", "parent_node_id": parent_node_id, "attr_desc": ldevice.LN0.Desc, "ied_name": "", "attr_inst": ldevice.LN0.Inst, "attr_ln_class": ldevice.LN0.LnClass, "attr_ln_type": ldevice.LN0.LnType, "attr_prefix": ldevice.LN0.Prefix, } rowset = append(rowset, rowobj) break case "LN": parent_node_id, _ := strconv.ParseInt(tools.IsEmpty(param["parent_node_id"]), 10, 64) scdidint64, _ := strconv.ParseInt(scdid, 10, 64) v_scdcache, _ := GlobalNodeMap.Load(scdidint64) if v_scdcache == nil { break } scdcache := v_scdcache.(map[int64]NodeCacheMap) ldevice := scdcache[parent_node_id].ObjAddr.(*node_attr.NLDevice) for _, ln := range ldevice.LN { rowobj := orm.Params{ "node_id": ln.NodeId, "node_name": "LN", "node_value": "", "parent_node_id": parent_node_id, "attr_desc": ln.Desc, "ied_name": "", "attr_inst": ln.Inst, "attr_ln_class": ln.LnClass, "attr_ln_type": ln.LnType, "attr_prefix": ln.Prefix, } rowset = append(rowset, rowobj) } break case "FCDA": parent_node_id, _ := strconv.ParseInt(tools.IsEmpty(param["parent_node_id"]), 10, 64) scdidint64, _ := strconv.ParseInt(scdid, 10, 64) v_scdcache, _ := GlobalNodeMap.Load(scdidint64) if v_scdcache == nil { break } scdcache := v_scdcache.(map[int64]NodeCacheMap) ds := scdcache[parent_node_id].ObjAddr.(*node_attr.NDataSet) for _, fcda := range ds.FCDA { rowobj := orm.Params{ "node_id": fcda.NodeId, "node_name": "FCDA", "node_value": "", "parent_node_id": parent_node_id, "attr_da_name": fcda.DaName, "attr_do_name": fcda.DoName, "attr_fc": fcda.Fc, "attr_ld_inst": fcda.LdInst, "attr_ln_class": fcda.LnClass, "attr_ln_inst": fcda.LnInst, "attr_prefix": fcda.Prefix, } rowset = append(rowset, rowobj) } default: break } } return rowset, len(rowset), nil } //获取指定节点的所有属性及属性值 func (c *ScdNode) GetAttrValues(param map[string]interface{}) (interface{}, error) { node_id := tools.IsEmpty(param["node_id"]) if node_id == "" { return nil, errors.New("节点编号不能为空") } node_id_int, _ := strconv.ParseInt(node_id, 10, 64) scdid := tools.IsEmpty(param["scd_id"]) scdidint64, _ := strconv.ParseInt(scdid, 10, 64) v_scdcache, _ := GlobalNodeMap.Load(scdidint64) if v_scdcache == nil { return nil, errors.New("无效的节点") } nodeInfo := v_scdcache.(map[int64]NodeCacheMap) nodeobj := nodeInfo[node_id_int].ObjAddr if nodeobj == nil { return nil, errors.New("无效的节点") } return new(node_attr.BaseNode).ToMap(nodeobj), nil } //统计指定节点的下级节点类型及数量 func (c *ScdNode) GetChildrenStat(scdid, nodeid string) ([]orm.Params, int, error) { if scdid == "" { return nil, 0, errors.New("SCD文件编号不能为空!") } if nodeid == "" { return nil, 0, errors.New("节点编号不能为空!") } db := orm.NewOrm() rowset := []orm.Params{} sql := "select node_name,count(1) cnt from t_scd_node_scl t where 1=1 and t.scd_id=? and t.parent_node_id=? GROUP BY t.node_name" sqllog := fmt.Sprintf("SQL:%s,参数:%s,%s", sql, scdid, nodeid) _, err := db.Raw(sql, scdid, nodeid).Values(&rowset) if err != nil { logger.Logger.Error(err, sqllog) new(SystemLog).Fail(enum.AuditType_scd_show, enum.LogType_datastat, enum.OptEventType_Bus, enum.OptEventLevel_Low, sqllog, c.GetUserInfo()) return rowset, 0, err } new(SystemLog).Success(enum.AuditType_scd_show, enum.LogType_datastat, enum.OptEventType_Bus, enum.OptEventLevel_Low, sqllog, c.GetUserInfo()) return rowset, len(rowset), nil } //获取指定accessPoint下的Ldevice节点列表 func (c *ScdNode) GetLdeviceList(scdid, accesspointid string) ([]orm.Params, int, error) { if scdid == "" { return nil, 0, errors.New("SCD文件编号不能为空!") } if accesspointid == "" { return nil, 0, errors.New("AccessPoint编号不能为空!") } scdXmlObj, serr := new(ScdParse).GetScdXmlObjectBySCDID(scdid) if serr != nil { return nil, 0, serr } if scdXmlObj == nil { return nil, 0, errors.New("无效的SCD文件!") } rowset := []orm.Params{} accesspointidInt, _ := strconv.ParseInt(accesspointid, 10, 64) for _, row := range scdXmlObj.IED { for _, r1 := range row.AccessPoint { if r1.Server == nil { continue } if r1.NodeId == accesspointidInt { for _, r2 := range r1.Server.LDevice { rowset = append(rowset, orm.Params{ "node_id": r2.NodeId, "attr_inst": r2.Inst, "attr_desc": r2.Desc, }) } break } } } return rowset, len(rowset), nil } func (c *ScdNode) GetIedByID(sclObj *node_attr.SCL, scdid string, ied_id int64) *node_attr.NIED { if sclObj == nil { return nil } var masterIed *node_attr.NIED for _, row := range sclObj.IED { if row.NodeId == ied_id { masterIed = row break } } return masterIed } //获取IED func (c *ScdNode) GetIed(sclObj *node_attr.SCL, scdid string, ied_name string) *node_attr.NIED { if sclObj == nil { return nil } var masterIed *node_attr.NIED for _, row := range sclObj.IED { if row.Name == ied_name { masterIed = row break } } return masterIed } //获取指定IED节点的关联关系 func (c *ScdNode) GetIedRelations(param map[string]interface{}) (map[string]interface{}, error) { scdid := tools.IsEmpty(param["scd_id"]) //判断是否需要重新分析关系 //isreset := tools.IsEmpty(param["reset"]) v_iedname := tools.IsEmpty(param["ied_name"]) cacheKey := "GetIedRelations_" + scdid cacheKey2 := "GetIedRelations_" + scdid + v_iedname if v_iedname == "" { if v, h := global.GoCahce.Get(cacheKey); h { return v.(map[string]interface{}), nil } } else { if v, h := global.GoCahce.Get(cacheKey2); h { return v.(map[string]interface{}), nil } if v, h := global.GoCahce.Get(cacheKey); h { alldata := v.(map[string]interface{}) result := map[string]interface{}{} result[v_iedname] = alldata[v_iedname] return result, nil } } //logger.Logger.Debug(fmt.Sprintf("\n\n加载IED装置%s的关联IED\n", v_iedname)) scdXmlObj, serr := new(ScdParse).GetScdXmlObjectBySCDID(scdid) if serr != nil { return nil, serr } if scdXmlObj == nil { return nil, errors.New("无效的SCD") } result := map[string]interface{}{} //ref为1时,查询的是该IED的输入关联IED //ref为0时,查询的是该iED的输出关联IED for _, row := range scdXmlObj.IED { ied_name := row.Name //查找输入的ied obj := orm.Params{"desc": row.Desc, "ied_name": row.Name, "node_id": row.NodeId, "list": []orm.Params{}} tmpAry := map[string]orm.Params{} for _, alist := range row.AccessPoint { if alist.Server == nil { logger.Logger.Error(errors.New(fmt.Sprintf("%s装置中的%s未发现Server定义", ied_name, alist.Name))) continue } for _, ldlist := range alist.Server.LDevice { if ldlist.LN0.Inputs != nil { for _, extreflist := range ldlist.LN0.Inputs.ExtRef { ref_ied_name := extreflist.IedName if _, h := tmpAry[ref_ied_name]; h { continue } refIedObj := c.GetIed(scdXmlObj, scdid, ref_ied_name) if refIedObj != nil { tmpAry[ref_ied_name] = orm.Params{"ied_desc": row.Desc, "ied_name": row.Name, "node_id": row.NodeId, "ref_ied_id": refIedObj.NodeId, "ref_ied_desc": refIedObj.Desc, "ref_ied_name": ref_ied_name, "ref_type": "1"} } } } } } for _, k := range tmpAry { obj["list"] = append(obj["list"].([]orm.Params), k) } //查找输出的ied tmpAry = map[string]orm.Params{} for _, outrow := range scdXmlObj.IED { if ied_name == outrow.Name { continue } for _, alist := range outrow.AccessPoint { if alist.Server == nil { logger.Logger.Error(errors.New(fmt.Sprintf("%s装置中的%s未发现Server定义", ied_name, alist.Name))) continue } for _, ldlist := range alist.Server.LDevice { if ldlist.LN0.Inputs != nil { for _, extreflist := range ldlist.LN0.Inputs.ExtRef { ref_ied_name := extreflist.IedName if ref_ied_name != ied_name { continue } if _, h := tmpAry[outrow.Name]; h { continue } refIedObj := c.GetIed(scdXmlObj, scdid, outrow.Name) if refIedObj != nil { tmpAry[outrow.Name] = orm.Params{"ied_desc": row.Desc, "ied_name": row.Name, "node_id": row.NodeId, "ref_ied_id": refIedObj.NodeId, "ref_ied_desc": outrow.Desc, "ref_ied_name": outrow.Name, "ref_type": "0"} } } } } } } for _, k := range tmpAry { obj["list"] = append(obj["list"].([]orm.Params), k) } result[ied_name] = obj } global.GoCahce.Set(cacheKey, result, -1) if v_iedname != "" { result2 := map[string]interface{}{} result2[v_iedname] = result[v_iedname] global.GoCahce.Set(cacheKey2, result2, -1) return result2, nil } return result, nil } //获取指定IED的控制块信息 func (c *ScdNode) GetIedCtrlBlock(scdid int64, iedname string) (map[string]interface{}, error) { key := fmt.Sprintf("GetIedCtrlBlock_%d_%s", scdid, iedname) if v, h := global.GoCahce.Get(key); h { return v.(map[string]interface{}), nil } scdXmlObj, serr := new(ScdParse).GetScdXmlObjectBySCDID(tools.IsEmpty(scdid)) if serr != nil { return nil, serr } if scdXmlObj == nil { return nil, errors.New("无效的SCD") } var iedObj *node_attr.NIED for _, row := range scdXmlObj.IED { if row.Name == iedname { iedObj = row break } } if iedObj == nil { return nil, errors.New("无效的IED装置名称") } result := map[string]interface{}{} gselist := []orm.Params{} smvlist := []orm.Params{} for _, row := range iedObj.AccessPoint { if row.Server == nil { logger.Logger.Error(errors.New(fmt.Sprintf("%s装置中的%s未发现Server定义", iedObj.Name, row.Name))) continue } for _, ld := range row.Server.LDevice { ldinst := ld.Inst if ld.LN0 != nil { for _, gse := range ld.LN0.GSEControl { datSetdesc := "" for _, ds := range ld.LN0.DataSet { if ds.Name == gse.DatSet { datSetdesc = ds.Desc break } } gooseaddress := orm.Params{} //获取控制块appid for _, subn := range scdXmlObj.Communication.SubNetwork { if subn.Type == "IECGOOSE" { for _, ap := range subn.ConnectedAP { if ap.IedName == iedObj.Name { for _, gse1 := range ap.GSE { if gse1.CbName == gse.Name && gse1.LdInst == ld.Inst { if gse1.Address != nil { for _, addrP := range gse1.Address.P { gooseaddress[strings.ReplaceAll(addrP.Type, "-", "_")] = addrP.InnerText } } break } } break } } break } } gselist = append(gselist, orm.Params{ "attr_appid": gse.AppID, "attr_dat_set": gse.DatSet, "attr_name": gse.Name, "attr_conf_rev": gse.ConfRev, "attr_desc": "", "attr_type": gse.Type, "datset_desc": datSetdesc, "ldinst": ldinst, "node_id": gse.NodeId, "address": gooseaddress, }) } for _, sv := range ld.LN0.SampledValueControl { datSetdesc := "" //获取控制块数据集信息 for _, ds := range ld.LN0.DataSet { if ds.Name == sv.DatSet { datSetdesc = ds.Desc break } } svaddress := orm.Params{} //获取控制块appid for _, subn := range scdXmlObj.Communication.SubNetwork { if subn.Type == "SMV" { for _, ap := range subn.ConnectedAP { if ap.IedName == iedObj.Name { for _, smv := range ap.SMV { if smv.CbName == sv.Name && smv.LdInst == ld.Inst { if smv.Address != nil { for _, addrP := range smv.Address.P { svaddress[strings.ReplaceAll(addrP.Type, "-", "_")] = addrP.InnerText } } break } } break } } break } } smvlist = append(smvlist, orm.Params{ "attr_smv_id": sv.SmvID, "attr_dat_set": sv.DatSet, "attr_smp_rate": sv.SmpRate, "attr_name": sv.Name, "attr_conf_rev": sv.ConfRev, "attr_desc": "", "attr_multicast": sv.Multicast, "datset_desc": datSetdesc, "ldinst": ldinst, "attr_nof_asdu": sv.NofASDU, "node_id": sv.NodeId, "address": svaddress, }) } } } } result["GSEControl"] = gselist result["SampledValueControl"] = smvlist global.GoCahce.Set(key, result, -1) return result, nil } //获取指定IED的指定SMV控制块发送端子列表 func (c *ScdNode) GetIedSMVCtrlBlockSendFcdaList(scdid int64, iedname string, ctrl_id int64) ([]orm.Params, error) { rowset := []orm.Params{} v_scdcache, _ := GlobalNodeMap.Load(scdid) if v_scdcache == nil { return nil, errors.New("无效的节点") } scdCacheObj := v_scdcache.(map[int64]NodeCacheMap) ctrlObj1 := scdCacheObj[ctrl_id] if ctrlObj1.ObjAddr == nil { return rowset, errors.New("无效的控制块ID") } //获取当前IED的输出IED relIed, err := c.GetIedRelations(map[string]interface{}{"scd_id": scdid, "ied_name": iedname}) if relIed == nil { return nil, err } ieds0 := relIed[iedname].(orm.Params) if ieds0 == nil { return rowset, nil } ieds := ieds0["list"].([]orm.Params) outtoieds := []*node_attr.NIED{} //获取当前IED输出的目标IED,即ref_type为0的.结果中需要返回输出IED中对应的端子信息 for _, r := range ieds { if tools.IsEmpty(r["ref_type"]) == "0" { iedid, _ := strconv.ParseInt(tools.IsEmpty(r["ref_ied_id"]), 10, 64) tmpIedObj := scdCacheObj[iedid].ObjAddr.(*node_attr.NIED) if tmpIedObj.Name == iedname { continue } outtoieds = append(outtoieds, tmpIedObj) } } if len(outtoieds) == 0 { return rowset, nil } ctrlObj := ctrlObj1.ObjAddr.(*node_attr.NSampledValueControl) datasetname := ctrlObj.DatSet ln0 := scdCacheObj[ctrlObj1.ParentNodeId].ObjAddr.(*node_attr.NLN0) ldid := scdCacheObj[ctrlObj1.ParentNodeId].ParentNodeId ld := scdCacheObj[ldid].ObjAddr.(*node_attr.NLDevice) for _, ds := range ln0.DataSet { if ds.Name == datasetname { for _, fcda := range ds.FCDA { obj := orm.Params{ "do_desc": "", "do_name": fcda.DoName, "ld_inst": fcda.LdInst, "ln_inst": fcda.LnInst, "ln_class": fcda.LnClass, "prefix": fcda.Prefix, "out_intaddr": "", "out_ied_name": "", "out_ied_desc": "", "out_do_desc": "", } doi_desc := "" if fcda.LnClass == "LLN0" { for _, doi := range ld.LN0.DOI { if doi.Name == fcda.DoName { doi_desc = doi.Desc break } } } else { for _, ln := range ld.LN { if ln.Inst == fcda.LnInst && ln.LnClass == fcda.LnClass && ln.Prefix == fcda.Prefix { for _, doi := range ln.DOI { if doi.Name == fcda.DoName { doi_desc = doi.Desc break } } } if doi_desc != "" { break } } } obj["do_desc"] = doi_desc //内部端子描述 //获取外部信息及端子描述 doi_desc = "" outFound := false //是否查找到对应的外部端子 out_lns := map[string]*node_attr.NLN{} for _, ied := range outtoieds { for _, acc := range ied.AccessPoint { if acc.Server != nil { for _, ld := range acc.Server.LDevice { if ld.LN0.Inputs != nil { for _, extref := range ld.LN0.Inputs.ExtRef { if extref.IedName == iedname && extref.DoName == fcda.DoName && extref.LdInst == fcda.LdInst && extref.LnClass == fcda.LnClass && extref.LnInst == fcda.LnInst && extref.Prefix == fcda.Prefix { outFound = true obj["out_intaddr"] = extref.IntAddr obj["out_ied_name"] = ied.Name obj["out_ied_desc"] = ied.Desc outLnStr := strings.Split(extref.IntAddr, ".")[0] outDoName := strings.Split(extref.IntAddr, ".")[1] var ln *node_attr.NLN if v, h := out_lns[outLnStr]; h { ln = v } else { //查找内部地址指向的Ln lnFound := false for _, tLd := range acc.Server.LDevice { if extref.LnClass == "LLN0" { for _, doi := range tLd.LN0.DOI { if doi.Name == fcda.DoName { doi_desc = doi.Desc lnFound = true break } } } if doi_desc != "" { obj["out_do_desc"] = doi_desc break } for _, tLn := range tLd.LN { if outLnStr == fmt.Sprintf("%s/%s%s%s", tLd.Inst, tLn.Prefix, tLn.LnClass, tLn.Inst) { out_lns[outLnStr] = tLn ln = tLn lnFound = true break } } if lnFound { break } } } if ln == nil { continue } for _, doi := range ln.DOI { if doi.Name == outDoName { obj["out_do_desc"] = doi.Desc break } } break } } } if outFound { break } } if outFound { break } } if outFound { break } } if outFound { break } } rowset = append(rowset, obj) } break } } return rowset, nil } //获取指定IED的SMV接收块及端子列表 func (c *ScdNode) GetIedSMVCtrlBlockRevList(scdid int64, iedname string) ([]orm.Params, error) { rowset := []orm.Params{} scdXmlObj, serr := new(ScdParse).GetScdXmlObjectBySCDID(tools.IsEmpty(scdid)) if serr != nil { return nil, serr } if scdXmlObj == nil { return nil, errors.New("无效的SCD") } currentIedObj := c.GetIed(scdXmlObj, tools.IsEmpty(scdid), iedname) if currentIedObj == nil { return rowset, errors.New("无效的IED装置名称") } fromiedObjs := map[string]interface{}{} for _, acc := range currentIedObj.AccessPoint { if acc.Server != nil { for _, ld := range acc.Server.LDevice { if ld.LN0 != nil && ld.LN0.Inputs != nil { for _, extref := range ld.LN0.Inputs.ExtRef { form_ied_name := extref.IedName var tmpFromIed *node_attr.NIED if v, h := fromiedObjs[form_ied_name]; h { tmpFromIed = v.(*node_attr.NIED) } else { tmpFromIed = c.GetIed(scdXmlObj, tools.IsEmpty(scdid), form_ied_name) } if tmpFromIed == nil { logger.Logger.Error(fmt.Sprintf("未发现IED装置%s", form_ied_name)) break } //获取目标IED的块 iedBlockList, _ := c.GetIedCtrlBlock(scdid, form_ied_name) //logger.Logger.Debug(fmt.Sprintf("=====%s 装置,extref:%+v", form_ied_name, iedBlockList)) if iedBlockList == nil { continue } smvBlcokList := iedBlockList["SampledValueControl"].([]orm.Params) if len(smvBlcokList) == 0 { continue } smvDataSetMap := map[string]int{} for _, smvRow := range smvBlcokList { smvDataSetMap[tools.IsEmpty(smvRow["attr_dat_set"])] = 1 } found := false out_lns := map[string]*node_attr.NLN{} for _, fromacc := range tmpFromIed.AccessPoint { if fromacc.Server != nil { for _, fromld := range fromacc.Server.LDevice { if fromld.Inst == extref.LdInst { for _, ds := range fromld.LN0.DataSet { _, h := smvDataSetMap[ds.Name] if !h { continue } for _, fromfcda := range ds.FCDA { if extref.LnClass == fromfcda.LnClass && extref.Prefix == fromfcda.Prefix && extref.LnInst == fromfcda.LnInst && extref.DoName == fromfcda.DoName { obj := orm.Params{ "int_addr": extref.IntAddr, "out_do_name": fromfcda.DoName, "out_ied_name": tmpFromIed.Name, "out_ied_desc": tmpFromIed.Desc, "out_dataset_name": ds.Name, "out_dataset_desc": ds.Desc, "out_smv_ctrl_name": "", "out_smv_ctrl_address": "", } //获取内部信号描述 doi_desc := "" outLnStr := strings.Split(extref.IntAddr, ".")[0] outDoName := strings.Split(extref.IntAddr, ".")[1] var ln *node_attr.NLN if v, h := out_lns[outLnStr]; h { ln = v } else { //查找内部地址指向的Ln lnFound := false for _, tLd := range acc.Server.LDevice { if extref.LnClass == "LLN0" { for _, doi := range tLd.LN0.DOI { if doi.Name == outDoName { doi_desc = doi.Desc lnFound = true break } } } if doi_desc != "" { obj["do_desc"] = doi_desc break } for _, tLn := range tLd.LN { if outLnStr == fmt.Sprintf("%s/%s%s%s", tLd.Inst, tLn.Prefix, tLn.LnClass, tLn.Inst) { out_lns[outLnStr] = tLn ln = tLn lnFound = true break } } if lnFound { break } } } if ln != nil { for _, doi := range ln.DOI { if doi.Name == outDoName { obj["do_desc"] = doi.Desc break } } } //获取输入块信息 for _, smvRow := range smvBlcokList { if tools.IsEmpty(smvRow["attr_dat_set"]) == ds.Name { obj["out_smv_ctrl_name"] = smvRow["attr_name"] obj["out_smv_ctrl_address"] = smvRow["address"] break } } doi_desc = "" if fromfcda.LnClass == "LLN0" { for _, doi := range fromld.LN0.DOI { if doi.Name == fromfcda.DoName { doi_desc = doi.Desc break } } } else { for _, ln := range fromld.LN { if ln.Inst == fromfcda.LnInst && ln.LnClass == fromfcda.LnClass && ln.Prefix == fromfcda.Prefix { for _, doi := range ln.DOI { if doi.Name == fromfcda.DoName { doi_desc = doi.Desc break } } } if doi_desc != "" { break } } } if doi_desc != "" { obj["out_do_desc"] = doi_desc } rowset = append(rowset, obj) } } } found = true break } } if found { break } } } } } } } } return rowset, nil } //获取指定IED的goose控制块发送端子列表 func (c *ScdNode) GetIedGooseCtrlBlockSendFcdaList(scdid int64, iedname string, ctrl_id int64) ([]orm.Params, error) { rowset := []orm.Params{} v_scdcache, _ := GlobalNodeMap.Load(scdid) if v_scdcache == nil { return nil, errors.New("无效的SCD") } scdCacheObj := v_scdcache.(map[int64]NodeCacheMap) ctrlObj1 := scdCacheObj[ctrl_id] if ctrlObj1.ObjAddr == nil { return rowset, errors.New("无效的控制块ID") } //获取当前IED的输出IED relIed, err := c.GetIedRelations(map[string]interface{}{"scd_id": scdid, "ied_name": iedname}) if relIed == nil { return nil, err } ieds0 := relIed[iedname].(orm.Params) if ieds0 == nil { return rowset, nil } ieds := ieds0["list"].([]orm.Params) outtoieds := []*node_attr.NIED{} //获取当前IED输出的目标IED,即ref_type为0的.结果中需要返回输出IED中对应的端子信息 for _, r := range ieds { if tools.IsEmpty(r["ref_type"]) == "0" { iedid, _ := strconv.ParseInt(tools.IsEmpty(r["ref_ied_id"]), 10, 64) tmpIedObj := scdCacheObj[iedid].ObjAddr.(*node_attr.NIED) if tmpIedObj.Name == iedname { continue } outtoieds = append(outtoieds, tmpIedObj) } } if len(outtoieds) == 0 { return rowset, nil } ctrlObj := ctrlObj1.ObjAddr.(*node_attr.NGSEControl) datasetname := ctrlObj.DatSet ln0 := scdCacheObj[ctrlObj1.ParentNodeId].ObjAddr.(*node_attr.NLN0) ldid := scdCacheObj[ctrlObj1.ParentNodeId].ParentNodeId ld := scdCacheObj[ldid].ObjAddr.(*node_attr.NLDevice) for _, ds := range ln0.DataSet { if ds.Name == datasetname { for _, fcda := range ds.FCDA { obj := orm.Params{ "do_desc": "", "do_name": fcda.DoName, "ld_inst": fcda.LdInst, "ln_inst": fcda.LnInst, "ln_class": fcda.LnClass, "prefix": fcda.Prefix, "out_intaddr": "", "out_ied_name": "", "out_ied_desc": "", "out_do_desc": "", } doi_desc := "" if fcda.LnClass == "LLN0" { for _, doi := range ld.LN0.DOI { if doi.Name == fcda.DoName { doi_desc = doi.Desc break } } } else { for _, ln := range ld.LN { if ln.Inst == fcda.LnInst && ln.LnClass == fcda.LnClass && ln.Prefix == fcda.Prefix { for _, doi := range ln.DOI { if doi.Name == fcda.DoName { doi_desc = doi.Desc break } } } if doi_desc != "" { break } } } obj["do_desc"] = doi_desc //内部端子描述 //获取外部信息及端子描述 doi_desc = "" outFound := false //是否查找到对应的外部端子 out_lns := map[string]*node_attr.NLN{} for _, ied := range outtoieds { for _, acc := range ied.AccessPoint { if acc.Server != nil { for _, ld := range acc.Server.LDevice { if ld.LN0.Inputs != nil { for _, extref := range ld.LN0.Inputs.ExtRef { if extref.IedName == iedname && extref.DoName == fcda.DoName && extref.LdInst == fcda.LdInst && extref.LnClass == fcda.LnClass && extref.LnInst == fcda.LnInst && extref.Prefix == fcda.Prefix { outFound = true obj["out_intaddr"] = extref.IntAddr obj["out_ied_name"] = ied.Name obj["out_ied_desc"] = ied.Desc outLnStr := strings.Split(extref.IntAddr, ".")[0] outDoName := strings.Split(extref.IntAddr, ".")[1] var ln *node_attr.NLN if v, h := out_lns[outLnStr]; h { ln = v } else { //查找内部地址指向的Ln lnFound := false for _, tLd := range acc.Server.LDevice { if extref.LnClass == "LLN0" { for _, doi := range tLd.LN0.DOI { if doi.Name == fcda.DoName { doi_desc = doi.Desc lnFound = true break } } } if doi_desc != "" { obj["out_do_desc"] = doi_desc break } for _, tLn := range tLd.LN { if outLnStr == fmt.Sprintf("%s/%s%s%s", tLd.Inst, tLn.Prefix, tLn.LnClass, tLn.Inst) { out_lns[outLnStr] = tLn ln = tLn lnFound = true break } } if lnFound { break } } } if ln == nil { continue } for _, doi := range ln.DOI { if doi.Name == outDoName { obj["out_do_desc"] = doi.Desc break } } break } } } if outFound { break } } if outFound { break } } if outFound { break } } if outFound { break } } rowset = append(rowset, obj) } break } } return rowset, nil } //获取指定IED的goose接收块及端子列表 func (c *ScdNode) GetIedGooseCtrlBlockRevList(scdid int64, iedname string) ([]orm.Params, error) { rowset := []orm.Params{} scdXmlObj, serr := new(ScdParse).GetScdXmlObjectBySCDID(tools.IsEmpty(scdid)) if serr != nil { return nil, serr } if scdXmlObj == nil { return nil, errors.New("无效的SCD") } currentIedObj := c.GetIed(scdXmlObj, tools.IsEmpty(scdid), iedname) if currentIedObj == nil { return rowset, errors.New("无效的IED装置名称") } fromiedObjs := map[string]interface{}{} for _, acc := range currentIedObj.AccessPoint { if acc.Server != nil { for _, ld := range acc.Server.LDevice { if ld.LN0 != nil && ld.LN0.Inputs != nil { for _, extref := range ld.LN0.Inputs.ExtRef { form_ied_name := extref.IedName var tmpFromIed *node_attr.NIED if v, h := fromiedObjs[form_ied_name]; h { tmpFromIed = v.(*node_attr.NIED) } else { tmpFromIed = c.GetIed(scdXmlObj, tools.IsEmpty(scdid), form_ied_name) } if tmpFromIed == nil { logger.Logger.Error(fmt.Sprintf("未发现IED装置%s", form_ied_name)) break } //获取目标IED的块 iedBlockList, _ := c.GetIedCtrlBlock(scdid, form_ied_name) //logger.Logger.Debug(fmt.Sprintf("=====%s 装置,iedBlockList:%+v", form_ied_name, iedBlockList)) if iedBlockList == nil { continue } smvBlcokList := iedBlockList["GSEControl"].([]orm.Params) if len(smvBlcokList) == 0 { continue } gooseDataSetMap := map[string]int{} for _, smvRow := range smvBlcokList { gooseDataSetMap[tools.IsEmpty(smvRow["attr_dat_set"])] = 1 } found := false out_lns := map[string]*node_attr.NLN{} for _, fromacc := range tmpFromIed.AccessPoint { if fromacc.Server != nil { for _, fromld := range fromacc.Server.LDevice { if fromld.Inst == extref.LdInst { for _, ds := range fromld.LN0.DataSet { _, h := gooseDataSetMap[ds.Name] if !h { continue } for _, fromfcda := range ds.FCDA { if extref.LnClass == fromfcda.LnClass && extref.Prefix == fromfcda.Prefix && extref.LnInst == fromfcda.LnInst && extref.DoName == fromfcda.DoName { obj := orm.Params{ "int_addr": extref.IntAddr, "out_do_name": fromfcda.DoName, "out_ied_name": tmpFromIed.Name, "out_ied_desc": tmpFromIed.Desc, "out_dataset_name": ds.Name, "out_dataset_desc": ds.Desc, "out_gse_ctrl_name": "", "out_gse_ctrl_address": "", } //获取内部信号描述 doi_desc := "" outLnStr := strings.Split(extref.IntAddr, ".")[0] outDoName := strings.Split(extref.IntAddr, ".")[1] var ln *node_attr.NLN if v, h := out_lns[outLnStr]; h { ln = v } else { //查找内部地址指向的Ln lnFound := false for _, tLd := range acc.Server.LDevice { if extref.LnClass == "LLN0" { for _, doi := range tLd.LN0.DOI { if doi.Name == outDoName { doi_desc = doi.Desc lnFound = true break } } } if doi_desc != "" { obj["do_desc"] = doi_desc break } for _, tLn := range tLd.LN { if outLnStr == fmt.Sprintf("%s/%s%s%s", tLd.Inst, tLn.Prefix, tLn.LnClass, tLn.Inst) { out_lns[outLnStr] = tLn ln = tLn lnFound = true break } } if lnFound { break } } } if ln != nil { for _, doi := range ln.DOI { if doi.Name == outDoName { obj["do_desc"] = doi.Desc break } } } //获取输入块信息 for _, smvRow := range smvBlcokList { if tools.IsEmpty(smvRow["attr_dat_set"]) == ds.Name { obj["out_gse_ctrl_name"] = smvRow["attr_name"] obj["out_gse_ctrl_address"] = smvRow["address"] break } } doi_desc = "" if fromfcda.LnClass == "LLN0" { for _, doi := range fromld.LN0.DOI { if doi.Name == fromfcda.DoName { doi_desc = doi.Desc break } } } else { for _, ln := range fromld.LN { if ln.Inst == fromfcda.LnInst && ln.LnClass == fromfcda.LnClass && ln.Prefix == fromfcda.Prefix { for _, doi := range ln.DOI { if doi.Name == fromfcda.DoName { doi_desc = doi.Desc break } } } if doi_desc != "" { break } } } if doi_desc != "" { obj["out_do_desc"] = doi_desc } rowset = append(rowset, obj) } } } found = true break } } if found { break } } } } } } } } return rowset, nil } //生成指定scd下的ied输入输出关系数据 func (c *ScdNode) MakeIedRelations(scdid int64, iedname ...string) error { db := orm.NewOrm() rowset := []orm.Params{} v_iedname := "" if len(iedname) > 0 { v_iedname = iedname[0] } var err error sql := "" if v_iedname != "" { sql = "select node_id, attr_name from t_scd_ied_attrs where scd_id=? and attr_name=?" _, err = db.Raw(sql, scdid, v_iedname).Values(&rowset) } else { sql = "select node_id, attr_name from t_scd_ied_attrs where scd_id=?" _, err = db.Raw(sql, scdid).Values(&rowset) } sqllog := fmt.Sprintf("SQL:%s,参数:%d,%s", sql, scdid, v_iedname) if err != nil { logger.Logger.Error(err, sqllog) new(SystemLog).Fail(enum.AuditType_scd_show, enum.LogType_Query, enum.OptEventType_Bus, enum.OptEventLevel_Low, sqllog, c.GetUserInfo()) return err } new(SystemLog).Success(enum.AuditType_scd_show, enum.LogType_Query, enum.OptEventType_Bus, enum.OptEventLevel_Low, sqllog, c.GetUserInfo()) if len(rowset) == 0 { return errors.New("无效的SCD文件编号") } //wg := sync.WaitGroup{} //wg.Add(len(rowset)) for _, row := range rowset { ied_name := tools.IsEmpty(row["attr_name"]) iedid := tools.IsEmpty(row["node_id"]) //go func(iedid, ied_name string) { // defer wg.Done() // time.Sleep(100 * time.Millisecond) //db0 := orm.NewOrm() //ref为1时,查询的是该IED的输入关联IED //ref为0时,查询的是该iED的输出关联IED sql := `insert into t_ied_relation(scd_id,ied_id,ied_name,ref_type,ref_ied_name) select ` + fmt.Sprintf("%d", scdid) + ` scdid, ` + iedid + ` iedid, '` + ied_name + `' iedname, '1' ref, t1.attr_ied_name ied_name from t_scd_node_scl t,t_scd_extref_attrs t1 where t.id =t1.node_id and t.scd_id=? and t1.scd_id=? and t.ied_name=? and t.node_name='ExtRef' GROUP BY t1.attr_ied_name union select ` + fmt.Sprintf("%d", scdid) + ` scdid, ` + iedid + ` iedid, '` + ied_name + `' iedname,'0' ref, t.ied_name from t_scd_extref_attrs t1,t_scd_node_scl t where t.id=t1.node_id and t.scd_id=? and t1.scd_id=? and t1.attr_ied_name=? GROUP BY t.ied_name` _, err = db.Raw(sql, scdid, scdid, ied_name, scdid, scdid, ied_name).Exec() sqllog := fmt.Sprintf("SQL:%s,参数:%+v", sql, []interface{}{scdid, scdid, ied_name, scdid, scdid, ied_name}) if err != nil { logger.Logger.Error(err, sqllog) new(SystemLog).Fail(enum.AuditType_scd_show, enum.LogType_Insert, enum.OptEventType_Bus, enum.OptEventLevel_Hight, sqllog, c.GetUserInfo()) return err } new(SystemLog).Success(enum.AuditType_scd_show, enum.LogType_Insert, enum.OptEventType_Bus, enum.OptEventLevel_Hight, sqllog, c.GetUserInfo()) //}(ied_id, ied_name) } //wg.Wait() return nil } //获取指定IEd节点的控制块关系 func (c *ScdNode) GetIedBlockRelations(scdid int64, ied_name string, forcerefresh ...bool) ([]orm.Params, error) { if ied_name == "" { return nil, errors.New("IEDname不能同时为空") } if scdid == 0 { return nil, errors.New("scd编号不能为空") } cacheKey := fmt.Sprintf("GetIedBlockRelations_%d_%s", scdid, ied_name) if v, h := global.GoCahce.Get(cacheKey); h { return v.([]orm.Params), nil } scdXmlObj, serr := new(ScdParse).GetScdXmlObjectBySCDID(tools.IsEmpty(scdid)) if serr != nil { return nil, serr } if scdXmlObj == nil { return nil, errors.New("无效的SCD") } queryRowset := []orm.Params{} var masterIed = c.GetIed(scdXmlObj, tools.IsEmpty(scdid), ied_name) if masterIed == nil { return nil, errors.New("无效的IED装备名称") } extreflist, _ := c.GetIedInputsRelations(map[string]interface{}{"ied_name": masterIed.Name, "scd_id": scdid}) if extreflist == nil || len(extreflist) == 0 { return nil, nil } //缓存每个块关联的详情 cachebBlockDetail := map[string][]orm.Params{} //获取当前IED的控制块,获取输入的IED及块 inputBlock := map[string]orm.Params{} for _, row := range extreflist { //"attr_ld_inst","attr_prefix","attr_ln_class","attr_ln_inst","attr_do_name","attr_da_name" tmpIedName := tools.IsEmpty(row["ied_name"]) if tmpIedName == masterIed.Name { continue } if tools.IsEmpty(row["inout_type"]) == "out" { //过滤该ied中的输出ExtRef continue } extrefid := row["node_id"] ldInst := tools.IsEmpty(row["attr_ld_inst"]) prefix := tools.IsEmpty(row["attr_prefix"]) lnClass := tools.IsEmpty(row["attr_ln_class"]) lnInst := tools.IsEmpty(row["attr_ln_inst"]) doName := tools.IsEmpty(row["attr_do_name"]) //daName := tools.IsEmpty(row["attr_da_name"]) inout := tools.IsEmpty(row["inout_type"]) //in:输入当前IED out:输出到其他IED inIed := c.GetIed(scdXmlObj, tools.IsEmpty(scdid), tmpIedName) if inIed.AccessPoint == nil { continue } for _, t1 := range inIed.AccessPoint { if t1.Server == nil { continue } for _, t2 := range t1.Server.LDevice { if t2.Inst == ldInst { for _, dataset := range t2.LN0.DataSet { foundCnt := 0 isfound := false obj := orm.Params{"scd_id": scdid, "master_ied_id": masterIed.NodeId, "master_ied_name": masterIed.Name, "ref_type": "", "inputs_cnt": 0, "out_ld_id": "", "out_ld_inst": "", "out_id_desc": "", "ld_id": "", "ld_inst": "", "id_desc": "", "ctrl_id": "", "ctrl_type": "", "ctrl_name": "", "datset_id": "", "datset_desc": "", "datset_name": ""} for _, fcda := range dataset.FCDA { if prefix == fcda.Prefix && doName == fcda.DoName && fcda.LdInst == ldInst && fcda.LnInst == lnInst && fcda.LnClass == lnClass { if foundCnt == 0 { obj["ld_id"] = t2.NodeId obj["ld_inst"] = t2.Inst obj["ld_desc"] = t2.Desc obj["datset_id"] = dataset.NodeId obj["datset_desc"] = dataset.Desc obj["datset_name"] = dataset.Name obj["fcda_id"] = fcda.NodeId obj["extref_id"] = extrefid } foundCnt = foundCnt + 1 //计算关联的端子数量 isfound = true break } } obj["inputs_cnt"] = foundCnt if isfound { datasetName := tools.IsEmpty(obj["datset_name"]) //获取控制块信息 for _, gse := range t2.LN0.GSEControl { if gse.DatSet == datasetName { obj["ctrl_id"] = gse.NodeId obj["ctrl_type"] = gse.Type obj["ctrl_name"] = gse.Name } } for _, smv := range t2.LN0.SampledValueControl { if smv.DatSet == datasetName { obj["ctrl_id"] = smv.NodeId obj["ctrl_type"] = "smv" obj["ctrl_name"] = smv.Name } } obj["ref_type"] = "1" obj["inout_type"] = inout obj["source_ied_id"] = masterIed.NodeId obj["source_ied_name"] = masterIed.Name obj["target_ied_id"] = inIed.NodeId obj["target_ied_name"] = tmpIedName obj["out_ld_id"] = t2.NodeId obj["out_ld_desc"] = t2.Desc obj["out_ld_inst"] = t2.Inst key := fmt.Sprintf("%d%s%s%d", scdid, masterIed.Name, tmpIedName, obj["ctrl_id"]) if v, h := inputBlock[key]; h { v1, _ := strconv.Atoi(tools.IsEmpty(v["inputs_cnt"])) v["inputs_cnt"] = v1 + 1 inputBlock[key] = v cachebBlockDetail[key] = append(cachebBlockDetail[key], obj) } else { //queryRowset = append(queryRowset, obj) inputBlock[key] = obj cachebBlockDetail[key] = []orm.Params{obj} } } } } } } } for _, r := range inputBlock { queryRowset = append(queryRowset, r) } //获取关联IED的控制块,获取输出的IED及块 inputBlock = map[string]orm.Params{} relIedlist, _ := c.GetIedRelations(map[string]interface{}{"scd_id": scdid, "ied_name": masterIed.Name}) if relIedlist != nil { relIedlist = relIedlist[masterIed.Name].(orm.Params) vList := relIedlist["list"].([]orm.Params) for _, refIed := range vList { if refIed["ref_ied_name"] == nil { continue } if refIed["ref_type"] == "1" { //输入IED continue } tmpIedName := refIed["ref_ied_name"].(string) extreflist, _ := c.GetIedInputsRelations(map[string]interface{}{"ied_name": tmpIedName, "scd_id": scdid}) if extreflist == nil || len(extreflist) == 0 { continue } for _, extref := range extreflist { if tools.IsEmpty(extref["inout_type"]) == "out" { //过滤该ied中的输出ExtRef continue } toIedName := tools.IsEmpty(extref["ied_name"]) if toIedName != masterIed.Name { //过虑输入ied非当前查询ied的extref continue } extrefid := extref["node_id"] ldInst := tools.IsEmpty(extref["attr_ld_inst"]) prefix := tools.IsEmpty(extref["attr_prefix"]) lnClass := tools.IsEmpty(extref["attr_ln_class"]) lnInst := tools.IsEmpty(extref["attr_ln_inst"]) doName := tools.IsEmpty(extref["attr_do_name"]) //daName := tools.IsEmpty(row["attr_da_name"]) inout := tools.IsEmpty(extref["inout_type"]) //in:输入当前IED out:输出到其他IED inIed := masterIed //c.GetIed(scdXmlObj, tools.IsEmpty(scdid), tmpIedName) if inIed.AccessPoint == nil { continue } for _, t1 := range inIed.AccessPoint { if t1.Server == nil { continue } for _, t2 := range t1.Server.LDevice { //logger.Logger.Debug(fmt.Sprintf("%s LDevice%+v:", tmpIedName, t2.Desc)) for _, dataset := range t2.LN0.DataSet { foundCnt := 0 isfound := false obj := orm.Params{"scd_id": scdid, "master_ied_id": masterIed.NodeId, "master_ied_name": masterIed.Name, "ref_type": "", "inputs_cnt": 0, "out_ld_id": "", "out_ld_inst": "", "out_id_desc": "", "ld_id": "", "ld_inst": "", "id_desc": "", "ctrl_id": "", "ctrl_type": "", "ctrl_name": "", "datset_id": "", "datset_desc": "", "datset_name": ""} for _, fcda := range dataset.FCDA { if prefix == fcda.Prefix && doName == fcda.DoName && fcda.LdInst == ldInst && fcda.LnInst == lnInst && fcda.LnClass == lnClass { if foundCnt == 0 { obj["ld_id"] = t2.NodeId obj["ld_inst"] = t2.Inst obj["ld_desc"] = t2.Desc obj["datset_id"] = dataset.NodeId obj["datset_desc"] = dataset.Desc obj["datset_name"] = dataset.Name obj["fcda_id"] = fcda.NodeId obj["extref_id"] = extrefid } foundCnt = foundCnt + 1 //计算关联的端子数量 isfound = true break } } obj["inputs_cnt"] = foundCnt if isfound { datasetName := tools.IsEmpty(obj["datset_name"]) //获取控制块信息 for _, gse := range t2.LN0.GSEControl { if gse.DatSet == datasetName { obj["ctrl_id"] = gse.NodeId obj["ctrl_type"] = gse.Type obj["ctrl_name"] = gse.Name } } for _, smv := range t2.LN0.SampledValueControl { if smv.DatSet == datasetName { obj["ctrl_id"] = smv.NodeId obj["ctrl_type"] = "smv" obj["ctrl_name"] = smv.Name } } obj["ref_type"] = "0" obj["source_ied_id"] = inIed.NodeId obj["source_ied_name"] = tmpIedName obj["target_ied_id"] = masterIed.NodeId obj["target_ied_name"] = masterIed.Name obj["out_ld_id"] = t2.NodeId obj["out_ld_desc"] = t2.Desc obj["out_ld_inst"] = t2.Inst obj["inout_type"] = inout key := fmt.Sprintf("%d%s%s%d", scdid, masterIed.Name, tmpIedName, obj["ctrl_id"]) if v, h := inputBlock[key]; h { v1, _ := strconv.Atoi(tools.IsEmpty(v["inputs_cnt"])) v["inputs_cnt"] = v1 + 1 inputBlock[key] = v cachebBlockDetail[key] = append(cachebBlockDetail[key], obj) } else { //queryRowset = append(queryRowset, obj) inputBlock[key] = obj cachebBlockDetail[key] = []orm.Params{obj} } } } } } } } } for _, r := range inputBlock { queryRowset = append(queryRowset, r) } mqtt.PublishMessage("/jujutong/scd_check_tools/iedblockrelations/"+tools.IsEmpty(scdid)+"/"+ied_name, `{"ied_name":"`+ied_name+`","code":1}`) //缓存块关联详情 global.GoCahce.Set(fmt.Sprintf("cachebBlockDetail_%d", scdid), cachebBlockDetail, -1) return queryRowset, nil } //获取指定IED节点的虚端子关系 func (c *ScdNode) GetIedInputsRelations(param map[string]interface{}) ([]orm.Params, error) { iedid := tools.IsEmpty(param["ied_id"]) ied_name := tools.IsEmpty(param["ied_name"]) if iedid == "" && ied_name == "" { return nil, errors.New("IED编号和name不能同时为空") } scdid := tools.IsEmpty(param["scd_id"]) if scdid == "" { return nil, errors.New("scd编号不能为空") } cacheKey1 := "GetIedInputsRelations_" + scdid + ied_name if v, h := global.GoCahce.Get(cacheKey1); h { return v.([]orm.Params), nil } scdobj, serr := new(ScdParse).GetScdXmlObjectBySCDID(scdid) if serr != nil { return nil, serr } if scdobj == nil { return nil, errors.New("该scd还未解析或解析未完成!") } if iedid != "" { has := false for _, item := range scdobj.IED { if tools.IsEmpty(item.NodeId) == iedid { has = true ied_name = item.Name break } } if !has { return nil, errors.New("无效的IED编号") } } attrsrows := []orm.Params{} //input输入输出虚端子关系 for _, item := range scdobj.IED { for _, accpointitem := range item.AccessPoint { if accpointitem.Server == nil { continue } for _, lditem := range accpointitem.Server.LDevice { if lditem.LN0.Inputs == nil { continue } no := 0 for _, extrefitem := range lditem.LN0.Inputs.ExtRef { no = no + 1 inout := "" tmpIedName := "" doinDesc := "" dooutDesc := "" if item.Name == ied_name { inout = "in" tmpIedName = extrefitem.IedName //获取内部地址的描述 _, _, doinDesc = c.GetIntAddrDesc(item, extrefitem.IntAddr) fcda_addr := fmt.Sprintf("%s/%s%s%s.%s", extrefitem.LdInst, extrefitem.Prefix, extrefitem.LnClass, extrefitem.LnInst, extrefitem.DoName) if extrefitem.DaName != "" { fcda_addr = fcda_addr + "." + extrefitem.DaName } extrefIed := c.GetIed(scdobj, scdid, tmpIedName) _, _, dooutDesc = c.GetIntAddrDesc(extrefIed, fcda_addr) } else if extrefitem.IedName == ied_name { inout = "out" tmpIedName = item.Name _, _, doinDesc = c.GetIntAddrDesc(item, extrefitem.IntAddr) //获取fcda的描述 fcda_addr := fmt.Sprintf("%s/%s%s%s.%s", extrefitem.LdInst, extrefitem.Prefix, extrefitem.LnClass, extrefitem.LnInst, extrefitem.DoName) if extrefitem.DaName != "" { fcda_addr = fcda_addr + "." + extrefitem.DaName } mIed := c.GetIed(scdobj, scdid, ied_name) _, _, dooutDesc = c.GetIntAddrDesc(mIed, fcda_addr) } else { continue } v_o := orm.Params{ "no": no, "inout_type": inout, "ied_name": tmpIedName, "node_id": extrefitem.NodeId, "attr_ld_inst": extrefitem.LdInst, "attr_prefix": extrefitem.Prefix, "attr_ln_class": extrefitem.LnClass, "attr_ln_inst": extrefitem.LnInst, "attr_do_name": extrefitem.DoName, "attr_da_name": extrefitem.DaName, "attr_int_addr": extrefitem.IntAddr, "line_no": extrefitem.Lineno, "do_target_desc": doinDesc, "do_source_desc": dooutDesc, } attrsrows = append(attrsrows, v_o) } } } } //logger.Logger.Debug(fmt.Sprintf("%+v", attrsrows)) global.GoCahce.Set(cacheKey1, attrsrows, -1) return attrsrows, nil } //获取指定IED节点及控制块ID的虚端子关系 func (c *ScdNode) GetIedCtrlInputsRelations(param map[string]interface{}) ([]orm.Params, error) { m_ied_name := tools.IsEmpty(param["m_ied_name"]) if m_ied_name == "" { return nil, errors.New("源IED name不能为空") } s_ied_name := tools.IsEmpty(param["s_ied_name"]) if s_ied_name == "" { return nil, errors.New("目标IED name不能为空") } scdid := tools.IsEmpty(param["scd_id"]) if scdid == "" { return nil, errors.New("scd编号不能为空") } scdidint64, _ := strconv.ParseInt(scdid, 10, 64) //缓存块关联详情 cachebBlockDetail, _ := global.GoCahce.Get(fmt.Sprintf("cachebBlockDetail_%s", scdid)) if cachebBlockDetail == nil { return nil, errors.New("未查询到数据") } scdXmlObj, serr := new(ScdParse).GetScdXmlObjectBySCDID(scdid) if serr != nil { return nil, serr } if scdXmlObj == nil { return nil, errors.New("无效的SCD") } m_ctrlid := tools.IsEmpty(param["m_ctrlid"]) s_ctrlid := tools.IsEmpty(param["s_ctrlid"]) key := fmt.Sprintf("%s%s%s%s%s", scdid, m_ied_name, s_ied_name, m_ctrlid, s_ctrlid) cachebBlockDetailMap := cachebBlockDetail.(map[string][]orm.Params) //logger.Logger.Debug(fmt.Sprintf("获取指定IED节点及控制块ID的虚端子关系:%s\n%+v", key, cachebBlockDetailMap)) attrsrows := cachebBlockDetailMap[key] //返回数据:id,fcda_id as node_id,from_doi_desc,from_ied,from_ln_desc,to_doi_desc,to_ied,to_ln_desc,attr_ld_inst,attr_ln_class,attr_ln_inst,attr_prefix,attr_ix,attr_int_addr,attr_fc,attr_do_name,attr_da_name rowset := []orm.Params{} v_scdcache, _ := GlobalNodeMap.Load(scdidint64) if v_scdcache == nil { return nil, errors.New("无效的SCD") } cacheNodeList := v_scdcache.(map[int64]NodeCacheMap) mIed := new(ScdNode).GetIed(scdXmlObj, scdid, m_ied_name) sIed := new(ScdNode).GetIed(scdXmlObj, scdid, s_ied_name) for _, row := range attrsrows { obj := orm.Params{} ln_desc := "" doi_desc := "" extrefid := tools.IsEmpty(row["extref_id"]) fcdaid := tools.IsEmpty(row["fcda_id"]) target_ied_name := tools.IsEmpty(row["target_ied_name"]) master_ied_name := tools.IsEmpty(row["master_ied_name"]) if m_ctrlid != "" && master_ied_name == m_ied_name { fcdaidint64, _ := strconv.ParseInt(fcdaid, 10, 64) //主IED向外输出,根据主IED的fcda查找from_doi等信息 nodeInfo := cacheNodeList[fcdaidint64] if nodeInfo.ObjAddr != nil { fcda := nodeInfo.ObjAddr.(*node_attr.NFCDA) //logger.Logger.Debug(fmt.Sprintf("fcda %s info:%+v", fcdaid, fcda)) obj["node_id"] = fcda.NodeId obj["attr_ld_inst"] = fcda.LdInst obj["attr_ln_class"] = fcda.LnClass obj["attr_ln_inst"] = fcda.LnInst obj["attr_prefix"] = fcda.Prefix obj["attr_ix"] = fcda.Ix obj["attr_fc"] = fcda.Fc obj["attr_do_name"] = fcda.DoName obj["attr_da_name"] = fcda.DaName var ld *node_attr.NLDevice ld, ln_desc, doi_desc = c.GetFcdaDesc(mIed, fcda) if ld != nil { obj["attr_ld_desc"] = ld.Desc } /* for _, ied := range mIed.AccessPoint { if ied.Server != nil { for _, ld := range ied.Server.LDevice { //logger.Logger.Debug(fmt.Sprintf(" ld========%s=============%s", ld.Inst, fcda.LdInst)) if ld.Inst == fcda.LdInst { obj["attr_ld_desc"] = ld.Desc if fcda.LnClass == "LLN0" { ln_desc = ld.LN0.Desc for _, doi := range ld.LN0.DOI { if doi.Name == fcda.DoName { doi_desc = doi.Desc break } } break } for _, ln := range ld.LN { if ln.Inst == fcda.LnInst && ln.LnClass == fcda.LnClass && ln.Prefix == fcda.Prefix { ln_desc = ln.Desc //logger.Logger.Debug(fmt.Sprintf(" LN=====================%+v", ln)) for _, doi := range ln.DOI { if doi.Name == fcda.DoName { doi_desc = doi.Desc break } } } if doi_desc != "" { break } } } if doi_desc != "" { break } } } if doi_desc != "" { break } } */ } obj["from_doi_desc"] = doi_desc obj["from_ln_desc"] = ln_desc //主IED向外输出,根据接收IED的extref的内部地址查找to_doi等信息 extrefidint64, _ := strconv.ParseInt(extrefid, 10, 64) nodeInfo = cacheNodeList[extrefidint64] ln_desc = "" doi_desc = "" var ld *node_attr.NLDevice if nodeInfo.ObjAddr != nil { extref := nodeInfo.ObjAddr.(*node_attr.NExtRef) //logger.Logger.Debug(fmt.Sprintf("extref %s info:%+v", extrefid, extref)) obj["attr_int_addr"] = extref.IntAddr ld, ln_desc, doi_desc = c.GetIntAddrDesc(sIed, extref.IntAddr) if ld != nil { obj["to_ld_inst"] = ld.Inst obj["to_ld_desc"] = ld.Desc } /* addrparts := strings.Split(extref.IntAddr, "/") to_ldinst := addrparts[0] //to_lnPri := addrparts[1] //ln标识符,由prefix+lnClass+inst.doname.daname组成 to_lnPriParts := strings.Split(addrparts[1], ".") to_doname := to_lnPriParts[1] for _, ied := range sIed.AccessPoint { if ied.Server != nil { for _, ld := range ied.Server.LDevice { if ld.Inst == to_ldinst { obj["to_ld_inst"] = ld.Inst obj["to_ld_desc"] = ld.Desc for _, ln := range ld.LN { //logger.Logger.Debug(fmt.Sprintf("to: %s==%s", ln.Prefix+ln.LnClass+ln.Inst, to_lnPriParts[0])) if (ln.Prefix + ln.LnClass + ln.Inst) == to_lnPriParts[0] { ln_desc = ln.Desc for _, doi := range ln.DOI { if doi.Name == to_doname { doi_desc = doi.Desc break } } } if doi_desc != "" { break } } } if doi_desc != "" { break } } } if doi_desc != "" { break } } */ } obj["to_doi_desc"] = doi_desc obj["to_ln_desc"] = ln_desc rowset = append(rowset, obj) } if s_ctrlid != "" && target_ied_name == s_ied_name { //向主IED输入 fcdaidint64, _ := strconv.ParseInt(fcdaid, 10, 64) //主IED向外输出,根据主IED的fcda查找from_doi等信息 nodeInfo := cacheNodeList[fcdaidint64] if nodeInfo.ObjAddr != nil { fcda := nodeInfo.ObjAddr.(*node_attr.NFCDA) //logger.Logger.Debug(fmt.Sprintf("fcda %s info:%+v", fcdaid, fcda)) obj["node_id"] = fcda.NodeId obj["attr_ld_inst"] = fcda.LdInst obj["attr_ln_class"] = fcda.LnClass obj["attr_ln_inst"] = fcda.LnInst obj["attr_prefix"] = fcda.Prefix obj["attr_ix"] = fcda.Ix obj["attr_fc"] = fcda.Fc obj["attr_do_name"] = fcda.DoName obj["attr_da_name"] = fcda.DaName var ld *node_attr.NLDevice ld, ln_desc, doi_desc = c.GetFcdaDesc(sIed, fcda) if ld != nil { obj["attr_ld_desc"] = ld.Desc } /* for _, ied := range sIed.AccessPoint { if ied.Server != nil { for _, ld := range ied.Server.LDevice { //logger.Logger.Debug(fmt.Sprintf(" ld========%s=============%s", ld.Inst, fcda.LdInst)) if ld.Inst == fcda.LdInst { obj["attr_ld_desc"] = ld.Desc if fcda.LnClass == "LLN0" { ln_desc = ld.LN0.Desc for _, doi := range ld.LN0.DOI { if doi.Name == fcda.DoName { doi_desc = doi.Desc break } } break } for _, ln := range ld.LN { if ln.Inst == fcda.LnInst && ln.LnClass == fcda.LnClass && ln.Prefix == fcda.Prefix { ln_desc = ln.Desc //logger.Logger.Debug(fmt.Sprintf(" LN=====================%+v", ln)) for _, doi := range ln.DOI { if doi.Name == fcda.DoName { doi_desc = doi.Desc break } } } if doi_desc != "" { break } } } if doi_desc != "" { break } } } if doi_desc != "" { break } } */ } obj["from_doi_desc"] = doi_desc obj["from_ln_desc"] = ln_desc //主IED向外输出,根据接收IED的extref的内部地址查找to_doi等信息 extrefidint64, _ := strconv.ParseInt(extrefid, 10, 64) nodeInfo = cacheNodeList[extrefidint64] ln_desc = "" doi_desc = "" var ld *node_attr.NLDevice if nodeInfo.ObjAddr != nil { extref := nodeInfo.ObjAddr.(*node_attr.NExtRef) //logger.Logger.Debug(fmt.Sprintf("extref %s info:%+v", extrefid, extref)) obj["attr_int_addr"] = extref.IntAddr ld, ln_desc, doi_desc = c.GetIntAddrDesc(mIed, extref.IntAddr) if ld != nil { obj["to_ld_inst"] = ld.Inst obj["to_ld_desc"] = ld.Desc } /* addrparts := strings.Split(extref.IntAddr, "/") to_ldinst := addrparts[0] //to_lnPri := addrparts[1] //ln标识符,由prefix+lnClass+inst.doname.daname组成 to_lnPriParts := strings.Split(addrparts[1], ".") to_doname := to_lnPriParts[1] for _, ied := range mIed.AccessPoint { if ied.Server != nil { for _, ld := range ied.Server.LDevice { if ld.Inst == to_ldinst { obj["to_ld_inst"] = ld.Inst obj["to_ld_desc"] = ld.Desc for _, ln := range ld.LN { //logger.Logger.Debug(fmt.Sprintf("to: %s==%s", ln.Prefix+ln.LnClass+ln.Inst, to_lnPriParts[0])) if (ln.Prefix + ln.LnClass + ln.Inst) == to_lnPriParts[0] { ln_desc = ln.Desc for _, doi := range ln.DOI { if doi.Name == to_doname { doi_desc = doi.Desc break } } } if doi_desc != "" { break } } } if doi_desc != "" { break } } } if doi_desc != "" { break } }*/ } obj["to_doi_desc"] = doi_desc obj["to_ln_desc"] = ln_desc rowset = append(rowset, obj) } } return rowset, nil } //获取指定FCDA的do或者Da描述 func (c *ScdNode) GetFcdaDesc(mIed *node_attr.NIED, fcda *node_attr.NFCDA) (rld *node_attr.NLDevice, lndesc string, dodesc string) { doi_desc := "" ln_desc := "" if mIed == nil || fcda == nil { return nil, ln_desc, doi_desc } doParts := strings.Split(fcda.DoName, ".") //拆分do中的有效name部分 to_doname := doParts[0] for _, ied := range mIed.AccessPoint { if ied.Server != nil { for _, ld := range ied.Server.LDevice { //logger.Logger.Debug(fmt.Sprintf(" ld========%s=============%s", ld.Inst, fcda.LdInst)) if ld.Inst == fcda.LdInst { rld = ld if fcda.LnClass == "LLN0" { ln_desc = ld.LN0.Desc for _, doi := range ld.LN0.DOI { if doi.Name == to_doname { doi_desc = doi.Desc break } } break } for _, ln := range ld.LN { if ln.Inst == fcda.LnInst && ln.LnClass == fcda.LnClass && ln.Prefix == fcda.Prefix { ln_desc = ln.Desc //logger.Logger.Debug(fmt.Sprintf(" LN=====================%+v", ln)) for _, doi := range ln.DOI { if doi.Name == to_doname { doi_desc = doi.Desc break } } } if doi_desc != "" { break } } } if doi_desc != "" { break } } } if doi_desc != "" { break } } return rld, ln_desc, doi_desc } //获取指定Extref的本地描述 func (c *ScdNode) GetIntAddrDesc(mIed *node_attr.NIED, intAddr string) (rld *node_attr.NLDevice, lndesc string, dodesc string) { doi_desc := "" ln_desc := "" if mIed == nil || intAddr == "" { return nil, ln_desc, doi_desc } addrs := strings.Split(intAddr, ":") if len(addrs) == 2 { intAddr = addrs[1] } addrparts := strings.Split(intAddr, "/") to_ldinst := addrparts[0] //addrparts[1] //ln标识符,由prefix+lnClass+inst.doname.daname组成 to_lnPriParts := strings.Split(addrparts[1], ".") to_doname := to_lnPriParts[1] for _, ied := range mIed.AccessPoint { if ied.Server != nil { for _, ld := range ied.Server.LDevice { if ld.Inst == to_ldinst { rld = ld for _, ln := range ld.LN { //logger.Logger.Debug(fmt.Sprintf("to: %s==%s", ln.Prefix+ln.LnClass+ln.Inst, to_lnPriParts[0])) if (ln.Prefix + ln.LnClass + ln.Inst) == to_lnPriParts[0] { ln_desc = ln.Desc for _, doi := range ln.DOI { if doi.Name == to_doname { doi_desc = doi.Desc break } } } if doi_desc != "" { break } } } if doi_desc != "" { break } } } if doi_desc != "" { break } } return rld, ln_desc, doi_desc } //获取指定IED的网络配置信息 func (c *ScdNode) GetIedNetworkInfo(scdid int64, ied_name string) ([]orm.Params, error) { cacheKey := fmt.Sprintf("networkinfo_%d", scdid) if scdid == 0 { return nil, errors.New("SCD编号不能为空") } if ied_name == "" { return nil, errors.New("IED名称不能为空") } networkInfo := []orm.Params{} cachedata, h := global.GoCahce.Get(cacheKey) if h { t1 := cachedata.([]orm.Params) if ied_name != "" { for _, row := range t1 { if row["ied_name"] == ied_name { networkInfo = append(networkInfo, row) } } } else { networkInfo = t1 } return networkInfo, nil } scdXmlObj, serr := new(ScdParse).GetScdXmlObjectBySCDID(tools.IsEmpty(scdid)) if serr != nil { return nil, serr } if scdXmlObj == nil { return nil, errors.New("无效的SCD") } iedList := []orm.Params{} for _, item1 := range scdXmlObj.Communication.SubNetwork { net_type := "GSE" if len(item1.Name) >= 3 && item1.Name[0:3] == "MMS" { net_type = "MMS" } for _, item2 := range item1.ConnectedAP { if len(item2.SMV) > 0 { net_type = "SV" for _, svitem := range item2.SMV { obj := orm.Params{ "ap_node_id": item2.NodeId, "ied_name": item2.IedName, "ap_name": item2.ApName, "subnetwork_name": item1.Name, "subnetwork_desc": item1.Desc, "subnetwork_type": item1.Type, "net_type": net_type, "net_node_id": svitem.NodeId, "cb_name": svitem.CbName, "ld_inst": svitem.LdInst, "address_json": "", } if svitem.Address != nil { jsonmap := map[string]string{} for _, r1 := range svitem.Address.P { jsonmap[r1.Type] = r1.InnerText } jsnstr, _ := json.Marshal(jsonmap) obj["address_json"] = string(jsnstr) } networkInfo = append(networkInfo, obj) if ied_name != "" && ied_name == item2.IedName { iedList = append(iedList, obj) } } } else if len(item2.GSE) > 0 { net_type = "GSE" for _, gseitem := range item2.GSE { obj := orm.Params{ "ap_node_id": item2.NodeId, "ied_name": item2.IedName, "ap_name": item2.ApName, "subnetwork_name": item1.Name, "subnetwork_desc": item1.Desc, "subnetwork_type": item1.Type, "net_type": net_type, "net_node_id": gseitem.NodeId, "cb_name": gseitem.CbName, "ld_inst": gseitem.LdInst, "address_json": "", } if gseitem.Address != nil { jsonmap := map[string]string{} for _, r1 := range gseitem.Address.P { jsonmap[r1.Type] = r1.InnerText } jsnstr, _ := json.Marshal(jsonmap) obj["address_json"] = string(jsnstr) } networkInfo = append(networkInfo, obj) if ied_name != "" && ied_name == item2.IedName { iedList = append(iedList, obj) } } } else { obj := orm.Params{ "ap_node_id": item2.NodeId, "ied_name": item2.IedName, "ap_name": item2.ApName, "subnetwork_name": item1.Name, "subnetwork_desc": item1.Desc, "subnetwork_type": item1.Type, "net_type": net_type, "net_node_id": item2.NodeId, "cb_name": "", "ld_inst": "", "address_json": "", } if item2.Address != nil { jsonmap := map[string]string{} for _, r1 := range item2.Address.P { jsonmap[r1.Type] = r1.InnerText } jsnstr, _ := json.Marshal(jsonmap) obj["address_json"] = string(jsnstr) } networkInfo = append(networkInfo, obj) if ied_name != "" && ied_name == item2.IedName { iedList = append(iedList, obj) } } } } global.GoCahce.Set(cacheKey, networkInfo, -1) if ied_name != "" { return iedList, nil } return networkInfo, nil } //获取指定IEd的指定GSEControl的网络配置信息 func (c *ScdNode) GetIedGseNetWorkInfo(scdid int64, ied_name, gocb_name string) (orm.Params, error) { if scdid == 0 { return nil, errors.New("SCD编号不能为空") } if ied_name == "" { return nil, errors.New("IED名称不能为空") } if gocb_name == "" { return nil, errors.New("gocb_name不能为空") } iedNetinfo, er := c.GetIedNetworkInfo(scdid, ied_name) if er != nil { return nil, er } for _, row := range iedNetinfo { cb_name := tools.IsEmpty(row["cb_name"]) if cb_name == gocb_name { return row, nil } } return nil, nil } func (c *ScdNode) Init(stationidint int, name, path string, isenable int, ischeckinscd int) (int64, error) { c.ScdName = name c.ScdPath = path c.StationID = stationidint c.NodeRuleList = map[string][]orm.Params{} c.NodeAttrRuleList = map[string][]orm.Params{} c.NodeAttrUniqueRuleList = []orm.Params{} c.NodeRuleFunctionList = []orm.Params{} c.NotEndNodeIdList = []int64{} c.NodeQue = map[int64]*t_scd_node_scl{} c.NodeAttrQue = []interface{}{} c.AreaMgr = new(ScdAreaMgr) m := t_scd_scl{ScdName: name, Path: path} m.IsCheckinScd = ischeckinscd m.Enable = isenable m.StationId = stationidint if c.RootID > 0 { m.Id = c.RootID } c.AreaMgr.ScdId = m.Id m.CreatedBy, _ = strconv.Atoi(c.GetUserId()) m.CreatedTime = tools.NowTime() db := orm.NewOrm() _, err := db.Insert(&m) if err != nil { //判断SCD是否已经存在 if !strings.Contains(err.Error(), "PRIMARY") { logger.Logger.Error(err, fmt.Sprintf("操作数据:%+v", m)) return 0, err } } c.Name = name //初始化间隔管理 c.AreaMgr.ScdId = m.Id //再次赋值,保证当scd不存在时,获取到新添加的SCD ID c.AreaMgr.Init(m.Id) //加载规则列表 //获取节点验证规则定义 lst := []orm.Params{} /* db.Raw("select * from t_scd_node_check").Values(&lst) for _, r := range lst { check_object := r["check_object"].(string) keys := strings.Split(check_object, ":") if ss, ok := c.NodeRuleList[keys[0]]; ok { c.NodeRuleList[keys[0]] = append(ss, r) } else { c.NodeRuleList[keys[0]] = []orm.Params{r} } } */ //获取节点属性验证规则 db.Raw("select * from t_scd_scl_check").Values(&lst) for _, r := range lst { object_name := r["object_name"].(string) object_type := r["object_type"].(string) if tools.IsEmpty(r["func_name"]) != "" { c.NodeRuleFunctionList = append(c.NodeRuleFunctionList, r) continue } //过滤出全局唯一或父节点下唯一的规则单独保存 if tools.IsEmpty(r["isunique_by_parent"]) == "1" || tools.IsEmpty(r["isunique_by_global"]) == "1" { c.NodeAttrUniqueRuleList = append(c.NodeAttrUniqueRuleList, r) continue } if object_type == "node" { if ss, ok := c.NodeRuleList[object_name]; ok { c.NodeRuleList[object_name] = append(ss, r) } else { c.NodeRuleList[object_name] = []orm.Params{r} } } else { //node_path := tools.IsEmpty(r["node_path"]) keys := strings.Split(object_name, "||") for _, k := range keys { if ss, ok := c.NodeAttrRuleList[k]; ok { c.NodeAttrRuleList[k] = append(ss, r) } else { c.NodeAttrRuleList[k] = []orm.Params{r} } } } } return m.Id, nil } func (c *ScdNode) AddNode(name string, attrs map[string]interface{}, lineno int64) error { m := new(t_scd_node_scl) m.CreatedBy = 0 m.CreatedTime = tools.NowTime() m.NodeName = name m.NodeValue = "" m.LineNo = lineno m.ScdId = c.RootID m.Id = c.GetID() c.NodeQue[m.Id] = m if attrs != nil && len(attrs) > 0 { if name == "Bay" { //如果存在bay元素,则间隔方式为Bay解析 c.IsBay = true } parentNodeNodeName := "" parentNode, ok := c.NodeQue[m.ParentNodeId] if ok { parentNodeNodeName = parentNode.NodeName } c.NodeAttrQue = append(c.NodeAttrQue, map[string]interface{}{"scdid": c.RootID, "parentNodeName": parentNodeNodeName, "nodeid": m.Id, "nodename": name, "lineno": m.LineNo, "attrs": attrs}) if !c.IsBay && m.NodeName == "IED" { c.AreaMgr.AppendIedNode(c.RootID, m.Id, tools.IsEmpty(attrs["name"]), tools.IsEmpty(attrs["desc"])) } } return nil } func (c *ScdNode) EndNode(name, txt string) error { return nil } func (c *ScdNode) Flush() { //更新关联附件项的scd id new(AttachmentMgr).UpdateScdID(c.StationID, c.ScdName, c.ScdPath, c.RootID) //c.writeNodeDB() //c.writeNodeAttrDB() //通知SCD管理对象,解析完成,更新状态 new(ScdMgr).ParseFinish(c.RootID, c.IsDefaultRunVersion) //test //c.GetIedInputsRelations(map[string]interface{}{"scd_id": c.RootID, "ied_name": "PB7520A"}) /* if c.AutoCompScdID > 0 { comp := new(ScdCompare) comp.CompareType = "SCD" comp.Sourceid = c.RootID comp.Targetid = c.AutoCompScdID comp.StationId = c.StationID comp.Compare(0) } */ } //获取指定SCD的校验码 func (c *ScdNode) GetScdCRC(scdid string) (string, error) { scdXmlObj, serr := new(ScdParse).GetScdXmlObjectBySCDID(scdid) if serr != nil { return "", serr } if scdXmlObj == nil { return "", errors.New("无效的SCD") } for _, pri := range scdXmlObj.Private { if pri.Type == "Substation virtual terminal conection CRC" { return pri.InnerText, nil } } return "", nil } //获取指定SCD的校验码 func (c *ScdNode) GetIedCRC(scdid, iedname string) (string, error) { scdXmlObj, serr := new(ScdParse).GetScdXmlObjectBySCDID(scdid) if serr != nil { return "", serr } if scdXmlObj == nil { return "", errors.New("无效的SCD") } iedObj := c.GetIed(scdXmlObj, scdid, iedname) if iedObj == nil { return "", errors.New("无效的IED装置名称") } for _, pri := range iedObj.Priavate { if pri.Type == "IED virtual terminal conection CRC" { return pri.InnerText, nil } } return "", nil } func (c *ScdNode) writeNodeDB() { stationIdStr := fmt.Sprintf("%d", c.StationID) scdIdStr := fmt.Sprintf("%d", c.RootID) db := orm.NewOrm() s1 := time.Now().Unix() nodeCols := "(id,scd_id,parent_node_id,node_name,node_value,line_no)" totalRec := tools.IsEmpty(len(c.NodeQue)) loadedRec := 0 nodeSqlValuesAry := []string{} data := map[string]string{"name": c.Name, "stationid": stationIdStr, "rootid": scdIdStr, "state": "0", "node": "write-db", "total": totalRec, "load": fmt.Sprintf("%d", loadedRec), "msg": ""} dataMsg, _ := json.Marshal(data) go mqtt.PublishMessage("/jujutong/scd_check_tools/parse/"+scdIdStr, string(dataMsg)) for _, m := range c.NodeQue { nodeSqlValuesAry = append(nodeSqlValuesAry, fmt.Sprintf("(%d,%d,%d,'%s','%s',%d)", m.Id, m.ScdId, m.ParentNodeId, m.NodeName, m.NodeValue, m.LineNo)) if len(nodeSqlValuesAry) == 5000 { sql := "insert into t_scd_node_scl" + nodeCols + "values" + strings.Join(nodeSqlValuesAry, ",") _, err := db.Raw(sql).Exec() if err != nil { logger.Logger.Error(err) } loadedRec = loadedRec + 5000 nodeSqlValuesAry = []string{} data = map[string]string{"name": c.Name, "stationid": stationIdStr, "rootid": scdIdStr, "state": "2", "node": "write-db", "total": totalRec, "load": fmt.Sprintf("%d", loadedRec), "msg": ""} dataMsg, _ = json.Marshal(data) go mqtt.PublishMessage("/jujutong/scd_check_tools/parse/"+scdIdStr, string(dataMsg)) } m = nil } if len(nodeSqlValuesAry) > 0 { sql := "insert into t_scd_node_scl" + nodeCols + "values" + strings.Join(nodeSqlValuesAry, ",") _, err := db.Raw(sql).Exec() if err != nil { log.Println(err) } nodeSqlValuesAry = nil } c.NodeQue = nil runtime.GC() data = map[string]string{"name": c.Name, "stationid": stationIdStr, "rootid": fmt.Sprintf("%d", c.RootID), "state": "1", "node": "write-db", "total": totalRec, "load": totalRec, "msg": ""} dataMsg, _ = json.Marshal(data) go mqtt.PublishMessage("/jujutong/scd_check_tools/parse/"+fmt.Sprintf("%d", c.RootID), string(dataMsg)) s2 := time.Now().Unix() logger.Logger.Println(fmt.Sprintf("===================Flush NodeQue 完成!。耗时:%d秒", s2-s1)) logger.Logger.Println("===========节点入库完成") } //查询定值 func (t *ScdNode) GetScdIedDingzhiList(scdid int64, ied_name string) ([]orm.Params, error) { scdXmlObj, serr := new(ScdParse).GetScdXmlObjectBySCDID(tools.IsEmpty(scdid)) if serr != nil { return nil, serr } if scdXmlObj == nil { return nil, errors.New("无效的SCD") } iedObj := t.GetIed(scdXmlObj, tools.IsEmpty(scdid), ied_name) if iedObj == nil { return nil, errors.New("无效的IED装置名称") } scdMgr := new(ScdMgr) mapTargetLNodeType := scdMgr.GetLNodeType(scdXmlObj) mapTargetLDoType := scdMgr.GetDOType(scdXmlObj) rowset := []orm.Params{} for _, acc := range iedObj.AccessPoint { if acc.Server != nil { for _, ld := range acc.Server.LDevice { if ld.LN0 != nil { for _, ds := range ld.LN0.DataSet { if ds.Name == "dsParameter" || ds.Name == "dsSetting" { obj := orm.Params{ "accesspoint_name": acc.Name, "ld_desc": ld.Desc, "ld_name": ld.Inst, "dataset_desc": ds.Desc, "dataset_name": ds.Name, "list": []orm.Params{}, } for _, fcda := range ds.FCDA { fcdaobj := orm.Params{} fcdaobj["short_addr"] = fmt.Sprintf("%s/%s%s%s.%s", fcda.LdInst, fcda.Prefix, fcda.LnClass, fcda.LnInst, fcda.DoName) fcdaobj["doi_name"] = fcda.DoName fcdaobj["doi_desc"] = "" fcdaobj["da_maxval"] = "" fcdaobj["da_minval"] = "" fcdaobj["da_stepsize"] = "" fcdaobj["da_units"] = "" found := false if fcda.LnClass == "LLN0" { if lnnodetpye, h := mapTargetLNodeType[ld.LN0.LnType]; h { for _, doitem := range lnnodetpye.DO { if doitem.Name == fcda.DoName { dotype := doitem.Type if dotypeobj, h := mapTargetLDoType[dotype]; h { fcdaobj["da_datatype"] = scdMgr.GetCdcDataTypeName(dotypeobj.Cdc) } break } } } for _, doi := range ld.LN0.DOI { if doi.Name == fcda.DoName { fcdaobj["doi_desc"] = doi.Desc for _, da := range doi.DAI { if da.Name == "maxVal" && da.Val != nil { fcdaobj["da_maxval"] = da.Val.InnerText } if da.Name == "minVal" && da.Val != nil { fcdaobj["da_minval"] = da.Val.InnerText } if da.Name == "stepSize" && da.Val != nil { fcdaobj["da_stepsize"] = da.Val.InnerText } if da.Name == "units" && da.Val != nil { fcdaobj["da_units"] = da.Val.InnerText } } found = true break } } } else { for _, ln := range ld.LN { if ln.LnClass == fcda.LnClass && ln.Inst == fcda.LnInst { if lnnodetpye, h := mapTargetLNodeType[ln.LnType]; h { for _, doitem := range lnnodetpye.DO { if doitem.Name == fcda.DoName { dotype := doitem.Type if dotypeobj, h := mapTargetLDoType[dotype]; h { fcdaobj["da_datatype"] = scdMgr.GetCdcDataTypeName(dotypeobj.Cdc) } break } } } for _, doi := range ln.DOI { if doi.Name == fcda.DoName { fcdaobj["doi_desc"] = doi.Desc for _, da := range doi.DAI { if da.Name == "maxVal" && da.Val != nil { fcdaobj["da_maxval"] = da.Val.InnerText } if da.Name == "minVal" && da.Val != nil { fcdaobj["da_minval"] = da.Val.InnerText } if da.Name == "stepSize" && da.Val != nil { fcdaobj["da_stepsize"] = da.Val.InnerText } if da.Name == "units" && da.Val != nil { fcdaobj["da_units"] = da.Val.InnerText } } if fcdaobj["da_maxval"] == "" { for _, sdi := range doi.SDI { if sdi.Name == "maxVal" { for _, dai2 := range sdi.DAI { if dai2.Name == "f" && dai2.Val != nil { fcdaobj["da_maxval"] = dai2.Val.InnerText } } } } } if fcdaobj["da_minval"] == "" { for _, sdi := range doi.SDI { if sdi.Name == "minVal" { for _, dai2 := range sdi.DAI { if dai2.Name == "f" && dai2.Val != nil { fcdaobj["da_minval"] = dai2.Val.InnerText } } } } } if fcdaobj["da_stepsize"] == "" { for _, sdi := range doi.SDI { if sdi.Name == "stepSize" { for _, dai2 := range sdi.DAI { if dai2.Name == "f" && dai2.Val != nil { fcdaobj["da_stepsize"] = dai2.Val.InnerText } } } } } unintsFound := false if fcdaobj["da_units"] == "" { for _, sdi := range doi.SDI { if sdi.Name == "units" { for _, dai2 := range sdi.DAI { if dai2.Name == "SIUnit" { for _, enumtype := range scdXmlObj.DataTypeTemplates.EnumType { if enumtype.Id == dai2.Name { for _, t123 := range enumtype.EnumVal { if dai2.Val == nil { fcdaobj["da_units"] = "" } else if t123.Ord == dai2.Val.InnerText { fcdaobj["da_units"] = t123.InnerText unintsFound = true break } } } if unintsFound { break } } } if unintsFound { break } } } if unintsFound { break } } } found = true break } } } if found { break } } } obj["list"] = append(obj["list"].([]orm.Params), fcdaobj) } rowset = append(rowset, obj) } } } } } } return rowset, nil } //查询信息点表 func (t *ScdNode) GetScdIedPointTableList(scdid int64, ied_name string) ([]orm.Params, error) { scdXmlObj, serr := new(ScdParse).GetScdXmlObjectBySCDID(tools.IsEmpty(scdid)) if serr != nil { return nil, serr } if scdXmlObj == nil { return nil, errors.New("无效的SCD") } iedObj := t.GetIed(scdXmlObj, tools.IsEmpty(scdid), ied_name) if iedObj == nil { return nil, errors.New("无效的IED装置名称") } scdMgr := new(ScdMgr) mapTargetLNodeType := scdMgr.GetLNodeType(scdXmlObj) mapTargetLDoType := scdMgr.GetDOType(scdXmlObj) rowset := []orm.Params{} for _, acc := range iedObj.AccessPoint { if acc.Server != nil { for _, ld := range acc.Server.LDevice { if ld.LN0 != nil { for _, rpc := range ld.LN0.ReportControl { obj := orm.Params{ "accesspoint_name": acc.Name, "ld_desc": ld.Desc, "ld_inst": ld.Inst, "block_desc": rpc.Desc, "block_name": rpc.Name, "block_datset": rpc.DatSet, "block_rptid": rpc.RptID, "block_intgpd": rpc.IntgPd, "block_confrev": rpc.ConfRev, "block_buftime": rpc.BufTime, "block_buffered": rpc.Buffered, "list": []orm.Params{}, } for _, ds := range ld.LN0.DataSet { if ds.Name == rpc.DatSet { for _, fcda := range ds.FCDA { fcdaobj := orm.Params{ "short_addr": fmt.Sprintf("%s/%s%s%s.%s", fcda.LdInst, fcda.Prefix, fcda.LnClass, fcda.LnInst, fcda.DoName), "doi_name": fcda.DoName, "doi_desc": "", } found := false if fcda.LnClass == "LLN0" { if lnnodetpye, h := mapTargetLNodeType[ld.LN0.LnType]; h { for _, doitem := range lnnodetpye.DO { if doitem.Name == fcda.DoName { dotype := doitem.Type if dotypeobj, h := mapTargetLDoType[dotype]; h { fcdaobj["da_datatype"] = scdMgr.GetCdcDataTypeName(dotypeobj.Cdc) } break } } } for _, doi := range ld.LN0.DOI { if doi.Name == fcda.DoName { fcdaobj["doi_desc"] = doi.Desc found = true break } } } else { for _, ln := range ld.LN { if ln.LnClass == fcda.LnClass && ln.Inst == fcda.LnInst { if lnnodetpye, h := mapTargetLNodeType[ln.LnType]; h { for _, doitem := range lnnodetpye.DO { if doitem.Name == fcda.DoName { dotype := doitem.Type if dotypeobj, h := mapTargetLDoType[dotype]; h { fcdaobj["da_datatype"] = scdMgr.GetCdcDataTypeName(dotypeobj.Cdc) } break } } } for _, doi := range ln.DOI { if doi.Name == fcda.DoName { fcdaobj["doi_desc"] = doi.Desc found = true break } } } if found { break } } } obj["list"] = append(obj["list"].([]orm.Params), fcdaobj) } break } } rowset = append(rowset, obj) } } } } } return rowset, nil } //查询源XML func (t *ScdNode) GetScdIedSourceXML(scdid int64, ied_name string) (string, error) { scdXmlObj, serr := new(ScdParse).GetScdXmlObjectBySCDID(tools.IsEmpty(scdid)) if serr != nil { return "", serr } if scdXmlObj == nil { return "", errors.New("无效的SCD") } startLineNo := int64(0) endLineNo := int64(0) for _, ied := range scdXmlObj.IED { if ied.Name == ied_name { //当前ied的开始行号 startLineNo = ied.Lineno } else { if startLineNo > 0 { //结束行为下一个ied的开始行减1 endLineNo = ied.Lineno - 1 break } } } //判断是不是最后一ied if startLineNo > 0 && endLineNo == 0 { //最后一个ied的结束行号 endLineNo = scdXmlObj.DataTypeTemplates.Lineno - 1 } if startLineNo == 0 { return "", errors.New("无效的IED装置名称") } logger.Logger.Debug(fmt.Sprintf("====startLineNo:%d,endLineNo:%d====", startLineNo, endLineNo)) scdinfo, _ := new(ScdMgr).One(tools.IsEmpty(scdid)) scdpath := scdinfo["path"].(string) parsedFile := strings.ReplaceAll(scdpath, "\\", "/") _, err := os.Stat(parsedFile) if err != nil { logger.Logger.Error(err) return "", err } f, _ := os.Open(parsedFile) reslist := []string{} if f != nil { defer f.Close() r1 := bufio.NewReader(f) startLineNo = startLineNo - 1 //跳过第一行xml标记行 lineno := int64(0) //初始行记数器。 for { txt, err := r1.ReadString('\n') if err == io.EOF { break } if lineno >= startLineNo { reslist = append(reslist, txt) } lineno = lineno + 1 if lineno == endLineNo { break } } } return strings.Join(reslist, ""), nil } //查询源XML func (t *ScdNode) GetScdLineSourceXML(scdid int64, lineno int64) ([]string, error) { scdXmlObj, serr := new(ScdParse).GetScdXmlObjectBySCDID(tools.IsEmpty(scdid)) if serr != nil { return nil, serr } if scdXmlObj == nil { return nil, errors.New("无效的SCD") } startLineNo := int64(0) endLineNo := int64(0) if lineno < 0 { lineno = 0 } if lineno < 100 { startLineNo = 0 //从最开始获取 endLineNo = lineno + 100 } else { startLineNo = lineno - 100 endLineNo = lineno + 100 } logger.Logger.Debug(fmt.Sprintf("====startLineNo:%d,endLineNo:%d====", startLineNo, endLineNo)) scdinfo, _ := new(ScdMgr).One(tools.IsEmpty(scdid)) scdpath := scdinfo["path"].(string) parsedFile := strings.ReplaceAll(scdpath, "\\", "/") _, err := os.Stat(parsedFile) if err != nil { logger.Logger.Error(err) return nil, err } f, _ := os.Open(parsedFile) reslist := []string{} if f != nil { defer f.Close() r1 := bufio.NewReader(f) startLineNo = startLineNo - 1 //跳过第一行xml标记行 c_lineno := int64(0) //初始行记数器。 for { txt, err := r1.ReadString('\n') if err == io.EOF { break } if c_lineno >= startLineNo { reslist = append(reslist, fmt.Sprintf("%d %s", c_lineno+1, txt)) } c_lineno = c_lineno + 1 if c_lineno == endLineNo { break } } } return reslist, nil }