コード例 #1
0
        /// <summary>
        /// Process a command line of the console sample application.
        /// </summary>
        public static string ProcessCommandLine(
            TextWriter output,
            string[] args,
            Mono.Options.OptionSet options,
            ref bool showHelp,
            bool noExtraArgs = true)
        {
            IList <string> extraArgs = null;

            try
            {
                extraArgs = options.Parse(args);
                if (noExtraArgs)
                {
                    foreach (string extraArg in extraArgs)
                    {
                        output.WriteLine("Error: Unknown option: {0}", extraArg);
                        showHelp = true;
                    }
                }
            }
            catch (OptionException e)
            {
                output.WriteLine(e.Message);
                showHelp = true;
            }

            if (showHelp)
            {
                options.WriteOptionDescriptions(output);
                throw new ErrorExitException("Invalid Commandline or help requested.", ExitCode.ErrorInvalidCommandLine);
            }

            return(extraArgs.FirstOrDefault());
        }
コード例 #2
0
ファイル: bingo.cs プロジェクト: lanzkron/bingo
        static void Main(string[] args)
        {
            var    options = new Options(4);
            string file    = "bingo.txt";
            string dir     = ".";
            uint   count   = 30;
            bool   rtl     = false;

            var opts = new Mono.Options.OptionSet {
                { "title=", "title of the bingo cards", t => options.title = t },
                { "file=", "text file containing the values to put in the bingo cells (an answer to a line)", f => file = f },
                { "center=", "value to be entered in center tile of all cards", c => options.center = c },
                { "size=", "dimensions of the bingo cards", s => options.size = UInt32.Parse(s) },
                { "count=", "number of bingo cards to create", c => count = UInt32.Parse(c) },
                { "rtl", "create Right To Left cards", x => rtl = true },
            };

            try
            {
                opts.Parse(args);
            }
            catch (OptionException e) {
                Console.WriteLine(e.Message);
                return;
            }

            if (options.center != null)
            {
                if ((options.size & 1) != 1)
                {
                    Console.WriteLine("Center should only be specified with odd sized cards");
                    return;
                }
            }

            var words = new List <string>();

            using (var r = new System.IO.StreamReader(Path.Combine(dir, file)))
            {
                while (!r.EndOfStream)
                {
                    string line = r.ReadLine();
                    if (!String.IsNullOrWhiteSpace(line))
                    {
                        words.Add(line);
                    }
                }
            }
            Console.WriteLine("Read {0} lines from {1}", words.Count, file);

            using (var w = new System.IO.StreamWriter(Path.Combine(dir, "output.html"), false, Encoding.UTF8))
            {
                writeCards(w, options, words, dir, count, rtl);
            }

            Console.WriteLine("done");
        }
コード例 #3
0
        public static int Main(string[] args)
        {
            Console.WriteLine(
                (Utils.IsRunningOnMono() ? "Mono" : ".Net Core") +
                " OPC UA Console Server sample");

            // command line options
            bool   showHelp                = false;
            int    stopTimeout             = 0;
            bool   autoAccept              = false;
            string reverseConnectUrlString = null;
            Uri    reverseConnectUrl       = null;

            Mono.Options.OptionSet options = new Mono.Options.OptionSet {
                { "h|help", "show this message and exit", h => showHelp = h != null },
                { "a|autoaccept", "auto accept certificates (for testing only)", a => autoAccept = a != null },
                { "t|timeout=", "the number of seconds until the server stops.", (int t) => stopTimeout = t },
                { "r|reverse=", "a url for a reverse connection", (string r) => reverseConnectUrlString = r }
            };

            try
            {
                IList <string> extraArgs = options.Parse(args);
                foreach (string extraArg in extraArgs)
                {
                    Console.WriteLine("Error: Unknown option: {0}", extraArg);
                    showHelp = true;
                }
                if (reverseConnectUrlString != null)
                {
                    reverseConnectUrl = new Uri(reverseConnectUrlString);
                }
            }
            catch (OptionException e)
            {
                Console.WriteLine(e.Message);
                showHelp = true;
            }

            if (showHelp)
            {
                Console.WriteLine(Utils.IsRunningOnMono() ? "Usage: mono NetCoreConsoleServer.exe [OPTIONS]" : "Usage: dotnet NetCoreConsoleServer.dll [OPTIONS]");
                Console.WriteLine();

                Console.WriteLine("Options:");
                options.WriteOptionDescriptions(Console.Out);
                return((int)ExitCode.ErrorInvalidCommandLine);
            }

            MySampleServer server = new MySampleServer(autoAccept, stopTimeout, reverseConnectUrl);

            server.Run();

            return((int)MySampleServer.ExitCode);
        }
コード例 #4
0
ファイル: Program.cs プロジェクト: Hpshboss/OpcuaCncControl
        public static int Main(string[] args)
        {
            #region Open a thread for pipeServer
            int      i;
            Thread[] servers = new Thread[Globals.numberThreads];

            Console.WriteLine("Waiting for client connect...\n");
            for (i = 0; i < Globals.numberThreads; i++)
            {
                servers[i] = new Thread(PipeServerThread);
                servers[i].Start();
            }
            #endregion
            Console.WriteLine("{0} OPC UA Reference Server", Utils.IsRunningOnMono() ? "Mono" : ".Net Core");

            // command line options
            bool showHelp   = false;
            bool autoAccept = false;

            Mono.Options.OptionSet options = new Mono.Options.OptionSet {
                { "h|help", "show this message and exit", h => showHelp = h != null },
                { "a|autoaccept", "auto accept certificates (for testing only)", a => autoAccept = a != null }
            };

            try
            {
                IList <string> extraArgs = options.Parse(args);
                foreach (string extraArg in extraArgs)
                {
                    Console.WriteLine("Error: Unknown option: {0}", extraArg);
                    showHelp = true;
                }
            }
            catch (OptionException e)
            {
                Console.WriteLine(e.Message);
                showHelp = true;
            }

            if (showHelp)
            {
                Console.WriteLine(Utils.IsRunningOnMono() ? "Usage: mono MonoReferenceServer.exe [OPTIONS]" : "Usage: dotnet ConsoleReferenceServer.dll [OPTIONS]");
                Console.WriteLine();

                Console.WriteLine("Options:");
                options.WriteOptionDescriptions(Console.Out);
                return((int)ExitCode.ErrorInvalidCommandLine);
            }

            MyRefServer server = new MyRefServer(autoAccept);
            server.Run();

            return((int)MyRefServer.ExitCode);
        }
コード例 #5
0
    public static async Task <int> MainAsync(string[] args)
    {
        string tests                = "";
        string correlationId        = "";
        string correlationIdFile    = "";
        bool   waitForJobCompletion = false;

        var options = new Mono.Options.OptionSet {
            { "tests=", "Tests to run", param => { if (param != null)
                                                   {
                                                       tests = param;
                                                   }
              } },
            { "correlationIdFile=", "File to write correlation ID to", param => { if (param != null)
                                                                                  {
                                                                                      correlationIdFile = param;
                                                                                  }
              } },
            { "wait=", "Wait for job to complete", param => {  if(param != null)
                                                              {
                                                                  correlationId = param; waitForJobCompletion = true;
                                                              } } },
        };

        try {
            options.Parse(args);
        } catch (Mono.Options.OptionException e) {
            Console.WriteLine("Option error: {0}", e.Message);
            return(1);
        }

        if (tests == "mainline" || tests == "mainline-cxx")
        {
            var t = new MainlineTests(tests);
            correlationId = await t.CreateJob().SendJob();

            if (!String.IsNullOrEmpty(correlationIdFile))
            {
                File.WriteAllText(correlationIdFile, correlationId);
            }

            return(0);
        }

        if (waitForJobCompletion)
        {
            var success = await new HelixBase().WaitForJobCompletion(correlationId);
            return(success ? 0 : 1);
        }

        Console.Error.WriteLine("Error: Invalid arguments.");
        return(1);
    }
コード例 #6
0
        public static async Task <int> Main(string[] args)
        {
            Console.WriteLine("{0} OPC UA Reference Server", Utils.IsRunningOnMono() ? "Mono" : ".Net Core");

            // command line options
            bool   showHelp   = false;
            bool   autoAccept = false;
            bool   console    = false;
            string password   = null;

            Mono.Options.OptionSet options = new Mono.Options.OptionSet {
                { "h|help", "show this message and exit", h => showHelp = h != null },
                { "a|autoaccept", "auto accept certificates (for testing only)", a => autoAccept = a != null },
                { "c|console", "log trace to console", c => console = c != null },
                { "p|password="******"optional password for private key", (string p) => password = p }
            };

            try
            {
                IList <string> extraArgs = options.Parse(args);
                foreach (string extraArg in extraArgs)
                {
                    Console.WriteLine("Error: Unknown option: {0}", extraArg);
                    showHelp = true;
                }
            }
            catch (OptionException e)
            {
                Console.WriteLine(e.Message);
                showHelp = true;
            }

            if (showHelp)
            {
                Console.WriteLine(Utils.IsRunningOnMono() ? "Usage: mono MonoReferenceServer.exe [OPTIONS]" : "Usage: dotnet ConsoleReferenceServer.dll [OPTIONS]");
                Console.WriteLine();

                Console.WriteLine("Options:");
                options.WriteOptionDescriptions(Console.Out);
                return((int)ExitCode.ErrorInvalidCommandLine);
            }

            var server = new MyRefServer()
            {
                AutoAccept = autoAccept,
                LogConsole = console,
                Password   = password
            };
            await server.Run().ConfigureAwait(false);

            return((int)server.ExitCode);
        }
コード例 #7
0
        static void Main(string[] args)
        {
            var shouldShowHelp = false;

            var nodesetFile     = default(string);
            var ns              = default(string);
            var assembliesNames = new List <string>();

            var p = new Mono.Options.OptionSet {
                { "f|nodeset=", "the nodeset file", f => nodesetFile = f },
                { "n|namespace=", "the .NET namespace.", n => ns = n },
                { "a|additional-assemblies=", "the .NET namespace.", a => assembliesNames.Add(a) },
                { "h|help", "show this message and exit", h => shouldShowHelp = h != null },
            };

            try
            {
                p.Parse(args);
            }
            catch (OptionException e)
            {
                Console.Write("UaTypeGenerator.exe: ");
                Console.WriteLine(e.Message);
                Console.WriteLine("Try `UaTypeGenerator.exe --help' for more information.");
                return;
            }

            if (shouldShowHelp)
            {
                ShowHelp(p);
                return;
            }

            var assemblies = assembliesNames
                             .Select(n => Assembly.LoadFrom(n))
                             .Prepend(typeof(OpenSecureChannelRequest).Assembly)
                             .ToArray();

            var nodeset = ReadNodeSet(nodesetFile);

            var typeset    = new TypeSet(nodeset, assemblies);
            var typewriter = new TypeSetWriter(typeset, ns);

            var outputFile = Path.ChangeExtension(nodesetFile, ".cs");

            using (var writer = File.CreateText(outputFile))
            {
                var intendedWriter = new IndentedTextWriter(writer);
                typewriter.Write(intendedWriter);
            }
        }
コード例 #8
0
        public static int Main(string[] args)
        {
            Console.WriteLine(Name);

            // command line options
            bool showHelp        = false;
            var  opcVaultOptions = new OpcVaultApiOptions();
            var  azureADOptions  = new OpcVaultAzureADOptions();

            Mono.Options.OptionSet options = new Mono.Options.OptionSet {
                { "v|vault=", "OpcVault Url", g => opcVaultOptions.BaseAddress = g },
                { "r|resource=", "OpcVault Resource Id", r => opcVaultOptions.ResourceId = r },
                { "c|clientid=", "AD Client Id", c => azureADOptions.ClientId = c },
                { "s|secret=", "AD Client Secret", s => azureADOptions.ClientSecret = s },
                { "a|authority=", "Authority", a => azureADOptions.Authority = a },
                { "t|tenantid=", "Tenant Id", t => azureADOptions.TenantId = t },
                { "h|help", "show this message and exit", h => showHelp = h != null },
            };

            try
            {
                IList <string> extraArgs = options.Parse(args);
                foreach (string extraArg in extraArgs)
                {
                    Console.WriteLine("Error: Unknown option: {0}", extraArg);
                    showHelp = true;
                }
            }
            catch (OptionException e)
            {
                Console.WriteLine(e.Message);
                showHelp = true;
            }

            if (showHelp)
            {
                Console.WriteLine("Usage: dotnet Microsoft.Azure.IIoT.OpcUa.Modules.Vault.dll [OPTIONS]");
                Console.WriteLine();

                Console.WriteLine("Options:");
                options.WriteOptionDescriptions(Console.Out);
                return((int)ExitCode.ErrorInvalidCommandLine);
            }

            var server = new VaultGlobalDiscoveryServer();

            server.Run(opcVaultOptions, azureADOptions);

            return((int)VaultGlobalDiscoveryServer.ExitCode);
        }
コード例 #9
0
        public static int Main(string[] args)
        {
            Console.WriteLine("OPC UA Reference Server.Net Core");

            // command line options
            bool showHelp   = false;
            bool autoAccept = false;
            bool console    = false;

            Mono.Options.OptionSet options = new Mono.Options.OptionSet {
                { "h|help", "show this message and exit", h => showHelp = h != null },
                { "a|autoaccept", "auto accept certificates (for testing only)", a => autoAccept = a != null },
                { "c|console", "log trace to console", c => console = c != null }
            };

            try
            {
                IList <string> extraArgs = options.Parse(args);
                foreach (string extraArg in extraArgs)
                {
                    Console.WriteLine("Error: Unknown option: {0}", extraArg);
                    showHelp = true;
                }
            }
            catch (OptionException e)
            {
                Console.WriteLine(e.Message);
                showHelp = true;
            }

            if (showHelp)
            {
                Console.WriteLine("Usage: dotnet ConsoleReferenceServer.dll [OPTIONS]");
                Console.WriteLine();

                Console.WriteLine("Options:");
                options.WriteOptionDescriptions(Console.Out);
                return((int)ExitCode.ErrorInvalidCommandLine);
            }

            MyRefServer server = new MyRefServer(autoAccept, console);

            server.Run();

            return((int)MyRefServer.ExitCode);
        }
コード例 #10
0
        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        public static int Main(string[] args)
        {
            Console.WriteLine("SampleCompany {0} OPC UA Sample Server", Utils.IsRunningOnMono() ? "Mono" : ".NET Core");

            // command line options
            var showHelp    = false;
            var stopTimeout = 0;
            var autoAccept  = false;

            var options = new Mono.Options.OptionSet {
                { "h|help", "show this message and exit", h => showHelp = h != null },
                { "a|autoaccept", "auto accept certificates (for testing only)", a => autoAccept = a != null },
                { "t|timeout=", "the number of seconds until the server stops.", (int t) => stopTimeout = t },
            };

            try
            {
                IList <string> extraArgs = options.Parse(args);
                foreach (var extraArg in extraArgs)
                {
                    Console.WriteLine("Error: Unknown option: {0}", extraArg);
                    showHelp = true;
                }
            }
            catch (OptionException e)
            {
                Console.WriteLine(e.Message);
                showHelp = true;
            }

            if (showHelp)
            {
                Console.WriteLine(Utils.IsRunningOnMono() ? "Usage: mono SampleCompany.SampleServer.exe [OPTIONS]" : "Usage: dotnet SampleCompany.SampleServer.dll [OPTIONS]");
                Console.WriteLine();

                Console.WriteLine("Options:");
                options.WriteOptionDescriptions(Console.Out);
                return((int)ExitCode.ErrorInvalidCommandLine);
            }

            var server = new MySampleServer(autoAccept, stopTimeout);

            server.Run();

            return((int)MySampleServer.ExitCode);
        }
コード例 #11
0
        public static int Main(string[] args)
        {
            Console.WriteLine(".Net Core OPC UA Global Discovery Server");

            // command line options
            bool showHelp = false;

            Mono.Options.OptionSet options = new Mono.Options.OptionSet {
                { "h|help", "show this message and exit", h => showHelp = h != null },
            };

            try
            {
                IList <string> extraArgs = options.Parse(args);
                foreach (string extraArg in extraArgs)
                {
                    Console.WriteLine("Error: Unknown option: {0}", extraArg);
                    showHelp = true;
                }
            }
            catch (OptionException e)
            {
                Console.WriteLine(e.Message);
                showHelp = true;
            }

            if (showHelp)
            {
                Console.WriteLine("Usage: dotnet NetCoreGlobalDiscoveryServer.dll [OPTIONS]");
                Console.WriteLine();

                Console.WriteLine("Options:");
                options.WriteOptionDescriptions(Console.Out);
                return((int)ExitCode.ErrorInvalidCommandLine);
            }

            NetCoreGlobalDiscoveryServer server = new NetCoreGlobalDiscoveryServer();

            server.Run();

            return((int)NetCoreGlobalDiscoveryServer.ExitCode);
        }
コード例 #12
0
    public Collage(string [] args)
    {
        bool showHelp = false;
        var  options  = new Mono.Options.OptionSet()
        {
            { "cols=", (int cols) => columns = cols },
            { "cellsize=", (int cell) => cellsize = cell },
            { "output=", (string file) => output = file },
            { "h|?|help", v => showHelp = true },
        };

        void Help()
        {
            Console.WriteLine("collage [options] DIRECTORY\n" +
                              $"Default output is {output}, columns {columns}, cell size {cellsize}");
            options.WriteOptionDescriptions(Console.Error);
            Environment.Exit(0);
        }

        if (showHelp)
        {
            Help();
        }

        var dir = options.Parse(args).FirstOrDefault();

        if (dir == null)
        {
            Help();
        }

        if (dir != null)
        {
            directory = dir;
        }
    }
コード例 #13
0
ファイル: Program.cs プロジェクト: zyc868/UA-.NETStandard
        public static int Main(string[] args)
        {
            Console.WriteLine(".Net Core OPC UA Complex Types Client sample");

            // command line options
            bool showHelp        = false;
            int  stopTimeout     = Timeout.Infinite;
            bool autoAccept      = false;
            bool writeComplexInt = false;
            bool noloadTypes     = false;
            bool verbose         = false;
            bool json            = false;

            Mono.Options.OptionSet options = new Mono.Options.OptionSet {
                { "h|help", "show this message and exit", h => showHelp = h != null },
                { "a|autoaccept", "auto accept certificates (for testing only)", a => autoAccept = a != null },
                { "t|timeout=", "the number of seconds until the client stops.", (int t) => stopTimeout = t },
                { "w|writeint", "Read and increment all complex types with an Int32.", w => writeComplexInt = w != null },
                { "n|noloadtypes", "Load the type system dictionary from the server.", n => noloadTypes = n != null },
                { "v|verbose", "Verbose output.", v => verbose = v != null },
                { "j|json", "Print custom nodes as Json.", j => json = j != null },
            };

            IList <string> extraArgs = null;

            try
            {
                extraArgs = options.Parse(args);
                if (extraArgs.Count > 1)
                {
                    foreach (string extraArg in extraArgs)
                    {
                        Console.WriteLine("Error: Unknown option: {0}", extraArg);
                        showHelp = true;
                    }
                }
            }
            catch (OptionException e)
            {
                Console.WriteLine(e.Message);
                showHelp = true;
            }

            if (showHelp)
            {
                // show some app description message
                Console.WriteLine("Usage: dotnet NetCoreConsoleClient.dll [OPTIONS] [ENDPOINTURL]");
                Console.WriteLine();

                // output the options
                Console.WriteLine("Options:");
                options.WriteOptionDescriptions(Console.Out);
                return((int)ExitCode.ErrorInvalidCommandLine);
            }

            string endpointURL;

            if (extraArgs.Count == 0)
            {
                // use OPC UA .Net Sample server
                endpointURL = "opc.tcp://localhost:51210/UA/SampleServer";
            }
            else
            {
                endpointURL = extraArgs[0];
            }

            MySampleClient client = new MySampleClient(endpointURL, autoAccept, stopTimeout)
            {
                Verbose         = verbose,
                LoadTypeSystem  = !noloadTypes,
                WriteComplexInt = writeComplexInt,
                PrintAsJson     = json
            };

            return((int)client.Run());
        }
コード例 #14
0
        /// <summary>
        /// Asynchronous part of the main method of the app.
        /// </summary>
        public async static Task MainAsync(string[] args)
        {
            var shouldShowHelp = false;

            // command line options
            Mono.Options.OptionSet options = new Mono.Options.OptionSet {
                // opc server configuration options
                { "lf|logfile=", $"the filename of the logfile to use.\nDefault: '{_logFileName}'", (string l) => _logFileName = l },
                { "ll|loglevel=", "the loglevel to use (allowed: fatal, error, warn, info, debug, verbose).\nDefault: info", (string l) => {
                      List <string> logLevels = new List <string> {
                          "fatal", "error", "warn", "info", "debug", "verbose"
                      };
                      if (logLevels.Contains(l.ToLowerInvariant()))
                      {
                          _logLevel = l.ToLowerInvariant();
                      }
                      else
                      {
                          throw new OptionException("The loglevel must be one of: fatal, error, warn, info, debug, verbose", "loglevel");
                      }
                  } },
                { "pn|portnum=", $"the server port of the OPC server endpoint.\nDefault: {ServerPort}", (ushort p) => ServerPort = p },
                { "op|path=", $"the enpoint URL path part of the OPC server endpoint.\nDefault: '{ServerPath}'", (string a) => ServerPath = a },
                { "ga|generatealerts", $"the station should generate alerts.\nDefault: {GenerateAlerts}", g => GenerateAlerts = g != null },
                { "pc|powerconsumption=", $"the stations average power consumption in kW\nDefault:  {PowerConsumption} kW", (double d) => PowerConsumption = d },
                { "ct|cycletime=", $"the stations cycle time in seconds\nDefault:  {IdealCycleTimeDefault} sec", (ulong ul) => IdealCycleTimeDefault = ul * 1000 },
                { "lr|ldsreginterval=", $"the LDS(-ME) registration interval in ms. If 0, then the registration is disabled.\nDefault: {LdsRegistrationInterval}", (int i) => {
                      if (i >= 0)
                      {
                          LdsRegistrationInterval = i;
                      }
                      else
                      {
                          throw new OptionException("The ldsreginterval must be larger or equal 0.", "ldsreginterval");
                      }
                  } },
                { "aa|autoacceptcerts", $"all certs are trusted when a connection is established.\nDefault: {AutoAcceptCerts}", a => AutoAcceptCerts = a != null },

                { "to|trustowncert", $"the cfstation certificate is put into the trusted certificate store automatically.\nDefault: {TrustMyself}", t => TrustMyself = t != null },

                // cert store options
                { "at|appcertstoretype=", $"the own application cert store type. \n(allowed values: Directory, X509Store)\nDefault: '{OpcOwnCertStoreType}'", (string s) => {
                      if (s.Equals(X509Store, StringComparison.OrdinalIgnoreCase) || s.Equals(CertificateStoreType.Directory, StringComparison.OrdinalIgnoreCase))
                      {
                          OpcOwnCertStoreType = s.Equals(X509Store, StringComparison.OrdinalIgnoreCase) ? X509Store : CertificateStoreType.Directory;
                          OpcOwnCertStorePath = s.Equals(X509Store, StringComparison.OrdinalIgnoreCase) ? OpcOwnCertX509StorePathDefault : OpcOwnCertDirectoryStorePathDefault;
                      }
                      else
                      {
                          throw new OptionException();
                      }
                  } },
                { "ap|appcertstorepath=", "the path where the own application cert should be stored\nDefault (depends on store type):\n" +
                  $"X509Store: '{OpcOwnCertX509StorePathDefault}'\n" +
                  $"Directory: '{OpcOwnCertDirectoryStorePathDefault}'", (string s) => OpcOwnCertStorePath = s },

                { "tp|trustedcertstorepath=", $"the path of the trusted cert store\nDefault: '{OpcTrustedCertDirectoryStorePathDefault}'", (string s) => OpcTrustedCertStorePath = s },

                { "rp|rejectedcertstorepath=", $"the path of the rejected cert store\nDefault '{OpcRejectedCertDirectoryStorePathDefault}'", (string s) => OpcRejectedCertStorePath = s },

                { "ip|issuercertstorepath=", $"the path of the trusted issuer cert store\nDefault '{OpcIssuerCertDirectoryStorePathDefault}'", (string s) => OpcIssuerCertStorePath = s },

                { "csr", $"show data to create a certificate signing request\nDefault '{ShowCreateSigningRequestInfo}'", c => ShowCreateSigningRequestInfo = c != null },

                { "ab|applicationcertbase64=", "update/set this applications certificate with the certificate passed in as bas64 string", (string s) => NewCertificateBase64String = s },
                { "af|applicationcertfile=", "update/set this applications certificate with the certificate file specified", (string s) =>
                  {
                      if (File.Exists(s))
                      {
                          NewCertificateFileName = s;
                      }
                      else
                      {
                          throw new OptionException("The file '{s}' does not exist.", "applicationcertfile");
                      }
                  } },

                { "pb|privatekeybase64=", "initial provisioning of the application certificate (with a PEM or PFX fomat) requires a private key passed in as base64 string", (string s) => PrivateKeyBase64String = s },
                { "pk|privatekeyfile=", "initial provisioning of the application certificate (with a PEM or PFX fomat) requires a private key passed in as file", (string s) =>
                  {
                      if (File.Exists(s))
                      {
                          PrivateKeyFileName = s;
                      }
                      else
                      {
                          throw new OptionException("The file '{s}' does not exist.", "privatekeyfile");
                      }
                  } },

                { "cp|certpassword="******"the optional password for the PEM or PFX or the installed application certificate", (string s) => CertificatePassword = s },

                { "tb|addtrustedcertbase64=", "adds the certificate to the applications trusted cert store passed in as base64 string (multiple strings supported)", (string s) => TrustedCertificateBase64Strings.AddRange(ParseListOfStrings(s)) },
                { "tf|addtrustedcertfile=", "adds the certificate file(s) to the applications trusted cert store passed in as base64 string (multiple filenames supported)", (string s) => TrustedCertificateFileNames.AddRange(ParseListOfFileNames(s, "addtrustedcertfile")) },

                { "ib|addissuercertbase64=", "adds the specified issuer certificate to the applications trusted issuer cert store passed in as base64 string (multiple strings supported)", (string s) => IssuerCertificateBase64Strings.AddRange(ParseListOfStrings(s)) },
                { "if|addissuercertfile=", "adds the specified issuer certificate file(s) to the applications trusted issuer cert store (multiple filenames supported)", (string s) => IssuerCertificateFileNames.AddRange(ParseListOfFileNames(s, "addissuercertfile")) },

                { "rb|updatecrlbase64=", "update the CRL passed in as base64 string to the corresponding cert store (trusted or trusted issuer)", (string s) => CrlBase64String = s },
                { "uc|updatecrlfile=", "update the CRL passed in as file to the corresponding cert store (trusted or trusted issuer)", (string s) =>
                  {
                      if (File.Exists(s))
                      {
                          CrlFileName = s;
                      }
                      else
                      {
                          throw new OptionException("The file '{s}' does not exist.", "updatecrlfile");
                      }
                  } },

                { "rc|removecert=", "remove cert(s) with the given thumbprint(s) (multiple thumbprints supported)", (string s) => ThumbprintsToRemove.AddRange(ParseListOfStrings(s)) },

                // misc
                { "h|help", "show this message and exit", h => shouldShowHelp = h != null },
            };

            List <string> extraArgs = new List <string>();

            try
            {
                // parse the command line
                extraArgs = options.Parse(args);
            }
            catch (OptionException e)
            {
                // initialize logging
                InitLogging();

                // show message
                Logger.Fatal(e, "Error in command line options");
                // show usage
                Usage(options);
                return;
            }

            // initialize logging
            InitLogging();

            // check args
            if (extraArgs.Count != 0 || shouldShowHelp)
            {
                // show usage
                Usage(options);
                return;
            }

            try
            {
                await ConsoleServerAsync().ConfigureAwait(false);
            }
            catch (Exception ex)
            {
                Logger.Fatal(ex, "OPC UA server failed unexpectedly.");
            }
            Logger.Information("OPC UA server exiting...");
        }
コード例 #15
0
        public static void Main(string[] args)
        {
            var opcTraceInitialized = false;

            try
            {
                var shouldShowHelp = false;

                // command line options configuration
                Mono.Options.OptionSet options = new Mono.Options.OptionSet {
                    // Publishing configuration options
                    { "pf|publishfile=", $"the filename to configure the nodes to publish.\nDefault: '{NodesToPublishAbsFilenameDefault}'", (string p) => NodesToPublishAbsFilename = p },
                    { "sd|shopfloordomain=", $"the domain of the shopfloor. if specified this domain is appended (delimited by a ':' to the 'ApplicationURI' property when telemetry is sent to IoTHub.\n" +
                      "The value must follow the syntactical rules of a DNS hostname.\nDefault: not set", (string s) => {
                          Regex domainNameRegex = new Regex("^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\\-]*[a-zA-Z0-9])\\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\\-]*[A-Za-z0-9])$");
                          if (domainNameRegex.IsMatch(s))
                          {
                              ShopfloorDomain = s;
                          }
                          else
                          {
                              throw new OptionException("The shopfloor domain is not a valid DNS hostname.", "shopfloordomain");
                          }
                      } },
                    { "sw|sessionconnectwait=", $"specify the wait time in seconds publisher is trying to connect to disconnected endpoints and starts monitoring unmonitored items\nMin: 10\nDefault: {PublisherSessionConnectWaitSec}", (int i) => {
                          if (i > 10)
                          {
                              PublisherSessionConnectWaitSec = i;
                          }
                          else
                          {
                              throw new OptionException("The sessionconnectwait must be greater than 10 sec", "sessionconnectwait");
                          }
                      } },
                    { "vc|verboseconsole=", $"the output of publisher is shown on the console.\nDefault: {VerboseConsole}", (bool b) => VerboseConsole = b },

                    // IoTHub specific options
                    { "ih|iothubprotocol=", $"the protocol to use for communication with Azure IoTHub (allowed values: {string.Join(", ", Enum.GetNames(IotHubProtocol.GetType()))}).\nDefault: {Enum.GetName(IotHubProtocol.GetType(), IotHubProtocol)}",
                      (Microsoft.Azure.Devices.Client.TransportType p) => IotHubProtocol = p },
                    { "ms|iothubmessagesize=", $"the max size of a message which can be send to IoTHub. when telemetry of this size is available it will be sent.\n0 will enforce immediate send when telemetry is available\nMin: 0\nMax: 256 * 1024\nDefault: {_MaxSizeOfIoTHubMessageBytes}", (uint u) => {
                          if (u >= 0 && u <= 256 * 1024)
                          {
                              _MaxSizeOfIoTHubMessageBytes = u;
                          }
                          else
                          {
                              throw new OptionException("The iothubmessagesize must be in the range between 1 and 256*1024.", "iothubmessagesize");
                          }
                      } },
                    { "si|iothubsendinterval=", $"the interval in seconds when telemetry should be send to IoTHub. If 0, then only the iothubmessagesize parameter controls when telemetry is sent.\nDefault: '{_DefaultSendIntervalSeconds}'", (int i) => {
                          if (i >= 0)
                          {
                              _DefaultSendIntervalSeconds = i;
                          }
                          else
                          {
                              throw new OptionException("The iothubsendinterval must be larger or equal 0.", "iothubsendinterval");
                          }
                      } },

                    // opc server configuration options
                    { "lf|logfile=", $"the filename of the logfile to use.\nDefault: './Logs/<applicationname>.log.txt'", (string l) => LogFileName = l },
                    { "pn|portnum=", $"the server port of the publisher OPC server endpoint.\nDefault: {PublisherServerPort}", (ushort p) => PublisherServerPort = p },
                    { "pa|path=", $"the enpoint URL path part of the publisher OPC server endpoint.\nDefault: '{PublisherServerPath}'", (string a) => PublisherServerPath = a },
                    { "lr|ldsreginterval=", $"the LDS(-ME) registration interval in ms. If 0, then the registration is disabled.\nDefault: {LdsRegistrationInterval}", (int i) => {
                          if (i >= 0)
                          {
                              LdsRegistrationInterval = i;
                          }
                          else
                          {
                              throw new OptionException("The ldsreginterval must be larger or equal 0.", "ldsreginterval");
                          }
                      } },
                    { "ot|operationtimeout=", $"the operation timeout of the publisher OPC UA client in ms.\nDefault: {OpcOperationTimeout}", (int i) => {
                          if (i >= 0)
                          {
                              OpcOperationTimeout = i;
                          }
                          else
                          {
                              throw new OptionException("The operation timeout must be larger or equal 0.", "operationtimeout");
                          }
                      } },
                    { "oi|opcsamplinginterval=", "the publisher is using this as default value in milliseconds to request the servers to sample the nodes with this interval\n" +
                      "this value might be revised by the OPC UA servers to a supported sampling interval.\n" +
                      "please check the OPC UA specification for details how this is handled by the OPC UA stack.\n" +
                      "a negative value will set the sampling interval to the publishing interval of the subscription this node is on.\n" +
                      $"0 will configure the OPC UA server to sample in the highest possible resolution and should be taken with care.\nDefault: {OpcSamplingInterval}", (int i) => OpcSamplingInterval = i },
                    { "op|opcpublishinginterval=", "the publisher is using this as default value in milliseconds for the publishing interval setting of the subscriptions established to the OPC UA servers.\n" +
                      "please check the OPC UA specification for details how this is handled by the OPC UA stack.\n" +
                      $"a value less than or equal zero will let the server revise the publishing interval.\nDefault: {OpcPublishingInterval}", (int i) => {
                          if (i > 0 && i >= OpcSamplingInterval)
                          {
                              OpcPublishingInterval = i;
                          }
                          else
                          {
                              if (i <= 0)
                              {
                                  OpcPublishingInterval = 0;
                              }
                              else
                              {
                                  throw new OptionException($"The opcpublishinterval ({i}) must be larger than the opcsamplinginterval ({OpcSamplingInterval}).", "opcpublishinterval");
                              }
                          }
                      } },
                    { "ct|createsessiontimeout=", $"specify the timeout in seconds used when creating a session to an endpoint. On unsuccessful connection attemps a backoff up to {OpcSessionCreationBackoffMax} times the specified timeout value is used.\nMin: 1\nDefault: {OpcSessionCreationTimeout}", (uint u) => {
                          if (u > 1)
                          {
                              OpcSessionCreationTimeout = u;
                          }
                          else
                          {
                              throw new OptionException("The createsessiontimeout must be greater than 1 sec", "createsessiontimeout");
                          }
                      } },
                    { "ki|keepaliveinterval=", $"specify the interval in seconds the publisher is sending keep alive messages to the OPC servers on the endpoints it is connected to.\nMin: 2\nDefault: {OpcKeepAliveIntervalInSec}", (int i) => {
                          if (i >= 2)
                          {
                              OpcKeepAliveIntervalInSec = i;
                          }
                          else
                          {
                              throw new OptionException("The keepaliveinterval must be greater or equal 2", "keepalivethreshold");
                          }
                      } },
                    { "kt|keepalivethreshold=", $"specify the number of keep alive packets a server can miss, before the session is disconneced\nMin: 1\nDefault: {OpcKeepAliveDisconnectThreshold}", (uint u) => {
                          if (u > 1)
                          {
                              OpcKeepAliveDisconnectThreshold = u;
                          }
                          else
                          {
                              throw new OptionException("The keepalivethreshold must be greater than 1", "keepalivethreshold");
                          }
                      } },
                    { "st|opcstacktracemask=", $"the trace mask for the OPC stack. See github OPC .NET stack for definitions.\nTo enable IoTHub telemetry tracing set it to 711.\nDefault: {OpcStackTraceMask:X}  ({Program.OpcStackTraceMask})", (int i) => {
                          if (i >= 0)
                          {
                              OpcStackTraceMask = i;
                          }
                          else
                          {
                              throw new OptionException("The OPC stack trace mask must be larger or equal 0.", "opcstacktracemask");
                          }
                      } },
                    { "as|autotrustservercerts=", $"the publisher trusts all servers it is establishing a connection to.\nDefault: {OpcPublisherAutoTrustServerCerts}", (bool b) => OpcPublisherAutoTrustServerCerts = b },

                    // trust own public cert option
                    { "tm|trustmyself=", $"the publisher certificate is put into the trusted certificate store automatically.\nDefault: {TrustMyself}", (bool b) => TrustMyself = b },

                    // own cert store options
                    { "at|appcertstoretype=", $"the own application cert store type. \n(allowed values: Directory, X509Store)\nDefault: '{OpcOwnCertStoreType}'", (string s) => {
                          if (s.Equals(X509Store, StringComparison.OrdinalIgnoreCase) || s.Equals(Directory, StringComparison.OrdinalIgnoreCase))
                          {
                              OpcOwnCertStoreType = s.Equals(X509Store, StringComparison.OrdinalIgnoreCase) ? X509Store : Directory;
                              OpcOwnCertStorePath = s.Equals(X509Store, StringComparison.OrdinalIgnoreCase) ? _opcOwnCertX509StorePathDefault : _opcOwnCertDirectoryStorePathDefault;
                          }
                          else
                          {
                              throw new OptionException();
                          }
                      } },
                    { "ap|appcertstorepath=", $"the path where the own application cert should be stored\nDefault (depends on store type):\n" +
                      $"X509Store: '{_opcOwnCertX509StorePathDefault}'\n" +
                      $"Directory: '{_opcOwnCertDirectoryStorePathDefault}'", (string s) => OpcOwnCertStorePath = s },

                    // trusted cert store options
                    {
                        "tt|trustedcertstoretype=", $"the trusted cert store type. \n(allowed values: Directory, X509Store)\nDefault: {OpcTrustedCertStoreType}", (string s) => {
                            if (s.Equals(X509Store, StringComparison.OrdinalIgnoreCase) || s.Equals(Directory, StringComparison.OrdinalIgnoreCase))
                            {
                                OpcTrustedCertStoreType = s.Equals(X509Store, StringComparison.OrdinalIgnoreCase) ? X509Store : Directory;
                                OpcTrustedCertStorePath = s.Equals(X509Store, StringComparison.OrdinalIgnoreCase) ? OpcTrustedCertX509StorePathDefault : OpcTrustedCertDirectoryStorePathDefault;
                            }
                            else
                            {
                                throw new OptionException();
                            }
                        }
                    },
                    { "tp|trustedcertstorepath=", $"the path of the trusted cert store\nDefault (depends on store type):\n" +
                      $"X509Store: '{OpcTrustedCertX509StorePathDefault}'\n" +
                      $"Directory: '{OpcTrustedCertDirectoryStorePathDefault}'", (string s) => OpcTrustedCertStorePath = s },

                    // rejected cert store options
                    { "rt|rejectedcertstoretype=", $"the rejected cert store type. \n(allowed values: Directory, X509Store)\nDefault: {OpcRejectedCertStoreType}", (string s) => {
                          if (s.Equals(X509Store, StringComparison.OrdinalIgnoreCase) || s.Equals(Directory, StringComparison.OrdinalIgnoreCase))
                          {
                              OpcRejectedCertStoreType = s.Equals(X509Store, StringComparison.OrdinalIgnoreCase) ? X509Store : Directory;
                              OpcRejectedCertStorePath = s.Equals(X509Store, StringComparison.OrdinalIgnoreCase) ? _opcRejectedCertX509StorePathDefault : _opcRejectedCertDirectoryStorePathDefault;
                          }
                          else
                          {
                              throw new OptionException();
                          }
                      } },
                    { "rp|rejectedcertstorepath=", $"the path of the rejected cert store\nDefault (depends on store type):\n" +
                      $"X509Store: '{_opcRejectedCertX509StorePathDefault}'\n" +
                      $"Directory: '{_opcRejectedCertDirectoryStorePathDefault}'", (string s) => OpcRejectedCertStorePath = s },

                    // issuer cert store options
                    {
                        "it|issuercertstoretype=", $"the trusted issuer cert store type. \n(allowed values: Directory, X509Store)\nDefault: {OpcIssuerCertStoreType}", (string s) => {
                            if (s.Equals(X509Store, StringComparison.OrdinalIgnoreCase) || s.Equals(Directory, StringComparison.OrdinalIgnoreCase))
                            {
                                OpcIssuerCertStoreType = s.Equals(X509Store, StringComparison.OrdinalIgnoreCase) ? X509Store : Directory;
                                OpcIssuerCertStorePath = s.Equals(X509Store, StringComparison.OrdinalIgnoreCase) ? _opcIssuerCertX509StorePathDefault : _opcIssuerCertDirectoryStorePathDefault;
                            }
                            else
                            {
                                throw new OptionException();
                            }
                        }
                    },
                    { "ip|issuercertstorepath=", $"the path of the trusted issuer cert store\nDefault (depends on store type):\n" +
                      $"X509Store: '{_opcIssuerCertX509StorePathDefault}'\n" +
                      $"Directory: '{_opcIssuerCertDirectoryStorePathDefault}'", (string s) => OpcIssuerCertStorePath = s },

                    // device connection string cert store options
                    { "dt|devicecertstoretype=", $"the iothub device cert store type. \n(allowed values: Directory, X509Store)\nDefault: {IotDeviceCertStoreType}", (string s) => {
                          if (s.Equals(X509Store, StringComparison.OrdinalIgnoreCase) || s.Equals(Directory, StringComparison.OrdinalIgnoreCase))
                          {
                              IotDeviceCertStoreType = s.Equals(X509Store, StringComparison.OrdinalIgnoreCase) ? X509Store : Directory;
                              IotDeviceCertStorePath = s.Equals(X509Store, StringComparison.OrdinalIgnoreCase) ? _iotDeviceCertX509StorePathDefault : _iotDeviceCertDirectoryStorePathDefault;
                          }
                          else
                          {
                              throw new OptionException();
                          }
                      } },
                    { "dp|devicecertstorepath=", $"the path of the iot device cert store\nDefault Default (depends on store type):\n" +
                      $"X509Store: '{_iotDeviceCertX509StorePathDefault}'\n" +
                      $"Directory: '{_iotDeviceCertDirectoryStorePathDefault}'", (string s) => IotDeviceCertStorePath = s },

                    // misc
                    { "h|help", "show this message and exit", h => shouldShowHelp = h != null },
                };

                List <string> arguments;
                try
                {
                    // parse the command line
                    arguments = options.Parse(args);
                }
                catch (OptionException e)
                {
                    // show message
                    WriteLine($"Error: {e.Message}");
                    // show usage
                    Usage(options);
                    return;
                }

                // Validate and parse arguments.
                if (arguments.Count > 2 || shouldShowHelp)
                {
                    Usage(options);
                    return;
                }
                else if (arguments.Count == 2)
                {
                    ApplicationName = arguments[0];
                    _IotHubOwnerConnectionString = arguments[1];
                }
                else if (arguments.Count == 1)
                {
                    ApplicationName = arguments[0];
                }
                else
                {
                    ApplicationName = Utils.GetHostName();
                }

                WriteLine("Publisher is starting up...");

                // init OPC configuration and tracing
                Init(OpcStackTraceMask, VerboseConsole);
                OpcStackConfiguration opcStackConfiguration = new OpcStackConfiguration(ApplicationName);
                opcTraceInitialized = true;
                OpcConfiguration    = opcStackConfiguration.Configuration;

                // log shopfloor domain setting
                if (string.IsNullOrEmpty(ShopfloorDomain))
                {
                    Trace("There is no shopfloor domain configured.");
                }
                else
                {
                    Trace($"Publisher is in shopfloor domain '{ShopfloorDomain}'.");
                }

                // Set certificate validator.
                if (OpcPublisherAutoTrustServerCerts)
                {
                    Trace("Publisher configured to auto trust server certificates of the servers it is connecting to.");
                    OpcConfiguration.CertificateValidator.CertificateValidation += new CertificateValidationEventHandler(CertificateValidator_AutoTrustServerCerts);
                }
                else
                {
                    Trace("Publisher configured to not auto trust server certificates. When connecting to servers, you need to manually copy the rejected server certs to the trusted store to trust them.");
                    OpcConfiguration.CertificateValidator.CertificateValidation += new CertificateValidationEventHandler(CertificateValidator_Default);
                }

                // start our server interface
                try
                {
                    Trace($"Starting server on endpoint {OpcConfiguration.ServerConfiguration.BaseAddresses[0].ToString()} ...");
                    _publisherServer = new PublisherServer();
                    _publisherServer.Start(OpcConfiguration);
                    Trace("Server started.");
                }
                catch (Exception e)
                {
                    Trace(e, $"Failed to start Publisher OPC UA server.");
                    Trace("exiting...");
                    return;
                }

                // get information on the nodes to publish and validate the json by deserializing it.
                try
                {
                    PublishDataSemaphore.Wait();
                    if (string.IsNullOrEmpty(NodesToPublishAbsFilename))
                    {
                        // check if we have an env variable specifying the published nodes path, otherwise use the default
                        NodesToPublishAbsFilename = NodesToPublishAbsFilenameDefault;
                        if (!string.IsNullOrEmpty(Environment.GetEnvironmentVariable("_GW_PNFP")))
                        {
                            Trace("Publishing node configuration file path read from environment.");
                            NodesToPublishAbsFilename = Environment.GetEnvironmentVariable("_GW_PNFP");
                        }
                    }

                    Trace($"Attempting to load nodes file from: {NodesToPublishAbsFilename}");
                    PublisherConfigFileEntries = JsonConvert.DeserializeObject <List <PublisherConfigFileEntry> >(File.ReadAllText(NodesToPublishAbsFilename));
                    Trace($"Loaded {PublisherConfigFileEntries.Count.ToString()} config file entry/entries.");

                    foreach (var publisherConfigFileEntry in PublisherConfigFileEntries)
                    {
                        if (publisherConfigFileEntry.NodeId == null)
                        {
                            // new node configuration syntax.
                            foreach (var opcNode in publisherConfigFileEntry.OpcNodes)
                            {
                                PublishConfig.Add(new NodeToPublishConfig(ExpandedNodeId.Parse(opcNode.ExpandedNodeId), publisherConfigFileEntry.EndpointUri, opcNode.OpcSamplingInterval ?? OpcSamplingInterval, opcNode.OpcPublishingInterval ?? OpcPublishingInterval));
                            }
                        }
                        else
                        {
                            // legacy (using ns=) node configuration syntax using default sampling and publishing interval.
                            PublishConfig.Add(new NodeToPublishConfig(publisherConfigFileEntry.NodeId, publisherConfigFileEntry.EndpointUri, OpcSamplingInterval, OpcPublishingInterval));
                        }
                    }
                }
                catch (Exception e)
                {
                    Trace(e, "Loading of the node configuration file failed. Does the file exist and has correct syntax?");
                    Trace("exiting...");
                    return;
                }
                finally
                {
                    PublishDataSemaphore.Release();
                }
                Trace($"There are {PublishConfig.Count.ToString()} nodes to publish.");

                // initialize and start IoTHub messaging
                IotHubCommunication = new IotHubMessaging();
                if (!IotHubCommunication.Init(_IotHubOwnerConnectionString, _MaxSizeOfIoTHubMessageBytes, _DefaultSendIntervalSeconds))
                {
                    return;
                }

                // create a list to manage sessions, subscriptions and monitored items.
                try
                {
                    PublishDataSemaphore.Wait();
                    OpcSessionsSemaphore.Wait();
                    var uniqueEndpointUrls = PublishConfig.Select(n => n.EndpointUri).Distinct();
                    foreach (var endpointUrl in uniqueEndpointUrls)
                    {
                        // create new session info.
                        OpcSession opcSession = new OpcSession(endpointUrl, OpcSessionCreationTimeout);

                        // create a subscription for each distinct publishing inverval
                        var nodesDistinctPublishingInterval = PublishConfig.Where(n => n.EndpointUri.Equals(endpointUrl)).Select(c => c.OpcPublishingInterval).Distinct();
                        foreach (var nodeDistinctPublishingInterval in nodesDistinctPublishingInterval)
                        {
                            // create a subscription for the publishing interval and add it to the session.
                            OpcSubscription opcSubscription = new OpcSubscription(nodeDistinctPublishingInterval);

                            // add all nodes with this OPC publishing interval to this subscription.
                            var nodesWithSamePublishingInterval = PublishConfig.Where(n => n.EndpointUri.Equals(endpointUrl)).Where(n => n.OpcPublishingInterval == nodeDistinctPublishingInterval);
                            foreach (var nodeInfo in nodesWithSamePublishingInterval)
                            {
                                // differentiate if legacy (using ns=) or new syntax (using nsu=) is used
                                if (nodeInfo.NodeId == null)
                                {
                                    // create a monitored item for the node
                                    OpcMonitoredItem opcMonitoredItem = new OpcMonitoredItem(nodeInfo.ExpandedNodeId, opcSession.EndpointUri)
                                    {
                                        RequestedSamplingInterval = nodeInfo.OpcSamplingInterval,
                                        SamplingInterval          = nodeInfo.OpcSamplingInterval
                                    };
                                    opcSubscription.OpcMonitoredItems.Add(opcMonitoredItem);
                                }
                                else
                                {
                                    // give user a warning that the syntax is obsolete
                                    Trace($"Please update the syntax of the configuration file and use ExpandedNodeId instead of NodeId property name for node with identifier '{nodeInfo.NodeId.ToString()}' on EndpointUrl '{nodeInfo.EndpointUri.AbsolutePath}'.");

                                    // create a monitored item for the node with the configured or default sampling interval
                                    OpcMonitoredItem opcMonitoredItem = new OpcMonitoredItem(nodeInfo.NodeId, opcSession.EndpointUri)
                                    {
                                        RequestedSamplingInterval = nodeInfo.OpcSamplingInterval,
                                        SamplingInterval          = nodeInfo.OpcSamplingInterval
                                    };
                                    opcSubscription.OpcMonitoredItems.Add(opcMonitoredItem);
                                }
                            }

                            // add subscription to session.
                            opcSession.OpcSubscriptions.Add(opcSubscription);
                        }

                        // add session.
                        OpcSessions.Add(opcSession);
                    }
                }
                finally
                {
                    OpcSessionsSemaphore.Release();
                    PublishDataSemaphore.Release();
                }

                // kick off the task to maintain all sessions
                var cts = new CancellationTokenSource();
                Task.Run(async() => await SessionConnector(cts.Token));

                // Show notification on session events
                _publisherServer.CurrentInstance.SessionManager.SessionActivated += ServerEventStatus;
                _publisherServer.CurrentInstance.SessionManager.SessionClosing   += ServerEventStatus;
                _publisherServer.CurrentInstance.SessionManager.SessionCreated   += ServerEventStatus;

                // stop on user request
                WriteLine("");
                WriteLine("");
                WriteLine("Publisher is running. Press ENTER to quit.");
                WriteLine("");
                WriteLine("");
                ReadLine();
                cts.Cancel();
                WriteLine("Publisher is shuting down...");

                // close all connected session
                PublisherShutdownInProgress = true;

                // stop the server
                _publisherServer.Stop();

                // Clean up Publisher sessions
                Task.Run(async() => await SessionShutdown()).Wait();

                // shutdown the IoTHub messaging
                IotHubCommunication.Shutdown();
            }
            catch (Exception e)
            {
                if (opcTraceInitialized)
                {
                    Trace(e, e.StackTrace);
                    e = e.InnerException ?? null;
                    while (e != null)
                    {
                        Trace(e, e.StackTrace);
                        e = e.InnerException ?? null;
                    }
                    Trace("Publisher exiting... ");
                }
                else
                {
                    WriteLine($"{DateTime.Now.ToString()}: {e.Message.ToString()}");
                    WriteLine($"{DateTime.Now.ToString()}: {e.StackTrace}");
                    e = e.InnerException ?? null;
                    while (e != null)
                    {
                        WriteLine($"{DateTime.Now.ToString()}: {e.Message.ToString()}");
                        WriteLine($"{DateTime.Now.ToString()}: {e.StackTrace}");
                        e = e.InnerException ?? null;
                    }
                    WriteLine($"{DateTime.Now.ToString()}: Publisher exiting...");
                }
            }
        }
コード例 #16
0
ファイル: Program.cs プロジェクト: thomjak/iot-edge-opc-plc
        /// <summary>
        /// Asynchronous part of the main method of the app.
        /// </summary>
        public static async Task MainAsync(string[] args)
        {
            Mono.Options.OptionSet options = InitCommandLineOptions();

            InitAppLocation();

            InitLogging();

            List <string> extraArgs;

            try
            {
                // parse the command line
                extraArgs = options.Parse(args);
            }
            catch (OptionException e)
            {
                // show message
                Logger.Fatal(e, "Error in command line options");
                Logger.Error($"Command line arguments: {string.Join(" ", args)}");
                // show usage
                Usage(options);
                return;
            }

            // show usage if requested
            if (ShowHelp)
            {
                Usage(options);
                return;
            }

            // validate and parse extra arguments
            if (extraArgs.Count > 0)
            {
                Logger.Error("Error in command line options");
                Logger.Error($"Command line arguments: {string.Join(" ", args)}");
                Usage(options);
                return;
            }

            //show version
            var fileVersion = FileVersionInfo.GetVersionInfo(Assembly.GetExecutingAssembly().Location);

            Logger.Information($"{ProgramName} V{fileVersion.ProductMajorPart}.{fileVersion.ProductMinorPart}.{fileVersion.ProductBuildPart} starting up...");
            Logger.Debug($"Informational version: V{(Attribute.GetCustomAttribute(Assembly.GetEntryAssembly(), typeof(AssemblyInformationalVersionAttribute)) as AssemblyInformationalVersionAttribute)?.InformationalVersion}");

            using var host = CreateHostBuilder(args);
            if (ShowPublisherConfigJsonIp || ShowPublisherConfigJsonPh)
            {
                StartWebServer(host);
            }

            try
            {
                await ConsoleServerAsync(args).ConfigureAwait(false);
            }
            catch (Exception ex)
            {
                Logger.Fatal(ex, "OPC UA server failed unexpectedly.");
            }

            Logger.Information("OPC UA server exiting...");
        }
コード例 #17
0
        public static int Main(string[] args)
        {
            Console.WriteLine(".Net Core OPC UA Complex Types Client sample");

            // command line options
            bool   showHelp        = false;
            int    stopTimeout     = Timeout.Infinite;
            bool   autoAccept      = false;
            bool   writeComplexInt = false;
            bool   noTypes         = false;
            bool   noBrowse        = false;
            bool   verbose         = false;
            bool   json            = false;
            bool   jsonReversible  = false;
            string username        = null;
            string pw = null;
            string reverseConnectUrlString = null;
            Uri    reverseConnectUrl       = null;

            Mono.Options.OptionSet options = new Mono.Options.OptionSet {
                { "h|help", "show this message and exit", h => showHelp = h != null },
                { "a|autoaccept", "auto accept certificates (for testing only)", a => autoAccept = a != null },
                { "t|timeout=", "the number of seconds until the client stops.", (int t) => stopTimeout = t },
                { "w|writeint", "Read and increment all complex types with an Int32.", w => writeComplexInt = w != null },
                { "n|notypes", "Do not load the type system dictionary from the server.", n => noTypes = n != null },
                { "b|nobrowse", "Do not browse the address space of the server.", n => noBrowse = n != null },
                { "u|username="******"Username to access server.", (string n) => username = n },
                { "p|password="******"Password to access server.", (string n) => pw = n },
                { "v|verbose", "Verbose output.", v => verbose = v != null },
                { "j|json", "Print custom nodes as Json.", j => json = j != null },
                { "r|jsonreversible", "Use Json reversible encoding.", r => jsonReversible = r != null },
                { "rc|reverseconnect=", "Connect using the reverse connection.", (string url) => reverseConnectUrlString = url },
            };

            IList <string> extraArgs = null;

            try
            {
                extraArgs = options.Parse(args);
                if (extraArgs.Count > 1)
                {
                    foreach (string extraArg in extraArgs)
                    {
                        Console.WriteLine("Error: Unknown option: {0}", extraArg);
                        showHelp = true;
                    }
                }
                if (reverseConnectUrlString != null)
                {
                    reverseConnectUrl = new Uri(reverseConnectUrlString);
                }
            }
            catch (OptionException e)
            {
                Console.WriteLine(e.Message);
                showHelp = true;
            }

            if (showHelp)
            {
                // show some app description message
                Console.WriteLine("Usage: dotnet NetCoreConsoleClient.dll [OPTIONS] [ENDPOINTURL]");
                Console.WriteLine();

                // output the options
                Console.WriteLine("Options:");
                options.WriteOptionDescriptions(Console.Out);
                return((int)ExitCode.ErrorInvalidCommandLine);
            }

            string endpointURL;

            if (extraArgs.Count == 0)
            {
                // use OPC UA .Net Sample server
                endpointURL = "opc.tcp://localhost:51210/UA/SampleServer";
            }
            else
            {
                endpointURL = extraArgs[0];
            }

            MySampleClient client = new MySampleClient(endpointURL, autoAccept, stopTimeout)
            {
                Verbose             = verbose,
                LoadTypeSystem      = !noTypes,
                BrowseAdddressSpace = !noBrowse,
                WriteComplexInt     = writeComplexInt,
                PrintAsJson         = json,
                JsonReversible      = jsonReversible,
                Username            = username,
                Password            = pw,
                ReverseConnectUri   = reverseConnectUrl
            };

            return((int)client.Run());
        }
コード例 #18
0
ファイル: Injector.cs プロジェクト: stephen1236/ModTek
        // ENTRY POINT
        public static int Main(string directory)
        {
            try
            {
                // parse options
                try
                {
                    Options.Parse(new string[0] {
                    });
                }
                catch (OptionException e)
                {
                    SayOptionException(e);
                    return(RC_BAD_OPTIONS);
                }

                // handle operations that don't require reading the assembly
                switch (OptionsIn.PerformOperation)
                {
                case ReceivedOptions.Operation.Help:
                    SayHelp(Options);
                    return(RC_NORMAL);

                case ReceivedOptions.Operation.Version:
                    SayVersion();
                    return(RC_NORMAL);
                }

                SayHeader();
                var managedDirectory = directory.PA("BattleTech_Data").PA("Managed");
                // find managed directory, setup assembly resolver to look there
                Log.M.TWL(0, managedDirectory);
                managedAssemblyResolver = new ManagedAssemblyResolver(managedDirectory);

                // setup paths to DLLs and backups
                var gameDLLPath      = Path.Combine(managedDirectory, GAME_DLL_FILE_NAME);
                var gameDLLPatchPath = Path.Combine(managedDirectory, GAME_DLL_FILE_NAME + RENAME_FILE_EXT);
                if (File.Exists(gameDLLPatchPath))
                {
                    File.Delete(gameDLLPatchPath);
                }
                File.Move(gameDLLPath, gameDLLPatchPath);
                File.Copy(gameDLLPatchPath, gameDLLPath);
                var    gameDLLBackupPath = Path.Combine(managedDirectory, GAME_DLL_FILE_NAME + BACKUP_FILE_EXT);
                var    modTekDLLPath     = directory.PA("Mods").PA("ModTek").PA(MODTEK_DLL_FILE_NAME); // Path.Combine(directory, MODTEK_DLL_FILE_NAME);
                var    modDirectory      = directory.PA("Mods");
                string HarmonySrcDLLPath = Path.Combine(Path.GetDirectoryName(modTekDLLPath), HARMONY_DLL_FILE_NAME);
                string HarmonyDstDLLPath = Path.Combine(managedDirectory, HARMONY_DLL_FILE_NAME);
                if (File.Exists(HarmonySrcDLLPath) == false)
                {
                    SayModTekAssemblyMissingError(HarmonySrcDLLPath);
                    return(RC_MISSING_MODTEK_ASSEMBLY);
                }
                if (File.Exists(HarmonyDstDLLPath) == false)
                {
                    File.Copy(HarmonySrcDLLPath, HarmonyDstDLLPath);
                }
                if (!File.Exists(gameDLLPath))
                {
                    SayGameAssemblyMissingError(OptionsIn.ManagedDirectory);
                    return(RC_BAD_MANAGED_DIRECTORY_PROVIDED);
                }

                if (!File.Exists(modTekDLLPath))
                {
                    SayModTekAssemblyMissingError(modTekDLLPath);
                    return(RC_MISSING_MODTEK_ASSEMBLY);
                }

                // setup factionsPath

                /*var factionsPath = GetFactionPath(OptionsIn.FactionsPath);
                 * if (!string.IsNullOrEmpty(OptionsIn.FactionsPath) && !File.Exists(factionsPath))
                 * {
                 *  SayFactionsFileMissing(factionsPath);
                 *  return RC_MISSING_FACTION_FILE;
                 * }
                 *
                 * if (string.IsNullOrEmpty(factionsPath) && OptionsIn.RequireKeyPress)
                 * {
                 *  var path = GetSingleZipFilePath(Directory.GetCurrentDirectory());
                 *
                 *  if (!string.IsNullOrEmpty(path))
                 *  {
                 *      SayMaybeInjectFactionZip(path);
                 *      if (PromptForYesNo(OptionsIn.RequireKeyPress))
                 *          factionsPath = path;
                 *  }
                 * }*/

                // read the assembly for game version and injected status
                bool   btmlInjected, modTekInjected, anyInjected;
                string gameVersion;
                using (var game = ModuleDefinition.ReadModule(gameDLLPath))
                {
                    gameVersion    = GetGameVersion(game);
                    btmlInjected   = IsBTMLInjected(game);
                    modTekInjected = IsModTekInjected(game);
                    anyInjected    = btmlInjected || modTekInjected;
                }


                // handle operations that require reading the assembly
                if (modTekInjected)
                {
                    SayAlreadyInjected();

                    Restore(gameDLLPath, gameDLLBackupPath);
                    gameDLLBackupPath = null;
                }

                // have restored a non-injected assembly or have a non injected assembly at this point
                // if backups restored, path to backup nullified, so not backed up again
                if (!string.IsNullOrEmpty(gameDLLBackupPath))
                {
                    Backup(gameDLLPath, gameDLLBackupPath);
                }

                Inject(gameDLLPath, modTekDLLPath, string.Empty); //factionsPath);

                if (HasOldFiles(modDirectory, managedDirectory))
                {
                    SayHasOldFiles();

                    if (PromptForYesNo(OptionsIn.RequireKeyPress))
                    {
                        DeleteOldFiles(modDirectory, managedDirectory);
                    }
                }

                PromptForKey(OptionsIn.RequireKeyPress);
                return(RC_NORMAL);
            }
            catch (BackupFileNotFound e)
            {
                SayException(e);
                SayHowToRecoverMissingBackup(e.BackupFileName);
                PromptForKey(true);
                return(RC_MISSING_BACKUP_FILE);
            }
            catch (BackupFileInjected e)
            {
                SayException(e);
                SayHowToRecoverInjectedBackup(e.BackupFileName);
                PromptForKey(true);
                return(RC_BACKUP_FILE_INJECTED);
            }
            catch (Exception e)
            {
                SayException(e);
                PromptForKey(true);
            }

            return(RC_UNHANDLED_STATE);
        }
コード例 #19
0
        public static void Main(string[] args)
        {
            Console.WriteLine("OPC UA Console Reference Subscriber");

            // command line options
            bool   showHelp      = false;
            bool   useMqttJson   = true;
            bool   useMqttUadp   = false;
            bool   useUdpUadp    = false;
            string subscriberUrl = null;

            Mono.Options.OptionSet options = new Mono.Options.OptionSet {
                { "h|help", "Show usage information", v => showHelp = v != null },
                { "m|mqtt_json", "Use MQTT with Json encoding Profile. This is the default option.", v => useMqttJson = v != null },
                { "p|mqtt_uadp", "Use MQTT with UADP encoding Profile.", v => useMqttUadp = v != null },
                { "u|udp_uadp", "Use UDP with UADP encoding Profile", v => useUdpUadp = v != null },
                { "url|subscriber_url=", "Subscriber Url Address", v => subscriberUrl = v },
            };

            IList <string> extraArgs = null;

            try
            {
                extraArgs = options.Parse(args);
                if (extraArgs.Count > 0)
                {
                    foreach (string extraArg in extraArgs)
                    {
                        Console.WriteLine("Error: Unknown option: {0}", extraArg);
                        showHelp = true;
                    }
                }
            }
            catch (OptionException e)
            {
                Console.WriteLine(e.Message);
                showHelp = true;
            }

            if (showHelp)
            {
                Console.WriteLine("Usage: dotnet ConsoleReferenceSubscriber.dll [OPTIONS]");
                Console.WriteLine();

                Console.WriteLine("Options:");
                options.WriteOptionDescriptions(Console.Out);
                return;
            }
            try
            {
                InitializeLog();

                PubSubConfigurationDataType pubSubConfiguration = null;
                if (useUdpUadp)
                {
                    // set default UDP Subscriber Url to local multicast if not sent in args.
                    if (string.IsNullOrEmpty(subscriberUrl))
                    {
                        subscriberUrl = "opc.udp://239.0.0.1:4840";
                    }

                    // Create configuration using UDP protocol and UADP Encoding
                    pubSubConfiguration = CreateSubscriberConfiguration_UdpUadp(subscriberUrl);
                    Console.WriteLine("The Pubsub Connection was initialized using UDP & UADP Profile.");
                }
                else
                {
                    // set default MQTT Broker Url to localhost if not sent in args.
                    if (string.IsNullOrEmpty(subscriberUrl))
                    {
                        subscriberUrl = "mqtt://localhost:1883";
                    }

                    if (useMqttUadp)
                    {
                        // Create configuration using MQTT protocol and UADP Encoding
                        pubSubConfiguration = CreateSubscriberConfiguration_MqttUadp(subscriberUrl);
                        Console.WriteLine("The PubSub Connection was initialized using MQTT & UADP Profile.");
                    }
                    else
                    {
                        // Create configuration using MQTT protocol and JSON Encoding
                        pubSubConfiguration = CreateSubscriberConfiguration_MqttJson(subscriberUrl);
                        Console.WriteLine("The PubSub Connection was initialized using MQTT & JSON Profile.");
                    }
                }

                // Create the UA Publisher application
                using (UaPubSubApplication uaPubSubApplication = UaPubSubApplication.Create(pubSubConfiguration))
                {
                    // Subscribte to RawDataReceived event
                    uaPubSubApplication.RawDataReceived += UaPubSubApplication_RawDataReceived;

                    // Subscribte to DataReceived event
                    uaPubSubApplication.DataReceived += UaPubSubApplication_DataReceived;

                    // Subscribte to MetaDataReceived event
                    uaPubSubApplication.MetaDataReceived += UaPubSubApplication_MetaDataDataReceived;

                    uaPubSubApplication.ConfigurationUpdating += UaPubSubApplication_ConfigurationUpdating;

                    // Start the publisher
                    uaPubSubApplication.Start();

                    Console.WriteLine("Subscriber Started. Press Ctrl-C to exit...");

                    ManualResetEvent quitEvent = new ManualResetEvent(false);
                    try
                    {
                        Console.CancelKeyPress += (sender, eArgs) => {
                            quitEvent.Set();
                            eArgs.Cancel = true;
                        };
                    }
                    catch
                    {
                    }

                    // wait for timeout or Ctrl-C
                    quitEvent.WaitOne();
                }

                Console.WriteLine("Program ended.");
                Console.WriteLine("Press any key to finish...");
                Console.ReadKey();
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }
コード例 #20
0
        public static int Main(string[] args)
        {
            Console.WriteLine("Technosoftware {0} OPC UA ModelDesign Client", Utils.IsRunningOnMono() ? "Mono" : ".NET Core");

            // command line options
            var    showHelp    = false;
            var    stopTimeout = Timeout.Infinite;
            var    autoAccept  = false;
            var    noBrowse    = false;
            var    verbose     = false;
            string username    = null;
            string password    = null;

            var options = new OptionSet {
                { "h|help", "show this message and exit", h => showHelp = h != null },
                { "a|autoaccept", "auto accept certificates (for testing only)", a => autoAccept = a != null },
                { "t|timeout=", "the number of seconds until the client stops.", (int t) => stopTimeout = t },
                { "b|nobrowse", "Do not browse the address space of the server.", n => noBrowse = n != null },
                { "u|username="******"Username to access server.", n => username = n },
                { "p|password="******"Password to access server.", n => password = n },
                { "v|verbose", "Verbose output.", v => verbose = v != null },
            };

            IList <string> extraArgs = null;

            try
            {
                extraArgs = options.Parse(args);
                if (extraArgs.Count > 1)
                {
                    foreach (var extraArg in extraArgs)
                    {
                        Console.WriteLine("Error: Unknown option: {0}", extraArg);
                        showHelp = true;
                    }
                }
            }
            catch (OptionException e)
            {
                Console.WriteLine(e.Message);
                showHelp = true;
            }

            if (showHelp)
            {
                // show some app description message
                Console.WriteLine("Usage: dotnet Technosoftware.ModelDesignClient.dll [OPTIONS] [ENDPOINTURL]");
                Console.WriteLine();

                // output the options
                Console.WriteLine("Options:");
                options.WriteOptionDescriptions(Console.Out);
                return((int)ExitCode.ErrorInvalidCommandLine);
            }

            string endpointUrl;

            if (extraArgs == null || extraArgs.Count == 0)
            {
                // use Technosoftware OPC UA ModelDesign Server
                endpointUrl = "opc.tcp://localhost:55552/TechnosoftwareModelDesignServer";
            }
            else
            {
                endpointUrl = extraArgs[0];
            }

            var client = new MySampleClient(endpointUrl, autoAccept, stopTimeout)
            {
                Verbose            = verbose,
                BrowseAddressSpace = !noBrowse,
                Username           = username,
                Password           = password,
            };

            return((int)client.Run());
        }
コード例 #21
0
ファイル: Program.cs プロジェクト: 8/serialportecho
        private OptionSet ParseArguments(string[] args, Settings settings)
        {
            var optionSet = new Mono.Options.OptionSet()
              {
            { "h|help", "shows this help", s => settings.Action = AppAction.ShowHelp },
            { "p|port=", "sets the name of the serialport (COM1, COM2, etc)", s => settings.PortName = s },
            { "l|listports", "lists the name of all available COM ports", s => settings.Action = AppAction.ListPorts },
            { "e|echo", "echoes the received byte back", s => settings.Echo = true },
            { "b|baudrate=", "sets the baudrate of the serialport", s => settings.BaudRate = TryParseBaudRate(s) },
            { "parity=", "sets the parity bit configuration of the serialport", s => settings.Parity = TryParseParity(s) },
            { "db|databits=", "sets the databits configuration of the serialport", s => settings.DataBits = TryParseDataBits(s) },
            { "sb|stopbits=", "sets the stopbits configuration of the serialport", s => settings.StopBits = TryParseStopBits(s) },
            { "f|send-file=", "sends the specified file over the serialport", s => { settings.FilePath = s; settings.Action = AppAction.SendFile; } },
            { "a|send-ascii=", "sends the specified ascii value over the serialport", s => { settings.Ascii = TryParseAscii(s); settings.Action = AppAction.SendAscii; } },
            { "c|count=", "specifies the number of files or ascii characters that are sent over the serialport", s => settings.Count = TryParseCount(s) },
            { "t|text=", "specifies the text that is to be sent over the serialport", s => { settings.Text = s; settings.Action = AppAction.SendText; } },
            { "r|receive", "listens on the serialport and writes received data to a file", s => { settings.Action = AppAction.Receive; settings.FilePath = s; } },
            { "d|dump-to-file=", "optional file to dump the received data to", s => settings.FilePath = s }
              };

              optionSet.Parse(args);

              return optionSet;
        }
コード例 #22
0
        /// <summary>
        /// Asynchronous part of the main method of the app.
        /// </summary>
        public async static Task MainAsync(string[] args)
        {
            try
            {
                var shouldShowHelp = false;

                // shutdown token sources
                ShutdownTokenSource = new CancellationTokenSource();

                // command line options
                Mono.Options.OptionSet options = new Mono.Options.OptionSet {
                    { "cf|configfile=", $"the filename containing action configuration.\nDefault: '{OpcActionConfigurationFilename}'", (string p) => OpcActionConfigurationFilename = p },

                    { "tc|testconnectivity", $"tests connectivity with the server.\nDefault: {TestConnectivity}", b => TestConnectivity = b != null },
                    { "tu|testunsecureconnectivity", $"tests connectivity with the server using an unsecured endpoint.\nDefault: {TestUnsecureConnectivity}", b => TestUnsecureConnectivity = b != null },

                    { "de|defaultendpointurl=", $"endpoint OPC UA server used as default.\nDefault: {DefaultEndpointUrl}", (string s) => DefaultEndpointUrl = s },

                    { "sw|sessionconnectwait=", $"specify the wait time in seconds we try to connect to disconnected endpoints and starts monitoring unmonitored items\nMin: 10\nDefault: {SessionConnectWait}", (int i) => {
                          if (i > 10)
                          {
                              SessionConnectWait = i;
                          }
                          else
                          {
                              throw new OptionException("The sessionconnectwait must be greater than 10 sec", "sessionconnectwait");
                          }
                      } },
                    { "di|diagnosticsinterval=", $"shows diagnostic info at the specified interval in seconds (need log level info). 0 disables diagnostic output.\nDefault: {DiagnosticsInterval}", (uint u) => DiagnosticsInterval = u },

                    { "lf|logfile=", $"the filename of the logfile to use.\nDefault: don't write logfile.", (string l) => _logFileName = l },
                    { "lt|logflushtimespan=", $"the timespan in seconds when the logfile should be flushed.\nDefault: {_logFileFlushTimeSpanSec} sec", (int s) => {
                          if (s > 0)
                          {
                              _logFileFlushTimeSpanSec = TimeSpan.FromSeconds(s);
                          }
                          else
                          {
                              throw new Mono.Options.OptionException("The logflushtimespan must be a positive number.", "logflushtimespan");
                          }
                      } },
                    { "ll|loglevel=", $"the loglevel to use (allowed: fatal, error, warn, info, debug, verbose).\nDefault: info", (string l) => {
                          List <string> logLevels = new List <string> {
                              "fatal", "error", "warn", "info", "debug", "verbose"
                          };
                          if (logLevels.Contains(l.ToLowerInvariant()))
                          {
                              _logLevel = l.ToLowerInvariant();
                          }
                          else
                          {
                              throw new Mono.Options.OptionException("The loglevel must be one of: fatal, error, warn, info, debug, verbose", "loglevel");
                          }
                      } },

                    // opc configuration options
                    { "ol|opcmaxstringlen=", $"the max length of a string opc can transmit/receive.\nDefault: {OpcMaxStringLength}", (int i) => {
                          if (i > 0)
                          {
                              OpcMaxStringLength = i;
                          }
                          else
                          {
                              throw new OptionException("The max opc string length must be larger than 0.", "opcmaxstringlen");
                          }
                      } },
                    { "ot|operationtimeout=", $"the operation timeout of the OPC UA client in ms.\nDefault: {OpcOperationTimeout}", (int i) => {
                          if (i >= 0)
                          {
                              OpcOperationTimeout = i;
                          }
                          else
                          {
                              throw new OptionException("The operation timeout must be larger or equal 0.", "operationtimeout");
                          }
                      } },
                    { "ct|createsessiontimeout=", $"specify the timeout in seconds used when creating a session to an endpoint. On unsuccessful connection attemps a backoff up to {OpcSessionCreationBackoffMax} times the specified timeout value is used.\nMin: 1\nDefault: {OpcSessionCreationTimeout}", (uint u) => {
                          if (u > 1)
                          {
                              OpcSessionCreationTimeout = u;
                          }
                          else
                          {
                              throw new OptionException("The createsessiontimeout must be greater than 1 sec", "createsessiontimeout");
                          }
                      } },
                    { "ki|keepaliveinterval=", $"specify the interval in seconds se send keep alive messages to the OPC servers on the endpoints it is connected to.\nMin: 2\nDefault: {OpcKeepAliveInterval}", (int i) => {
                          if (i >= 2)
                          {
                              OpcKeepAliveInterval = i;
                          }
                          else
                          {
                              throw new OptionException("The keepaliveinterval must be greater or equal 2", "keepalivethreshold");
                          }
                      } },
                    { "kt|keepalivethreshold=", $"specify the number of keep alive packets a server can miss, before the session is disconneced\nMin: 1\nDefault: {OpcKeepAliveDisconnectThreshold}", (uint u) => {
                          if (u > 1)
                          {
                              OpcKeepAliveDisconnectThreshold = u;
                          }
                          else
                          {
                              throw new OptionException("The keepalivethreshold must be greater than 1", "keepalivethreshold");
                          }
                      } },

                    { "csvOutput=|csvoutput=", $"filename to store readed values in CSV format.\nDefault: './{_csvFileName}'", (string path) => _csvFileName = path },

                    { "aa|autoaccept", $"trusts all servers we establish a connection to.\nDefault: {AutoAcceptCerts}", b => AutoAcceptCerts = b != null },

                    { "to|trustowncert", $"our own certificate is put into the trusted certificate store automatically.\nDefault: {TrustMyself}", t => TrustMyself = t != null },

                    // cert store options
                    { "at|appcertstoretype=", $"the own application cert store type. \n(allowed values: Directory, X509Store)\nDefault: '{OpcOwnCertStoreType}'", (string s) => {
                          if (s.Equals(CertificateStoreType.X509Store, StringComparison.OrdinalIgnoreCase) || s.Equals(CertificateStoreType.Directory, StringComparison.OrdinalIgnoreCase))
                          {
                              OpcOwnCertStoreType = s.Equals(CertificateStoreType.X509Store, StringComparison.OrdinalIgnoreCase) ? CertificateStoreType.X509Store : CertificateStoreType.Directory;
                              OpcOwnCertStorePath = s.Equals(CertificateStoreType.X509Store, StringComparison.OrdinalIgnoreCase) ? OpcOwnCertX509StorePathDefault : OpcOwnCertDirectoryStorePathDefault;
                          }
                          else
                          {
                              throw new OptionException();
                          }
                      } },
                    { "ap|appcertstorepath=", $"the path where the own application cert should be stored\nDefault (depends on store type):\n" +
                      $"X509Store: '{OpcOwnCertX509StorePathDefault}'\n" +
                      $"Directory: '{OpcOwnCertDirectoryStorePathDefault}'", (string s) => OpcOwnCertStorePath = s },

                    { "tp|trustedcertstorepath=", $"the path of the trusted cert store\nDefault '{OpcTrustedCertDirectoryStorePathDefault}'", (string s) => OpcTrustedCertStorePath = s },

                    { "rp|rejectedcertstorepath=", $"the path of the rejected cert store\nDefault '{OpcRejectedCertDirectoryStorePathDefault}'", (string s) => OpcRejectedCertStorePath = s },

                    { "ip|issuercertstorepath=", $"the path of the trusted issuer cert store\nDefault '{OpcIssuerCertDirectoryStorePathDefault}'", (string s) => OpcIssuerCertStorePath = s },

                    { "csr", $"show data to create a certificate signing request\nDefault '{ShowCreateSigningRequestInfo}'", c => ShowCreateSigningRequestInfo = c != null },

                    { "ab|applicationcertbase64=", $"update/set this applications certificate with the certificate passed in as bas64 string", (string s) =>
                      {
                          NewCertificateBase64String = s;
                      } },
                    { "af|applicationcertfile=", $"update/set this applications certificate with the certificate file specified", (string s) =>
                      {
                          if (File.Exists(s))
                          {
                              NewCertificateFileName = s;
                          }
                          else
                          {
                              throw new OptionException($"The file '{s}' does not exist.", "applicationcertfile");
                          }
                      } },

                    { "pb|privatekeybase64=", $"initial provisioning of the application certificate (with a PEM or PFX fomat) requires a private key passed in as base64 string", (string s) =>
                      {
                          PrivateKeyBase64String = s;
                      } },
                    { "pk|privatekeyfile=", $"initial provisioning of the application certificate (with a PEM or PFX fomat) requires a private key passed in as file", (string s) =>
                      {
                          if (File.Exists(s))
                          {
                              PrivateKeyFileName = s;
                          }
                          else
                          {
                              throw new OptionException($"The file '{s}' does not exist.", "privatekeyfile");
                          }
                      } },

                    { "cp|certpassword="******"the optional password for the PEM or PFX or the installed application certificate", (string s) =>
                      {
                          CertificatePassword = s;
                      } },

                    { "tb|addtrustedcertbase64=", $"adds the certificate to the applications trusted cert store passed in as base64 string (multiple strings supported)", (string s) =>
                      {
                          TrustedCertificateBase64Strings = ParseListOfStrings(s);
                      } },
                    { "tf|addtrustedcertfile=", $"adds the certificate file(s) to the applications trusted cert store passed in as base64 string (multiple filenames supported)", (string s) =>
                      {
                          TrustedCertificateFileNames = ParseListOfFileNames(s, "addtrustedcertfile");
                      } },

                    { "ib|addissuercertbase64=", $"adds the specified issuer certificate to the applications trusted issuer cert store passed in as base64 string (multiple strings supported)", (string s) =>
                      {
                          IssuerCertificateBase64Strings = ParseListOfStrings(s);
                      } },
                    { "if|addissuercertfile=", $"adds the specified issuer certificate file(s) to the applications trusted issuer cert store (multiple filenames supported)", (string s) =>
                      {
                          IssuerCertificateFileNames = ParseListOfFileNames(s, "addissuercertfile");
                      } },

                    { "rb|updatecrlbase64=", $"update the CRL passed in as base64 string to the corresponding cert store (trusted or trusted issuer)", (string s) =>
                      {
                          CrlBase64String = s;
                      } },
                    { "uc|updatecrlfile=", $"update the CRL passed in as file to the corresponding cert store (trusted or trusted issuer)", (string s) =>
                      {
                          if (File.Exists(s))
                          {
                              CrlFileName = s;
                          }
                          else
                          {
                              throw new OptionException($"The file '{s}' does not exist.", "updatecrlfile");
                          }
                      } },

                    { "rc|removecert=", $"remove cert(s) with the given thumbprint(s) (multiple thumbprints supported)", (string s) =>
                      {
                          ThumbprintsToRemove = ParseListOfStrings(s);
                      } },

                    // misc
                    { "h|help", "show this message and exit", h => shouldShowHelp = h != null },
                };

                List <string> extraArgs = new List <string>();
                try
                {
                    // parse the command line
                    extraArgs = options.Parse(args);
                }
                catch (OptionException e)
                {
                    // initialize logging
                    InitLogging();

                    // show message
                    Logger.Fatal(e, "Error in command line options");
                    Environment.ExitCode = 1;
                    Logger.Error($"Command line arguments: {String.Join(" ", args)}");

                    // show usage
                    Usage(options);
                    return;
                }

                // initialize logging
                InitLogging();

                // show usage if requested
                if (shouldShowHelp)
                {
                    Usage(options);
                    return;
                }

                // validate and parse extra arguments
                if (extraArgs.Count > 0)
                {
                    Logger.Error("Error in command line options");
                    Environment.ExitCode = 1;
                    Logger.Error($"Command line arguments: {String.Join(" ", args)}");
                    Usage(options);
                    return;
                }

                //show version
                Logger.Information($"{ProgramName} V{FileVersionInfo.GetVersionInfo(Assembly.GetExecutingAssembly().Location).FileVersion} starting up...");
                Logger.Debug($"Informational version: V{(Attribute.GetCustomAttribute(Assembly.GetEntryAssembly(), typeof(AssemblyInformationalVersionAttribute)) as AssemblyInformationalVersionAttribute).InformationalVersion}");

                // allow canceling the application
                var quitEvent = new ManualResetEvent(false);
                try
                {
                    Console.CancelKeyPress += (sender, eArgs) =>
                    {
                        quitEvent.Set();
                        eArgs.Cancel = true;
                        ShutdownTokenSource.Cancel();
                    };
                }
                catch
                {
                }

                // init OPC configuration and tracing
                OpcApplicationConfiguration applicationStackConfiguration = new OpcApplicationConfiguration();
                await applicationStackConfiguration.ConfigureAsync();

                // read OPC action configuration
                OpcConfiguration.Init();
                if (!await ReadOpcConfigurationAsync())
                {
                    return;
                }

                // add well known actions
                if (!await CreateOpcActionDataAsync())
                {
                    return;
                }

                // kick off OPC client activities
                await SessionStartAsync();

                // initialize diagnostics
                Diagnostics.Init();

                await OpcSessionsListSemaphore.WaitAsync();

                var pendingOperations = OpcSessions.Sum(s => s.OpcActions.Count);
                OpcSessionsListSemaphore.Release();
                while (pendingOperations > 0 && ShutdownTokenSource.IsCancellationRequested != true)
                {
                    Logger.Information($"{pendingOperations} pending operation(s).");
                    Logger.Information("");
                    Logger.Information($"{ProgramName} is running. Press CTRL-C to quit.");
                    Thread.Sleep(1000);
                    await OpcSessionsListSemaphore.WaitAsync();

                    pendingOperations = OpcSessions.Sum(s => s.OpcActions.Count);
                    OpcSessionsListSemaphore.Release();
                }

                Logger.Information("No pending operations.");
                Logger.Information("");
                ShutdownTokenSource.Cancel();
                Logger.Information($"{ProgramName} is shutting down...");

                // shutdown all OPC sessions
                await SessionShutdownAsync();

                // shutdown diagnostics
                await ShutdownAsync();

                ShutdownTokenSource = null;
            }
            catch (Exception e)
            {
                Logger.Fatal(e, e.StackTrace);
                Environment.ExitCode = 1;
                e = e.InnerException ?? null;
                while (e != null)
                {
                    Logger.Fatal(e, e.StackTrace);
                    e = e.InnerException ?? null;
                }
                Logger.Fatal($"{ProgramName} exiting... ");
            }
        }
コード例 #23
0
        /// <summary>
        /// Asynchronous part of the main method of the app.
        /// </summary>
        public async static Task MainAsync(string[] args)
        {
            try
            {
                var shouldShowHelp = false;

                // command line options configuration
                Mono.Options.OptionSet options = new Mono.Options.OptionSet {
                    // Publishing configuration options
                    { "pf|publishfile=", $"the filename to configure the nodes to publish (fallback procedure).\nDefault: '{PublisherNodeConfigurationFilename}'", (string p) => PublisherNodeConfigurationFilename = p },
                    { "tc|telemetryconfigfile=", $"the filename to configure the ingested telemetry\nDefault: '{PublisherTelemetryConfigurationFilename}'", (string p) => PublisherTelemetryConfigurationFilename = p },
                    { "sd|shopfloordomain=", $"the domain of the shopfloor. if specified this domain is appended (delimited by a ':' to the 'ApplicationURI' property when telemetry is sent to IoTHub.\n" +
                      "The value must follow the syntactical rules of a DNS hostname.\nDefault: not set", (string s) => {
                          Regex domainNameRegex = new Regex("^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\\-]*[a-zA-Z0-9])\\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\\-]*[A-Za-z0-9])$");
                          if (domainNameRegex.IsMatch(s))
                          {
                              ShopfloorDomain = s;
                          }
                          else
                          {
                              throw new OptionException("The shopfloor domain is not a valid DNS hostname.", "shopfloordomain");
                          }
                      } },
                    { "sw|sessionconnectwait=", $"specify the wait time in seconds publisher is trying to connect to disconnected endpoints and starts monitoring unmonitored items\nMin: 10\nDefault: {_publisherSessionConnectWaitSec}", (int i) => {
                          if (i > 10)
                          {
                              _publisherSessionConnectWaitSec = i;
                          }
                          else
                          {
                              throw new OptionException("The sessionconnectwait must be greater than 10 sec", "sessionconnectwait");
                          }
                      } },
                    { "mq|monitoreditemqueuecapacity=", $"specify how many notifications of monitored items can be stored in the internal queue, if the data can not be sent quick enough to IoTHub\nMin: 1024\nDefault: {MonitoredItemsQueueCapacity}", (int i) => {
                          if (i >= 1024)
                          {
                              MonitoredItemsQueueCapacity = i;
                          }
                          else
                          {
                              throw new OptionException("The monitoreditemqueueitems must be greater than 1024", "monitoreditemqueueitems");
                          }
                      } },
                    { "di|diagnosticsinterval=", $"shows publisher diagnostic info at the specified interval in seconds. 0 disables diagnostic output.\nDefault: {DiagnosticsInterval}", (uint u) => DiagnosticsInterval = u },

                    { "vc|verboseconsole=", $"the output of publisher is shown on the console.\nDefault: {VerboseConsole}", (bool b) => VerboseConsole = b },

                    { "ns|noshutdown=", $"publisher can not be stopped by pressing a key on the console, but will run forever.\nDefault: {_noShutdown}", (bool b) => _noShutdown = b },

                    // IoTHub specific options
                    { "ih|iothubprotocol=", $"the protocol to use for communication with Azure IoTHub (allowed values: {string.Join(", ", Enum.GetNames(IotHubProtocol.GetType()))}).\nDefault: {Enum.GetName(IotHubProtocol.GetType(), IotHubProtocol)}",
                      (Microsoft.Azure.Devices.Client.TransportType p) => IotHubProtocol = p },
                    { "ms|iothubmessagesize=", $"the max size of a message which can be send to IoTHub. when telemetry of this size is available it will be sent.\n0 will enforce immediate send when telemetry is available\nMin: 0\nMax: {IotHubMessageSizeMax}\nDefault: {IotHubMessageSize}", (uint u) => {
                          if (u >= 0 && u <= IotHubMessageSizeMax)
                          {
                              IotHubMessageSize = u;
                          }
                          else
                          {
                              throw new OptionException("The iothubmessagesize must be in the range between 1 and 256*1024.", "iothubmessagesize");
                          }
                      } },
                    { "si|iothubsendinterval=", $"the interval in seconds when telemetry should be send to IoTHub. If 0, then only the iothubmessagesize parameter controls when telemetry is sent.\nDefault: '{DefaultSendIntervalSeconds}'", (int i) => {
                          if (i >= 0)
                          {
                              DefaultSendIntervalSeconds = i;
                          }
                          else
                          {
                              throw new OptionException("The iothubsendinterval must be larger or equal 0.", "iothubsendinterval");
                          }
                      } },
                    { "dc|deviceconnectionstring=", $"if publisher is not able to register itself with IoTHub, you can create a device with name <applicationname> manually and pass in the connectionstring of this device.\nDefault: none",
                      (string dc) => DeviceConnectionString = dc },
                    { "lf|logfile=", $"the filename of the logfile to use.\nDefault: './Logs/<applicationname>.log.txt'", (string l) => LogFileName = l },
                    { "ot|operationtimeout=", $"the operation timeout of the publisher OPC UA client in ms.\nDefault: {OpcOperationTimeout}", (int i) => {
                          if (i >= 0)
                          {
                              OpcOperationTimeout = i;
                          }
                          else
                          {
                              throw new OptionException("The operation timeout must be larger or equal 0.", "operationtimeout");
                          }
                      } },
                    { "oi|opcsamplinginterval=", "the publisher is using this as default value in milliseconds to request the servers to sample the nodes with this interval\n" +
                      "this value might be revised by the OPC UA servers to a supported sampling interval.\n" +
                      "please check the OPC UA specification for details how this is handled by the OPC UA stack.\n" +
                      "a negative value will set the sampling interval to the publishing interval of the subscription this node is on.\n" +
                      $"0 will configure the OPC UA server to sample in the highest possible resolution and should be taken with care.\nDefault: {OpcSamplingInterval}", (int i) => OpcSamplingInterval = i },
                    { "op|opcpublishinginterval=", "the publisher is using this as default value in milliseconds for the publishing interval setting of the subscriptions established to the OPC UA servers.\n" +
                      "please check the OPC UA specification for details how this is handled by the OPC UA stack.\n" +
                      $"a value less than or equal zero will let the server revise the publishing interval.\nDefault: {OpcPublishingInterval}", (int i) => {
                          if (i > 0 && i >= OpcSamplingInterval)
                          {
                              OpcPublishingInterval = i;
                          }
                          else
                          {
                              if (i <= 0)
                              {
                                  OpcPublishingInterval = 0;
                              }
                              else
                              {
                                  throw new OptionException($"The opcpublishinterval ({i}) must be larger than the opcsamplinginterval ({OpcSamplingInterval}).", "opcpublishinterval");
                              }
                          }
                      } },
                    { "ct|createsessiontimeout=", $"specify the timeout in seconds used when creating a session to an endpoint. On unsuccessful connection attemps a backoff up to {OpcSessionCreationBackoffMax} times the specified timeout value is used.\nMin: 1\nDefault: {OpcSessionCreationTimeout}", (uint u) => {
                          if (u > 1)
                          {
                              OpcSessionCreationTimeout = u;
                          }
                          else
                          {
                              throw new OptionException("The createsessiontimeout must be greater than 1 sec", "createsessiontimeout");
                          }
                      } },
                    { "ki|keepaliveinterval=", $"specify the interval in seconds the publisher is sending keep alive messages to the OPC servers on the endpoints it is connected to.\nMin: 2\nDefault: {OpcKeepAliveIntervalInSec}", (int i) => {
                          if (i >= 2)
                          {
                              OpcKeepAliveIntervalInSec = i;
                          }
                          else
                          {
                              throw new OptionException("The keepaliveinterval must be greater or equal 2", "keepalivethreshold");
                          }
                      } },
                    { "kt|keepalivethreshold=", $"specify the number of keep alive packets a server can miss, before the session is disconneced\nMin: 1\nDefault: {OpcKeepAliveDisconnectThreshold}", (uint u) => {
                          if (u > 1)
                          {
                              OpcKeepAliveDisconnectThreshold = u;
                          }
                          else
                          {
                              throw new OptionException("The keepalivethreshold must be greater than 1", "keepalivethreshold");
                          }
                      } },
                    { "st|opcstacktracemask=", $"the trace mask for the OPC stack. See github OPC .NET stack for definitions.\nTo enable IoTHub telemetry tracing set it to 711.\nDefault: {OpcStackTraceMask:X}  ({OpcStackTraceMask})", (int i) => {
                          if (i >= 0)
                          {
                              OpcStackTraceMask = i;
                          }
                          else
                          {
                              throw new OptionException("The OPC stack trace mask must be larger or equal 0.", "opcstacktracemask");
                          }
                      } },
                    { "as|autotrustservercerts=", $"the publisher trusts all servers it is establishing a connection to.\nDefault: {OpcPublisherAutoTrustServerCerts}", (bool b) => OpcPublisherAutoTrustServerCerts = b },

                    // trust own public cert option
                    { "tm|trustmyself=", $"the publisher certificate is put into the trusted certificate store automatically.\nDefault: {TrustMyself}", (bool b) => TrustMyself = b },

                    // read the display name of the nodes to publish from the server and publish them instead of the node id
                    { "fd|fetchdisplayname=", $"enable to read the display name of a published node from the server. this will increase the runtime.\nDefault: {FetchOpcNodeDisplayName}", (bool b) => FetchOpcNodeDisplayName = b },

                    // own cert store options
                    { "at|appcertstoretype=", $"the own application cert store type. \n(allowed values: Directory, X509Store)\nDefault: '{OpcOwnCertStoreType}'", (string s) => {
                          if (s.Equals(X509Store, StringComparison.OrdinalIgnoreCase) || s.Equals(Directory, StringComparison.OrdinalIgnoreCase))
                          {
                              OpcOwnCertStoreType = s.Equals(X509Store, StringComparison.OrdinalIgnoreCase) ? X509Store : Directory;
                              OpcOwnCertStorePath = s.Equals(X509Store, StringComparison.OrdinalIgnoreCase) ? OpcOwnCertX509StorePathDefault : OpcOwnCertDirectoryStorePathDefault;
                          }
                          else
                          {
                              throw new OptionException();
                          }
                      } },
                    { "ap|appcertstorepath=", $"the path where the own application cert should be stored\nDefault (depends on store type):\n" +
                      $"X509Store: '{OpcOwnCertX509StorePathDefault}'\n" +
                      $"Directory: '{OpcOwnCertDirectoryStorePathDefault}'", (string s) => OpcOwnCertStorePath = s },

                    // trusted cert store options
                    {
                        "tt|trustedcertstoretype=", $"the trusted cert store type. \n(allowed values: Directory, X509Store)\nDefault: {OpcTrustedCertStoreType}", (string s) => {
                            if (s.Equals(X509Store, StringComparison.OrdinalIgnoreCase) || s.Equals(Directory, StringComparison.OrdinalIgnoreCase))
                            {
                                OpcTrustedCertStoreType = s.Equals(X509Store, StringComparison.OrdinalIgnoreCase) ? X509Store : Directory;
                                OpcTrustedCertStorePath = s.Equals(X509Store, StringComparison.OrdinalIgnoreCase) ? OpcTrustedCertX509StorePathDefault : OpcTrustedCertDirectoryStorePathDefault;
                            }
                            else
                            {
                                throw new OptionException();
                            }
                        }
                    },
                    { "tp|trustedcertstorepath=", $"the path of the trusted cert store\nDefault (depends on store type):\n" +
                      $"X509Store: '{OpcTrustedCertX509StorePathDefault}'\n" +
                      $"Directory: '{OpcTrustedCertDirectoryStorePathDefault}'", (string s) => OpcTrustedCertStorePath = s },

                    // rejected cert store options
                    { "rt|rejectedcertstoretype=", $"the rejected cert store type. \n(allowed values: Directory, X509Store)\nDefault: {OpcRejectedCertStoreType}", (string s) => {
                          if (s.Equals(X509Store, StringComparison.OrdinalIgnoreCase) || s.Equals(Directory, StringComparison.OrdinalIgnoreCase))
                          {
                              OpcRejectedCertStoreType = s.Equals(X509Store, StringComparison.OrdinalIgnoreCase) ? X509Store : Directory;
                              OpcRejectedCertStorePath = s.Equals(X509Store, StringComparison.OrdinalIgnoreCase) ? OpcRejectedCertX509StorePathDefault : OpcRejectedCertDirectoryStorePathDefault;
                          }
                          else
                          {
                              throw new OptionException();
                          }
                      } },
                    { "rp|rejectedcertstorepath=", $"the path of the rejected cert store\nDefault (depends on store type):\n" +
                      $"X509Store: '{OpcRejectedCertX509StorePathDefault}'\n" +
                      $"Directory: '{OpcRejectedCertDirectoryStorePathDefault}'", (string s) => OpcRejectedCertStorePath = s },

                    // issuer cert store options
                    {
                        "it|issuercertstoretype=", $"the trusted issuer cert store type. \n(allowed values: Directory, X509Store)\nDefault: {OpcIssuerCertStoreType}", (string s) => {
                            if (s.Equals(X509Store, StringComparison.OrdinalIgnoreCase) || s.Equals(Directory, StringComparison.OrdinalIgnoreCase))
                            {
                                OpcIssuerCertStoreType = s.Equals(X509Store, StringComparison.OrdinalIgnoreCase) ? X509Store : Directory;
                                OpcIssuerCertStorePath = s.Equals(X509Store, StringComparison.OrdinalIgnoreCase) ? OpcIssuerCertX509StorePathDefault : OpcIssuerCertDirectoryStorePathDefault;
                            }
                            else
                            {
                                throw new OptionException();
                            }
                        }
                    },
                    { "ip|issuercertstorepath=", $"the path of the trusted issuer cert store\nDefault (depends on store type):\n" +
                      $"X509Store: '{OpcIssuerCertX509StorePathDefault}'\n" +
                      $"Directory: '{OpcIssuerCertDirectoryStorePathDefault}'", (string s) => OpcIssuerCertStorePath = s },

                    // device connection string cert store options
                    { "dt|devicecertstoretype=", $"the iothub device cert store type. \n(allowed values: Directory, X509Store)\nDefault: {IotDeviceCertStoreType}", (string s) => {
                          if (s.Equals(X509Store, StringComparison.OrdinalIgnoreCase) || s.Equals(Directory, StringComparison.OrdinalIgnoreCase))
                          {
                              IotDeviceCertStoreType = s.Equals(X509Store, StringComparison.OrdinalIgnoreCase) ? X509Store : Directory;
                              IotDeviceCertStorePath = s.Equals(X509Store, StringComparison.OrdinalIgnoreCase) ? IotDeviceCertX509StorePathDefault : IotDeviceCertDirectoryStorePathDefault;
                          }
                          else
                          {
                              throw new OptionException();
                          }
                      } },
                    { "dp|devicecertstorepath=", $"the path of the iot device cert store\nDefault Default (depends on store type):\n" +
                      $"X509Store: '{IotDeviceCertX509StorePathDefault}'\n" +
                      $"Directory: '{IotDeviceCertDirectoryStorePathDefault}'", (string s) => IotDeviceCertStorePath = s },

                    // misc
                    { "h|help", "show this message and exit", h => shouldShowHelp = h != null },
                };

                List <string> arguments             = new List <string>();
                int           maxAllowedArguments   = 2;
                int           applicationNameIndex  = 0;
                int           connectionStringIndex = 1;
                if (IsIotEdgeModule)
                {
                    maxAllowedArguments   = 3;
                    applicationNameIndex  = 1;
                    connectionStringIndex = 2;
                }
                try
                {
                    // parse the command line
                    arguments = options.Parse(args);
                }
                catch (OptionException e)
                {
                    // show message
                    WriteLine($"Error: {e.Message}");
                    // show usage
                    Usage(options);
                    return;
                }

                // Validate and parse arguments.
                if (arguments.Count > maxAllowedArguments || shouldShowHelp)
                {
                    Usage(options);
                    return;
                }
                else if (arguments.Count == maxAllowedArguments)
                {
                    ApplicationName             = arguments[applicationNameIndex];
                    IotHubOwnerConnectionString = arguments[connectionStringIndex];
                }
                else if (arguments.Count == maxAllowedArguments - 1)
                {
                    ApplicationName = arguments[applicationNameIndex];
                }
                else
                {
                    ApplicationName = Utils.GetHostName();
                }

                WriteLine("Publisher is starting up...");

                // Shutdown token sources.
                ShutdownTokenSource = new CancellationTokenSource();

                // init OPC configuration and tracing
                OpcStackConfiguration opcStackConfiguration = new OpcStackConfiguration();
                await opcStackConfiguration.ConfigureAsync();

                _opcTraceInitialized = true;

                // log shopfloor domain setting
                if (string.IsNullOrEmpty(ShopfloorDomain))
                {
                    Trace("There is no shopfloor domain configured.");
                }
                else
                {
                    Trace($"Publisher is in shopfloor domain '{ShopfloorDomain}'.");
                }

                // Set certificate validator.
                if (OpcPublisherAutoTrustServerCerts)
                {
                    Trace("Publisher configured to auto trust server certificates of the servers it is connecting to.");
                    PublisherOpcApplicationConfiguration.CertificateValidator.CertificateValidation += new CertificateValidationEventHandler(CertificateValidator_AutoTrustServerCerts);
                }
                else
                {
                    Trace("Publisher configured to not auto trust server certificates. When connecting to servers, you need to manually copy the rejected server certs to the trusted store to trust them.");
                    PublisherOpcApplicationConfiguration.CertificateValidator.CertificateValidation += new CertificateValidationEventHandler(CertificateValidator_Default);
                }

                // read telemetry configuration file
                PublisherTelemetryConfiguration.Init();
                if (!await PublisherTelemetryConfiguration.ReadConfigAsync())
                {
                    return;
                }

                // read node configuration file
                // read it before loading desired properties in case of misconfigurations
                PublisherNodeConfiguration.Init();
                if (!await PublisherNodeConfiguration.ReadConfigAsync())
                {
                    return;
                }

                // initialize and start IoTHub messaging
                IotHubCommunication = new IotHubMessaging();
                if (!await IotHubCommunication.InitAsync())
                {
                    return;
                }

                if (!await PublisherNodeConfiguration.CreateOpcPublishingDataAsync())
                {
                    return;
                }

                // kick off the task to maintain all sessions
                Task sessionConnectorAsync = Task.Run(async() => await SessionConnectorAsync(ShutdownTokenSource.Token));

                // initialize publisher diagnostics
                Diagnostics.Init();

                // stop on user request
                WriteLine("");
                WriteLine("");
                if (_noShutdown)
                {
                    // wait forever if asked to do so
                    WriteLine("Publisher is running infinite...");
                    await Task.Delay(Timeout.Infinite);
                }
                else
                {
                    WriteLine("Publisher is running. Press any key to quit.");
                    try
                    {
                        ReadKey(true);
                    }
                    catch
                    {
                        // wait forever if there is no console
                        WriteLine("There is no console. Publisher is running infinite...");
                        await Task.Delay(Timeout.Infinite);
                    }
                }
                WriteLine("");
                WriteLine("");
                ShutdownTokenSource.Cancel();
                WriteLine("Publisher is shutting down...");

                // Wait for session connector completion
                await sessionConnectorAsync;

                // Clean up Publisher sessions
                await SessionShutdownAsync();

                // shutdown the IoTHub messaging
                await IotHubCommunication.ShutdownAsync();

                IotHubCommunication = null;

                // shutdown diagnostics
                await ShutdownAsync();

                // free resources
                PublisherTelemetryConfiguration.Deinit();
                PublisherNodeConfiguration.Deinit();
                ShutdownTokenSource = null;
            }
            catch (Exception e)
            {
                if (_opcTraceInitialized)
                {
                    Trace(e, e.StackTrace);
                    e = e.InnerException ?? null;
                    while (e != null)
                    {
                        Trace(e, e.StackTrace);
                        e = e.InnerException ?? null;
                    }
                    Trace("Publisher exiting... ");
                }
                else
                {
                    WriteLine($"{DateTime.Now.ToString()}: {e.Message.ToString()}");
                    WriteLine($"{DateTime.Now.ToString()}: {e.StackTrace}");
                    e = e.InnerException ?? null;
                    while (e != null)
                    {
                        WriteLine($"{DateTime.Now.ToString()}: {e.Message.ToString()}");
                        WriteLine($"{DateTime.Now.ToString()}: {e.StackTrace}");
                        e = e.InnerException ?? null;
                    }
                    WriteLine($"{DateTime.Now.ToString()}: Publisher exiting...");
                }
            }
        }
コード例 #24
0
        public static int Main(string[] args)
        {
            Console.WriteLine(
                (Utils.IsRunningOnMono() ? "Mono" : ".Net Core") +
                " OPC UA Console Client sample");

            // command line options
            bool showHelp    = false;
            int  stopTimeout = Timeout.Infinite;
            bool autoAccept  = false;

            Mono.Options.OptionSet options = new Mono.Options.OptionSet {
                { "h|help", "show this message and exit", h => showHelp = h != null },
                { "a|autoaccept", "auto accept certificates (for testing only)", a => autoAccept = a != null },
                { "t|timeout=", "the number of seconds until the client stops.", (int t) => stopTimeout = t }
            };

            IList <string> extraArgs = null;

            try
            {
                extraArgs = options.Parse(args);
                if (extraArgs.Count > 1)
                {
                    foreach (string extraArg in extraArgs)
                    {
                        Console.WriteLine("Error: Unknown option: {0}", extraArg);
                        showHelp = true;
                    }
                }
            }
            catch (OptionException e)
            {
                Console.WriteLine(e.Message);
                showHelp = true;
            }

            if (showHelp)
            {
                // show some app description message
                Console.WriteLine(Utils.IsRunningOnMono() ?
                                  "Usage: mono MonoConsoleClient.exe [OPTIONS] [ENDPOINTURL]" :
                                  "Usage: dotnet NetCoreConsoleClient.dll [OPTIONS] [ENDPOINTURL]");
                Console.WriteLine();

                // output the options
                Console.WriteLine("Options:");
                options.WriteOptionDescriptions(Console.Out);
                return((int)ExitCode.ErrorInvalidCommandLine);
            }

            string endpointURL;

            if (extraArgs.Count == 0)
            {
                // use OPC UA .Net Sample server
                endpointURL = "opc.tcp://localhost:51210/UA/SampleServer";
            }
            else
            {
                endpointURL = extraArgs[0];
            }

            MySampleClient client = new MySampleClient(endpointURL, autoAccept, stopTimeout);

            client.Run();

            return((int)MySampleClient.ExitCode);
        }
コード例 #25
0
#pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously
        /// <summary>
        /// Asynchronous part of the main method of the app.
        /// </summary>
        public async static Task MainAsync(string[] args)
#pragma warning restore CS1998 // Async method lacks 'await' operators and will run synchronously
        {
            Logger = new LoggerConfiguration()
                     .WriteTo.Console()
                     .MinimumLevel.Debug()
                     .CreateLogger();

            Logger.Information($"OPC Publisher testclient");

            // command line options
            bool   showHelp                  = false;
            int    testTimeMillisec          = Timeout.Infinite;
            bool   opcMethods                = false;
            bool   iotHubMethods             = false;
            string iotHubConnectionString    = string.Empty;
            string iotHubPublisherDeviceName = string.Empty;
            string iotHubPublisherModuleName = string.Empty;
            int    initialWait               = 10000;

            Mono.Options.OptionSet options = new Mono.Options.OptionSet {
                { "h|help", "show this message and exit", h => showHelp = h != null },
                { "ip|initialpause=", $"initial wait in sec to allow other services to start up.\nDefault: {initialWait/1000}", (int i) => initialWait = i * 1000 },
                { "aa|autoaccept", "auto accept certificates (for testing only)", a => AutoAccept = a != null },
                { "ne|noexclusive", "do not execute any exclusive tests", ne => RunExclusiveTests = ne == null },
                { "tt|testtime=", "the number of seconds to run the different tests", (int t) => testTimeMillisec = t * 1000 },
                { "tu|testserverurl=", "URL of the OPC UA test server", (string s) => TestserverUrl = s },
                { "pu|publisherurl=", "URL of the OPC Publisher (required when using OPC UA methods)", (string s) => PublisherUrl = s },
                { "o1|opcmethods", "use the OPC UA methods calls to test", b => opcMethods = b != null },
                { "ic|iothubconnectionstring=", "IoTHub owner connectionstring", (string s) => iotHubConnectionString = s },
                { "id|iothubdevicename=", "IoTHub device name of the OPC Publisher (required when using IoT methods)", (string s) => iotHubPublisherDeviceName = s },
                { "im|iothubmodulename=", "IoTEdge module name of the OPC Publisher which runs in IoTEdge specified by im/iothubdevicename(required when using IoT methods and IoTEdge)", (string s) => iotHubPublisherModuleName = s },
                { "i1|iothubmethods", "use IoTHub direct methods calls to test", b => iotHubMethods = b != null },
                { "lf|logfile=", $"the filename of the logfile to use.\nDefault: './{_logFileName}'", (string l) => _logFileName = l },
                { "ll|loglevel=", $"the loglevel to use (allowed: fatal, error, warn, info, debug, verbose).\nDefault: info", (string l) => {
                      List <string> logLevels = new List <string> {
                          "fatal", "error", "warn", "info", "debug", "verbose"
                      };
#pragma warning disable CA1308 // Normalize strings to uppercase
                      if (logLevels.Contains(l.ToLowerInvariant()))
                      {
                          _logLevel = l.ToLowerInvariant();
                      }
#pragma warning restore CA1308 // Normalize strings to uppercase
                      else
                      {
                          throw new OptionException("The loglevel must be one of: fatal, error, warn, info, debug, verbose", "loglevel");
                      }
                  } }
            };

            IList <string> extraArgs = null;
            try
            {
                extraArgs = options.Parse(args);
            }
            catch (OptionException e)
            {
                // initialize logging
                InitLogging();

                // show message
                Logger.Fatal(e, "Error in command line options");

                // show usage
                Usage(options, args);
                return;
            }

            // initialize logging
            InitLogging();

            // show usage if requested
            if (showHelp)
            {
                Usage(options);
                return;
            }

            // by default we are connecting to the OPC UA servers in the testbed
            if (extraArgs.Count > 0)
            {
                for (int i = 1; i < extraArgs.Count; i++)
                {
                    Logger.Error("Error: Unknown option: {0}", extraArgs[i]);
                }
                Usage(options, args);
                return;
            }

            // initial wait
            Logger.Information($"Waiting for {initialWait/1000} secondes...");
            Thread.Sleep(initialWait);

            // sanity check parameters
            if (opcMethods == false && iotHubMethods == false)
            {
                Logger.Information($"No specific test area specified, enabling all.");
                opcMethods = iotHubMethods = true;
            }
            if (opcMethods)
            {
                Logger.Information($"Publisher URL: {PublisherUrl}");
            }
            if (iotHubMethods)
            {
                if (string.IsNullOrEmpty(iotHubConnectionString) || string.IsNullOrEmpty(iotHubPublisherDeviceName))
                {
                    Logger.Fatal("For any tests via IoTHub communication an IoTHub connection string and the publisher devicename (and modulename) must be specified.");
                    return;
                }
                Logger.Information($"IoTHub connectionstring: {iotHubConnectionString}");
                if (string.IsNullOrEmpty(iotHubPublisherModuleName))
                {
                    Logger.Information($"Testing OPC Publisher device.");
                    Logger.Information($"IoTHub Publisher device name: {iotHubPublisherDeviceName}");
                }
                else
                {
                    Logger.Information($"Testing OPC Publisher IoTEdge module.");
                    Logger.Information($"IoTEdge device name: {iotHubPublisherDeviceName}");
                    Logger.Information($"IoTHub Publisher device name: {iotHubPublisherModuleName}");
                }
            }
            CancellationTokenSource cts = new CancellationTokenSource();
            CancellationToken       ct  = cts.Token;

            ManualResetEvent quitEvent = new ManualResetEvent(false);
            try
            {
                Console.CancelKeyPress += (sender, eArgs) =>
                {
                    quitEvent.Set();
                    eArgs.Cancel = true;
                };
            }
            catch
            {
            }

            // instantiate test objectes
            OpcMethodTest    opcMethodTest    = null;
            IotHubMethodTest iotHubMethodTest = null;
            if (opcMethods)
            {
                opcMethodTest = new OpcMethodTest(TestserverUrl, MaxShortWaitSec, MaxLongWaitSec, ct);
            }

            if (iotHubMethods)
            {
                iotHubMethodTest = new IotHubMethodTest(iotHubConnectionString, iotHubPublisherDeviceName, iotHubPublisherModuleName, TestserverUrl,
                                                        MaxShortWaitSec, MaxLongWaitSec, ct);
            }

            // run all tests with need exclusive access to the server
            if (RunExclusiveTests && opcMethods)
            {
                opcMethodTest.RunExclusiveTests(ct);
            }

            if (RunExclusiveTests && iotHubMethods)
            {
                iotHubMethodTest.RunExclusiveTests(ct);
            }

            // run all tests which can be executed concurrently
            List <Task> testTasks = new List <Task>();
            if (opcMethods)
            {
                testTasks.AddRange(opcMethodTest.RunConcurrentTests(ct));
            }

            if (iotHubMethods)
            {
                testTasks.AddRange(iotHubMethodTest.RunConcurrentTests(ct));
            }

            // run all tests for the specified time or Ctrl-C is pressed
            Logger.Information($"Run tests {(testTimeMillisec != Timeout.Infinite ? $"for {testTimeMillisec/1000} seconds or" : "till")} CTRL-C is pressed");
            quitEvent.WaitOne(testTimeMillisec);
            Logger.Information($"Signal cancellation and wait will everything is completed.");
            cts.Cancel();
            // wait till all tasks are completed
            Task.WaitAll(testTasks.ToArray());
            Logger.Information($"Exiting....");
            return;
        }
コード例 #26
0
        /// <summary>
        /// Asynchronous part of the main method of the app.
        /// </summary>
        public async static Task MainAsync(string[] args)
        {
            Logger = new LoggerConfiguration()
                     .WriteTo.Console()
                     .MinimumLevel.Debug()
                     .CreateLogger();

            Logger.Information($"OPC Publisher node configuration tool");

            // command line options
            bool   showHelp = false;
            string iotHubConnectionString    = string.Empty;
            string iotHubPublisherDeviceName = string.Empty;
            string iotHubPublisherModuleName = string.Empty;

            Mono.Options.OptionSet options = new Mono.Options.OptionSet {
                { "h|help", "show this message and exit", h => showHelp = h != null },

                { "ic|iotHubConnectionString=", "IoTHub owner or service connectionstring", (string s) => iotHubConnectionString = s },
                { "id|iothubdevicename=", "IoTHub device name of the OPC Publisher", (string s) => iotHubPublisherDeviceName = s },
                { "im|iothubmodulename=", "IoT Edge module name of the OPC Publisher which runs in the IoT Edge device specified by id/iothubdevicename", (string s) => iotHubPublisherModuleName = s },

                { "pc|purgeconfig", "remove all configured nodes before pushing new ones", b => _purgeConfig = b != null },
                { "bf|backupfile=", $"the filename to store the existing node configuration of OPC Publisher\nDefault: './{_backupFileName}'", (string l) => _backupFileName = l },
                { "nc|nodeconfigfile=", $"the filename of the new node configuration to be set", (string l) => _nodeConfigFileName = l },

                { "lf|logfile=", $"the filename of the logfile to use\nDefault: './{_logFileName}'", (string l) => _logFileName = l },
                { "ll|loglevel=", $"the loglevel to use (allowed: fatal, error, warn, info, debug, verbose).\nDefault: info", (string l) => {
                      List <string> logLevels = new List <string> {
                          "fatal", "error", "warn", "info", "debug", "verbose"
                      };
                      if (logLevels.Contains(l.ToLowerInvariant()))
                      {
                          _logLevel = l.ToLowerInvariant();
                      }
                      else
                      {
                          throw new OptionException("The loglevel must be one of: fatal, error, warn, info, debug, verbose", "loglevel");
                      }
                  } }
            };

            IList <string> extraArgs = null;

            try
            {
                extraArgs = options.Parse(args);
            }
            catch (OptionException e)
            {
                // initialize logging
                InitLogging();

                // show message
                Logger.Fatal(e, "Error in command line options");

                // show usage
                Usage(options, args);
                return;
            }

            // initialize logging
            InitLogging();

            // show usage if requested
            if (showHelp)
            {
                Usage(options);
                return;
            }

            // no extra options
            if (extraArgs.Count > 0)
            {
                for (int i = 1; i < extraArgs.Count; i++)
                {
                    Logger.Error("Error: Unknown option: {0}", extraArgs[i]);
                }
                Usage(options, args);
                return;
            }

            // sanity check parameters
            if (string.IsNullOrEmpty(iotHubConnectionString) || string.IsNullOrEmpty(iotHubPublisherDeviceName))
            {
                Logger.Fatal("For IoTHub communication an IoTHub connection string and the publisher devicename (and modulename) must be specified.");
                return;
            }
            Logger.Information($"IoTHub connectionstring: {iotHubConnectionString}");
            if (string.IsNullOrEmpty(iotHubPublisherModuleName))
            {
                Logger.Information($"OPC Publisher not running in IoT Edge.");
                Logger.Information($"IoTHub OPC Publisher device name: {iotHubPublisherDeviceName}");
            }
            else
            {
                Logger.Information($"OPC Publisher running as IoT Edge module.");
                Logger.Information($"IoT Edge device name: {iotHubPublisherDeviceName}");
                Logger.Information($"OPC Publisher module name: {iotHubPublisherModuleName}");
            }
            CancellationTokenSource cts = new CancellationTokenSource();
            CancellationToken       ct  = cts.Token;

            // read new configuration
            if (!string.IsNullOrEmpty(_nodeConfigFileName))
            {
                try
                {
                    _configurationFileEntries = JsonConvert.DeserializeObject <List <PublisherConfigurationFileEntryLegacyModel> >(File.ReadAllText(_nodeConfigFileName));
                }
                catch (Exception e)
                {
                    Logger.Fatal(e, $"Error reading configuration file. Exiting...");
                    return;
                }
                Logger.Information($"The configuration file '{_nodeConfigFileName}' to be applied contains {_configurationFileEntries.Count} entries.");
            }

            // instantiate OPC Publisher interface
            Publisher publisher = new Publisher(iotHubConnectionString, iotHubPublisherDeviceName, iotHubPublisherModuleName, MAX_SHORT_WAIT_SEC, MAX_LONG_WAIT_SEC, ct);

            // read existing configuration
            List <PublisherConfigurationFileEntryModel> currentConfiguration = new List <PublisherConfigurationFileEntryModel>();
            List <string> configuredEndpoints = publisher.GetConfiguredEndpoints(ct);

            if (configuredEndpoints.Count > 0)
            {
                Logger.Information($"OPC Publisher has the following node configuration:");
            }
            else
            {
                Logger.Information($"OPC Publisher is not publishing any data.");
            }
            foreach (var configuredEndpoint in configuredEndpoints)
            {
                List <NodeModel> configuredNodesOnEndpoint       = publisher.GetConfiguredNodesOnEndpoint(configuredEndpoint, ct);
                PublisherConfigurationFileEntryModel configEntry = new PublisherConfigurationFileEntryModel();
                configEntry.EndpointUrl = new Uri(configuredEndpoint);
                List <OpcNodeOnEndpointModel> nodesOnEndpoint = new List <OpcNodeOnEndpointModel>();
                Logger.Information($"For endpoint '{configuredEndpoint}' there are {configuredNodesOnEndpoint.Count} nodes configured.");
                foreach (var configuredNode in configuredNodesOnEndpoint)
                {
                    Logger.Debug($"Id '{configuredNode.Id}', " +
                                 $"OpcPublishingInterval: {(configuredNode.OpcPublishingInterval == null ? "default" : configuredNode.OpcPublishingInterval.ToString())}, " +
                                 $"OpcSamplingInterval: {(configuredNode.OpcSamplingInterval == null ? "default" : configuredNode.OpcSamplingInterval.ToString())}");
                    OpcNodeOnEndpointModel opcNodeOnEndpoint = new OpcNodeOnEndpointModel();
                    opcNodeOnEndpoint.Id = configuredNode.Id;
                    opcNodeOnEndpoint.OpcSamplingInterval   = configuredNode.OpcSamplingInterval;
                    opcNodeOnEndpoint.OpcPublishingInterval = configuredNode.OpcPublishingInterval;
                    nodesOnEndpoint.Add(opcNodeOnEndpoint);
                }
                configEntry.OpcNodes = nodesOnEndpoint;
                currentConfiguration.Add(configEntry);
            }

            // save it on request
            if (!string.IsNullOrEmpty(_backupFileName) && currentConfiguration.Count > 0)
            {
                await File.WriteAllTextAsync(_backupFileName, JsonConvert.SerializeObject(currentConfiguration, Formatting.Indented));

                Logger.Information($"The existing OPC Publisher node configuration was saved in '{_backupFileName}'");
            }

            // remove existing configuration on request
            if (_purgeConfig)
            {
                publisher.UnpublishAllConfiguredNodes(ct);
                Logger.Information($"The existing node configuration was purged. OPC Publisher should no longer publish any data.");
            }

            // push new configuration, if required
            if (_configurationFileEntries != null)
            {
                var uniqueEndpoints = _configurationFileEntries.Select(e => e.EndpointUrl).Distinct();
                Logger.Information($"The new node configuration will now be set in OPC Publisher.");
                foreach (var uniqueEndpoint in uniqueEndpoints)
                {
                    var endpointConfigurationfileEntries       = _configurationFileEntries.Where(e => e.EndpointUrl == uniqueEndpoint);
                    List <NodeIdInfo> configurationNodeIdInfos = new List <NodeIdInfo>();
                    foreach (var endpointConfigurationFileEntry in endpointConfigurationfileEntries)
                    {
                        foreach (var opcNode in endpointConfigurationFileEntry.OpcNodes)
                        {
                            Logger.Debug($"Id '{opcNode.Id}', " +
                                         $"OpcPublishingInterval: {(opcNode.OpcPublishingInterval == null ? "default" : opcNode.OpcPublishingInterval.ToString())}, " +
                                         $"OpcSamplingInterval: {(opcNode.OpcSamplingInterval == null ? "default" : opcNode.OpcSamplingInterval.ToString())}");
                            NodeIdInfo nodeIdInfo = new NodeIdInfo(opcNode.Id);
                            configurationNodeIdInfos.Add(nodeIdInfo);
                        }
                    }
                    if (!publisher.PublishNodes(configurationNodeIdInfos, ct, uniqueEndpoint.AbsoluteUri))
                    {
                        Logger.Error($"Not able to send the new node configuration to OPC Publisher.");
                    }
                }
            }

            // done
            Logger.Information($"Done. Exiting....");
            return;
        }
コード例 #27
0
        /// <summary>
        /// Parse arguments and set values in the environment the way the new configuration expects it.
        /// </summary>
        /// <param name="args">The specified command line arguments.</param>
        public StandaloneCliOptions(string[] args)
        {
            _logger = ConsoleLogger.Create(LogEventLevel.Warning);

            bool          showHelp           = false;
            List <string> unsupportedOptions = new List <string>();
            List <string> legacyOptions      = new List <string>();

            // command line options
            var options = new Mono.Options.OptionSet {
                // Publisher configuration options
                { $"pf|publishfile=|{StandaloneCliConfigKeys.PublishedNodesConfigurationFilename}=", "The filename to configure the nodes to publish.",
                  s => this[StandaloneCliConfigKeys.PublishedNodesConfigurationFilename] = s },
                { $"pfs|publishfileschema=|{StandaloneCliConfigKeys.PublishedNodesConfigurationSchemaFilename}=", "The validation schema filename for publish file. Disabled by default.",
                  s => this[StandaloneCliConfigKeys.PublishedNodesConfigurationSchemaFilename] = s },
                { "s|site=", "The site OPC Publisher is working in.",
                  s => this[StandaloneCliConfigKeys.PublisherSite] = s },

                { $"di|diagnosticsinterval=|{StandaloneCliConfigKeys.DiagnosticsInterval}=", "Shows publisher diagnostic info at the specified interval " +
                  "in seconds (need log level info).\n-1 disables remote diagnostic log and diagnostic output",
                  (int i) => this[StandaloneCliConfigKeys.DiagnosticsInterval] = TimeSpan.FromSeconds(i).ToString() },
                { $"lf|logfile=|{StandaloneCliConfigKeys.LogFileName}=", "The filename of the logfile to use.",
                  s => this[StandaloneCliConfigKeys.LogFileName] = s },
                { $"lt|logflushtimespan=|{StandaloneCliConfigKeys.LogFileFlushTimeSpanSec}=", "The timespan in seconds when the logfile should be flushed.",
                  (int i) => this[StandaloneCliConfigKeys.LogFileFlushTimeSpanSec] = TimeSpan.FromSeconds(i).ToString() },
                { "ll|loglevel=", "The loglevel to use (allowed: fatal, error, warn, info, debug, verbose).",
                  (LogEventLevel l) => LogControl.Level.MinimumLevel = l },
                { $"ih|iothubprotocol=|{StandaloneCliConfigKeys.HubTransport}=", "Protocol to use for communication with the hub. " +
                  $"(allowed values: {string.Join(", ", Enum.GetNames(typeof(TransportOption)))}).",
                  (TransportOption p) => this[StandaloneCliConfigKeys.HubTransport] = p.ToString() },
                { "dc|deviceconnectionstring=", "A device or edge module connection string to use.",
                  dc => this[StandaloneCliConfigKeys.EdgeHubConnectionString] = dc },
                { $"ec|edgehubconnectionstring=|{StandaloneCliConfigKeys.EdgeHubConnectionString}=", "An edge module connection string to use",
                  dc => this[StandaloneCliConfigKeys.EdgeHubConnectionString] = dc },
                { $"{StandaloneCliConfigKeys.BypassCertVerificationKey}=", "Enables bypass of certificate verification for upstream communication to edgeHub.",
                  (bool b) => this[StandaloneCliConfigKeys.BypassCertVerificationKey] = b.ToString() },
                { $"{StandaloneCliConfigKeys.EnableMetricsKey}=", "Enables upstream metrics propagation.",
                  (bool b) => this[StandaloneCliConfigKeys.EnableMetricsKey] = b.ToString() },

                { $"hb|heartbeatinterval=|{StandaloneCliConfigKeys.HeartbeatIntervalDefault}=", "The publisher is using this as default value in seconds " +
                  "for the heartbeat interval setting of nodes without a heartbeat interval setting.",
                  (int i) => this[StandaloneCliConfigKeys.HeartbeatIntervalDefault] = TimeSpan.FromSeconds(i).ToString() },
                // ToDo: Bring back once SkipFirst mechanism is implemented.
                //{ "sf|skipfirstevent=", "The publisher is using this as default value for the skip first " +
                //    "event setting of nodes without a skip first event setting.",
                //    (bool b) => this[StandaloneCliConfigKeys.SkipFirstDefault] = b.ToString() },

                { $"fm|fullfeaturedmessage=|{StandaloneCliConfigKeys.FullFeaturedMessage}=", "The full featured mode for messages (all fields filled in)." +
                  "Default is 'false' for legacy compatibility.",
                  (bool b) => this[StandaloneCliConfigKeys.FullFeaturedMessage] = b.ToString() },

                // Client settings
                { $"ot|operationtimeout=|{StandaloneCliConfigKeys.OpcOperationTimeout}=", "The operation timeout of the publisher OPC UA client in milliseconds.",
                  (uint u) => this[StandaloneCliConfigKeys.OpcOperationTimeout] = u.ToString() },
                { $"ol|opcmaxstringlen=|{StandaloneCliConfigKeys.OpcMaxStringLength}=", "The max length of a string opc can transmit/receive.",
                  (uint u) => this[StandaloneCliConfigKeys.OpcMaxStringLength] = u.ToString() },
                { $"{StandaloneCliConfigKeys.SecurityTokenLifetimeKey}=", "OPC UA Stack Transport Secure Channel - Security token lifetime in milliseconds.",
                  (uint u) => this[StandaloneCliConfigKeys.SecurityTokenLifetimeKey] = u.ToString() },
                { $"{StandaloneCliConfigKeys.ChannelLifetimeKey}=", "OPC UA Stack Transport Secure Channel - Channel lifetime in milliseconds.",
                  (uint u) => this[StandaloneCliConfigKeys.ChannelLifetimeKey] = u.ToString() },
                { $"{StandaloneCliConfigKeys.MaxBufferSizeKey}=", "OPC UA Stack Transport Secure Channel - Max buffer size.",
                  (uint u) => this[StandaloneCliConfigKeys.MaxBufferSizeKey] = u.ToString() },
                { $"{StandaloneCliConfigKeys.MaxMessageSizeKey}=", "OPC UA Stack Transport Secure Channel - Max message size.",
                  (uint u) => this[StandaloneCliConfigKeys.MaxMessageSizeKey] = u.ToString() },
                { $"{StandaloneCliConfigKeys.MaxArrayLengthKey}=", "OPC UA Stack Transport Secure Channel - Max array length.",
                  (uint u) => this[StandaloneCliConfigKeys.MaxArrayLengthKey] = u.ToString() },
                { $"{StandaloneCliConfigKeys.MaxByteStringLengthKey}=", "OPC UA Stack Transport Secure Channel - Max byte string length.",
                  (uint u) => this[StandaloneCliConfigKeys.MaxByteStringLengthKey] = u.ToString() },

                { $"oi|opcsamplinginterval=|{StandaloneCliConfigKeys.OpcSamplingInterval}=", "Default value in milliseconds to request the servers to " +
                  "sample values.",
                  (int i) => this[StandaloneCliConfigKeys.OpcSamplingInterval] = TimeSpan.FromMilliseconds(i).ToString() },
                { $"op|opcpublishinginterval=|{StandaloneCliConfigKeys.OpcPublishingInterval}=", "Default value in milliseconds for the publishing interval " +
                  "setting of the subscriptions against the OPC UA server.",
                  (int i) => this[StandaloneCliConfigKeys.OpcPublishingInterval] = TimeSpan.FromMilliseconds(i).ToString() },

                { $"{StandaloneCliConfigKeys.ApplicationUriKey}=", "OPC UA Client Application Config - Application URI as per OPC UA definition.",
                  s => this[StandaloneCliConfigKeys.ApplicationUriKey] = s },
                { $"{StandaloneCliConfigKeys.ProductUriKey}=", "OPC UA Client Application Config - Product URI as per OPC UA definition.",
                  s => this[StandaloneCliConfigKeys.ProductUriKey] = s },
                { $"ct|createsessiontimeout=|{StandaloneCliConfigKeys.OpcSessionCreationTimeout}=", "Maximum amount of time in seconds that a session should " +
                  "remain open by the OPC server without any activity (session timeout) " +
                  "- to request from the OPC server at session creation.",
                  (uint u) => this[StandaloneCliConfigKeys.OpcSessionCreationTimeout] = u.ToString() },
                { $"{StandaloneCliConfigKeys.MinSubscriptionLifetimeKey}=", "OPC UA Client Application Config - " +
                  "Minimum subscription lifetime in seconds as per OPC UA definition.",
                  (int i) => this[StandaloneCliConfigKeys.MinSubscriptionLifetimeKey] = i.ToString() },
                { $"ki|keepaliveinterval=|{StandaloneCliConfigKeys.OpcKeepAliveIntervalInSec}=", "The interval in seconds the publisher is sending keep alive messages " +
                  "to the OPC servers on the endpoints it is connected to.",
                  (int i) => this[StandaloneCliConfigKeys.OpcKeepAliveIntervalInSec] = i.ToString() },
                { $"kt|keepalivethreshold=|{StandaloneCliConfigKeys.OpcKeepAliveDisconnectThreshold}=",
                  "Specify the number of keep alive packets a server can miss, before the session is disconneced.",
                  (uint u) => this[StandaloneCliConfigKeys.OpcKeepAliveDisconnectThreshold] = u.ToString() },

                { $"fd|fetchdisplayname=|{StandaloneCliConfigKeys.FetchOpcNodeDisplayName}=", "Fetches the displayname for the monitored items subscribed.",
                  (bool b) => this[StandaloneCliConfigKeys.FetchOpcNodeDisplayName] = b.ToString() },
                { $"mq|monitoreditemqueuecapacity=|{StandaloneCliConfigKeys.DefaultQueueSize}=", "Default queue size for monitored items.",
                  (uint u) => this[StandaloneCliConfigKeys.DefaultQueueSize] = u.ToString() },

                // cert store option
                { $"aa|autoaccept", "The publisher trusts all servers it is establishing a connection to.",
                  b => this[StandaloneCliConfigKeys.AutoAcceptCerts] = (b != null).ToString() },
                { $"{StandaloneCliConfigKeys.AutoAcceptCerts}=", "The publisher trusts all servers it is establishing a connection to.",
                  (bool b) => this[StandaloneCliConfigKeys.AutoAcceptCerts] = b.ToString() },
                { $"tm|trustmyself", "The publisher certificate is put into the trusted store automatically.",
                  b => this[StandaloneCliConfigKeys.TrustMyself] = (b != null).ToString() },
                { $"{StandaloneCliConfigKeys.TrustMyself}=", "The publisher certificate is put into the trusted store automatically.",
                  (bool b) => this[StandaloneCliConfigKeys.TrustMyself] = b.ToString() },
                { $"at|appcertstoretype=|{StandaloneCliConfigKeys.OpcOwnCertStoreType}=", "The own application cert store type (allowed: Directory, X509Store).",
                  s => {
                      if (s.Equals(CertificateStoreType.X509Store, StringComparison.OrdinalIgnoreCase) ||
                          s.Equals(CertificateStoreType.Directory, StringComparison.OrdinalIgnoreCase))
                      {
                          this[StandaloneCliConfigKeys.OpcOwnCertStoreType] = s;
                          return;
                      }
                      throw new OptionException("Bad store type", "at");
                  } },
                { $"ap|appcertstorepath=|{StandaloneCliConfigKeys.OpcOwnCertStorePath}=", "The path where the own application cert should be stored.",
                  s => this[StandaloneCliConfigKeys.OpcOwnCertStorePath] = s },
                { $"tp|trustedcertstorepath=|{StandaloneCliConfigKeys.OpcTrustedCertStorePath}=", "The path of the trusted cert store.",
                  s => this[StandaloneCliConfigKeys.OpcTrustedCertStorePath] = s },
                { $"sn|appcertsubjectname=|{StandaloneCliConfigKeys.OpcApplicationCertificateSubjectName}=", "The subject name for the app cert.",
                  s => this[StandaloneCliConfigKeys.OpcApplicationCertificateSubjectName] = s },
                { $"an|appname=|{StandaloneCliConfigKeys.OpcApplicationName}=", "The name for the app (used during OPC UA authentication).",
                  s => this[StandaloneCliConfigKeys.OpcApplicationName] = s },
                { "tt|trustedcertstoretype=", "Legacy - do not use.", b => { legacyOptions.Add("tt|trustedcertstoretype"); } },
                { $"rp|rejectedcertstorepath=|{StandaloneCliConfigKeys.OpcRejectedCertStorePath}=", "The path of the rejected cert store.",
                  s => this[StandaloneCliConfigKeys.OpcRejectedCertStorePath] = s },
                { "rt|rejectedcertstoretype=", "Legacy - do not use.", b => { legacyOptions.Add("rt|rejectedcertstoretype"); } },
                { $"ip|issuercertstorepath=|{StandaloneCliConfigKeys.OpcIssuerCertStorePath}=", "The path of the trusted issuer cert store.",
                  s => this[StandaloneCliConfigKeys.OpcIssuerCertStorePath] = s },
                { $"{StandaloneCliConfigKeys.PkiRootPathKey}=", "PKI certificate store root path.",
                  s => this[StandaloneCliConfigKeys.PkiRootPathKey] = s },
                { $"{StandaloneCliConfigKeys.TrustedIssuerCertificatesTypeKey}=", "Trusted issuer certificate types.",
                  s => this[StandaloneCliConfigKeys.TrustedIssuerCertificatesTypeKey] = s },
                { $"{StandaloneCliConfigKeys.TrustedPeerCertificatesTypeKey}=", "Trusted peer certificate types.",
                  s => this[StandaloneCliConfigKeys.TrustedPeerCertificatesTypeKey] = s },
                { $"{StandaloneCliConfigKeys.RejectedCertificateStoreTypeKey}=", "Rejected certificate types.",
                  s => this[StandaloneCliConfigKeys.RejectedCertificateStoreTypeKey] = s },
                { $"{StandaloneCliConfigKeys.RejectSha1SignedCertificatesKey}=", "The publisher rejects deprecated SHA1 certificates.",
                  (bool b) => this[StandaloneCliConfigKeys.RejectSha1SignedCertificatesKey] = b.ToString() },
                { $"{StandaloneCliConfigKeys.MinimumCertificateKeySizeKey}=", "Minimum accepted certificate size.",
                  s => this[StandaloneCliConfigKeys.MinimumCertificateKeySizeKey] = s },
                { "it|issuercertstoretype=", "Legacy - do not use.", b => { legacyOptions.Add("it|issuercertstoretype"); } },
                { $"bs|batchsize=|{StandaloneCliConfigKeys.BatchSize}=", "The size of message batching buffer.",
                  (int i) => this[StandaloneCliConfigKeys.BatchSize] = i.ToString() },
                { $"si|iothubsendinterval=|{StandaloneCliConfigKeys.BatchTriggerInterval}=", "The trigger batching interval in seconds.",
                  (int k) => this[StandaloneCliConfigKeys.BatchTriggerInterval] = TimeSpan.FromSeconds(k).ToString() },
                { $"ms|iothubmessagesize=|{StandaloneCliConfigKeys.IoTHubMaxMessageSize}=", "The maximum size of the (IoT D2C) message.",
                  (int i) => this[StandaloneCliConfigKeys.IoTHubMaxMessageSize] = i.ToString() },
                { $"om|maxoutgressmessages=|{StandaloneCliConfigKeys.MaxOutgressMessages}=", "The maximum size of the (IoT D2C) message outgress buffer",
                  (int i) => this[StandaloneCliConfigKeys.MaxOutgressMessages] = i.ToString() },
                { $"{StandaloneCliConfigKeys.MaxNodesPerDataSet}=", "Maximum number of nodes within a DataSet/Subscription.",
                  (int i) => this[StandaloneCliConfigKeys.MaxNodesPerDataSet] = i.ToString() },
                { $"mm|messagingmode=|{StandaloneCliConfigKeys.MessagingMode}=", "The messaging mode for messages " +
                  $"(allowed values: {string.Join(", ", Enum.GetNames(typeof(MessagingMode)))}).",
                  (MessagingMode m) => this[StandaloneCliConfigKeys.MessagingMode] = m.ToString() },
                { $"me|messageencoding=|{StandaloneCliConfigKeys.MessageEncoding}=", "The message encoding for messages " +
                  $"(allowed values: {string.Join(", ", Enum.GetNames(typeof(MessageEncoding)))}).",
                  (MessageEncoding m) => this[StandaloneCliConfigKeys.MessageEncoding] = m.ToString() },
                { $"lc|legacycompatibility=|{StandaloneCliConfigKeys.LegacyCompatibility}=", "Run the publisher in legacy (2.5.x) compatibility mode. " +
                  "Default is 'false'.",
                  (bool b) => this[StandaloneCliConfigKeys.LegacyCompatibility] = b.ToString() },
                { $"rs|runtimestatereporting=|{StandaloneCliConfigKeys.RuntimeStateReporting}=", "The publisher reports its restarts. By default this is disabled.",
                  (bool b) => this[StandaloneCliConfigKeys.RuntimeStateReporting] = b.ToString() },
                { $"ri|enableroutinginfo=|{StandaloneCliConfigKeys.EnableRoutingInfo}=", "Enable adding routing info to telemetry. By default this is disabled.",
                  (bool b) => this[StandaloneCliConfigKeys.EnableRoutingInfo] = b.ToString() },

                // testing purposes
                { "sc|scaletestcount=", "The number of monitored item clones in scale tests.",
                  (int i) => this[StandaloneCliConfigKeys.ScaleTestCount] = i.ToString() },

                // show help
                { "h|help", "show this message and exit.",
                  b => showHelp = true },

                // Legacy: unsupported
                { "tc|telemetryconfigfile=", "Legacy - do not use.", b => { legacyOptions.Add("tc|telemetryconfigfile"); } },
                { "ic|iotcentral=", "Legacy - do not use.", b => { legacyOptions.Add("ic|iotcentral"); } },
                { "ns|noshutdown=", "Legacy - do not use.", b => { legacyOptions.Add("ns|noshutdown"); } },
                { "rf|runforever", "Legacy - do not use.", b => { legacyOptions.Add("rf|runforever"); } },
                { "pn|portnum=", "Legacy - do not use.", b => { legacyOptions.Add("pn|portnum"); } },
                { "pa|path=", "Legacy - do not use.", b => { legacyOptions.Add("pa|path"); } },
                { "lr|ldsreginterval=", "Legacy - do not use.", b => { legacyOptions.Add("lr|ldsreginterval"); } },
                { "ss|suppressedopcstatuscodes=", "Legacy - do not use.", b => { legacyOptions.Add("ss|suppressedopcstatuscodes"); } },
                { "csr", "Legacy - do not use.", b => { legacyOptions.Add("csr"); } },
                { "ab|applicationcertbase64=", "Legacy - do not use.", b => { legacyOptions.Add("ab|applicationcertbase64"); } },
                { "af|applicationcertfile=", "Legacy - do not use.", b => { legacyOptions.Add("af|applicationcertfile"); } },
                { "pk|privatekeyfile=", "Legacy - do not use.", b => { legacyOptions.Add("pk|privatekeyfile"); } },
                { "pb|privatekeybase64=", "Legacy - do not use.", b => { legacyOptions.Add("pb|privatekeybase64"); } },
                { "cp|certpassword="******"Legacy - do not use.", b => { legacyOptions.Add("cp|certpassword"); } },
                { "tb|addtrustedcertbase64=", "Legacy - do not use.", b => { legacyOptions.Add("tb|addtrustedcertbase64"); } },
                { "tf|addtrustedcertfile=", "Legacy - do not use.", b => { legacyOptions.Add("tf|addtrustedcertfile"); } },
                { "ib|addissuercertbase64=", "Legacy - do not use.", b => { legacyOptions.Add("ib|addissuercertbase64"); } },
                { "if|addissuercertfile=", "Legacy - do not use.", b => { legacyOptions.Add("if|addissuercertfile"); } },
                { "rb|updatecrlbase64=", "Legacy - do not use.", b => { legacyOptions.Add("rb|updatecrlbase64"); } },
                { "uc|updatecrlfile=", "Legacy - do not use.", b => { legacyOptions.Add("uc|updatecrlfile"); } },
                { "rc|removecert=", "Legacy - do not use.", b => { legacyOptions.Add("rc|removecert"); } },
                { "dt|devicecertstoretype=", "Legacy - do not use.", b => { legacyOptions.Add("dt|devicecertstoretype"); } },
                { "dp|devicecertstorepath=", "Legacy - do not use.", b => { legacyOptions.Add("dp|devicecertstorepath"); } },
                { "i|install", "Legacy - do not use.", b => { legacyOptions.Add("i|install"); } },
                { "st|opcstacktracemask=", "Legacy - do not use.", b => { legacyOptions.Add("st|opcstacktracemask"); } },
                { "sd|shopfloordomain=", "Legacy - do not use.", b => { legacyOptions.Add("sd|shopfloordomain"); } },
                { "vc|verboseconsole=", "Legacy - do not use.", b => { legacyOptions.Add("vc|verboseconsole"); } },
                { "as|autotrustservercerts=", "Legacy - do not use.", b => { legacyOptions.Add("as|autotrustservercerts"); } },
            };

            try {
                unsupportedOptions = options.Parse(args);
            }
            catch (Exception e) {
                Warning("Parse args exception: " + e.Message);
                Exit(160);
            }

            if (_logger.IsEnabled(LogEventLevel.Debug))
            {
                foreach (var key in this.Keys)
                {
                    Debug("Parsed command line option: '{key}'='{value}'", key, this[key]);
                }
            }

            if (unsupportedOptions.Count > 0)
            {
                foreach (var option in unsupportedOptions)
                {
                    Warning("Option {option} wrong or not supported, " +
                            "please use -h option to get all the supported options.", option);
                }
            }

            if (legacyOptions.Count > 0)
            {
                foreach (var option in legacyOptions)
                {
                    Warning("Legacy option {option} not supported, please use -h option to get all the supported options.", option);
                }
            }

            if (showHelp)
            {
                options.WriteOptionDescriptions(Console.Out);
                Exit(0);
            }
            Config = ToAgentConfigModel();
        }
コード例 #28
0
        // TODO: Figure out which are actually supported in the new publisher implementation

        /// <summary>
        /// Parse arguments and set values in the environment the way the new configuration expects it.
        /// </summary>
        /// <param name="args">The specified command line arguments.</param>
        public LegacyCliOptions(string[] args)
        {
            // command line options
            var options = new Mono.Options.OptionSet {
                // Publisher configuration options
                { "pf|publishfile=", "the filename to configure the nodes to publish.",
                  s => this[LegacyCliConfigKeys.PublisherNodeConfigurationFilename] = s },
                { "s|site=", "the site OPC Publisher is working in.",
                  s => this[LegacyCliConfigKeys.PublisherSite] = s },

                { "di|diagnosticsinterval=", "Shows publisher diagnostic info at the specified interval " +
                  "in seconds (need log level info).\n-1 disables remote diagnostic log and diagnostic output",
                  (int i) => this[LegacyCliConfigKeys.DiagnosticsInterval] = TimeSpan.FromSeconds(i).ToString() },
                { "lf|logfile=", "the filename of the logfile to use.",
                  s => this[LegacyCliConfigKeys.LogFileName] = s },
                { "lt|logflushtimespan=", "the timespan in seconds when the logfile should be flushed.",
                  (int i) => this[LegacyCliConfigKeys.LogFileFlushTimeSpanSec] = TimeSpan.FromSeconds(i).ToString() },
                { "ll|loglevel=", "the loglevel to use (allowed: fatal, error, warn, info, debug, verbose).",
                  (LogEventLevel l) => LogControl.Level.MinimumLevel = l },

                { "ih|iothubprotocol=", "Protocol to use for communication with the hub. " +
                  $"(allowed values: {string.Join(", ", Enum.GetNames(typeof(TransportOption)))}).",
                  (TransportOption p) => this[LegacyCliConfigKeys.HubTransport] = p.ToString() },
                { "dc|deviceconnectionstring=", "A device or edge module connection string to use.",
                  dc => this[LegacyCliConfigKeys.EdgeHubConnectionString] = dc },
                { "ec|edgehubconnectionstring=", "An edge module connection string to use",
                  dc => this[LegacyCliConfigKeys.EdgeHubConnectionString] = dc },

                { "hb|heartbeatinterval=", "the publisher is using this as default value in seconds " +
                  "for the heartbeat interval setting of nodes without a heartbeat interval setting.",
                  (int i) => this[LegacyCliConfigKeys.HeartbeatIntervalDefault] = TimeSpan.FromSeconds(i).ToString() },
                { "sf|skipfirstevent=", "the publisher is using this as default value for the skip first " +
                  "event setting of nodes without a skip first event setting.",
                  (bool b) => this[LegacyCliConfigKeys.SkipFirstDefault] = b.ToString() },
                { "mm|messagingmode=", "The messaging mode for messages " +
                  $"(allowed values: {string.Join(", ", Enum.GetNames(typeof(MessagingMode)))}).",
                  (MessagingMode m) => this[LegacyCliConfigKeys.MessagingMode] = m.ToString() },

                // Client settings
                { "ot|operationtimeout=", "the operation timeout of the publisher OPC UA client in ms.",
                  (uint i) => this[LegacyCliConfigKeys.OpcOperationTimeout] = TimeSpan.FromMilliseconds(i).ToString() },
                { "ol|opcmaxstringlen=", "the max length of a string opc can transmit/receive.",
                  (uint i) => this[LegacyCliConfigKeys.OpcMaxStringLength] = i.ToString() },
                { "oi|opcsamplinginterval=", "Default value in milliseconds to request the servers to " +
                  "sample values.",
                  (int i) => this[LegacyCliConfigKeys.OpcSamplingInterval] = TimeSpan.FromMilliseconds(i).ToString() },
                { "op|opcpublishinginterval=", "Default value in milliseconds for the publishing interval " +
                  "setting of the subscriptions against the OPC UA server.",
                  (int i) => this[LegacyCliConfigKeys.OpcPublishingInterval] = TimeSpan.FromMilliseconds(i).ToString() },
                { "ct|createsessiontimeout=", "The timeout in seconds used when creating a session to an endpoint.",
                  (uint u) => this[LegacyCliConfigKeys.OpcSessionCreationTimeout] = TimeSpan.FromSeconds(u).ToString() },
                { "ki|keepaliveinterval=", "The interval in seconds the publisher is sending keep alive messages " +
                  "to the OPC servers on the endpoints it is connected to.",
                  (int i) => this[LegacyCliConfigKeys.OpcKeepAliveIntervalInSec] = TimeSpan.FromSeconds(i).ToString() },
                { "kt|keepalivethreshold=", "specify the number of keep alive packets a server can miss, " +
                  "before the session is disconneced.",
                  (uint u) => this[LegacyCliConfigKeys.OpcKeepAliveDisconnectThreshold] = u.ToString() },
                { "fd|fetchdisplayname=", "same as fetchname.",
                  (bool b) => this[LegacyCliConfigKeys.FetchOpcNodeDisplayName] = b.ToString() },
                { "sw|sessionconnectwait=", "Wait time in seconds publisher is trying to connect " +
                  "to disconnected endpoints and starts monitoring unmonitored items.",
                  (int s) => this[LegacyCliConfigKeys.SessionConnectWaitSec] = TimeSpan.FromSeconds(s).ToString() },

                // cert store options
                { "aa|autoaccept", "the publisher trusts all servers it is establishing a connection to.",
                  b => this[LegacyCliConfigKeys.AutoAcceptCerts] = (b != null).ToString() },
                { "to|trustowncert", "the publisher certificate is put into the trusted store automatically.",
                  t => this[LegacyCliConfigKeys.TrustMyself] = (t != null).ToString() },
                { "at|appcertstoretype=", "the own application cert store type (allowed: Directory, X509Store).",
                  s => {
                      if (s.Equals(CertificateStoreType.X509Store, StringComparison.OrdinalIgnoreCase) ||
                          s.Equals(CertificateStoreType.Directory, StringComparison.OrdinalIgnoreCase))
                      {
                          this[LegacyCliConfigKeys.OpcOwnCertStoreType] = s;
                          return;
                      }
                      throw new OptionException("Bad store type", "at");
                  } },
                { "ap|appcertstorepath=", "the path where the own application cert should be stored.",
                  s => this[LegacyCliConfigKeys.OpcOwnCertStorePath] = s },
                { "tp|trustedcertstorepath=", "the path of the trusted cert store.",
                  s => this[LegacyCliConfigKeys.OpcTrustedCertStorePath] = s },
                { "tt|trustedcertstoretype=", "Legacy - do not use.", _ => {} },
                { "rp|rejectedcertstorepath=", "the path of the rejected cert store.",
                  s => this[LegacyCliConfigKeys.OpcRejectedCertStorePath] = s },
                { "rt|rejectedcertstoretype=", "Legacy - do not use.", _ => {} },
                { "ip|issuercertstorepath=", "the path of the trusted issuer cert store.",
                  s => this[LegacyCliConfigKeys.OpcIssuerCertStorePath] = s },
                { "it|issuercertstoretype=", "Legacy - do not use.", _ => {} },

                // Legacy unsupported
                { "si|iothubsendinterval=", "Legacy - do not use.", _ => {} },
                { "tc|telemetryconfigfile=", "Legacy - do not use.", _ => {} },
                { "ic|iotcentral=", "Legacy - do not use.", _ => {} },
                { "mq|monitoreditemqueuecapacity=", "Legacy - do not use.", _ => {} },
                { "ns|noshutdown=", "Legacy - do not use.", _ => {} },
                { "rf|runforever", "Legacy - do not use.", _ => {} },
                { "ms|iothubmessagesize=", "Legacy - do not use.", _ => {} },
                { "pn|portnum=", "Legacy - do not use.", _ => {} },
                { "pa|path=", "Legacy - do not use.", _ => {} },
                { "lr|ldsreginterval=", "Legacy - do not use.", _ => {} },
                { "ss|suppressedopcstatuscodes=", "Legacy - do not use.", _ => {} },
                { "csr", "Legacy - do not use.", _ => {} },
                { "ab|applicationcertbase64=", "Legacy - do not use.", _ => {} },
                { "af|applicationcertfile=", "Legacy - do not use.", _ => {} },
                { "pk|privatekeyfile=", "Legacy - do not use.", _ => {} },
                { "pb|privatekeybase64=", "Legacy - do not use.", _ => {} },
                { "cp|certpassword="******"Legacy - do not use.", _ => {} },
                { "tb|addtrustedcertbase64=", "Legacy - do not use.", _ => {} },
                { "tf|addtrustedcertfile=", "Legacy - do not use.", _ => {} },
                { "ib|addissuercertbase64=", "Legacy - do not use.", _ => {} },
                { "if|addissuercertfile=", "Legacy - do not use.", _ => {} },
                { "rb|updatecrlbase64=", "Legacy - do not use.", _ => {} },
                { "uc|updatecrlfile=", "Legacy - do not use.", _ => {} },
                { "rc|removecert=", "Legacy - do not use.", _ => {} },
                { "dt|devicecertstoretype=", "Legacy - do not use.", _ => {} },
                { "dp|devicecertstorepath=", "Legacy - do not use.", _ => {} },
                { "i|install", "Legacy - do not use.", _ => {} },
                { "st|opcstacktracemask=", "Legacy - do not use.", _ => {} },
                { "sd|shopfloordomain=", "Legacy - do not use.", _ => {} },
                { "vc|verboseconsole=", "Legacy - do not use.", _ => {} },
                { "as|autotrustservercerts=", "Legacy - do not use.", _ => {} }
            };

            options.Parse(args);

            Config         = ToAgentConfigModel();
            LegacyCliModel = ToLegacyCliModel();
        }
コード例 #29
0
        /// <summary>
        /// Asynchronous part of the main method of the app.
        /// </summary>
        public async static Task MainAsync(string[] args)
        {
            try
            {
                var shouldShowHelp = false;

                // Shutdown token sources.
                ShutdownTokenSource = new CancellationTokenSource();

                // detect the runtime environment. either we run standalone (native or containerized) or as IoT Edge module (containerized)
                // check if we have an environment variable containing an IoT Edge connectionstring, we run as IoT Edge module
                if (IsIotEdgeModule)
                {
                    WriteLine("IoTEdge detected.");
                }

                // command line options
                Mono.Options.OptionSet options = new Mono.Options.OptionSet {
                    // Publisher configuration options
                    { "pf|publishfile=", $"the filename to configure the nodes to publish.\nDefault: '{PublisherNodeConfigurationFilename}'", (string p) => PublisherNodeConfigurationFilename = p },
                    { "tc|telemetryconfigfile=", $"the filename to configure the ingested telemetry\nDefault: '{PublisherTelemetryConfigurationFilename}'", (string p) => PublisherTelemetryConfigurationFilename = p },
                    { "s|site=", $"the site OPC Publisher is working in. if specified this domain is appended (delimited by a ':' to the 'ApplicationURI' property when telemetry is sent to IoTHub.\n" +
                      "The value must follow the syntactical rules of a DNS hostname.\nDefault: not set", (string s) => {
                          Regex siteNameRegex = new Regex("^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\\-]*[a-zA-Z0-9])\\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\\-]*[A-Za-z0-9])$");
                          if (siteNameRegex.IsMatch(s))
                          {
                              PublisherSite = s;
                          }
                          else
                          {
                              throw new OptionException("The shopfloor site is not a valid DNS hostname.", "site");
                          }
                      } },
                    { "sd|shopfloordomain=", $"same as site option, only there for backward compatibility\n" +
                      "The value must follow the syntactical rules of a DNS hostname.\nDefault: not set", (string s) => {
                          Regex siteNameRegex = new Regex("^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\\-]*[a-zA-Z0-9])\\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\\-]*[A-Za-z0-9])$");
                          if (siteNameRegex.IsMatch(s))
                          {
                              PublisherSite = s;
                          }
                          else
                          {
                              throw new OptionException("The shopfloor domain is not a valid DNS hostname.", "shopfloordomain");
                          }
                      } },
                    { "ic|iotcentral", $"publisher will send OPC UA data in IoTCentral compatible format (DisplayName of a node is used as key, this key is the Field name in IoTCentral). you need to ensure that all DisplayName's are unique. (Auto enables fetch display name)\nDefault: {IotCentralMode}", b => IotCentralMode = FetchOpcNodeDisplayName = b != null },
                    { "sw|sessionconnectwait=", $"specify the wait time in seconds publisher is trying to connect to disconnected endpoints and starts monitoring unmonitored items\nMin: 10\nDefault: {SessionConnectWaitSec}", (int i) => {
                          if (i > 10)
                          {
                              SessionConnectWaitSec = i;
                          }
                          else
                          {
                              throw new OptionException("The sessionconnectwait must be greater than 10 sec", "sessionconnectwait");
                          }
                      } },
                    { "mq|monitoreditemqueuecapacity=", $"specify how many notifications of monitored items can be stored in the internal queue, if the data can not be sent quick enough to IoTHub\nMin: 1024\nDefault: {MonitoredItemsQueueCapacity}", (int i) => {
                          if (i >= 1024)
                          {
                              MonitoredItemsQueueCapacity = i;
                          }
                          else
                          {
                              throw new OptionException("The monitoreditemqueueitems must be greater than 1024", "monitoreditemqueueitems");
                          }
                      } },
                    { "di|diagnosticsinterval=", $"shows publisher diagnostic info at the specified interval in seconds (need log level info). 0 disables diagnostic output.\nDefault: {DiagnosticsInterval}", (uint u) => DiagnosticsInterval = u },

                    { "vc|verboseconsole=", $"ignored, only supported for backward comaptibility.", b => {} },

                    { "ns|noshutdown=", $"same as runforever.\nDefault: {_noShutdown}", (bool b) => _noShutdown = b },
                    { "rf|runforever", $"publisher can not be stopped by pressing a key on the console, but will run forever.\nDefault: {_noShutdown}", b => _noShutdown = b != null },

                    { "lf|logfile=", $"the filename of the logfile to use.\nDefault: './{_logFileName}'", (string l) => _logFileName = l },
                    { "lt|logflushtimespan=", $"the timespan in seconds when the logfile should be flushed.\nDefault: {_logFileFlushTimeSpanSec} sec", (int s) => {
                          if (s > 0)
                          {
                              _logFileFlushTimeSpanSec = TimeSpan.FromSeconds(s);
                          }
                          else
                          {
                              throw new Mono.Options.OptionException("The logflushtimespan must be a positive number.", "logflushtimespan");
                          }
                      } },
                    { "ll|loglevel=", $"the loglevel to use (allowed: fatal, error, warn, info, debug, verbose).\nDefault: info", (string l) => {
                          List <string> logLevels = new List <string> {
                              "fatal", "error", "warn", "info", "debug", "verbose"
                          };
                          if (logLevels.Contains(l.ToLowerInvariant()))
                          {
                              _logLevel = l.ToLowerInvariant();
                          }
                          else
                          {
                              throw new Mono.Options.OptionException("The loglevel must be one of: fatal, error, warn, info, debug, verbose", "loglevel");
                          }
                      } },
                    // IoTHub specific options
                    { "ih|iothubprotocol=", $"{(IsIotEdgeModule ? "not supported when running as IoTEdge module (Mqtt_Tcp_Only is enforced)\n" : $"the protocol to use for communication with Azure IoTHub (allowed values: {string.Join(", ", Enum.GetNames(IotHubProtocol.GetType()))}).\nDefault: {Enum.GetName(IotHubProtocol.GetType(), IotHubProtocol)}")}",
                      (Microsoft.Azure.Devices.Client.TransportType p) => {
                          if (IsIotEdgeModule)
                          {
                              if (p != Microsoft.Azure.Devices.Client.TransportType.Mqtt_Tcp_Only)
                              {
                                  WriteLine("When running as IoTEdge module Mqtt_Tcp_Only is enforced.");
                                  IotHubProtocol = Microsoft.Azure.Devices.Client.TransportType.Mqtt_Tcp_Only;
                              }
                          }
                          else
                          {
                              IotHubProtocol = p;
                          }
                      } },
                    { "ms|iothubmessagesize=", $"the max size of a message which can be send to IoTHub. when telemetry of this size is available it will be sent.\n0 will enforce immediate send when telemetry is available\nMin: 0\nMax: {HubMessageSizeMax}\nDefault: {HubMessageSize}", (uint u) => {
                          if (u >= 0 && u <= HubMessageSizeMax)
                          {
                              HubMessageSize = u;
                          }
                          else
                          {
                              throw new OptionException("The iothubmessagesize must be in the range between 1 and 256*1024.", "iothubmessagesize");
                          }
                      } },
                    { "si|iothubsendinterval=", $"the interval in seconds when telemetry should be send to IoTHub. If 0, then only the iothubmessagesize parameter controls when telemetry is sent.\nDefault: '{DefaultSendIntervalSeconds}'", (int i) => {
                          if (i >= 0)
                          {
                              DefaultSendIntervalSeconds = i;
                          }
                          else
                          {
                              throw new OptionException("The iothubsendinterval must be larger or equal 0.", "iothubsendinterval");
                          }
                      } },
                    { "dc|deviceconnectionstring=", $"{(IsIotEdgeModule ? "not supported when running as IoTEdge module\n" : $"if publisher is not able to register itself with IoTHub, you can create a device with name <applicationname> manually and pass in the connectionstring of this device.\nDefault: none")}",
                      (string dc) => DeviceConnectionString = (IsIotEdgeModule ? null : dc) },
                    { "c|connectionstring=", $"the IoTHub owner connectionstring.\nDefault: none",
                      (string cs) => IotHubOwnerConnectionString = cs },

                    // opc server configuration options
                    { "pn|portnum=", $"the server port of the publisher OPC server endpoint.\nDefault: {PublisherServerPort}", (ushort p) => PublisherServerPort = p },
                    { "pa|path=", $"the enpoint URL path part of the publisher OPC server endpoint.\nDefault: '{PublisherServerPath}'", (string a) => PublisherServerPath = a },
                    { "lr|ldsreginterval=", $"the LDS(-ME) registration interval in ms. If 0, then the registration is disabled.\nDefault: {LdsRegistrationInterval}", (int i) => {
                          if (i >= 0)
                          {
                              LdsRegistrationInterval = i;
                          }
                          else
                          {
                              throw new OptionException("The ldsreginterval must be larger or equal 0.", "ldsreginterval");
                          }
                      } },
                    { "ol|opcmaxstringlen=", $"the max length of a string opc can transmit/receive.\nDefault: {OpcMaxStringLength}", (int i) => {
                          if (i > 0)
                          {
                              OpcMaxStringLength = i;
                          }
                          else
                          {
                              throw new OptionException("The max opc string length must be larger than 0.", "opcmaxstringlen");
                          }
                      } },
                    { "ot|operationtimeout=", $"the operation timeout of the publisher OPC UA client in ms.\nDefault: {OpcOperationTimeout}", (int i) => {
                          if (i >= 0)
                          {
                              OpcOperationTimeout = i;
                          }
                          else
                          {
                              throw new OptionException("The operation timeout must be larger or equal 0.", "operationtimeout");
                          }
                      } },
                    { "oi|opcsamplinginterval=", "the publisher is using this as default value in milliseconds to request the servers to sample the nodes with this interval\n" +
                      "this value might be revised by the OPC UA servers to a supported sampling interval.\n" +
                      "please check the OPC UA specification for details how this is handled by the OPC UA stack.\n" +
                      "a negative value will set the sampling interval to the publishing interval of the subscription this node is on.\n" +
                      $"0 will configure the OPC UA server to sample in the highest possible resolution and should be taken with care.\nDefault: {OpcSamplingInterval}", (int i) => OpcSamplingInterval = i },
                    { "op|opcpublishinginterval=", "the publisher is using this as default value in milliseconds for the publishing interval setting of the subscriptions established to the OPC UA servers.\n" +
                      "please check the OPC UA specification for details how this is handled by the OPC UA stack.\n" +
                      $"a value less than or equal zero will let the server revise the publishing interval.\nDefault: {OpcPublishingInterval}", (int i) => {
                          if (i > 0 && i >= OpcSamplingInterval)
                          {
                              OpcPublishingInterval = i;
                          }
                          else
                          {
                              if (i <= 0)
                              {
                                  OpcPublishingInterval = 0;
                              }
                              else
                              {
                                  throw new OptionException($"The opcpublishinterval ({i}) must be larger than the opcsamplinginterval ({OpcSamplingInterval}).", "opcpublishinterval");
                              }
                          }
                      } },
                    { "ct|createsessiontimeout=", $"specify the timeout in seconds used when creating a session to an endpoint. On unsuccessful connection attemps a backoff up to {OpcSessionCreationBackoffMax} times the specified timeout value is used.\nMin: 1\nDefault: {OpcSessionCreationTimeout}", (uint u) => {
                          if (u > 1)
                          {
                              OpcSessionCreationTimeout = u;
                          }
                          else
                          {
                              throw new OptionException("The createsessiontimeout must be greater than 1 sec", "createsessiontimeout");
                          }
                      } },
                    { "ki|keepaliveinterval=", $"specify the interval in seconds the publisher is sending keep alive messages to the OPC servers on the endpoints it is connected to.\nMin: 2\nDefault: {OpcKeepAliveIntervalInSec}", (int i) => {
                          if (i >= 2)
                          {
                              OpcKeepAliveIntervalInSec = i;
                          }
                          else
                          {
                              throw new OptionException("The keepaliveinterval must be greater or equal 2", "keepalivethreshold");
                          }
                      } },
                    { "kt|keepalivethreshold=", $"specify the number of keep alive packets a server can miss, before the session is disconneced\nMin: 1\nDefault: {OpcKeepAliveDisconnectThreshold}", (uint u) => {
                          if (u > 1)
                          {
                              OpcKeepAliveDisconnectThreshold = u;
                          }
                          else
                          {
                              throw new OptionException("The keepalivethreshold must be greater than 1", "keepalivethreshold");
                          }
                      } },
                    { "st|opcstacktracemask=", $"ignored, only supported for backward comaptibility.", i => {} },

                    { "as|autotrustservercerts=", $"same as autoaccept, only supported for backward cmpatibility.\nDefault: {OpcPublisherAutoTrustServerCerts}", (bool b) => OpcPublisherAutoTrustServerCerts = b },
                    { "aa|autoaccept", $"the publisher trusts all servers it is establishing a connection to.\nDefault: {OpcPublisherAutoTrustServerCerts}", b => OpcPublisherAutoTrustServerCerts = b != null },

                    // trust own public cert option
                    { "tm|trustmyself=", $"same as trustowncert.\nDefault: {TrustMyself}", (bool b) => TrustMyself = b },
                    { "to|trustowncert", $"the publisher certificate is put into the trusted certificate store automatically.\nDefault: {TrustMyself}", t => TrustMyself = t != null },
                    // read the display name of the nodes to publish from the server and publish them instead of the node id
                    { "fd|fetchdisplayname=", $"same as fetchname.\nDefault: {FetchOpcNodeDisplayName}", (bool b) => FetchOpcNodeDisplayName = IotCentralMode ? true : b },
                    { "fn|fetchname", $"enable to read the display name of a published node from the server. this will increase the runtime.\nDefault: {FetchOpcNodeDisplayName}", b => FetchOpcNodeDisplayName = IotCentralMode ? true : b != null },

                    // own cert store options
                    { "at|appcertstoretype=", $"the own application cert store type. \n(allowed values: Directory, X509Store)\nDefault: '{OpcOwnCertStoreType}'", (string s) => {
                          if (s.Equals(X509Store, StringComparison.OrdinalIgnoreCase) || s.Equals(CertificateStoreType.Directory, StringComparison.OrdinalIgnoreCase))
                          {
                              OpcOwnCertStoreType = s.Equals(X509Store, StringComparison.OrdinalIgnoreCase) ? X509Store : CertificateStoreType.Directory;
                              OpcOwnCertStorePath = s.Equals(X509Store, StringComparison.OrdinalIgnoreCase) ? OpcOwnCertX509StorePathDefault : OpcOwnCertDirectoryStorePathDefault;
                          }
                          else
                          {
                              throw new OptionException();
                          }
                      } },
                    { "ap|appcertstorepath=", $"the path where the own application cert should be stored\nDefault (depends on store type):\n" +
                      $"X509Store: '{OpcOwnCertX509StorePathDefault}'\n" +
                      $"Directory: '{OpcOwnCertDirectoryStorePathDefault}'", (string s) => OpcOwnCertStorePath = s },

                    // trusted cert store options
                    {
                        "tt|trustedcertstoretype=", $"the trusted cert store type. \n(allowed values: Directory, X509Store)\nDefault: {OpcTrustedCertStoreType}", (string s) => {
                            if (s.Equals(X509Store, StringComparison.OrdinalIgnoreCase) || s.Equals(CertificateStoreType.Directory, StringComparison.OrdinalIgnoreCase))
                            {
                                OpcTrustedCertStoreType = s.Equals(X509Store, StringComparison.OrdinalIgnoreCase) ? X509Store : CertificateStoreType.Directory;
                                OpcTrustedCertStorePath = s.Equals(X509Store, StringComparison.OrdinalIgnoreCase) ? OpcTrustedCertX509StorePathDefault : OpcTrustedCertDirectoryStorePathDefault;
                            }
                            else
                            {
                                throw new OptionException();
                            }
                        }
                    },
                    { "tp|trustedcertstorepath=", $"the path of the trusted cert store\nDefault (depends on store type):\n" +
                      $"X509Store: '{OpcTrustedCertX509StorePathDefault}'\n" +
                      $"Directory: '{OpcTrustedCertDirectoryStorePathDefault}'", (string s) => OpcTrustedCertStorePath = s },

                    // rejected cert store options
                    { "rt|rejectedcertstoretype=", $"the rejected cert store type. \n(allowed values: Directory, X509Store)\nDefault: {OpcRejectedCertStoreType}", (string s) => {
                          if (s.Equals(X509Store, StringComparison.OrdinalIgnoreCase) || s.Equals(CertificateStoreType.Directory, StringComparison.OrdinalIgnoreCase))
                          {
                              OpcRejectedCertStoreType = s.Equals(X509Store, StringComparison.OrdinalIgnoreCase) ? X509Store : CertificateStoreType.Directory;
                              OpcRejectedCertStorePath = s.Equals(X509Store, StringComparison.OrdinalIgnoreCase) ? OpcRejectedCertX509StorePathDefault : OpcRejectedCertDirectoryStorePathDefault;
                          }
                          else
                          {
                              throw new OptionException();
                          }
                      } },
                    { "rp|rejectedcertstorepath=", $"the path of the rejected cert store\nDefault (depends on store type):\n" +
                      $"X509Store: '{OpcRejectedCertX509StorePathDefault}'\n" +
                      $"Directory: '{OpcRejectedCertDirectoryStorePathDefault}'", (string s) => OpcRejectedCertStorePath = s },

                    // issuer cert store options
                    {
                        "it|issuercertstoretype=", $"the trusted issuer cert store type. \n(allowed values: Directory, X509Store)\nDefault: {OpcIssuerCertStoreType}", (string s) => {
                            if (s.Equals(X509Store, StringComparison.OrdinalIgnoreCase) || s.Equals(CertificateStoreType.Directory, StringComparison.OrdinalIgnoreCase))
                            {
                                OpcIssuerCertStoreType = s.Equals(X509Store, StringComparison.OrdinalIgnoreCase) ? X509Store : CertificateStoreType.Directory;
                                OpcIssuerCertStorePath = s.Equals(X509Store, StringComparison.OrdinalIgnoreCase) ? OpcIssuerCertX509StorePathDefault : OpcIssuerCertDirectoryStorePathDefault;
                            }
                            else
                            {
                                throw new OptionException();
                            }
                        }
                    },
                    { "ip|issuercertstorepath=", $"the path of the trusted issuer cert store\nDefault (depends on store type):\n" +
                      $"X509Store: '{OpcIssuerCertX509StorePathDefault}'\n" +
                      $"Directory: '{OpcIssuerCertDirectoryStorePathDefault}'", (string s) => OpcIssuerCertStorePath = s },

                    // device connection string cert store options
                    { "dt|devicecertstoretype=", $"the iothub device cert store type. \n(allowed values: Directory, X509Store)\nDefault: {IotDeviceCertStoreType}", (string s) => {
                          if (s.Equals(X509Store, StringComparison.OrdinalIgnoreCase) || s.Equals(CertificateStoreType.Directory, StringComparison.OrdinalIgnoreCase))
                          {
                              IotDeviceCertStoreType = s.Equals(X509Store, StringComparison.OrdinalIgnoreCase) ? X509Store : CertificateStoreType.Directory;
                              IotDeviceCertStorePath = s.Equals(X509Store, StringComparison.OrdinalIgnoreCase) ? IotDeviceCertX509StorePathDefault : IotDeviceCertDirectoryStorePathDefault;
                          }
                          else
                          {
                              throw new OptionException();
                          }
                      } },
                    { "dp|devicecertstorepath=", $"the path of the iot device cert store\nDefault Default (depends on store type):\n" +
                      $"X509Store: '{IotDeviceCertX509StorePathDefault}'\n" +
                      $"Directory: '{IotDeviceCertDirectoryStorePathDefault}'", (string s) => IotDeviceCertStorePath = s },

                    // misc
                    { "i|install", $"register OPC Publisher with IoTHub and then exits.\nDefault:  {_installOnly}", i => _installOnly = i != null },
                    { "h|help", "show this message and exit", h => shouldShowHelp = h != null },
                };


                List <string> extraArgs = new List <string>();
                try
                {
                    // parse the command line
                    extraArgs = options.Parse(args);
                }
                catch (OptionException e)
                {
                    // initialize logging
                    InitLogging();

                    // show message
                    Logger.Error(e, "Error in command line options");
                    Logger.Error($"Command line arguments: {String.Join(" ", args)}");

                    // show usage
                    Usage(options);
                    return;
                }

                // initialize logging
                InitLogging();

                // show usage if requested
                if (shouldShowHelp)
                {
                    Usage(options);
                    return;
                }

                // Validate and parse extra arguments.
                const int APP_NAME_INDEX = 0;
                const int CS_INDEX       = 1;
                switch (extraArgs.Count)
                {
                case 0:
                {
                    ApplicationName = Utils.GetHostName();
                    break;
                }

                case 1:
                {
                    ApplicationName = extraArgs[APP_NAME_INDEX];
                    break;
                }

                case 2:
                {
                    ApplicationName = extraArgs[APP_NAME_INDEX];
                    if (IsIotEdgeModule)
                    {
                        WriteLine($"Warning: connection string parameter is not supported in IoTEdge context, given parameter is ignored");
                    }
                    else
                    {
                        IotHubOwnerConnectionString = extraArgs[CS_INDEX];
                    }
                    break;
                }

                default:
                {
                    Logger.Error("Error in command line options");
                    Logger.Error($"Command line arguments: {String.Join(" ", args)}");
                    Usage(options);
                    return;
                }
                }

                // install only if requested
                if (_installOnly)
                {
                    // initialize and start IoTHub communication
                    IotHubCommunication = new IotHubCommunication(ShutdownTokenSource.Token);
                    if (!await IotHubCommunication.InitAsync())
                    {
                        return;
                    }
                    Logger.Information("Installation completed. Exiting...");
                    return;
                }

                // start operation
                Logger.Information("Publisher is starting up...");

                // allow canceling the application
                var quitEvent = new ManualResetEvent(false);
                try
                {
                    Console.CancelKeyPress += (sender, eArgs) =>
                    {
                        quitEvent.Set();
                        eArgs.Cancel = true;
                        ShutdownTokenSource.Cancel();
                    };
                }
                catch
                {
                }

                // init OPC configuration and tracing
                OpcStackConfiguration opcStackConfiguration = new OpcStackConfiguration();
                await opcStackConfiguration.ConfigureAsync();

                // log shopfloor site setting
                if (string.IsNullOrEmpty(PublisherSite))
                {
                    Logger.Information("There is no site configured.");
                }
                else
                {
                    Logger.Information($"Publisher is in site '{PublisherSite}'.");
                }

                // Set certificate validator.
                if (OpcPublisherAutoTrustServerCerts)
                {
                    Logger.Information("Publisher configured to auto trust server certificates of the servers it is connecting to.");
                    PublisherOpcApplicationConfiguration.CertificateValidator.CertificateValidation += new CertificateValidationEventHandler(CertificateValidator_AutoTrustServerCerts);
                }
                else
                {
                    Logger.Information("Publisher configured to not auto trust server certificates. When connecting to servers, you need to manually copy the rejected server certs to the trusted store to trust them.");
                    PublisherOpcApplicationConfiguration.CertificateValidator.CertificateValidation += new CertificateValidationEventHandler(CertificateValidator_Default);
                }

                // start our server interface
                try
                {
                    Logger.Information($"Starting server on endpoint {PublisherOpcApplicationConfiguration.ServerConfiguration.BaseAddresses[0].ToString()} ...");
                    _publisherServer = new PublisherServer();
                    _publisherServer.Start(PublisherOpcApplicationConfiguration);
                    Logger.Information("Server started.");
                }
                catch (Exception e)
                {
                    Logger.Fatal(e, "Failed to start Publisher OPC UA server.");
                    Logger.Fatal("exiting...");
                    return;
                }

                // read telemetry configuration file
                PublisherTelemetryConfiguration.Init(ShutdownTokenSource.Token);
                if (!await PublisherTelemetryConfiguration.ReadConfigAsync())
                {
                    return;
                }

                // read node configuration file
                PublisherNodeConfiguration.Init();
                if (!await PublisherNodeConfiguration.ReadConfigAsync())
                {
                    return;
                }

                // initialize hub communication
                if (IsIotEdgeModule)
                {
                    // initialize and start EdgeHub communication
                    IotEdgeHubCommunication = new IotEdgeHubCommunication(ShutdownTokenSource.Token);
                    if (!await IotEdgeHubCommunication.InitAsync())
                    {
                        return;
                    }
                }
                else
                {
                    // initialize and start IoTHub communication
                    IotHubCommunication = new IotHubCommunication(ShutdownTokenSource.Token);
                    if (!await IotHubCommunication.InitAsync())
                    {
                        return;
                    }
                }

                if (!await CreateOpcPublishingDataAsync())
                {
                    return;
                }

                // kick off OPC session creation and node monitoring
                await SessionStartAsync();

                // Show notification on session events
                _publisherServer.CurrentInstance.SessionManager.SessionActivated += ServerEventStatus;
                _publisherServer.CurrentInstance.SessionManager.SessionClosing   += ServerEventStatus;
                _publisherServer.CurrentInstance.SessionManager.SessionCreated   += ServerEventStatus;

                // initialize publisher diagnostics
                Diagnostics.Init();

                // stop on user request
                Logger.Information("");
                Logger.Information("");
                if (_noShutdown)
                {
                    // wait forever if asked to do so
                    Logger.Information("Publisher is running infinite...");
                    await Task.Delay(Timeout.Infinite);
                }
                else
                {
                    Logger.Information("Publisher is running. Press CTRL-C to quit.");

                    // wait for Ctrl-C
                    quitEvent.WaitOne(Timeout.Infinite);
                }

                Logger.Information("");
                Logger.Information("");
                ShutdownTokenSource.Cancel();
                Logger.Information("Publisher is shutting down...");

                // stop the server
                _publisherServer.Stop();

                // shutdown all OPC sessions
                await SessionShutdownAsync();

                // shutdown the IoTHub messaging
                await IotHubCommunication.ShutdownAsync();

                IotHubCommunication = null;

                // shutdown diagnostics
                await ShutdownAsync();

                // free resources
                PublisherTelemetryConfiguration.Deinit();
                PublisherNodeConfiguration.Deinit();
                ShutdownTokenSource = null;
            }
            catch (Exception e)
            {
                Logger.Fatal(e, e.StackTrace);
                e = e.InnerException ?? null;
                while (e != null)
                {
                    Logger.Fatal(e, e.StackTrace);
                    e = e.InnerException ?? null;
                }
                Logger.Fatal("Publisher exiting... ");
            }
        }
コード例 #30
0
        /// <summary>
        /// Asynchronous part of the main method of the app.
        /// </summary>
        public async static Task MainAsync(string[] args)
        {
            var shouldShowHelp = false;

            // command line options
            Mono.Options.OptionSet options = new Mono.Options.OptionSet {
                // log configuration
                { "lf|logfile=", $"the filename of the logfile to use.\nDefault: './{_logFileName}'", (string l) => _logFileName = l },
                { "lt|logflushtimespan=", $"the timespan in seconds when the logfile should be flushed.\nDefault: {_logFileFlushTimeSpanSec} sec", (int s) => {
                      if (s > 0)
                      {
                          _logFileFlushTimeSpanSec = TimeSpan.FromSeconds(s);
                      }
                      else
                      {
                          throw new Mono.Options.OptionException("The logflushtimespan must be a positive number.", "logflushtimespan");
                      }
                  } },
                { "ll|loglevel=", $"the loglevel to use (allowed: fatal, error, warn, info, debug, verbose).\nDefault: info", (string l) => {
                      List <string> logLevels = new List <string> {
                          "fatal", "error", "warn", "info", "debug", "verbose"
                      };
                      if (logLevels.Contains(l.ToLowerInvariant()))
                      {
                          _logLevel = l.ToLowerInvariant();
                      }
                      else
                      {
                          throw new OptionException("The loglevel must be one of: fatal, error, warn, info, debug, verbose", "loglevel");
                      }
                  } },

                // simulation configuration
                { "sc|simulationcyclecount=", $"count of cycles in one simulation phase\nDefault:  {SimulationCycleCount} cycles", (int i) => SimulationCycleCount = i },
                { "ct|cycletime=", $"length of one cycle time in milliseconds\nDefault:  {SimulationCycleLength} msec", (int i) => SimulationCycleLength = i },
                { "ns|nospikes", $"do not generate spike data\nDefault: {!GenerateSpikes}", a => GenerateSpikes = a == null },
                { "nd|nodips", $"do not generate dip data\nDefault: {!GenerateDips}", a => GenerateDips = a == null },
                { "np|nopostrend", $"do not generate positive trend data\nDefault: {!GeneratePosTrend}", a => GeneratePosTrend = a == null },
                { "nn|nonegtrend", $"do not generate negative trend data\nDefault: {!GenerateNegTrend}", a => GenerateNegTrend = a == null },
                { "nv|nodatavalues", $"do not generate data values\nDefault: {!GenerateData}", a => GenerateData = a == null },

                // opc configuration
                { "pn|portnum=", $"the server port of the OPC server endpoint.\nDefault: {ServerPort}", (ushort p) => ServerPort = p },
                { "op|path=", $"the enpoint URL path part of the OPC server endpoint.\nDefault: '{ServerPath}'", (string a) => ServerPath = a },
                { "ph|plchostname=", $"the fullqualified hostname of the plc.\nDefault: {Hostname}", (string a) => Hostname = a },
                { "ol|opcmaxstringlen=", $"the max length of a string opc can transmit/receive.\nDefault: {OpcMaxStringLength}", (int i) => {
                      if (i > 0)
                      {
                          OpcMaxStringLength = i;
                      }
                      else
                      {
                          throw new OptionException("The max opc string length must be larger than 0.", "opcmaxstringlen");
                      }
                  } },
                { "lr|ldsreginterval=", $"the LDS(-ME) registration interval in ms. If 0, then the registration is disabled.\nDefault: {LdsRegistrationInterval}", (int i) => {
                      if (i >= 0)
                      {
                          LdsRegistrationInterval = i;
                      }
                      else
                      {
                          throw new OptionException("The ldsreginterval must be larger or equal 0.", "ldsreginterval");
                      }
                  } },
                { "aa|autoaccept", $"all certs are trusted when a connection is established.\nDefault: {AutoAcceptCerts}", a => AutoAcceptCerts = a != null },

                { "ut|unsecuretransport", $"enables the unsecured transport.\nDefault: {EnableUnsecureTransport}", u => EnableUnsecureTransport = u != null },

                { "to|trustowncert", $"the own certificate is put into the trusted certificate store automatically.\nDefault: {TrustMyself}", t => TrustMyself = t != null },

                // cert store options
                { "at|appcertstoretype=", $"the own application cert store type. \n(allowed values: Directory, X509Store)\nDefault: '{OpcOwnCertStoreType}'", (string s) => {
                      if (s.Equals(CertificateStoreType.X509Store, StringComparison.OrdinalIgnoreCase) || s.Equals(CertificateStoreType.Directory, StringComparison.OrdinalIgnoreCase))
                      {
                          OpcOwnCertStoreType = s.Equals(CertificateStoreType.X509Store, StringComparison.OrdinalIgnoreCase) ? CertificateStoreType.X509Store : CertificateStoreType.Directory;
                          OpcOwnCertStorePath = s.Equals(CertificateStoreType.X509Store, StringComparison.OrdinalIgnoreCase) ? OpcOwnCertX509StorePathDefault : OpcOwnCertDirectoryStorePathDefault;
                      }
                      else
                      {
                          throw new OptionException();
                      }
                  } },

                { "ap|appcertstorepath=", $"the path where the own application cert should be stored\nDefault (depends on store type):\n" +
                  $"X509Store: '{OpcOwnCertX509StorePathDefault}'\n" +
                  $"Directory: '{OpcOwnCertDirectoryStorePathDefault}'", (string s) => OpcOwnCertStorePath = s },

                { "tp|trustedcertstorepath=", $"the path of the trusted cert store\nDefault '{OpcTrustedCertDirectoryStorePathDefault}'", (string s) => OpcTrustedCertStorePath = s },

                { "rp|rejectedcertstorepath=", $"the path of the rejected cert store\nDefault '{OpcRejectedCertDirectoryStorePathDefault}'", (string s) => OpcRejectedCertStorePath = s },

                { "ip|issuercertstorepath=", $"the path of the trusted issuer cert store\nDefault '{OpcIssuerCertDirectoryStorePathDefault}'", (string s) => OpcIssuerCertStorePath = s },

                { "csr", $"show data to create a certificate signing request\nDefault '{ShowCreateSigningRequestInfo}'", c => ShowCreateSigningRequestInfo = c != null },

                { "ab|applicationcertbase64=", $"update/set this applications certificate with the certificate passed in as bas64 string", (string s) =>
                  {
                      NewCertificateBase64String = s;
                  } },
                { "af|applicationcertfile=", $"update/set this applications certificate with the certificate file specified", (string s) =>
                  {
                      if (File.Exists(s))
                      {
                          NewCertificateFileName = s;
                      }
                      else
                      {
                          throw new OptionException("The file '{s}' does not exist.", "applicationcertfile");
                      }
                  } },

                { "pb|privatekeybase64=", $"initial provisioning of the application certificate (with a PEM or PFX fomat) requires a private key passed in as base64 string", (string s) =>
                  {
                      PrivateKeyBase64String = s;
                  } },
                { "pk|privatekeyfile=", $"initial provisioning of the application certificate (with a PEM or PFX fomat) requires a private key passed in as file", (string s) =>
                  {
                      if (File.Exists(s))
                      {
                          PrivateKeyFileName = s;
                      }
                      else
                      {
                          throw new OptionException("The file '{s}' does not exist.", "privatekeyfile");
                      }
                  } },

                { "cp|certpassword="******"the optional password for the PEM or PFX or the installed application certificate", (string s) =>
                  {
                      CertificatePassword = s;
                  } },

                { "tb|addtrustedcertbase64=", $"adds the certificate to the applications trusted cert store passed in as base64 string (multiple strings supported)", (string s) =>
                  {
                      TrustedCertificateBase64Strings = ParseListOfStrings(s);
                  } },
                { "tf|addtrustedcertfile=", $"adds the certificate file(s) to the applications trusted cert store passed in as base64 string (multiple filenames supported)", (string s) =>
                  {
                      TrustedCertificateFileNames = ParseListOfFileNames(s, "addtrustedcertfile");
                  } },

                { "ib|addissuercertbase64=", $"adds the specified issuer certificate to the applications trusted issuer cert store passed in as base64 string (multiple strings supported)", (string s) =>
                  {
                      IssuerCertificateBase64Strings = ParseListOfStrings(s);
                  } },
                { "if|addissuercertfile=", $"adds the specified issuer certificate file(s) to the applications trusted issuer cert store (multiple filenames supported)", (string s) =>
                  {
                      IssuerCertificateFileNames = ParseListOfFileNames(s, "addissuercertfile");
                  } },

                { "rb|updatecrlbase64=", $"update the CRL passed in as base64 string to the corresponding cert store (trusted or trusted issuer)", (string s) =>
                  {
                      CrlBase64String = s;
                  } },
                { "uc|updatecrlfile=", $"update the CRL passed in as file to the corresponding cert store (trusted or trusted issuer)", (string s) =>
                  {
                      if (File.Exists(s))
                      {
                          CrlFileName = s;
                      }
                      else
                      {
                          throw new OptionException("The file '{s}' does not exist.", "updatecrlfile");
                      }
                  } },

                { "rc|removecert=", $"remove cert(s) with the given thumbprint(s) (multiple thumbprints supported)", (string s) =>
                  {
                      ThumbprintsToRemove = ParseListOfStrings(s);
                  } },

                // misc
                { "h|help", "show this message and exit", h => shouldShowHelp = h != null },
            };

            List <string> extraArgs = new List <string>();

            try
            {
                // parse the command line
                extraArgs = options.Parse(args);
            }
            catch (OptionException e)
            {
                // initialize logging
                InitLogging();

                // show message
                Logger.Fatal(e, "Error in command line options");
                Logger.Error($"Command line arguments: {String.Join(" ", args)}");
                // show usage
                Usage(options);
                return;
            }

            // initialize logging
            InitLogging();

            // show usage if requested
            if (shouldShowHelp)
            {
                Usage(options);
                return;
            }

            // validate and parse extra arguments
            if (extraArgs.Count > 0)
            {
                Logger.Error("Error in command line options");
                Logger.Error($"Command line arguments: {String.Join(" ", args)}");
                Usage(options);
                return;
            }

            //show version
            Logger.Information($"{ProgramName} V{FileVersionInfo.GetVersionInfo(Assembly.GetExecutingAssembly().Location).FileVersion} starting up...");
            Logger.Debug($"Informational version: V{(Attribute.GetCustomAttribute(Assembly.GetEntryAssembly(), typeof(AssemblyInformationalVersionAttribute)) as AssemblyInformationalVersionAttribute).InformationalVersion}");

            try
            {
                await ConsoleServerAsync(args);
            }
            catch (Exception ex)
            {
                Logger.Fatal(ex, "OPC UA server failed unexpectedly.");
            }
            Logger.Information("OPC UA server exiting...");
        }
コード例 #31
0
        /// <summary>
        /// Asynchronous part of the main method of the app.
        /// </summary>
        public async static Task MainAsync(string[] args)
        {
            try
            {
                var shouldShowHelp = false;

                // Shutdown token sources.
                ShutdownTokenSource = new CancellationTokenSource();

                // command line options
                Mono.Options.OptionSet options = new Mono.Options.OptionSet {
                    { "cf|configfile=", $"the filename containing action configuration.\nDefault: '{OpcActionConfigurationFilename}'", (string p) => OpcActionConfigurationFilename = p },

                    { "tc|testconnectivity", $"URL of the OPC UA server used to test connectivity with.\nDefault: {TestConnectivity}", b => TestConnectivity = b != null },

                    { "tu|testurl=", $"URL of the OPC UA server used for tests.\nDefault: {TestConnectivityUrl}", (string s) => TestConnectivityUrl = s },


                    { "sw|sessionconnectwait=", $"specify the wait time in seconds we try to connect to disconnected endpoints and starts monitoring unmonitored items\nMin: 10\nDefault: {SessionConnectWaitSec}", (int i) => {
                          if (i > 10)
                          {
                              SessionConnectWaitSec = i;
                          }
                          else
                          {
                              throw new OptionException("The sessionconnectwait must be greater than 10 sec", "sessionconnectwait");
                          }
                      } },
                    { "di|diagnosticsinterval=", $"shows diagnostic info at the specified interval in seconds (need log level info). 0 disables diagnostic output.\nDefault: {DiagnosticsInterval}", (uint u) => DiagnosticsInterval = u },

                    { "lf|logfile=", $"the filename of the logfile to use.\nDefault: './{_logFileName}'", (string l) => _logFileName = l },
                    { "lt|logflushtimespan=", $"the timespan in seconds when the logfile should be flushed.\nDefault: {_logFileFlushTimeSpanSec} sec", (int s) => {
                          if (s > 0)
                          {
                              _logFileFlushTimeSpanSec = TimeSpan.FromSeconds(s);
                          }
                          else
                          {
                              throw new Mono.Options.OptionException("The logflushtimespan must be a positive number.", "logflushtimespan");
                          }
                      } },
                    { "ll|loglevel=", $"the loglevel to use (allowed: fatal, error, warn, info, debug, verbose).\nDefault: info", (string l) => {
                          List <string> logLevels = new List <string> {
                              "fatal", "error", "warn", "info", "debug", "verbose"
                          };
                          if (logLevels.Contains(l.ToLowerInvariant()))
                          {
                              _logLevel = l.ToLowerInvariant();
                          }
                          else
                          {
                              throw new Mono.Options.OptionException("The loglevel must be one of: fatal, error, warn, info, debug, verbose", "loglevel");
                          }
                      } },
                    // opc configuration options
                    { "ol|opcmaxstringlen=", $"the max length of a string opc can transmit/receive.\nDefault: {OpcMaxStringLength}", (int i) => {
                          if (i > 0)
                          {
                              OpcMaxStringLength = i;
                          }
                          else
                          {
                              throw new OptionException("The max opc string length must be larger than 0.", "opcmaxstringlen");
                          }
                      } },
                    { "ot|operationtimeout=", $"the operation timeout of the OPC UA client in ms.\nDefault: {OpcOperationTimeout}", (int i) => {
                          if (i >= 0)
                          {
                              OpcOperationTimeout = i;
                          }
                          else
                          {
                              throw new OptionException("The operation timeout must be larger or equal 0.", "operationtimeout");
                          }
                      } },
                    { "ct|createsessiontimeout=", $"specify the timeout in seconds used when creating a session to an endpoint. On unsuccessful connection attemps a backoff up to {OpcSessionCreationBackoffMax} times the specified timeout value is used.\nMin: 1\nDefault: {OpcSessionCreationTimeout}", (uint u) => {
                          if (u > 1)
                          {
                              OpcSessionCreationTimeout = u;
                          }
                          else
                          {
                              throw new OptionException("The createsessiontimeout must be greater than 1 sec", "createsessiontimeout");
                          }
                      } },
                    { "ki|keepaliveinterval=", $"specify the interval in seconds se send keep alive messages to the OPC servers on the endpoints it is connected to.\nMin: 2\nDefault: {OpcKeepAliveIntervalInSec}", (int i) => {
                          if (i >= 2)
                          {
                              OpcKeepAliveIntervalInSec = i;
                          }
                          else
                          {
                              throw new OptionException("The keepaliveinterval must be greater or equal 2", "keepalivethreshold");
                          }
                      } },
                    { "kt|keepalivethreshold=", $"specify the number of keep alive packets a server can miss, before the session is disconneced\nMin: 1\nDefault: {OpcKeepAliveDisconnectThreshold}", (uint u) => {
                          if (u > 1)
                          {
                              OpcKeepAliveDisconnectThreshold = u;
                          }
                          else
                          {
                              throw new OptionException("The keepalivethreshold must be greater than 1", "keepalivethreshold");
                          }
                      } },

                    { "aa|autoaccept", $"trusts all servers we establish a connection to.\nDefault: {OpcAutoTrustServerCerts}", b => OpcAutoTrustServerCerts = b != null },

                    // trust own public cert option
                    { "to|trustowncert", $"our own certificate is put into the trusted certificate store automatically.\nDefault: {TrustMyself}", t => TrustMyself = t != null },

                    // own cert store options
                    { "at|appcertstoretype=", $"the own application cert store type. \n(allowed values: Directory, X509Store)\nDefault: '{OpcOwnCertStoreType}'", (string s) => {
                          if (s.Equals(CertificateStoreType.X509Store, StringComparison.OrdinalIgnoreCase) || s.Equals(CertificateStoreType.Directory, StringComparison.OrdinalIgnoreCase))
                          {
                              OpcOwnCertStoreType = s.Equals(CertificateStoreType.X509Store, StringComparison.OrdinalIgnoreCase) ? CertificateStoreType.X509Store : CertificateStoreType.Directory;
                              OpcOwnCertStorePath = s.Equals(CertificateStoreType.X509Store, StringComparison.OrdinalIgnoreCase) ? OpcOwnCertX509StorePathDefault : OpcOwnCertDirectoryStorePathDefault;
                          }
                          else
                          {
                              throw new OptionException();
                          }
                      } },
                    { "ap|appcertstorepath=", $"the path where the own application cert should be stored\nDefault (depends on store type):\n" +
                      $"X509Store: '{OpcOwnCertX509StorePathDefault}'\n" +
                      $"Directory: '{OpcOwnCertDirectoryStorePathDefault}'", (string s) => OpcOwnCertStorePath = s },

                    // trusted cert store options
                    {
                        "tt|trustedcertstoretype=", $"the trusted cert store type. \n(allowed values: Directory, X509Store)\nDefault: {OpcTrustedCertStoreType}", (string s) => {
                            if (s.Equals(CertificateStoreType.X509Store, StringComparison.OrdinalIgnoreCase) || s.Equals(CertificateStoreType.Directory, StringComparison.OrdinalIgnoreCase))
                            {
                                OpcTrustedCertStoreType = s.Equals(CertificateStoreType.X509Store, StringComparison.OrdinalIgnoreCase) ? CertificateStoreType.X509Store : CertificateStoreType.Directory;
                                OpcTrustedCertStorePath = s.Equals(CertificateStoreType.X509Store, StringComparison.OrdinalIgnoreCase) ? OpcTrustedCertX509StorePathDefault : OpcTrustedCertDirectoryStorePathDefault;
                            }
                            else
                            {
                                throw new OptionException();
                            }
                        }
                    },
                    { "tp|trustedcertstorepath=", $"the path of the trusted cert store\nDefault (depends on store type):\n" +
                      $"X509Store: '{OpcTrustedCertX509StorePathDefault}'\n" +
                      $"Directory: '{OpcTrustedCertDirectoryStorePathDefault}'", (string s) => OpcTrustedCertStorePath = s },

                    // rejected cert store options
                    { "rt|rejectedcertstoretype=", $"the rejected cert store type. \n(allowed values: Directory, X509Store)\nDefault: {OpcRejectedCertStoreType}", (string s) => {
                          if (s.Equals(CertificateStoreType.X509Store, StringComparison.OrdinalIgnoreCase) || s.Equals(CertificateStoreType.Directory, StringComparison.OrdinalIgnoreCase))
                          {
                              OpcRejectedCertStoreType = s.Equals(CertificateStoreType.X509Store, StringComparison.OrdinalIgnoreCase) ? CertificateStoreType.X509Store : CertificateStoreType.Directory;
                              OpcRejectedCertStorePath = s.Equals(CertificateStoreType.X509Store, StringComparison.OrdinalIgnoreCase) ? OpcRejectedCertX509StorePathDefault : OpcRejectedCertDirectoryStorePathDefault;
                          }
                          else
                          {
                              throw new OptionException();
                          }
                      } },
                    { "rp|rejectedcertstorepath=", $"the path of the rejected cert store\nDefault (depends on store type):\n" +
                      $"X509Store: '{OpcRejectedCertX509StorePathDefault}'\n" +
                      $"Directory: '{OpcRejectedCertDirectoryStorePathDefault}'", (string s) => OpcRejectedCertStorePath = s },

                    // issuer cert store options
                    {
                        "it|issuercertstoretype=", $"the trusted issuer cert store type. \n(allowed values: Directory, X509Store)\nDefault: {OpcIssuerCertStoreType}", (string s) => {
                            if (s.Equals(CertificateStoreType.X509Store, StringComparison.OrdinalIgnoreCase) || s.Equals(CertificateStoreType.Directory, StringComparison.OrdinalIgnoreCase))
                            {
                                OpcIssuerCertStoreType = s.Equals(CertificateStoreType.X509Store, StringComparison.OrdinalIgnoreCase) ? CertificateStoreType.X509Store : CertificateStoreType.Directory;
                                OpcIssuerCertStorePath = s.Equals(CertificateStoreType.X509Store, StringComparison.OrdinalIgnoreCase) ? OpcIssuerCertX509StorePathDefault : OpcIssuerCertDirectoryStorePathDefault;
                            }
                            else
                            {
                                throw new OptionException();
                            }
                        }
                    },
                    { "ip|issuercertstorepath=", $"the path of the trusted issuer cert store\nDefault (depends on store type):\n" +
                      $"X509Store: '{OpcIssuerCertX509StorePathDefault}'\n" +
                      $"Directory: '{OpcIssuerCertDirectoryStorePathDefault}'", (string s) => OpcIssuerCertStorePath = s },

                    // misc
                    { "h|help", "show this message and exit", h => shouldShowHelp = h != null },
                };


                List <string> extraArgs = new List <string>();
                try
                {
                    // parse the command line
                    extraArgs = options.Parse(args);
                }
                catch (OptionException e)
                {
                    // initialize logging
                    InitLogging();

                    // show message
                    Logger.Error(e, "Error in command line options");
                    Logger.Error($"Command line arguments: {String.Join(" ", args)}");

                    // show usage
                    Usage(options);
                    return;
                }

                // initialize logging
                InitLogging();

                // show usage if requested
                if (shouldShowHelp)
                {
                    Usage(options);
                    return;
                }

                // Validate and parse extra arguments.
                if (extraArgs.Count > 1)
                {
                    Logger.Error("Error in command line options");
                    Logger.Error($"Command line arguments: {String.Join(" ", args)}");
                    Usage(options);
                    return;
                }

                // start operation
                Logger.Information($"{ProgramName} is starting up...");

                // allow canceling the application
                var quitEvent = new ManualResetEvent(false);
                try
                {
                    Console.CancelKeyPress += (sender, eArgs) =>
                    {
                        quitEvent.Set();
                        eArgs.Cancel = true;
                        ShutdownTokenSource.Cancel();
                    };
                }
                catch
                {
                }

                // init OPC configuration and tracing
                OpcStackConfiguration opcStackConfiguration = new OpcStackConfiguration();
                await opcStackConfiguration.ConfigureAsync();

                // Set certificate validator.
                if (OpcAutoTrustServerCerts)
                {
                    Logger.Information($"{ProgramName} configured to auto trust server certificates of the servers it is connecting to.");
                    OpcApplicationConfiguration.CertificateValidator.CertificateValidation += new CertificateValidationEventHandler(CertificateValidator_AutoTrustServerCerts);
                }
                else
                {
                    Logger.Information($"{ProgramName} configured to not auto trust server certificates. When connecting to servers, you need to manually copy the rejected server certs to the trusted store to trust them.");
                    OpcApplicationConfiguration.CertificateValidator.CertificateValidation += new CertificateValidationEventHandler(CertificateValidator_Default);
                }

                // read OPC action configuration
                OpcConfiguration.Init();
                if (!await ReadOpcConfigurationAsync())
                {
                    return;
                }

                // create OPC action data
                if (!await CreateOpcActionDataAsync())
                {
                    return;
                }

                // kick off OPC client activities
                await SessionStartAsync();

                // initialize diagnostics
                Diagnostics.Init();

                // stop on user request
                Logger.Information("");
                Logger.Information("");
                Logger.Information($"{ProgramName} is running. Press CTRL-C to quit.");

                // wait for Ctrl-C
                quitEvent.WaitOne(Timeout.Infinite);

                Logger.Information("");
                Logger.Information("");
                ShutdownTokenSource.Cancel();
                Logger.Information($"{ProgramName} is shutting down...");

                // shutdown all OPC sessions
                await SessionShutdownAsync();

                // shutdown diagnostics
                await ShutdownAsync();

                ShutdownTokenSource = null;
            }
            catch (Exception e)
            {
                Logger.Fatal(e, e.StackTrace);
                e = e.InnerException ?? null;
                while (e != null)
                {
                    Logger.Fatal(e, e.StackTrace);
                    e = e.InnerException ?? null;
                }
                Logger.Fatal($"{ProgramName} exiting... ");
            }
        }