Inserito prototipo gestione password calcolabile + master
This commit is contained in:
@@ -77,6 +77,7 @@
|
||||
<ItemGroup>
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="Services\ConsolePrinter.cs" />
|
||||
<Compile Include="Services\CryptoUtils.cs" />
|
||||
<Compile Include="Services\DataRecorder.cs" />
|
||||
<Compile Include="Services\IPrinter.cs" />
|
||||
<Compile Include="Services\LogPrinter.cs" />
|
||||
|
||||
@@ -0,0 +1,224 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace OpcUaCommon.Services
|
||||
{
|
||||
/// <summary>
|
||||
/// utils x cifrature passeword e Crypto functionality in genere
|
||||
/// </summary>
|
||||
public static class CryptoUtils
|
||||
{
|
||||
#region Public Methods
|
||||
|
||||
/// <summary>
|
||||
/// Decifra un messaggio AES
|
||||
/// </summary>
|
||||
/// <param name="Message"></param>
|
||||
/// <param name="Passphrase"></param>
|
||||
/// <returns></returns>
|
||||
public static string DecryptString(string Message, string Passphrase)
|
||||
{
|
||||
string answ = Message;
|
||||
byte[] Results = null;
|
||||
UTF8Encoding UTF8 = new UTF8Encoding();
|
||||
|
||||
// Step 1. faccio hash per ottenere la Key a 128 bit + l'InitVector a 256 bit
|
||||
// - MD5 hash generator --> 128 bit byte array
|
||||
// - Sha256 hash generator --> 256 bit byte array
|
||||
MD5CryptoServiceProvider MD5HashProv = new MD5CryptoServiceProvider();
|
||||
SHA256CryptoServiceProvider Sha256HashProv = new SHA256CryptoServiceProvider();
|
||||
byte[] AESKey = Sha256HashProv.ComputeHash(UTF8.GetBytes(Passphrase));
|
||||
byte[] AESIV = MD5HashProv.ComputeHash(UTF8.GetBytes(Passphrase));
|
||||
|
||||
// Step 2. Crea oggett AESCryptoServiceProvider
|
||||
AesCryptoServiceProvider AESAlgorithm = new AesCryptoServiceProvider();
|
||||
|
||||
// Step 3. Setup del dencoder
|
||||
AESAlgorithm.Key = AESKey;
|
||||
AESAlgorithm.IV = AESIV;
|
||||
|
||||
// Step 4. Conversione della stringa in ingresso in un byte[]
|
||||
byte[] DataToDecrypt = null;
|
||||
try
|
||||
{
|
||||
DataToDecrypt = Convert.FromBase64String(Message);
|
||||
}
|
||||
catch
|
||||
{ }
|
||||
if (DataToDecrypt != null)
|
||||
{
|
||||
// Step 5. Attempt to decrypt the string
|
||||
try
|
||||
{
|
||||
ICryptoTransform Decryptor = AESAlgorithm.CreateDecryptor();
|
||||
Results = Decryptor.TransformFinalBlock(DataToDecrypt, 0, DataToDecrypt.Length);
|
||||
}
|
||||
finally
|
||||
{
|
||||
// Clear the TripleDes and Hashprovider services of any sensitive information
|
||||
AESAlgorithm.Clear();
|
||||
MD5HashProv.Clear();
|
||||
Sha256HashProv.Clear();
|
||||
}
|
||||
// Step 6. Return the decrypted string in UTF8 format
|
||||
answ = UTF8.GetString(Results);
|
||||
}
|
||||
return answ;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Cifra un messaggio con AES
|
||||
/// </summary>
|
||||
/// <param name="Message">Messaggio da cifrare (la password)</param>
|
||||
/// <param name="Passphrase">Stringa usate per generare le key/IV da 128/256bit</param>
|
||||
/// <returns></returns>
|
||||
public static string EncryptString(string Message, string Passphrase)
|
||||
{
|
||||
byte[] Results;
|
||||
UTF8Encoding UTF8 = new UTF8Encoding();
|
||||
|
||||
// Step 1. faccio hash per ottenere la Key a 128 bit + l'InitVector a 256 bit
|
||||
// - MD5 hash generator --> 128 bit byte array
|
||||
// - Sha256 hash generator --> 256 bit byte array
|
||||
MD5CryptoServiceProvider MD5HashProv = new MD5CryptoServiceProvider();
|
||||
SHA256CryptoServiceProvider Sha256HashProv = new SHA256CryptoServiceProvider();
|
||||
byte[] AESKey = Sha256HashProv.ComputeHash(UTF8.GetBytes(Passphrase));
|
||||
byte[] AESIV = MD5HashProv.ComputeHash(UTF8.GetBytes(Passphrase));
|
||||
|
||||
// Step 2. Crea oggett AESCryptoServiceProvider
|
||||
AesCryptoServiceProvider AESAlgorithm = new AesCryptoServiceProvider();
|
||||
|
||||
// Step 3. Setup dell'encoder
|
||||
AESAlgorithm.Key = AESKey;
|
||||
AESAlgorithm.IV = AESIV;
|
||||
|
||||
// Step 4. Conversione della stringa in ingresso in un byte[]
|
||||
byte[] DataToEncrypt = UTF8.GetBytes(Message);
|
||||
|
||||
// Step 5. Attempt to encrypt the string
|
||||
try
|
||||
{
|
||||
ICryptoTransform Encryptor = AESAlgorithm.CreateEncryptor();
|
||||
Results = Encryptor.TransformFinalBlock(DataToEncrypt, 0, DataToEncrypt.Length);
|
||||
}
|
||||
finally
|
||||
{
|
||||
// ripulisce il provider di ogni informazione sensibile
|
||||
AESAlgorithm.Clear();
|
||||
MD5HashProv.Clear();
|
||||
Sha256HashProv.Clear();
|
||||
}
|
||||
|
||||
// Step 6. Restitusice stringa cifrata come una "base64 encoded string"
|
||||
return Convert.ToBase64String(Results);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Genera una password valida
|
||||
/// </summary>
|
||||
/// <param name="userName"></param>
|
||||
/// <param name="passphrase"></param>
|
||||
/// <returns></returns>
|
||||
public static string generatePwd(string userName, string passphrase)
|
||||
{
|
||||
// Check preliminare della "master password"
|
||||
return EncryptString(userName, passphrase);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// genera hash di una stringa in MD5 (es x hash gravatar)
|
||||
/// </summary>
|
||||
/// <param name="Message"></param>
|
||||
/// <returns></returns>
|
||||
public static string getHashStringMD5(string Message)
|
||||
{
|
||||
string hash = "";
|
||||
using (MD5 md5Hash = MD5.Create())
|
||||
{
|
||||
hash = GetMd5Hash(md5Hash, Message);
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Crea un hash MD5
|
||||
/// </summary>
|
||||
/// <param name="md5Hash"></param>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
public static string GetMd5Hash(MD5 md5Hash, string input)
|
||||
{
|
||||
// Convert the input string to a byte array and compute the hash.
|
||||
byte[] data = md5Hash.ComputeHash(Encoding.UTF8.GetBytes(input));
|
||||
|
||||
// Create a new Stringbuilder to collect the bytes
|
||||
// and create a string.
|
||||
StringBuilder sBuilder = new StringBuilder();
|
||||
|
||||
// Loop through each byte of the hashed data
|
||||
// and format each one as a hexadecimal string.
|
||||
for (int i = 0; i < data.Length; i++)
|
||||
{
|
||||
sBuilder.Append(data[i].ToString("x2"));
|
||||
}
|
||||
|
||||
// Return the hexadecimal string.
|
||||
return sBuilder.ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Effettua validazione password
|
||||
/// </summary>
|
||||
/// <param name="userName"></param>
|
||||
/// <param name="password"></param>
|
||||
/// <param name="passphrase"></param>
|
||||
/// <returns></returns>
|
||||
public static bool validateUserPwd(string userName, string password, string passphrase)
|
||||
{
|
||||
#if false
|
||||
// helper calcolo pwd..
|
||||
//string correctPwd = generatePwd(userName, passphrase);
|
||||
#endif
|
||||
// Check preliminare della "master password"
|
||||
bool answ = (userName == "scmAdmin" && password == "1PasswordDavveroDifficil3!");
|
||||
// verifico password avanzata
|
||||
if (!answ)
|
||||
{
|
||||
string plainText = DecryptString(password, passphrase);
|
||||
answ = (userName == plainText);
|
||||
}
|
||||
return answ;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verify a hash against a string.
|
||||
/// </summary>
|
||||
/// <param name="md5Hash"></param>
|
||||
/// <param name="input"></param>
|
||||
/// <param name="hash"></param>
|
||||
/// <returns></returns>
|
||||
public static bool VerifyMd5Hash(MD5 md5Hash, string input, string hash)
|
||||
{
|
||||
// Hash the input.
|
||||
string hashOfInput = GetMd5Hash(md5Hash, input);
|
||||
|
||||
// Create a StringComparer an compare the hashes.
|
||||
StringComparer comparer = StringComparer.OrdinalIgnoreCase;
|
||||
|
||||
if (0 == comparer.Compare(hashOfInput, hash))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion Public Methods
|
||||
}
|
||||
}
|
||||
@@ -114,13 +114,7 @@ namespace OpcUaServer.Server
|
||||
|
||||
#region Public Methods
|
||||
|
||||
public override ResponseHeader Browse(
|
||||
RequestHeader requestHeader,
|
||||
ViewDescription view,
|
||||
uint requestedMaxReferencesPerNode,
|
||||
BrowseDescriptionCollection nodesToBrowse,
|
||||
out BrowseResultCollection results,
|
||||
out DiagnosticInfoCollection diagnosticInfos)
|
||||
public override ResponseHeader Browse(RequestHeader requestHeader, ViewDescription view, uint requestedMaxReferencesPerNode, BrowseDescriptionCollection nodesToBrowse, out BrowseResultCollection results, out DiagnosticInfoCollection diagnosticInfos)
|
||||
{
|
||||
results = null;
|
||||
diagnosticInfos = null;
|
||||
@@ -141,18 +135,24 @@ namespace OpcUaServer.Server
|
||||
if (context.UserIdentity.TokenType == UserTokenType.Anonymous)
|
||||
filter = true;
|
||||
|
||||
ServerInternal.NodeManager.Browse(
|
||||
context,
|
||||
view,
|
||||
requestedMaxReferencesPerNode,
|
||||
nodesToBrowse,
|
||||
out results,
|
||||
out diagnosticInfos);
|
||||
// legge gli oggetti contenuti nell'elemento richeisto
|
||||
ServerInternal.NodeManager.Browse(context, view, requestedMaxReferencesPerNode, nodesToBrowse, out results, out diagnosticInfos);
|
||||
|
||||
if (filter) foreach (var res in results)
|
||||
// se attivato il filtro == utente anonimo
|
||||
if (filter)
|
||||
{
|
||||
foreach (var res in results)
|
||||
{
|
||||
var filtrati = res.References.FindAll(x => x.NodeClass == NodeClass.Variable && (x.BrowseName.Name.StartsWith("Machine/") && x.BrowseName.Name != "Machine/Status"));
|
||||
|
||||
// rimuove tutto tranne status...
|
||||
//res.References.RemoveAll(x => x.NodeClass == NodeClass.Variable && (x.BrowseName.Name.StartsWith("Machine/") && x.BrowseName.Name != "Machine/Status"));
|
||||
res.References.RemoveAll(x => x.BrowseName.Name.StartsWith("Machine/") && x.BrowseName.Name != "Machine/Status");
|
||||
|
||||
//// includo SOLO SE VGroup = "A" (All)
|
||||
//res.References.RemoveAll(x => x.BrowseName.Name.StartsWith("Machine/") && x.BrowseName.Name != "Machine/Status");
|
||||
}
|
||||
}
|
||||
|
||||
return CreateResponse(requestHeader, context.StringTable);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
using Opc.Ua;
|
||||
using OpcUaCommon.Services;
|
||||
|
||||
namespace OpcUaServer.Server.Services
|
||||
{
|
||||
@@ -23,6 +25,13 @@ namespace OpcUaServer.Server.Services
|
||||
|
||||
#region Public Methods
|
||||
|
||||
public static string ReverseString(string s)
|
||||
{
|
||||
char[] array = s.ToCharArray();
|
||||
Array.Reverse(array);
|
||||
return new string(array);
|
||||
}
|
||||
|
||||
public IUserIdentity VerifyPassword(UserNameIdentityToken userNameToken, string productUri)
|
||||
{
|
||||
var userName = userNameToken.UserName;
|
||||
@@ -48,7 +57,10 @@ namespace OpcUaServer.Server.Services
|
||||
//}
|
||||
|
||||
// standard users for CTT verification
|
||||
if ((userName == "scmAdmin" && password == "password123"))
|
||||
string passphrase = $"{userName}_{ReverseString(userName)}";
|
||||
//bool hashUser = CryptoUtils.validateUserPwd(userName, password, passphrase);
|
||||
//if ((userName == "scmAdmin" && password == "passwordDifficile"))
|
||||
if (CryptoUtils.validateUserPwd(userName, password, passphrase))
|
||||
return new UserIdentity(userNameToken);
|
||||
|
||||
// construct translation object with default text.
|
||||
|
||||
@@ -69,13 +69,6 @@ namespace OpcUaServer.Server.Services
|
||||
AddProperty(folder, xmlElement, stringFolderName, nameSpaceIndex, folderInstanceState);
|
||||
break;
|
||||
|
||||
#if false
|
||||
case "Events":
|
||||
// aggiungo "Events:"
|
||||
AddVariable(folderInstanceState, nameSpaceIndex, xmlElement, $"{stringFolderName}/Events", folder);
|
||||
break;
|
||||
#endif
|
||||
|
||||
case "Condition":
|
||||
AddCondition(folderInstanceState, nameSpaceIndex, xmlElement, stringFolderName, folder);
|
||||
break;
|
||||
|
||||
@@ -8,7 +8,10 @@ namespace SOUR.Core
|
||||
private readonly List<TreeNodeInstance> _children;
|
||||
public string BrowseName { get; set; }
|
||||
public string DisplayName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Visibilità dell'oggetto nodo d'albero
|
||||
/// </summary>
|
||||
public string Visibility { get; set; } = "A";
|
||||
|
||||
|
||||
public TreeNodeInstance[] Children
|
||||
|
||||
+214
-211
@@ -6,236 +6,239 @@ using System.Xml;
|
||||
|
||||
namespace SOUR.Core
|
||||
{
|
||||
public class XmlParser
|
||||
{
|
||||
private readonly IEventMessageRepository _eventMessageRepository;
|
||||
|
||||
public XmlParser(IEventMessageRepository eventMessageRepository)
|
||||
public class XmlParser
|
||||
{
|
||||
_eventMessageRepository = eventMessageRepository;
|
||||
}
|
||||
#region Private Fields
|
||||
|
||||
private readonly IEventMessageRepository _eventMessageRepository;
|
||||
|
||||
public IDictionary<string, NodeProperties> CreateDictionaryFromXmlToGenerateValues(string tracciatoXml)
|
||||
{
|
||||
IDictionary<string, NodeProperties> nodeNameAndBuiltInTypes = new Dictionary<string, NodeProperties>();
|
||||
var xmlDocument = new XmlDocument();
|
||||
// carico XML appena salvato
|
||||
xmlDocument.Load(tracciatoXml);
|
||||
ParseXml(xmlDocument, nodeNameAndBuiltInTypes, new TreeNodeInstance());
|
||||
#endregion Private Fields
|
||||
|
||||
return nodeNameAndBuiltInTypes;
|
||||
#region Public Constructors
|
||||
|
||||
}
|
||||
|
||||
public TreeNodeInstance CreateTree(string tracciatoXml)
|
||||
{
|
||||
IDictionary<string, NodeProperties> nodeNameAndBuiltInTypes = new Dictionary<string, NodeProperties>();
|
||||
var treeNodeInstance = new TreeNodeInstance();
|
||||
var xmlDocument = new XmlDocument();
|
||||
xmlDocument.Load(tracciatoXml);
|
||||
|
||||
ParseXml(xmlDocument, nodeNameAndBuiltInTypes, treeNodeInstance);
|
||||
return treeNodeInstance;
|
||||
|
||||
}
|
||||
|
||||
private void CreateSubDictionary(string path, XmlNode component, IDictionary<string, NodeProperties> nodeNameAndBuiltInTypes, TreeNodeInstance treeNodeInstance)
|
||||
{
|
||||
string redisPath = path.Replace("/", ":");
|
||||
foreach (XmlElement xmlElement in component)
|
||||
{
|
||||
if (xmlElement.Name != "Component" && xmlElement.Name != "Conditions" && xmlElement.Name != "Property")
|
||||
public XmlParser(IEventMessageRepository eventMessageRepository)
|
||||
{
|
||||
var nodeName = xmlElement.Attributes["BrowseName"].Value;
|
||||
var symbolicName = xmlElement.Attributes["SymbolicName"].Value;
|
||||
var nodeDataType = xmlElement.Attributes["DataType"].Value;
|
||||
// range NON lo richiediamo x cui controllo NULL "a monte"...
|
||||
var nodeRange = component.Attributes["Range"] != null ? (component.Attributes["Range"].Value ?? "null") : "null";
|
||||
//// vecchio modo che genera eccezioni se manca attributo...
|
||||
//var nodeRange = xmlElement.Attributes["Range"].Value ?? "null";
|
||||
var nodeUnits = xmlElement.Attributes["Units"]?.Value ?? "null";
|
||||
var severity = xmlElement.Attributes["Severity"]?.Value ?? "null";
|
||||
|
||||
// 2019.01.29 aggiunta decodifica nuove conf XML, con valori default
|
||||
var nodeSGroup = xmlElement.Attributes["SGroup"]?.Value ?? "3";
|
||||
var nodeDBand = xmlElement.Attributes["DBand"]?.Value ?? "";
|
||||
var nodeVGroup = xmlElement.Attributes["VGroup"]?.Value ?? "A"; // default: ALL
|
||||
|
||||
//var parentName = component.Attributes["Name"].Value ?? "";
|
||||
|
||||
if (!Enum.TryParse(xmlElement.Name, out NodePropertiesType nodePropertyType))
|
||||
{
|
||||
nodePropertyType = NodePropertiesType.Variable;
|
||||
}
|
||||
|
||||
NodeProperties nodeProperties;
|
||||
if (xmlElement.Name == "Condition")
|
||||
{
|
||||
// allarmi SEMPRE alla massima priorità...
|
||||
nodeSGroup = "1";
|
||||
// HARD CODED traduzione messaggi a lingua corrente... in area AdpConf...
|
||||
string redAlarmPath = string.Format("{0}:{1}", redisPath, symbolicName);
|
||||
var eventMessages = _eventMessageRepository.getAlarmList(redAlarmPath);
|
||||
var vetoCodes = _eventMessageRepository.getVetoCodes(redAlarmPath);
|
||||
nodeProperties = new ConditionNodeProperties(nodeName, nodeDataType, nodeRange, nodeUnits, severity, nodeSGroup, nodeDBand, nodeVGroup, nodePropertyType, eventMessages, vetoCodes);
|
||||
}
|
||||
else
|
||||
{
|
||||
nodeProperties = new NodeProperties(nodeName, nodeDataType, nodeRange, nodeUnits, severity, nodeSGroup, nodeDBand, nodeVGroup, nodePropertyType);
|
||||
}
|
||||
|
||||
nodeNameAndBuiltInTypes.Add(path + "/" + symbolicName, nodeProperties);
|
||||
|
||||
treeNodeInstance.AddChild(new TreeNodeInstance()
|
||||
{
|
||||
BrowseName = path + "/" + symbolicName,
|
||||
DisplayName = symbolicName,
|
||||
NodePropertyType = nodeProperties.NodePropertiesType,
|
||||
NodeDataType = nodeProperties.NodeDataType
|
||||
});
|
||||
_eventMessageRepository = eventMessageRepository;
|
||||
}
|
||||
else if (xmlElement.Name == "Property")
|
||||
|
||||
#endregion Public Constructors
|
||||
|
||||
#region Private Methods
|
||||
|
||||
private void CreateSubDictionary(string path, XmlNode component, IDictionary<string, NodeProperties> nodeNameAndBuiltInTypes, TreeNodeInstance treeNodeInstance)
|
||||
{
|
||||
var propName = xmlElement.Attributes["BrowseName"].Value;
|
||||
var propSymbolicName = xmlElement.Attributes["SymbolicName"].Value;
|
||||
var propNodeDataType = xmlElement.Attributes["DataType"].Value ?? null;
|
||||
string nodeSGroup = "5"; // fix a 5
|
||||
var propNodeVGroup = xmlElement.Attributes["VGroup"]?.Value ?? "A"; // default: ALL
|
||||
|
||||
var nodeProperties = new NodeProperties(propName, propNodeDataType, "", null, null, nodeSGroup, null, propNodeVGroup, NodePropertiesType.Property);
|
||||
var key = path.EndsWith("/") ? path + propSymbolicName : path + "/" + propSymbolicName;
|
||||
nodeNameAndBuiltInTypes.Add(key, nodeProperties);
|
||||
|
||||
|
||||
treeNodeInstance.AddChild(new TreeNodeInstance()
|
||||
{
|
||||
BrowseName = key,
|
||||
DisplayName = propSymbolicName,
|
||||
NodePropertyType = nodeProperties.NodePropertiesType,
|
||||
NodeDataType = nodeProperties.NodeDataType
|
||||
});
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
if (xmlElement.Name != "Property")
|
||||
{
|
||||
|
||||
var name = xmlElement.Attributes["Name"].Value;
|
||||
var treeNodeChild = new TreeNodeInstance()
|
||||
string redisPath = path.Replace("/", ":");
|
||||
foreach (XmlElement xmlElement in component)
|
||||
{
|
||||
BrowseName = path + "/" + name,
|
||||
DisplayName = name,
|
||||
NodePropertyType = NodePropertiesType.Folder,
|
||||
NodeDataType = null
|
||||
};
|
||||
var nodeVGroup = xmlElement.Attributes["VGroup"]?.Value ?? "A"; // default: ALL
|
||||
if (xmlElement.Name != "Component" && xmlElement.Name != "Conditions" && xmlElement.Name != "Property")
|
||||
{
|
||||
var nodeName = xmlElement.Attributes["BrowseName"].Value;
|
||||
var symbolicName = xmlElement.Attributes["SymbolicName"].Value;
|
||||
var nodeDataType = xmlElement.Attributes["DataType"].Value;
|
||||
// range NON lo richiediamo x cui controllo NULL "a monte"...
|
||||
var nodeRange = component.Attributes["Range"] != null ? (component.Attributes["Range"].Value ?? "null") : "null";
|
||||
//// vecchio modo che genera eccezioni se manca attributo...
|
||||
//var nodeRange = xmlElement.Attributes["Range"].Value ?? "null";
|
||||
var nodeUnits = xmlElement.Attributes["Units"]?.Value ?? "null";
|
||||
var severity = xmlElement.Attributes["Severity"]?.Value ?? "null";
|
||||
|
||||
treeNodeInstance.AddChild(treeNodeChild);
|
||||
// 2019.01.29 aggiunta decodifica nuove conf XML, con valori default
|
||||
var nodeSGroup = xmlElement.Attributes["SGroup"]?.Value ?? "3";
|
||||
var nodeDBand = xmlElement.Attributes["DBand"]?.Value ?? "";
|
||||
|
||||
CreateSubDictionary(path + "/" + name, xmlElement, nodeNameAndBuiltInTypes, treeNodeChild);
|
||||
//var parentName = component.Attributes["Name"].Value ?? "";
|
||||
|
||||
}
|
||||
if (!Enum.TryParse(xmlElement.Name, out NodePropertiesType nodePropertyType))
|
||||
{
|
||||
nodePropertyType = NodePropertiesType.Variable;
|
||||
}
|
||||
|
||||
NodeProperties nodeProperties;
|
||||
if (xmlElement.Name == "Condition")
|
||||
{
|
||||
// allarmi SEMPRE alla massima priorità...
|
||||
nodeSGroup = "1";
|
||||
// HARD CODED traduzione messaggi a lingua corrente... in area AdpConf...
|
||||
string redAlarmPath = string.Format("{0}:{1}", redisPath, symbolicName);
|
||||
var eventMessages = _eventMessageRepository.getAlarmList(redAlarmPath);
|
||||
var vetoCodes = _eventMessageRepository.getVetoCodes(redAlarmPath);
|
||||
nodeProperties = new ConditionNodeProperties(nodeName, nodeDataType, nodeRange, nodeUnits, severity, nodeSGroup, nodeDBand, nodeVGroup, nodePropertyType, eventMessages, vetoCodes);
|
||||
}
|
||||
else
|
||||
{
|
||||
nodeProperties = new NodeProperties(nodeName, nodeDataType, nodeRange, nodeUnits, severity, nodeSGroup, nodeDBand, nodeVGroup, nodePropertyType);
|
||||
}
|
||||
|
||||
nodeNameAndBuiltInTypes.Add(path + "/" + symbolicName, nodeProperties);
|
||||
|
||||
treeNodeInstance.AddChild(new TreeNodeInstance()
|
||||
{
|
||||
BrowseName = path + "/" + symbolicName,
|
||||
DisplayName = symbolicName,
|
||||
NodePropertyType = nodeProperties.NodePropertiesType,
|
||||
NodeDataType = nodeProperties.NodeDataType,
|
||||
Visibility = nodeVGroup
|
||||
});
|
||||
}
|
||||
else if (xmlElement.Name == "Property")
|
||||
{
|
||||
var propName = xmlElement.Attributes["BrowseName"].Value;
|
||||
var propSymbolicName = xmlElement.Attributes["SymbolicName"].Value;
|
||||
var propNodeDataType = xmlElement.Attributes["DataType"].Value ?? null;
|
||||
string nodeSGroup = "5"; // fix a 5
|
||||
|
||||
var nodeProperties = new NodeProperties(propName, propNodeDataType, "", null, null, nodeSGroup, null, nodeVGroup, NodePropertiesType.Property);
|
||||
var key = path.EndsWith("/") ? path + propSymbolicName : path + "/" + propSymbolicName;
|
||||
nodeNameAndBuiltInTypes.Add(key, nodeProperties);
|
||||
|
||||
treeNodeInstance.AddChild(new TreeNodeInstance()
|
||||
{
|
||||
BrowseName = key,
|
||||
DisplayName = propSymbolicName,
|
||||
NodePropertyType = nodeProperties.NodePropertiesType,
|
||||
NodeDataType = nodeProperties.NodeDataType,
|
||||
Visibility = nodeVGroup
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
if (xmlElement.Name != "Property")
|
||||
{
|
||||
var name = xmlElement.Attributes["Name"].Value;
|
||||
var treeNodeChild = new TreeNodeInstance()
|
||||
{
|
||||
BrowseName = path + "/" + name,
|
||||
DisplayName = name,
|
||||
NodePropertyType = NodePropertiesType.Folder,
|
||||
NodeDataType = null,
|
||||
Visibility = nodeVGroup
|
||||
};
|
||||
|
||||
treeNodeInstance.AddChild(treeNodeChild);
|
||||
|
||||
CreateSubDictionary(path + "/" + name, xmlElement, nodeNameAndBuiltInTypes, treeNodeChild);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void ParseXml(XmlDocument xmlDocument, IDictionary<string, NodeProperties> nodeNameAndBuiltInTypes,
|
||||
TreeNodeInstance treeNodeInstance)
|
||||
{
|
||||
var itemRef = xmlDocument.GetElementsByTagName("Machine");
|
||||
string rootName = "Machine"; //itemRef[0]?.Attributes?["Name"].Value + "_" + itemRef[0]?.Attributes?["Serial"].Value;
|
||||
|
||||
treeNodeInstance.BrowseName = rootName;
|
||||
treeNodeInstance.DisplayName = rootName;
|
||||
treeNodeInstance.NodePropertyType = NodePropertiesType.Folder;
|
||||
treeNodeInstance.NodeDataType = null;
|
||||
|
||||
var xmlNodeList = itemRef[0]?.ChildNodes;
|
||||
if (xmlNodeList == null)
|
||||
{
|
||||
nodeNameAndBuiltInTypes = null;
|
||||
return;
|
||||
}
|
||||
foreach (XmlNode component in xmlNodeList)
|
||||
{
|
||||
|
||||
var stringFolderName = rootName + "/";
|
||||
if (component.Name != "Component" && component.Name != "Components" && component.Name != "Property")
|
||||
private void ParseXml(XmlDocument xmlDocument, IDictionary<string, NodeProperties> nodeNameAndBuiltInTypes,
|
||||
TreeNodeInstance treeNodeInstance)
|
||||
{
|
||||
var nodeName = component.Attributes["BrowseName"].Value;
|
||||
var symbolicName = component.Attributes["SymbolicName"].Value;
|
||||
var nodeDataType = component.Attributes["DataType"].Value ?? null;
|
||||
// range NON lo richiediamo x cui controllo NULL "a monte"...
|
||||
var nodeRange = component.Attributes["Range"] != null ? (component.Attributes["Range"].Value ?? "null") : "null";
|
||||
//// vecchio modo che genera eccezioni se manca attributo...
|
||||
//var nodeRange = component.Attributes["Range"].Value ?? "null";
|
||||
var nodeUnits = component.Attributes["Units"]?.Value ?? "null";
|
||||
var severity = component.Attributes["Severity"]?.Value ?? "null";
|
||||
var nodeSGroup = component.Attributes["SGroup"]?.Value ?? "3";
|
||||
var nodeDBand = component.Attributes["DBand"]?.Value ?? "";
|
||||
var nodeVGroup = component.Attributes["VGroup"]?.Value ?? "A"; // default: ALL
|
||||
var itemRef = xmlDocument.GetElementsByTagName("Machine");
|
||||
string rootName = "Machine"; //itemRef[0]?.Attributes?["Name"].Value + "_" + itemRef[0]?.Attributes?["Serial"].Value;
|
||||
|
||||
if (!Enum.TryParse(component.Name, out NodePropertiesType nodePropertyType))
|
||||
{
|
||||
nodePropertyType = NodePropertiesType.Variable;
|
||||
}
|
||||
treeNodeInstance.BrowseName = rootName;
|
||||
treeNodeInstance.DisplayName = rootName;
|
||||
treeNodeInstance.NodePropertyType = NodePropertiesType.Folder;
|
||||
treeNodeInstance.NodeDataType = null;
|
||||
|
||||
NodeProperties nodeProperties;
|
||||
|
||||
|
||||
if (component.Name == "Condition")
|
||||
{
|
||||
// HARD CODED traduzione messaggi a lingua corrente... in area AdpConf...
|
||||
string redAlarmPath = string.Format("{0}:{1}", rootName, symbolicName);
|
||||
var eventMessages = _eventMessageRepository.getAlarmList(redAlarmPath);
|
||||
var vetoCodes = _eventMessageRepository.getVetoCodes(redAlarmPath);
|
||||
nodeProperties = new ConditionNodeProperties(nodeName, nodeDataType, nodeRange, nodeUnits, severity, nodeSGroup, nodeDBand, nodeVGroup, nodePropertyType, eventMessages, vetoCodes);
|
||||
}
|
||||
else
|
||||
{
|
||||
nodeProperties = new NodeProperties(nodeName, nodeDataType, nodeRange, nodeUnits, severity, nodeSGroup, nodeDBand, nodeVGroup, nodePropertyType);
|
||||
}
|
||||
treeNodeInstance.AddChild(new TreeNodeInstance() { BrowseName = stringFolderName + symbolicName, DisplayName = symbolicName, NodePropertyType = nodeProperties.NodePropertiesType, NodeDataType = nodeProperties.NodeDataType });
|
||||
|
||||
nodeNameAndBuiltInTypes.Add(stringFolderName + symbolicName, nodeProperties);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (component.Name == "Property")
|
||||
{
|
||||
var propName = component.Attributes["BrowseName"].Value;
|
||||
var propSymbolicName = component.Attributes["SymbolicName"].Value;
|
||||
var propNodeDataType = component.Attributes["DataType"].Value ?? null;
|
||||
var propNodeVGroup = component.Attributes["VGroup"]?.Value ?? "A"; // default: ALL
|
||||
|
||||
var nodeProperties = new NodeProperties(propName, propNodeDataType, "", null, null, null, null, propNodeVGroup, NodePropertiesType.Property);
|
||||
nodeNameAndBuiltInTypes.Add(stringFolderName + propSymbolicName, nodeProperties);
|
||||
|
||||
treeNodeInstance.AddChild(new TreeNodeInstance() { BrowseName = stringFolderName + propSymbolicName, DisplayName = propSymbolicName, NodePropertyType = nodeProperties.NodePropertiesType, NodeDataType = nodeProperties.NodeDataType });
|
||||
|
||||
}
|
||||
|
||||
if (component.Name != "Property" && component.Attributes != null)
|
||||
{
|
||||
var treeNodeChild = new TreeNodeInstance()
|
||||
var xmlNodeList = itemRef[0]?.ChildNodes;
|
||||
if (xmlNodeList == null)
|
||||
{
|
||||
BrowseName = stringFolderName + component.Attributes["Name"].Value,
|
||||
DisplayName = component.Attributes["Name"].Value,
|
||||
NodePropertyType = NodePropertiesType.Folder,
|
||||
NodeDataType = null
|
||||
};
|
||||
treeNodeInstance.AddChild(treeNodeChild);
|
||||
nodeNameAndBuiltInTypes = null;
|
||||
return;
|
||||
}
|
||||
foreach (XmlNode component in xmlNodeList)
|
||||
{
|
||||
var stringFolderName = rootName + "/";
|
||||
if (component.Name != "Component" && component.Name != "Components" && component.Name != "Property")
|
||||
{
|
||||
var nodeName = component.Attributes["BrowseName"].Value;
|
||||
var symbolicName = component.Attributes["SymbolicName"].Value;
|
||||
var nodeDataType = component.Attributes["DataType"].Value ?? null;
|
||||
// range NON lo richiediamo x cui controllo NULL "a monte"...
|
||||
var nodeRange = component.Attributes["Range"] != null ? (component.Attributes["Range"].Value ?? "null") : "null";
|
||||
//// vecchio modo che genera eccezioni se manca attributo...
|
||||
//var nodeRange = component.Attributes["Range"].Value ?? "null";
|
||||
var nodeUnits = component.Attributes["Units"]?.Value ?? "null";
|
||||
var severity = component.Attributes["Severity"]?.Value ?? "null";
|
||||
var nodeSGroup = component.Attributes["SGroup"]?.Value ?? "3";
|
||||
var nodeDBand = component.Attributes["DBand"]?.Value ?? "";
|
||||
var nodeVGroup = component.Attributes["VGroup"]?.Value ?? "A"; // default: ALL
|
||||
|
||||
CreateSubDictionary(stringFolderName + component.Attributes["Name"].Value, component, nodeNameAndBuiltInTypes, treeNodeChild);
|
||||
}
|
||||
if (!Enum.TryParse(component.Name, out NodePropertiesType nodePropertyType))
|
||||
{
|
||||
nodePropertyType = NodePropertiesType.Variable;
|
||||
}
|
||||
|
||||
NodeProperties nodeProperties;
|
||||
|
||||
if (component.Name == "Condition")
|
||||
{
|
||||
// HARD CODED traduzione messaggi a lingua corrente... in area AdpConf...
|
||||
string redAlarmPath = string.Format("{0}:{1}", rootName, symbolicName);
|
||||
var eventMessages = _eventMessageRepository.getAlarmList(redAlarmPath);
|
||||
var vetoCodes = _eventMessageRepository.getVetoCodes(redAlarmPath);
|
||||
nodeProperties = new ConditionNodeProperties(nodeName, nodeDataType, nodeRange, nodeUnits, severity, nodeSGroup, nodeDBand, nodeVGroup, nodePropertyType, eventMessages, vetoCodes);
|
||||
}
|
||||
else
|
||||
{
|
||||
nodeProperties = new NodeProperties(nodeName, nodeDataType, nodeRange, nodeUnits, severity, nodeSGroup, nodeDBand, nodeVGroup, nodePropertyType);
|
||||
}
|
||||
treeNodeInstance.AddChild(new TreeNodeInstance() { BrowseName = stringFolderName + symbolicName, DisplayName = symbolicName, NodePropertyType = nodeProperties.NodePropertiesType, NodeDataType = nodeProperties.NodeDataType });
|
||||
|
||||
nodeNameAndBuiltInTypes.Add(stringFolderName + symbolicName, nodeProperties);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (component.Name == "Property")
|
||||
{
|
||||
var propName = component.Attributes["BrowseName"].Value;
|
||||
var propSymbolicName = component.Attributes["SymbolicName"].Value;
|
||||
var propNodeDataType = component.Attributes["DataType"].Value ?? null;
|
||||
var propNodeVGroup = component.Attributes["VGroup"]?.Value ?? "A"; // default: ALL
|
||||
|
||||
var nodeProperties = new NodeProperties(propName, propNodeDataType, "", null, null, null, null, propNodeVGroup, NodePropertiesType.Property);
|
||||
nodeNameAndBuiltInTypes.Add(stringFolderName + propSymbolicName, nodeProperties);
|
||||
|
||||
treeNodeInstance.AddChild(new TreeNodeInstance() { BrowseName = stringFolderName + propSymbolicName, DisplayName = propSymbolicName, NodePropertyType = nodeProperties.NodePropertiesType, NodeDataType = nodeProperties.NodeDataType });
|
||||
}
|
||||
|
||||
if (component.Name != "Property" && component.Attributes != null)
|
||||
{
|
||||
var treeNodeChild = new TreeNodeInstance()
|
||||
{
|
||||
BrowseName = stringFolderName + component.Attributes["Name"].Value,
|
||||
DisplayName = component.Attributes["Name"].Value,
|
||||
NodePropertyType = NodePropertiesType.Folder,
|
||||
NodeDataType = null
|
||||
};
|
||||
treeNodeInstance.AddChild(treeNodeChild);
|
||||
|
||||
CreateSubDictionary(stringFolderName + component.Attributes["Name"].Value, component, nodeNameAndBuiltInTypes, treeNodeChild);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion Private Methods
|
||||
|
||||
#region Public Methods
|
||||
|
||||
public IDictionary<string, NodeProperties> CreateDictionaryFromXmlToGenerateValues(string tracciatoXml)
|
||||
{
|
||||
IDictionary<string, NodeProperties> nodeNameAndBuiltInTypes = new Dictionary<string, NodeProperties>();
|
||||
var xmlDocument = new XmlDocument();
|
||||
// carico XML appena salvato
|
||||
xmlDocument.Load(tracciatoXml);
|
||||
ParseXml(xmlDocument, nodeNameAndBuiltInTypes, new TreeNodeInstance());
|
||||
|
||||
return nodeNameAndBuiltInTypes;
|
||||
}
|
||||
|
||||
public TreeNodeInstance CreateTree(string tracciatoXml)
|
||||
{
|
||||
IDictionary<string, NodeProperties> nodeNameAndBuiltInTypes = new Dictionary<string, NodeProperties>();
|
||||
var treeNodeInstance = new TreeNodeInstance();
|
||||
var xmlDocument = new XmlDocument();
|
||||
xmlDocument.Load(tracciatoXml);
|
||||
|
||||
ParseXml(xmlDocument, nodeNameAndBuiltInTypes, treeNodeInstance);
|
||||
return treeNodeInstance;
|
||||
}
|
||||
|
||||
#endregion Public Methods
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -11,7 +11,7 @@
|
||||
<Variable SymbolicName="Power" BrowseName="Power" DataType="ua:Boolean" ValueRank="Scalar" Units="Bool" />
|
||||
<Variable SymbolicName="ActiveTime" BrowseName="ActiveTime" DataType="ua:Float" ValueRank="Scalar" Units="h" CmsDataType="CounterList" CmsDataIndex="001" CmsDataOpt="HOURS" />
|
||||
<Variable SymbolicName="ActiveWorkingTime" BrowseName="ActiveTime" DataType="ua:Float" ValueRank="Scalar" Units="h" CmsDataType="CounterList" CmsDataIndex="002" CmsDataOpt="HOURS" />
|
||||
<Component Name="Events">
|
||||
<Component Name="Events" VGroup="P">
|
||||
<Variable SymbolicName="Production" BrowseName="Production" DataType="ua:String" ValueRank="Scalar" Units="" SGroup="1" VGroup="P" />
|
||||
<Variable SymbolicName="Kpis" BrowseName="Kpis" DataType="ua:String" ValueRank="Scalar" Units="" SGroup="1" VGroup="P" />
|
||||
<Variable SymbolicName="Tools" BrowseName="Tools" DataType="ua:String" ValueRank="Scalar" Units="" SGroup="1" VGroup="P" />
|
||||
|
||||
Reference in New Issue
Block a user