Compare commits
26 Commits
2.3.2011.285
...
develop
| Author | SHA1 | Date | |
|---|---|---|---|
| 85552ba0aa | |||
| c17d2c0a16 | |||
| 3e297579e3 | |||
| ee9957ae3c | |||
| 28e7f19eeb | |||
| 7f776d0e2a | |||
| b386f99ecf | |||
| a817d8758a | |||
| 8f635ca7e1 | |||
| 1e91fee62e | |||
| 969840acb4 | |||
| 28c1de8c14 | |||
| 89be5893d3 | |||
| 5a78d159c9 | |||
| f8b08a34d7 | |||
| 9dcad07d13 | |||
| 8f0a5913d5 | |||
| 9be98a6818 | |||
| 19a28711a4 | |||
| 35477d0daa | |||
| 962c19e134 | |||
| bd49fbb743 | |||
| aa8f776659 | |||
| 46eae821f8 | |||
| b94b0a8d33 | |||
| 172d68c1ec |
+153
@@ -0,0 +1,153 @@
|
||||
variables:
|
||||
NUGET_PATH: 'C:\Tools\nuget.exe'
|
||||
MSBUILD_PATH: 'C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools\MSBuild\Current\Bin\MSBuild.exe'
|
||||
ASPNET_MERGE_PATH: 'C:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.8 Tools'
|
||||
NEXUS_PATH: 'OPC-UA-REDIS/SOUR'
|
||||
APP_NAME: 'SOUR'
|
||||
SOL_NAME: 'SOUR'
|
||||
VERS_MAIN: '1.2'
|
||||
NEW_REL: ''
|
||||
OUTPUT_DIR: ''
|
||||
|
||||
# helper x fix pacchetti nuget da repo locale nexus.steamware.net
|
||||
.nuget-fix: &nuget-fix
|
||||
- |
|
||||
$hasSource = C:\Tools\nuget.exe sources list | find "`"Steamware Nexus`"" /C
|
||||
if ($hasSource -eq 0) {
|
||||
C:\Tools\nuget.exe sources Add -Name "`"Steamware Nexus`"" -Source https://nexus.steamware.net/repository/nuget-group -username "`"nugetUser`"" -password "`"$NEXUS_PASSWD`""
|
||||
} else {
|
||||
C:\Tools\nuget.exe sources Update -Name "`"Steamware Nexus`"" -Source https://nexus.steamware.net/repository/nuget-group -username "`"nugetUser`"" -password "`"$NEXUS_PASSWD`""
|
||||
}
|
||||
echo $hasSource
|
||||
|
||||
# helper x fix version number
|
||||
.version-fix: &version-fix
|
||||
- |
|
||||
$env:NEW_REL = $env:VERS_MAIN+"."+(get-date –format yyMM)+"."+$CI_PIPELINE_IID
|
||||
$contenuto = Get-Content -path 'VersGen\VersGen.cs' -Raw
|
||||
$newContenuto = $contenuto -replace '0.0.0.0', $env:NEW_REL
|
||||
$newContenuto | Set-Content -Path 'VersGen\VersGen.cs'
|
||||
echo "Set vers: $env:NEW_REL"
|
||||
|
||||
# helper pulizia files zip
|
||||
.cleanup-zip: &cleanup-zip
|
||||
- |
|
||||
$env:OUTPUT_DIR = "Releases\" + $CI_COMMIT_BRANCH + "\*"
|
||||
if ((Test-Path $env:OUTPUT_DIR))
|
||||
{
|
||||
Remove-Item $env:OUTPUT_DIR -Force -Recurse -ErrorAction Ignore
|
||||
}
|
||||
echo "Clening ZIP dir: $env:OUTPUT_DIR"
|
||||
|
||||
# helper creazione files zip
|
||||
.zipper: &zipper
|
||||
- |
|
||||
$7zipPath = $env:ProgramFiles+"\7-Zip\7z.exe"
|
||||
if (-not (Test-Path -Path $7zipPath -PathType Leaf)) {
|
||||
throw "7 zip file '$7zipPath' not found"
|
||||
}
|
||||
Set-Alias 7zip $7zipPath
|
||||
$Target = "Releases\" + $CI_COMMIT_BRANCH + "\" + $env:APP_NAME + ".zip"
|
||||
$Source = "$env:APP_NAME\bin\*"
|
||||
7zip a -tzip $Target $Source
|
||||
echo "called ZIP $Source --> $Target"
|
||||
|
||||
# helper creazione hash files
|
||||
.hashBuild: &hashBuild
|
||||
- |
|
||||
$Target = "Releases\" + $CI_COMMIT_BRANCH + "\" + $env:APP_NAME + ".zip"
|
||||
$MD5 = Get-FileHash $Target -Algorithm MD5
|
||||
$SHA1 = Get-FileHash $Target -Algorithm SHA1
|
||||
New-Item $Target".md5"
|
||||
New-Item $Target".sha1"
|
||||
$MD5.Hash | Set-Content -Path $Target".md5"
|
||||
$SHA1.Hash | Set-Content -Path $Target".sha1"
|
||||
|
||||
echo "Created HASH files for $Target"
|
||||
|
||||
# helper x send su NEXUS
|
||||
.nexusUpload: &nexusUpload
|
||||
- |
|
||||
Set-Alias mCurl C:\Windows\system32\curl.exe
|
||||
$currentDate = get-date -format yyMM;
|
||||
$currentTime = get-date -format ddHH;
|
||||
$VersNumb = $env:NEW_REL
|
||||
echo "Curr Version: $VersNumb"
|
||||
$FileManIn="VersGen\manifest.xml"
|
||||
$FileManOut=$env:APP_NAME +"\Resources\manifest.xml"
|
||||
$FileCLogIn="VersGen\ChangeLog.html"
|
||||
$FileCLogOut=$env:APP_NAME +"\Resources\ChangeLog.html"
|
||||
echo "Manifest path: $FileManOut"
|
||||
echo "ChangeLog path: $FileCLogOut"
|
||||
|
||||
if($CI_COMMIT_BRANCH -eq "master")
|
||||
{
|
||||
$version = "stable"
|
||||
}
|
||||
else
|
||||
{
|
||||
$version = "unstable"
|
||||
}
|
||||
$manData = Get-Content $FileManIn
|
||||
$manData = $manData -replace "1.0.0.0", $VersNumb
|
||||
$manData = $manData -replace "{{DIRNAME}}", $env:NEXUS_PATH
|
||||
$manData = $manData -replace "{{BRANCHNAME}}", "$version/LAST"
|
||||
$manData = $manData -replace "{{PACKNAME}}", $env:APP_NAME
|
||||
Set-Content -Path $FileManOut -Value $manData
|
||||
$clogData = Get-Content $FileCLogIn
|
||||
$clogData = $clogData -replace "{{CURRENT-REL}}", $VersNumb
|
||||
Set-Content -Path $FileCLogOut -Value $clogData
|
||||
$File2Send = Get-ChildItem("Releases\$CI_COMMIT_BRANCH\*")
|
||||
ForEach ($File in $File2Send) {
|
||||
$FileName = Split-Path $File -leaf
|
||||
echo "mCurl -s -u GitLab:$NEXUS_PASSWD --upload-file $File https://nexus.steamware.net/repository/SWS/$env:NEXUS_PATH/$version/LAST/$FileName"
|
||||
mCurl -s -u GitLab:$NEXUS_PASSWD --upload-file $File https://nexus.steamware.net/repository/SWS/$env:NEXUS_PATH/$version/LAST/$FileName
|
||||
echo "mCurl -s -u GitLab:$NEXUS_PASSWD --upload-file $File https://nexus.steamware.net/repository/SWS/$env:NEXUS_PATH/$version/ARCHIVE/$VersNumb/$FileName"
|
||||
mCurl -s -u GitLab:$NEXUS_PASSWD --upload-file $File https://nexus.steamware.net/repository/SWS/$env:NEXUS_PATH/$version/ARCHIVE/$VersNumb/$FileName
|
||||
}
|
||||
echo "mCurl -s -u GitLab:$NEXUS_PASSWD --upload-file $FileManOut https://nexus.steamware.net/repository/SWS/$env:NEXUS_PATH/$version/LAST/manifest.xml"
|
||||
mCurl -s -u GitLab:$NEXUS_PASSWD --upload-file $FileManOut https://nexus.steamware.net/repository/SWS/$env:NEXUS_PATH/$version/LAST/manifest.xml
|
||||
echo "mCurl -s -u GitLab:$NEXUS_PASSWD --upload-file $FileCLogOut https://nexus.steamware.net/repository/SWS/$env:NEXUS_PATH/$version/LAST/ChangeLog.html"
|
||||
mCurl -s -u GitLab:$NEXUS_PASSWD --upload-file $FileCLogOut https://nexus.steamware.net/repository/SWS/$env:NEXUS_PATH/$version/LAST/ChangeLog.html
|
||||
|
||||
# $File2Send = "Releases\" + $CI_COMMIT_BRANCH + "\" + $env:APP_NAME + ".zip"
|
||||
# mCurl -v -u GitLab:$NEXUS_PASSWD --upload-file $File2Send https://nexus.steamware.net/repository/SWS/$env:NEXUS_PATH/$CI_COMMIT_BRANCH/LAST/$env:APP_NAME-$version.zip
|
||||
# mCurl -v -u GitLab:$NEXUS_PASSWD --upload-file $File2Send https://nexus.steamware.net/repository/SWS/$env:NEXUS_PATH/$CI_COMMIT_BRANCH/ARCHIVE/$VersNumb/$env:APP_NAME-$version.zip
|
||||
# mCurl -v -u GitLab:$NEXUS_PASSWD --upload-file $File2Send".md5" https://nexus.steamware.net/repository/SWS/$env:NEXUS_PATH/$version/$env:APP_NAME-$version.zip".md5
|
||||
# mCurl -v -u GitLab:$NEXUS_PASSWD --upload-file $File2Send".sha1" https://nexus.steamware.net/repository/SWS/$env:NEXUS_PATH/$version/$env:APP_NAME-$version.zip".sha1"
|
||||
|
||||
|
||||
# mCurl -v -u $env:NEXUS_USER:$env:NEXUS_PASSWD --upload-file bin/release/$env:APP_NAME.zip $env:NEXUS_SERVER/utility/$env:NEXUS_PATH/$version/$env:APP_NAME-$version.zip
|
||||
|
||||
stages:
|
||||
- build
|
||||
- deploy
|
||||
|
||||
PUB:Build:
|
||||
stage: build
|
||||
tags:
|
||||
- win
|
||||
#variables:
|
||||
# - APP_NAME: 'PUB'
|
||||
before_script:
|
||||
- *nuget-fix
|
||||
- '& "$env:NUGET_PATH" restore $env:SOL_NAME.sln' # path alla solution corrente
|
||||
- *version-fix
|
||||
script:
|
||||
- '& "$env:MSBUILD_PATH" src\$env:APP_NAME\$env:APP_NAME.csproj -target:Build /p:Configuration=Release /p:Platform="Any CPU" /p:OutputPath=bin/ /verbosity:minimal /m'
|
||||
|
||||
PUB:Deploy:
|
||||
stage: deploy
|
||||
tags:
|
||||
- win
|
||||
before_script:
|
||||
- *nuget-fix
|
||||
- '& "$env:NUGET_PATH" restore $env:SOL_NAME.sln' # path alla solution corrente
|
||||
- *version-fix
|
||||
- *cleanup-zip
|
||||
script:
|
||||
- '& "$env:MSBUILD_PATH" src\$env:APP_NAME\$env:APP_NAME.csproj -target:Build /p:Configuration=Release /p:Platform="Any CPU" /p:OutputPath=bin/ /verbosity:minimal /m'
|
||||
- *zipper
|
||||
- *hashBuild
|
||||
- *nexusUpload
|
||||
needs: ["PUB:Build"]
|
||||
Vendored
+1
-1
@@ -10,7 +10,7 @@ pipeline {
|
||||
|
||||
/* calcolo numero versione... diverso x branch MASTER/DEVELOP */
|
||||
script {
|
||||
withEnv(['NEXT_BUILD_NUMBER=285']) {
|
||||
withEnv(['NEXT_BUILD_NUMBER=291']) {
|
||||
// env.versionNumber = VersionNumber(versionNumberString : '2.3.${BUILD_DATE_FORMATTED, "yyMM"}.${BUILDS_ALL_TIME}', projectStartDate : '2006-01-01', skipFailedBuilds: true)
|
||||
env.versionNumber = VersionNumber(versionNumberString : '2.3.${BUILD_DATE_FORMATTED, "yyMM"}.${BUILDS_ALL_TIME}', projectStartDate : '2006-01-01', skipFailedBuilds: true, overrideBuildsAllTime: '${NEXT_BUILD_NUMBER}')
|
||||
env.APP_NAME = 'SOUR'
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>OpcUaCommon</RootNamespace>
|
||||
<AssemblyName>OpcUaCommon</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
|
||||
<TargetFrameworkVersion>v4.6.2</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<NuGetPackageImportStamp>
|
||||
</NuGetPackageImportStamp>
|
||||
@@ -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,154 @@
|
||||
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>
|
||||
/// 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)
|
||||
{
|
||||
// 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;
|
||||
}
|
||||
|
||||
#endregion Public Methods
|
||||
}
|
||||
}
|
||||
@@ -8,7 +8,7 @@
|
||||
<OutputType>Exe</OutputType>
|
||||
<RootNamespace>OpcUaServer.Server</RootNamespace>
|
||||
<AssemblyName>OpcUaServer.Server</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
|
||||
<TargetFrameworkVersion>v4.6.2</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
||||
<NuGetPackageImportStamp>
|
||||
|
||||
@@ -7,105 +7,198 @@ using System.Collections.Generic;
|
||||
|
||||
namespace OpcUaServer.Server
|
||||
{
|
||||
public class Server : StandardServer
|
||||
{
|
||||
private ServerNodeManager _serverNodeManager;
|
||||
private readonly IPrinter _printer;
|
||||
private readonly string _pathXml;
|
||||
private readonly ServerAuthenticationService _serverAuthenticationService;
|
||||
|
||||
/// <summary>
|
||||
/// Evento richiesta refresh invio dellos tato attuale delel conditions
|
||||
/// </summary>
|
||||
public event EventHandler eh_reqRefreshCondition;
|
||||
|
||||
public Server(IPrinter printer, string pathXml)
|
||||
public class Server : StandardServer
|
||||
{
|
||||
_printer = printer;
|
||||
_pathXml = pathXml;
|
||||
_serverAuthenticationService = new ServerAuthenticationService(this);
|
||||
}
|
||||
#region Private Fields
|
||||
|
||||
public void SetNodeValue(string nodeName, object value)
|
||||
{
|
||||
_serverNodeManager.SetNodeValue(nodeName, value);
|
||||
}
|
||||
private readonly string _pathXml;
|
||||
private readonly IPrinter _printer;
|
||||
private readonly ServerAuthenticationService _serverAuthenticationService;
|
||||
private ServerNodeManager _serverNodeManager;
|
||||
|
||||
public void ReportEvent(string nodeName, string eventMessage, string severity, string value, bool active)
|
||||
{
|
||||
_serverNodeManager.ReportEvent(nodeName, eventMessage, severity, value, active);
|
||||
}
|
||||
#endregion Private Fields
|
||||
|
||||
protected override MasterNodeManager CreateMasterNodeManager(IServerInternal server, ApplicationConfiguration configuration)
|
||||
{
|
||||
_printer.Print(">>>>> Server: Creating node manager");
|
||||
#region Public Fields
|
||||
|
||||
_serverNodeManager = new ServerNodeManager(server, configuration, _printer, new XmlNodeParser(), _pathXml);
|
||||
var nodeManagers = new List<INodeManager>
|
||||
/// <summary>
|
||||
/// Elenco dei nodi vietati ("P") per user non autenticati
|
||||
/// </summary>
|
||||
public static List<string> NodeVetoList = new List<string>();
|
||||
|
||||
#endregion Public Fields
|
||||
|
||||
#region Public Constructors
|
||||
|
||||
public Server(IPrinter printer, string pathXml)
|
||||
{
|
||||
_printer = printer;
|
||||
_pathXml = pathXml;
|
||||
_serverAuthenticationService = new ServerAuthenticationService(this);
|
||||
}
|
||||
|
||||
#endregion Public Constructors
|
||||
|
||||
#region Public Events
|
||||
|
||||
/// <summary>
|
||||
/// Evento richiesta refresh invio dellos tato attuale delel conditions
|
||||
/// </summary>
|
||||
public event EventHandler eh_reqRefreshCondition;
|
||||
|
||||
#endregion Public Events
|
||||
|
||||
#region Private Methods
|
||||
|
||||
private void SessionManager_ImpersonateUser(Session session, ImpersonateEventArgs args)
|
||||
{
|
||||
// check for a user name token.
|
||||
_printer.Print(">>>>> Server: Authentication for session starting");
|
||||
|
||||
switch (args.NewIdentity)
|
||||
{
|
||||
case UserNameIdentityToken userNameToken:
|
||||
args.Identity =
|
||||
_serverAuthenticationService.VerifyPassword(userNameToken,
|
||||
LoadServerProperties().ProductUri);
|
||||
_printer.Print(">>>>> Server: Authentication for session userNameToken Accepted: " + args.Identity.DisplayName);
|
||||
break;
|
||||
|
||||
case X509IdentityToken x509Token:
|
||||
_serverAuthenticationService.VerifyUserTokenCertificate(x509Token.Certificate,
|
||||
LoadServerProperties().ProductUri);
|
||||
args.Identity = new UserIdentity(x509Token);
|
||||
|
||||
_printer.Print(">>>>> Server: Authentication for session X509 Token Accepted: " +
|
||||
args.Identity.DisplayName);
|
||||
break;
|
||||
|
||||
default:
|
||||
_printer.Print(">>>>> Server: Authentication for session Anonymous: ");
|
||||
break;
|
||||
}
|
||||
// 2019.04.08: aggiunta task x forzare il refresh/reinvio di TUTTE le conditions attive al momento in cui si è connesso il NUOVO client...
|
||||
sendCurrCond();
|
||||
}
|
||||
|
||||
#endregion Private Methods
|
||||
|
||||
#region Protected Methods
|
||||
|
||||
protected override MasterNodeManager CreateMasterNodeManager(IServerInternal server, ApplicationConfiguration configuration)
|
||||
{
|
||||
_printer.Print(">>>>> Server: Creating node manager");
|
||||
|
||||
_serverNodeManager = new ServerNodeManager(server, configuration, _printer, new XmlNodeParser(), _pathXml);
|
||||
var nodeManagers = new List<INodeManager>
|
||||
{
|
||||
_serverNodeManager
|
||||
};
|
||||
|
||||
return new MasterNodeManager(server, configuration, null, nodeManagers.ToArray());
|
||||
return new MasterNodeManager(server, configuration, null, nodeManagers.ToArray());
|
||||
}
|
||||
|
||||
protected override ServerProperties LoadServerProperties()
|
||||
{
|
||||
var properties = new ServerProperties
|
||||
{
|
||||
ManufacturerName = "Steamware",
|
||||
ProductName = "Server",
|
||||
ProductUri = "http://opcfoundation.org/Quickstart/ReferenceServer/v1.03",
|
||||
SoftwareVersion = Utils.GetAssemblySoftwareVersion(),
|
||||
BuildNumber = Utils.GetAssemblyBuildNumber(),
|
||||
BuildDate = Utils.GetAssemblyTimestamp()
|
||||
};
|
||||
|
||||
return properties;
|
||||
}
|
||||
|
||||
protected override void OnServerStarted(IServerInternal server)
|
||||
{
|
||||
base.OnServerStarted(server);
|
||||
|
||||
server.SessionManager.ImpersonateUser += SessionManager_ImpersonateUser;
|
||||
}
|
||||
|
||||
#endregion Protected Methods
|
||||
|
||||
#region Public Methods
|
||||
|
||||
public override ResponseHeader Browse(RequestHeader requestHeader, ViewDescription view, uint requestedMaxReferencesPerNode, BrowseDescriptionCollection nodesToBrowse, out BrowseResultCollection results, out DiagnosticInfoCollection diagnosticInfos)
|
||||
{
|
||||
results = null;
|
||||
diagnosticInfos = null;
|
||||
|
||||
OperationContext context = ValidateRequest(requestHeader, RequestType.Browse);
|
||||
|
||||
try
|
||||
{
|
||||
if (nodesToBrowse == null || nodesToBrowse.Count == 0)
|
||||
{
|
||||
throw new ServiceResultException(StatusCodes.BadNothingToDo);
|
||||
}
|
||||
|
||||
bool filter = false;
|
||||
|
||||
// return empty browse results for Anonymous users
|
||||
// This logic should be further extended....
|
||||
if (context.UserIdentity.TokenType == UserTokenType.Anonymous)
|
||||
filter = true;
|
||||
|
||||
// legge gli oggetti contenuti nell'elemento richeisto
|
||||
ServerInternal.NodeManager.Browse(context, view, requestedMaxReferencesPerNode, nodesToBrowse, out results, out diagnosticInfos);
|
||||
|
||||
// se attivato il filtro == utente anonimo
|
||||
if (filter)
|
||||
{
|
||||
foreach (var res in results)
|
||||
{
|
||||
// rimuove tutto tranne status...
|
||||
//res.References.RemoveAll(x => x.BrowseName.Name.StartsWith("Machine/") && x.BrowseName.Name != "Machine/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/") && NodeVetoList.Contains(x.BrowseName.Name));
|
||||
}
|
||||
}
|
||||
|
||||
return CreateResponse(requestHeader, context.StringTable);
|
||||
}
|
||||
catch (ServiceResultException e)
|
||||
{
|
||||
lock (ServerInternal.DiagnosticsWriteLock)
|
||||
{
|
||||
ServerInternal.ServerDiagnostics.RejectedRequestsCount++;
|
||||
|
||||
if (IsSecurityError(e.StatusCode))
|
||||
{
|
||||
ServerInternal.ServerDiagnostics.SecurityRejectedRequestsCount++;
|
||||
}
|
||||
}
|
||||
|
||||
throw TranslateException(context, e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
OnRequestComplete(context);
|
||||
}
|
||||
}
|
||||
|
||||
public void ReportEvent(string nodeName, string eventMessage, string severity, string value, bool active)
|
||||
{
|
||||
_serverNodeManager.ReportEvent(nodeName, eventMessage, severity, value, active);
|
||||
}
|
||||
|
||||
public void sendCurrCond()
|
||||
{
|
||||
if (eh_reqRefreshCondition != null)
|
||||
{
|
||||
eh_reqRefreshCondition(this, new EventArgs());
|
||||
}
|
||||
}
|
||||
|
||||
public void SetNodeValue(string nodeName, object value)
|
||||
{
|
||||
_serverNodeManager.SetNodeValue(nodeName, value);
|
||||
}
|
||||
|
||||
#endregion Public Methods
|
||||
}
|
||||
|
||||
protected override ServerProperties LoadServerProperties()
|
||||
{
|
||||
var properties = new ServerProperties
|
||||
{
|
||||
ManufacturerName = "Steamware",
|
||||
ProductName = "Server",
|
||||
ProductUri = "http://opcfoundation.org/Quickstart/ReferenceServer/v1.03",
|
||||
SoftwareVersion = Utils.GetAssemblySoftwareVersion(),
|
||||
BuildNumber = Utils.GetAssemblyBuildNumber(),
|
||||
BuildDate = Utils.GetAssemblyTimestamp()
|
||||
};
|
||||
|
||||
return properties;
|
||||
}
|
||||
|
||||
protected override void OnServerStarted(IServerInternal server)
|
||||
{
|
||||
base.OnServerStarted(server);
|
||||
|
||||
server.SessionManager.ImpersonateUser += SessionManager_ImpersonateUser;
|
||||
}
|
||||
|
||||
private void SessionManager_ImpersonateUser(Session session, ImpersonateEventArgs args)
|
||||
{
|
||||
// check for a user name token.
|
||||
_printer.Print(">>>>> Server: Authentication for session starting");
|
||||
|
||||
switch (args.NewIdentity)
|
||||
{
|
||||
case UserNameIdentityToken userNameToken:
|
||||
args.Identity =
|
||||
_serverAuthenticationService.VerifyPassword(userNameToken,
|
||||
LoadServerProperties().ProductUri);
|
||||
_printer.Print(">>>>> Server: Authentication for session userNameToken Accepted: " + args.Identity.DisplayName);
|
||||
break;
|
||||
case X509IdentityToken x509Token:
|
||||
_serverAuthenticationService.VerifyUserTokenCertificate(x509Token.Certificate,
|
||||
LoadServerProperties().ProductUri);
|
||||
args.Identity = new UserIdentity(x509Token);
|
||||
|
||||
_printer.Print(">>>>> Server: Authentication for session X509 Token Accepted: " +
|
||||
args.Identity.DisplayName);
|
||||
break;
|
||||
default:
|
||||
_printer.Print(">>>>> Server: Authentication for session Anonymous: ");
|
||||
break;
|
||||
}
|
||||
// 2019.04.08: aggiunta task x forzare il refresh/reinvio di TUTTE le conditions attive al momento in cui si è connesso il NUOVO client...
|
||||
sendCurrCond();
|
||||
}
|
||||
|
||||
public void sendCurrCond()
|
||||
{
|
||||
if(eh_reqRefreshCondition!=null)
|
||||
{
|
||||
eh_reqRefreshCondition(this, new EventArgs());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,18 +1,37 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
using Opc.Ua;
|
||||
using OpcUaCommon.Services;
|
||||
|
||||
namespace OpcUaServer.Server.Services
|
||||
{
|
||||
public class ServerAuthenticationService
|
||||
{
|
||||
#region Private Fields
|
||||
|
||||
private readonly Server _server;
|
||||
|
||||
#endregion Private Fields
|
||||
|
||||
#region Public Constructors
|
||||
|
||||
public ServerAuthenticationService(Server server)
|
||||
{
|
||||
_server = server;
|
||||
}
|
||||
|
||||
#endregion Public Constructors
|
||||
|
||||
#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;
|
||||
@@ -37,9 +56,16 @@ namespace OpcUaServer.Server.Services
|
||||
// return new SystemConfigurationIdentity(new UserIdentity(userNameToken));
|
||||
//}
|
||||
|
||||
// user / passphrase / pwd
|
||||
// 9206 / 9206_6029 / lH01JCwOzgPG5zjl26p1qA==
|
||||
|
||||
// standard users for CTT verification
|
||||
if ((userName == "user1" && password == "password") ||
|
||||
(userName == "user2" && password == "password1")) return new UserIdentity(userNameToken);
|
||||
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.
|
||||
var info = new TranslationInfo(
|
||||
"InvalidPassword",
|
||||
@@ -53,7 +79,6 @@ namespace OpcUaServer.Server.Services
|
||||
"InvalidPassword",
|
||||
productUri,
|
||||
new LocalizedText(info)));
|
||||
|
||||
}
|
||||
|
||||
public void VerifyUserTokenCertificate(X509Certificate2 certificate, string productUri)
|
||||
@@ -104,5 +129,6 @@ namespace OpcUaServer.Server.Services
|
||||
}
|
||||
}
|
||||
|
||||
#endregion Public Methods
|
||||
}
|
||||
}
|
||||
@@ -10,6 +10,12 @@ namespace OpcUaServer.Server.Services
|
||||
{
|
||||
public class XmlNodeParser : INodeParser
|
||||
{
|
||||
#region Public Properties
|
||||
|
||||
public Server Server { get; }
|
||||
|
||||
#endregion Public Properties
|
||||
|
||||
#region Private Methods
|
||||
|
||||
private static int GetValueRankFromString(string valueRank)
|
||||
@@ -38,11 +44,15 @@ namespace OpcUaServer.Server.Services
|
||||
|
||||
var varName = component.Attributes["BrowseName"].Value;
|
||||
var symbolicName = component.Attributes["SymbolicName"].Value;
|
||||
var baseObjectState = CreateCondition(root, rootName + "/" + symbolicName, symbolicName, varName, component.Attributes["Type"].Value,
|
||||
var bName = rootName + "/" + symbolicName;
|
||||
var baseObjectState = CreateCondition(root, bName, symbolicName, varName, component.Attributes["Type"].Value,
|
||||
nameSpaceIndex);
|
||||
|
||||
treeInstance.Variables.Add(rootName + "/" + symbolicName,
|
||||
treeInstance.Variables.Add(bName,
|
||||
baseObjectState);
|
||||
|
||||
// verifico se l'elemento sia di quelli permessi --> metto in lista...
|
||||
string VGroup = component.Attributes["VGroup"]?.Value ?? "A";
|
||||
checkVisibGroup(VGroup, bName);
|
||||
}
|
||||
|
||||
private void AddEvent(FolderInstanceState treeInstance, ushort nameSpaceIndex, XmlNode component, string rootName, FolderState root)
|
||||
@@ -69,13 +79,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;
|
||||
@@ -96,6 +99,11 @@ namespace OpcUaServer.Server.Services
|
||||
{
|
||||
CreateFolder(folder, stringFolderName + "/" + varName, varName, xmlElement, stringFolderName, folderInstanceState, nameSpaceIndex);
|
||||
}
|
||||
|
||||
// verifico se l'elemento sia di quelli permessi --> metto in lista...
|
||||
string VGroup = xmlElement.Attributes["VGroup"]?.Value ?? "A";
|
||||
string bName = stringFolderName + "/" + varName;
|
||||
checkVisibGroup(VGroup, bName);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -159,6 +167,10 @@ namespace OpcUaServer.Server.Services
|
||||
treeInstance.Variables.Add(bName,
|
||||
CreateVariable(parent, bName, bName, bName, type, rank,
|
||||
nameSpaceIndex));
|
||||
|
||||
// verifico se l'elemento sia di quelli permessi --> metto in lista...
|
||||
string VGroup = component.Attributes["VGroup"]?.Value ?? "A";
|
||||
checkVisibGroup(VGroup, bName);
|
||||
}
|
||||
|
||||
private void AddVariable(FolderInstanceState treeInstance, ushort nameSpaceIndex, XmlNode component,
|
||||
@@ -177,11 +189,24 @@ namespace OpcUaServer.Server.Services
|
||||
var valueRank = component.Attributes["ValueRank"].Value;
|
||||
var builtInType = (uint)GetBuiltInTypeFromString(dataType);
|
||||
var valueRankFromString = GetValueRankFromString(valueRank);
|
||||
var baseDataVariableState = CreateVariable(root, rootName + "/" + symbolicName, symbolicName, varName, builtInType, valueRankFromString,
|
||||
var bName = rootName + "/" + symbolicName;
|
||||
var baseDataVariableState = CreateVariable(root, bName, symbolicName, varName, builtInType, valueRankFromString,
|
||||
nameSpaceIndex);
|
||||
|
||||
treeInstance.Variables.Add(rootName + "/" + symbolicName,
|
||||
treeInstance.Variables.Add(bName,
|
||||
baseDataVariableState);
|
||||
|
||||
// verifico se l'elemento sia di quelli permessi --> metto in lista...
|
||||
string VGroup = component.Attributes["VGroup"]?.Value ?? "A";
|
||||
checkVisibGroup(VGroup, bName);
|
||||
}
|
||||
|
||||
private void checkVisibGroup(string VGroup, string BrowseName)
|
||||
{
|
||||
if (VGroup != "A")
|
||||
{
|
||||
Server.NodeVetoList.Add(BrowseName);
|
||||
}
|
||||
}
|
||||
|
||||
private BaseObjectState CreateCondition(NodeState parent, string path, string symbolicName, string name, string conditiontype, ushort nameSpaceIndex)
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>SOUR.Core</RootNamespace>
|
||||
<AssemblyName>SOUR.Core</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
|
||||
<TargetFrameworkVersion>v4.6.2</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
|
||||
@@ -5,6 +5,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Configuration;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace SOUR.Core.Services
|
||||
{
|
||||
@@ -498,7 +499,7 @@ namespace SOUR.Core.Services
|
||||
/// <returns></returns>
|
||||
public long ListLen(string queueName)
|
||||
{
|
||||
return connRedis.GetDatabase().ListLength((RedisKey)queueName);
|
||||
return currDB.ListLength((RedisKey)queueName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -508,7 +509,7 @@ namespace SOUR.Core.Services
|
||||
/// <returns></returns>
|
||||
public string ListPop(string queueName)
|
||||
{
|
||||
return connRedis.GetDatabase().ListLeftPop((RedisKey)queueName).ToString();
|
||||
return currDB.ListLeftPop((RedisKey)queueName).ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -518,7 +519,7 @@ namespace SOUR.Core.Services
|
||||
/// <returns></returns>
|
||||
public void ListPush(string queueName, string value)
|
||||
{
|
||||
connRedis.GetDatabase().ListRightPush((RedisKey)queueName, (RedisValue)value);
|
||||
currDB.ListRightPush((RedisKey)queueName, (RedisValue)value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1076,9 +1077,29 @@ namespace SOUR.Core.Services
|
||||
public bool setRKeys(KeyValuePair<RedisKey, RedisValue>[] valori)
|
||||
{
|
||||
bool answ = false;
|
||||
// calcolo i valori "buoni" per evitare eccezione dei nulli in caso di area redis che scompaia
|
||||
List<KeyValuePair<RedisKey, RedisValue>> valList = new List<KeyValuePair<RedisKey, RedisValue>>();
|
||||
foreach (var item in valori)
|
||||
{
|
||||
if (!item.Value.IsNull)
|
||||
{
|
||||
valList.Add(item);
|
||||
}
|
||||
else
|
||||
{ }
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
currDB.StringSet(valori);
|
||||
// se le numerosità non corrispondono --> scrivo solo i "buoni"
|
||||
if (valori.Count() != valList.Count)
|
||||
{
|
||||
currDB.StringSet(valList.ToArray());
|
||||
}
|
||||
else
|
||||
{
|
||||
currDB.StringSet(valori);
|
||||
}
|
||||
answ = true;
|
||||
}
|
||||
catch (Exception exc)
|
||||
@@ -1163,7 +1184,7 @@ namespace SOUR.Core.Services
|
||||
/// <returns></returns>
|
||||
public long StackLen(string stackName)
|
||||
{
|
||||
return connRedis.GetDatabase().ListLength((RedisKey)stackName);
|
||||
return currDB.ListLength((RedisKey)stackName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1173,7 +1194,7 @@ namespace SOUR.Core.Services
|
||||
/// <returns></returns>
|
||||
public string StackPop(string stackName)
|
||||
{
|
||||
return connRedis.GetDatabase().ListRightPop((RedisKey)stackName).ToString();
|
||||
return currDB.ListRightPop((RedisKey)stackName).ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1183,7 +1204,7 @@ namespace SOUR.Core.Services
|
||||
/// <param name="value"></param>
|
||||
public void StackPush(string stackName, string value)
|
||||
{
|
||||
connRedis.GetDatabase().ListRightPush((RedisKey)stackName, (RedisValue)value);
|
||||
currDB.ListRightPush((RedisKey)stackName, (RedisValue)value);
|
||||
}
|
||||
|
||||
#endregion Public Methods
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -17,7 +17,6 @@
|
||||
<add key="waitResendCondition" value="1500" />
|
||||
<add key="waitEventDequeue" value="1000" />
|
||||
<add key="simRequeue" value="true" />
|
||||
|
||||
<!--Gestione allarmi: modo tra TEXT / LIST-->
|
||||
<add key="AlarmListMode" value="LIST" />
|
||||
<!--Indica se allarmi statici (=true) oppure da rileggere SEMPRE da REDIS (=false) -->
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
<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">
|
||||
<Variable SymbolicName="Production" BrowseName="Production" DataType="ua:String" ValueRank="Scalar" Units="" SGroup="1" VGroup="P" />
|
||||
<Variable SymbolicName="Production" BrowseName="Production" DataType="ua:String" ValueRank="Scalar" Units="" SGroup="1" />
|
||||
<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" />
|
||||
<Variable SymbolicName="Downtimes" BrowseName="Downtimes" DataType="ua:String" ValueRank="Scalar" Units="" SGroup="1" VGroup="P" />
|
||||
@@ -22,7 +22,7 @@
|
||||
<Property SymbolicName="Name" BrowseName="Name" DataType="ua:String" ValueRank="Scalar" Value="OSAI" />
|
||||
<Property SymbolicName="Version" BrowseName="Version" DataType="ua:String" ValueRank="Scalar" Value="2019" />
|
||||
<Condition SymbolicName="Condition" BrowseName="Condition" DataType="ua:String" ValueRank="Scalar" Type="OffNormalAlarmState" Units="" />
|
||||
<Component Name="CncProcesses">
|
||||
<Component Name="CncProcesses" VGroup="P">
|
||||
<Component Name="01">
|
||||
<Variable SymbolicName="Type" BrowseName="Type" DataType="ua:String" ValueRank="Scalar" Units="Enum" />
|
||||
<Variable SymbolicName="CodG" BrowseName="CodG" DataType="ua:String" ValueRank="Scalar" Units="" SGroup="2" VGroup="P" />
|
||||
@@ -41,12 +41,12 @@
|
||||
</Component>
|
||||
</Component>
|
||||
</Component>
|
||||
<Component Name="Plc">
|
||||
<Component Name="Plc" VGroup="P">
|
||||
<Property SymbolicName="Name" BrowseName="Name" DataType="ua:String" ValueRank="Scalar" Value="SIEMENS" />
|
||||
<Property SymbolicName="Version" BrowseName="Version" DataType="ua:String" ValueRank="Scalar" Value="2019" />
|
||||
<Condition SymbolicName="Condition" BrowseName="Condition" DataType="ua:String" ValueRank="Scalar" Type="OffNormalAlarmState" Units="" />
|
||||
</Component>
|
||||
<Component Name="Hmi">
|
||||
<Component Name="Hmi" VGroup="P">
|
||||
<Property SymbolicName="Name" BrowseName="Name" DataType="ua:String" ValueRank="Scalar" Value="CMS Active" />
|
||||
<Property SymbolicName="Version" BrowseName="Version" DataType="ua:String" ValueRank="Scalar" Value="1.00.02" />
|
||||
<Condition SymbolicName="Condition" BrowseName="Condition" DataType="ua:String" ValueRank="Scalar" Type="OffNormalAlarmState" Units="" />
|
||||
@@ -55,7 +55,7 @@
|
||||
<Variable SymbolicName="ActiveSection" BrowseName="ActiveSection" DataType="ua:String" ValueRank="Scalar" Units="h" />
|
||||
<Variable SymbolicName="ActiveTimeSession" BrowseName="ActiveTimeSession" DataType="ua:String" ValueRank="Scalar" Units="" />
|
||||
</Component>
|
||||
<Component Name="Axes">
|
||||
<Component Name="Axes" VGroup="P">
|
||||
<Component Name="01">
|
||||
<Property SymbolicName="Type" BrowseName="Type" DataType="ua:String" ValueRank="Scalar" Value="LINEAR" />
|
||||
<Variable SymbolicName="Name" BrowseName="Name" DataType="ua:String" ValueRank="Scalar" Units="Enum" />
|
||||
@@ -159,7 +159,7 @@
|
||||
<Variable SymbolicName="ParentProc" BrowseName="ParentProc" DataType="ua:UInt32" ValueRank="Scalar" Units="" />
|
||||
</Component>
|
||||
</Component>
|
||||
<Component Name="OperatingGroups">
|
||||
<Component Name="OperatingGroups" VGroup="P">
|
||||
<Component Name="01">
|
||||
<Property SymbolicName="Type" BrowseName="Type" DataType="ua:String" ValueRank="Scalar" Value="SPINDLE" />
|
||||
<Property SymbolicName="Model" BrowseName="Model" DataType="ua:String" ValueRank="Scalar" Value="CMS-SPINDLE-01" />
|
||||
@@ -174,7 +174,7 @@
|
||||
<Variable SymbolicName="ParentProc" BrowseName="ParentProc" DataType="ua:UInt32" ValueRank="Scalar" Units="" />
|
||||
</Component>
|
||||
</Component>
|
||||
<Component Name="AuxiliaryGroups">
|
||||
<Component Name="AuxiliaryGroups" VGroup="P">
|
||||
<Component Name="01">
|
||||
<Property SymbolicName="Type" BrowseName="Type" DataType="ua:String" ValueRank="Scalar" Value="LUBRO" />
|
||||
<Variable SymbolicName="Repetitions" BrowseName="Repetitions" DataType="ua:Float" ValueRank="Scalar" Units="Count" CmsDataType="CounterList" CmsDataIndex="021" CmsDataOpt="NUM" />
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
<body>
|
||||
<i>Server gestione Scehde di Collaudo</i>
|
||||
<h4>Versione: {{CURRENT-REL}}</h4>
|
||||
<br />
|
||||
Note di rilascio:
|
||||
<ul>
|
||||
<li>
|
||||
<b>Ultime modifiche:</b>
|
||||
<ul>{{LAST-CHANGES}}</ul>
|
||||
</li>
|
||||
<li>
|
||||
<b>v.3.1.* →</b>
|
||||
<ul>
|
||||
<li>Revisione ruoli</li>
|
||||
<li>Gestione fasi con revisione e congelamento fasi</li>
|
||||
<li>Nuovi elementi schede di collaudo</li>
|
||||
<li>Implementazione sistema traduzione in campi schede/misure/parametri</li>
|
||||
<li>Sistemi supporto traduzione/visualizzazione in lingua</li>
|
||||
<li>Nuovi reports</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
<b>v.2.* →</b>
|
||||
<ul>
|
||||
<li>Implementazione modifiche per gestione in CMS</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
<b>v.1.* →</b>
|
||||
<ul>
|
||||
<li>Implementazione iniziale con gestione standard Ms AX + ISO9000 e succ</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<div>
|
||||
<div style="float: left;">
|
||||
<img src="logoSteamware.png" />
|
||||
</div>
|
||||
<div style="float: right;">
|
||||
<a href="https://www.steamware.net/IOT" target="_blank">© Steamware 2006-2018</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 3.3 KiB |
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<item>
|
||||
<version>1.0.0.0</version>
|
||||
<url>http://seriate.steamware.net:8083/SWS/CMS_SC/{{PACKNAME}}/{{BRANCHNAME}}/{{PACKNAME}}.zip</url>
|
||||
<changelog>http://seriate.steamware.net:8083/SWS/CMS_SC/{{PACKNAME}}/{{BRANCHNAME}}/ChangeLog.html</changelog>
|
||||
<mandatory>false</mandatory>
|
||||
</item>
|
||||
@@ -9,7 +9,7 @@
|
||||
<OutputType>Exe</OutputType>
|
||||
<RootNamespace>SOUR</RootNamespace>
|
||||
<AssemblyName>SOUR</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
|
||||
<TargetFrameworkVersion>v4.6.2</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
||||
<NuGetPackageImportStamp>
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
<OutputType>WinExe</OutputType>
|
||||
<RootNamespace>TestApp</RootNamespace>
|
||||
<AssemblyName>TestApp</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
|
||||
<TargetFrameworkVersion>v4.6.2</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
||||
<Deterministic>true</Deterministic>
|
||||
|
||||
Reference in New Issue
Block a user