2using System.Collections.Generic;
 
    3using System.Diagnostics;
 
    5using System.Reflection;
 
    6using System.ServiceProcess;
 
   10using Microsoft.Deployment.WindowsInstaller;
 
   14using static System.Environment;
 
   21        public static ActionResult CreateEventSource(Session Session)
 
   23            Session.Log(
"Checking event sources.");
 
   27                if (!EventLog.Exists(
"IoTGateway") || !EventLog.SourceExists(
"IoTGateway"))
 
   29                    Session.Log(
"Creating event source.");
 
   30                    EventLog.CreateEventSource(
new EventSourceCreationData(
"IoTGateway", 
"IoTGateway"));
 
   31                    Session.Log(
"Event source created.");
 
   34                return ActionResult.Success;
 
   38                Session.Log(
"Unable to create event source. Error reported: " + ex.Message);
 
   39                return ActionResult.Failure;
 
   44        public static ActionResult DeleteEventSource(Session Session)
 
   46            Session.Log(
"Checking event sources.");
 
   48            if (EventLog.Exists(
"IoTGateway"))
 
   52                    Session.Log(
"Deleting event log.");
 
   53                    EventLog.Delete(
"IoTGateway");
 
   54                    Session.Log(
"Event log deleted.");
 
   58                    Session.Log(
"Unable to delete event log. Error reported: " + ex.Message);
 
   62            if (EventLog.SourceExists(
"IoTGateway"))
 
   66                    Session.Log(
"Deleting event source.");
 
   67                    EventLog.DeleteEventSource(
"IoTGateway");
 
   68                    Session.Log(
"Event source deleted.");
 
   72                    Session.Log(
"Unable to delete event source. Error reported: " + ex.Message);
 
   77            return ActionResult.Success;
 
   80        private static void Log(Session Session, 
string Msg)
 
   86        public static string AppDataFolder
 
   90                string Result = Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData);
 
   92                if (!Result.EndsWith(
new string(Path.DirectorySeparatorChar, 1)))
 
   93                    Result += Path.DirectorySeparatorChar;
 
   95                Result += 
"IoT Gateway" + Path.DirectorySeparatorChar;
 
   96                if (!Directory.Exists(Result))
 
   97                    Directory.CreateDirectory(Result);
 
  120        public static ActionResult InstallAndStartService(Session Session)
 
  122            Session.Log(
"Installing service.");
 
  125                string DisplayName = Session[
"SERVICEDISPLAYNAME"];
 
  126                string Description = Session[
"SERVICEDESCRIPTION"];
 
  127                string InstallDir = Session[
"INSTALLDIR"];
 
  129                if (!InstallDir.EndsWith(
new string(Path.DirectorySeparatorChar, 1)))
 
  130                    InstallDir += Path.DirectorySeparatorChar;
 
  132                Session.Log(
"Service Display Name: " + DisplayName);
 
  133                Session.Log(
"Service Description: " + Description);
 
  134                Session.Log(
"Working folder: " + InstallDir);
 
  136                StringBuilder sb = 
new StringBuilder();
 
  138                sb.Append(
"-install -displayname \"");
 
  139                sb.Append(DisplayName);
 
  140                sb.Append(
"\" -description \"");
 
  141                sb.Append(Description);
 
  142                sb.Append(
"\" -start AutoStart -immediate");
 
  144                ProcessStartInfo ProcessInformation = 
new ProcessStartInfo()
 
  146                    FileName = InstallDir + 
"Waher.IotGateway.Svc.exe",
 
  147                    Arguments = sb.ToString(),
 
  148                    UseShellExecute = 
false,
 
  149                    RedirectStandardError = 
true,
 
  150                    RedirectStandardOutput = 
true,
 
  151                    WorkingDirectory = InstallDir,
 
  152                    CreateNoWindow = 
true,
 
  153                    WindowStyle = ProcessWindowStyle.Hidden
 
  156                using (Process P = 
new Process())
 
  160                    P.ErrorDataReceived += (Sender, e) =>
 
  163                        Session.Log(
"ERROR: " + e.Data);
 
  166                    P.Exited += (Sender, e) =>
 
  168                        Session.Log(
"Process exited.");
 
  171                    P.OutputDataReceived += (Sender, e) =>
 
  176                    P.StartInfo = ProcessInformation;
 
  179                    if (!P.WaitForExit(60000) || Error)
 
  180                        throw new Exception(
"Timeout. Service did not install properly.");
 
  183                        if (!P.StandardError.EndOfStream)
 
  184                            Session.Log(P.StandardError.ReadToEnd());
 
  186                        if (!P.StandardOutput.EndOfStream)
 
  187                            Session.Log(P.StandardOutput.ReadToEnd());
 
  190                            throw new Exception(
"Installation failed. Exit code: " + P.ExitCode.ToString());
 
  194                Session.Log(
"Service installed and started.");
 
  196                return WaitAllModulesStarted(Session);
 
  200                Session.Log(
"Unable to install service. Error reported: " + ex.Message);
 
  201                return ActionResult.Failure;
 
  206        public static ActionResult UninstallService(Session Session)
 
  208            Session.Log(
"Uninstalling service.");
 
  211                string InstallDir = Session[
"INSTALLDIR"];
 
  213                if (!InstallDir.EndsWith(
new string(Path.DirectorySeparatorChar, 1)))
 
  214                    InstallDir += Path.DirectorySeparatorChar;
 
  216                Session.Log(
"Working folder: " + InstallDir);
 
  218                ProcessStartInfo ProcessInformation = 
new ProcessStartInfo()
 
  220                    FileName = InstallDir + 
"Waher.IotGateway.Svc.exe",
 
  221                    Arguments = 
"-uninstall",
 
  222                    UseShellExecute = 
false,
 
  223                    RedirectStandardError = 
true,
 
  224                    RedirectStandardOutput = 
true,
 
  225                    WorkingDirectory = InstallDir,
 
  226                    CreateNoWindow = 
true,
 
  227                    WindowStyle = ProcessWindowStyle.Hidden
 
  230                using (Process P = 
new Process())
 
  234                    P.ErrorDataReceived += (Sender, e) =>
 
  237                        Session.Log(
"ERROR: " + e.Data);
 
  240                    P.Exited += (Sender, e) =>
 
  242                        Session.Log(
"Process exited.");
 
  245                    P.OutputDataReceived += (Sender, e) =>
 
  250                    P.StartInfo = ProcessInformation;
 
  253                    if (!P.WaitForExit(60000) || Error)
 
  254                        Session.Log(
"Timeout. Service did not uninstall properly.");
 
  257                        if (!P.StandardError.EndOfStream)
 
  258                            Session.Log(P.StandardError.ReadToEnd());
 
  260                        if (!P.StandardOutput.EndOfStream)
 
  261                            Session.Log(P.StandardOutput.ReadToEnd());
 
  264                            Session.Log(
"Uninstallation failed. Exit code: " + P.ExitCode.ToString());
 
  267                            Session.Log(
"Service uninstalled.");
 
  268                            return ActionResult.Success;
 
  275                Session.Log(
"Unable to uninstall service. Error reported: " + ex.Message);
 
  278            return UninstallService2(Session);
 
  281        public static ActionResult UninstallService2(Session Session)
 
  283            Session.Log(
"Uninstalling service (method 2).");
 
  286                string InstallDir = Session[
"INSTALLDIR"];
 
  288                if (!InstallDir.EndsWith(
new string(Path.DirectorySeparatorChar, 1)))
 
  289                    InstallDir += Path.DirectorySeparatorChar;
 
  291                Session.Log(
"Working folder: " + InstallDir);
 
  293                ProcessStartInfo ProcessInformation = 
new ProcessStartInfo()
 
  296                    Arguments = 
"delete \"IoT Gateway Service\"",
 
  297                    UseShellExecute = 
false,
 
  298                    RedirectStandardError = 
true,
 
  299                    RedirectStandardOutput = 
true,
 
  300                    WorkingDirectory = InstallDir,
 
  301                    CreateNoWindow = 
true,
 
  302                    WindowStyle = ProcessWindowStyle.Hidden
 
  305                using (Process P = 
new Process())
 
  309                    P.ErrorDataReceived += (Sender, e) =>
 
  312                        Session.Log(
"ERROR: " + e.Data);
 
  315                    P.Exited += (Sender, e) =>
 
  317                        Session.Log(
"Process exited.");
 
  320                    P.OutputDataReceived += (Sender, e) =>
 
  325                    P.StartInfo = ProcessInformation;
 
  328                    if (!P.WaitForExit(60000) || Error)
 
  329                        Session.Log(
"Timeout. Service did not uninstall properly.");
 
  332                        if (!P.StandardError.EndOfStream)
 
  333                            Session.Log(P.StandardError.ReadToEnd());
 
  335                        if (!P.StandardOutput.EndOfStream)
 
  336                            Session.Log(P.StandardOutput.ReadToEnd());
 
  339                            Session.Log(
"Uninstallation failed. Exit code: " + P.ExitCode.ToString());
 
  341                            Session.Log(
"Service uninstalled.");
 
  347                Session.Log(
"Unable to uninstall service. Error reported: " + ex.Message);
 
  351            return ActionResult.Success;
 
  355        public static ActionResult StartService(Session Session)
 
  357            Session.Log(
"Starting service.");
 
  360                string InstallDir = Session[
"INSTALLDIR"];
 
  362                ProcessStartInfo ProcessInformation = 
new ProcessStartInfo()
 
  365                    Arguments = 
"start \"IoT Gateway Service\"",
 
  366                    UseShellExecute = 
false,
 
  367                    RedirectStandardError = 
true,
 
  368                    RedirectStandardOutput = 
true,
 
  369                    WorkingDirectory = InstallDir,
 
  370                    CreateNoWindow = 
true,
 
  371                    WindowStyle = ProcessWindowStyle.Hidden
 
  374                using (Process P = 
new Process())
 
  378                    P.ErrorDataReceived += (Sender, e) =>
 
  381                        Session.Log(
"ERROR: " + e.Data);
 
  384                    P.Exited += (Sender, e) =>
 
  386                        Session.Log(
"Process exited.");
 
  389                    P.OutputDataReceived += (Sender, e) =>
 
  394                    P.StartInfo = ProcessInformation;
 
  397                    if (!P.WaitForExit(60000) || Error)
 
  398                        throw new Exception(
"Timeout. Service did not start properly.");
 
  401                        if (!P.StandardError.EndOfStream)
 
  402                            Session.Log(P.StandardError.ReadToEnd());
 
  404                        if (!P.StandardOutput.EndOfStream)
 
  405                            Session.Log(P.StandardOutput.ReadToEnd());
 
  408                            throw new Exception(
"Service start failed. Exit code: " + P.ExitCode.ToString());
 
  412                Session.Log(
"Service started.");
 
  414                return WaitAllModulesStarted(Session);
 
  418                Session.Log(
"Unable to start service. Error reported: " + ex.Message);
 
  420                return ActionResult.Success;
 
  425        public static ActionResult StopService(Session Session)
 
  427            Session.Log(
"Stopping service.");
 
  430                string InstallDir = Session[
"INSTALLDIR"];
 
  432                ProcessStartInfo ProcessInformation = 
new ProcessStartInfo()
 
  435                    Arguments = 
"stop \"IoT Gateway Service\"",
 
  436                    UseShellExecute = 
false,
 
  437                    RedirectStandardError = 
true,
 
  438                    RedirectStandardOutput = 
true,
 
  439                    WorkingDirectory = InstallDir,
 
  440                    CreateNoWindow = 
true,
 
  441                    WindowStyle = ProcessWindowStyle.Hidden
 
  444                using (Process P = 
new Process())
 
  448                    P.ErrorDataReceived += (Sender, e) =>
 
  451                        Session.Log(
"ERROR: " + e.Data);
 
  454                    P.Exited += (Sender, e) =>
 
  456                        Session.Log(
"Process exited.");
 
  459                    P.OutputDataReceived += (Sender, e) =>
 
  464                    P.StartInfo = ProcessInformation;
 
  467                    if (!P.WaitForExit(60000) || Error)
 
  468                        Session.Log(
"Timeout. Service did not stop properly.");
 
  471                        if (!P.StandardError.EndOfStream)
 
  472                            Session.Log(P.StandardError.ReadToEnd());
 
  474                        if (!P.StandardOutput.EndOfStream)
 
  475                            Session.Log(P.StandardOutput.ReadToEnd());
 
  478                            Session.Log(
"Stopping service failed. Exit code: " + P.ExitCode.ToString());
 
  481                            DateTime Started = DateTime.Now;
 
  484                            Session.Log(
"Service stop request successful. Checking process has stopped");
 
  488                                using (Mutex RunningServer = 
new Mutex(
false, 
"Waher.IoTGateway.Running"))
 
  490                                    Stopped = RunningServer.WaitOne(1000);
 
  493                                        RunningServer.ReleaseMutex();
 
  496                            while (!Stopped && (DateTime.Now - Started).TotalSeconds < 30);
 
  499                                Session.Log(
"Service stopped.");
 
  501                                throw new Exception(
"Service stop procedure seems to take time. Cancelling wait.");
 
  508                Session.Log(
"Unable to stop service. Error reported: " + ex.Message);
 
  511            return ActionResult.Success;
 
  625        public static ActionResult OpenLocalhost(Session Session)
 
  627            Session.Log(
"Starting browser.");
 
  632                string StartPage = Session[
"STARTPAGE"];
 
  633                if (StartPage == 
"unset")
 
  634                    StartPage = 
string.Empty;
 
  636                string Port = 
string.Empty;
 
  637                string Protocol = 
"http";
 
  641                    string s = File.ReadAllText(AppDataFolder + 
"Ports.txt");
 
  642                    string[] Rows = s.Split(
new char[] { 
'\r', 
'\n' }, StringSplitOptions.RemoveEmptyEntries);
 
  643                    SortedDictionary<int, bool> Ports = 
new SortedDictionary<int, bool>();
 
  645                    foreach (
string Row 
in Rows)
 
  647                        if (
int.TryParse(Row, out 
int i))
 
  651                    if (!Ports.ContainsKey(80))
 
  653                        if (Ports.ContainsKey(8080))
 
  655                        else if (Ports.ContainsKey(8081))
 
  657                        else if (Ports.ContainsKey(8082))
 
  659                        else if (Ports.ContainsKey(443))
 
  661                        else if (Ports.ContainsKey(8088))
 
  670                    Session.Log(
"Unable to get opened ports. Error reported: " + ex.Message);
 
  673                StartPage = Protocol + 
"://localhost" + Port + 
"/" + StartPage;
 
  674                Session.Log(
"Start Page: " + StartPage);
 
  676                Process.Start(StartPage);
 
  677                Session.Log(
"Browser started.");
 
  681                Session.Log(
"Unable to start browser. Error reported: " + ex.Message);
 
  684            return ActionResult.Success;
 
  687        public static ActionResult WaitAllModulesStarted(Session Session)
 
  689            Session.Log(
"Waiting for all modules to start.");
 
  692                DateTime Start = DateTime.Now;
 
  695                Session.Log(
"Waiting for service to start.");
 
  701                    using (Mutex RunningServer = 
new Mutex(
false, 
"Waher.IoTGateway.Running"))
 
  703                        Running = !RunningServer.WaitOne(1000);
 
  706                            RunningServer.ReleaseMutex();
 
  712                while (!Running && (DateTime.Now - Start).TotalSeconds < 30);
 
  716                    Session.Log(
"Could not detect a start of service. Cancelling wait and continuing.");
 
  717                    return ActionResult.Success;
 
  720                Session.Log(
"Waiting for service startup procedure to complete.");
 
  722                using (Mutex StartingServer = 
new Mutex(
false, 
"Waher.IoTGateway.Starting"))
 
  724                    if (StartingServer.WaitOne(120000))
 
  726                        StartingServer.ReleaseMutex();
 
  727                        Session.Log(
"All modules started.");
 
  730                        Session.Log(
"Modules takes too long to start. Cancelling wait and continuing.");
 
  735                Session.Log(
"Unable to wait for all modules to start. The following error was reported: " + ex.Message);
 
  738            return ActionResult.Success;
 
  742        public static ActionResult BeforeUninstallEvent(Session Session)
 
  744            Session.Log(
"Sending BeforeUninstall event.");
 
  747                using (ServiceController ServiceController = 
new ServiceController(
"IoT Gateway Service"))
 
  749                    ServiceController.ExecuteCommand(128);
 
  754                Session.Log(
"Unable to send event. The following error was reported: " + ex.Message);
 
  757            return ActionResult.Success;
 
  761        public static ActionResult InstallManifest(Session Session)
 
  763            string ManifestFile = Path.Combine(Session[
"INSTALLDIR"], Session[
"ManifestFile"]);
 
  764            string ServerApplication = Path.Combine(Session[
"INSTALLDIR"], 
"Waher.IoTGateway.Svc.dll");
 
  765            string ProgramDataFolder = Session[
"APPDATADIR"];
 
  767            Session.Log(
"Installing module: " + ManifestFile);
 
  768            Session.Log(
"Server application: " + ServerApplication);
 
  769            Session.Log(
"Program data folder: " + ProgramDataFolder);
 
  773                Install(Session, ManifestFile, ServerApplication, ProgramDataFolder);
 
  774                return ActionResult.Success;
 
  778                Session.Log(ex.Message);
 
  779                return ActionResult.Failure;
 
  784        public static ActionResult StopServiceAndUninstallManifest(Session Session)
 
  786            ActionResult Result = StopService(Session);
 
  787            if (Result != ActionResult.Success)
 
  790            return UninstallManifest(Session);
 
  794        public static ActionResult UninstallManifest(Session Session)
 
  796            string ManifestFile = Path.Combine(Session[
"INSTALLDIR"], Session[
"ManifestFile"]);
 
  797            string ServerApplication = Path.Combine(Session[
"INSTALLDIR"], 
"Waher.IoTGateway.Svc.dll");
 
  798            string ProgramDataFolder = Session[
"APPDATADIR"];
 
  800            Session.Log(
"Uninstalling module: " + ManifestFile);
 
  801            Session.Log(
"Server application: " + ServerApplication);
 
  802            Session.Log(
"Program data folder: " + ProgramDataFolder);
 
  806                Uninstall(Session, ManifestFile, ServerApplication, ProgramDataFolder, 
true);
 
  810                Session.Log(ex.Message);
 
  813            return ActionResult.Success;
 
  816        #region From Waher.Utility.Install 
  818        private static AssemblyName GetAssemblyName(
string ServerApplication)
 
  820            if (ServerApplication.EndsWith(
".exe", StringComparison.CurrentCultureIgnoreCase))
 
  821                ServerApplication = ServerApplication.Substring(0, ServerApplication.Length - 4) + 
".dll";
 
  823            return AssemblyName.GetAssemblyName(ServerApplication);
 
  826        private static void Install(Session Session, 
string ManifestFile, 
string ServerApplication, 
string ProgramDataFolder)
 
  834            if (
string.IsNullOrEmpty(ManifestFile))
 
  835                throw new Exception(
"Missing manifest file.");
 
  837            if (
string.IsNullOrEmpty(ProgramDataFolder))
 
  839                ProgramDataFolder = Path.Combine(Environment.GetFolderPath(SpecialFolder.CommonApplicationData), 
"IoT Gateway");
 
  843                Session.Log(
"Using default program data folder: " + ProgramDataFolder);
 
  846            if (
string.IsNullOrEmpty(ServerApplication))
 
  847                throw new Exception(
"Missing server application.");
 
  849            if (!File.Exists(ServerApplication))
 
  850                throw new Exception(
"Server application not found: " + ServerApplication);
 
  852            Session.Log(
"Getting assembly name of server.");
 
  853            AssemblyName ServerName = GetAssemblyName(ServerApplication);
 
  854            Session.Log(
"Server assembly name: " + ServerName.ToString());
 
  856            string DepsJsonFileName;
 
  858            int i = ServerApplication.LastIndexOf(
'.');
 
  860                DepsJsonFileName = ServerApplication;
 
  862                DepsJsonFileName = ServerApplication.Substring(0, i);
 
  864            DepsJsonFileName += 
".deps.json";
 
  866            Session.Log(
"deps.json file name: " + DepsJsonFileName);
 
  868            if (!File.Exists(DepsJsonFileName))
 
  869                throw new Exception(
"Invalid server executable. No corresponding deps.json file found.");
 
  871            Session.Log(
"Opening " + DepsJsonFileName);
 
  873            string s = File.ReadAllText(DepsJsonFileName);
 
  875            Session.Log(
"Parsing " + DepsJsonFileName);
 
  877            if (!(
JSON.
Parse(s) is Dictionary<string, object> Deps))
 
  878                throw new Exception(
"Invalid deps.json file. Unable to install.");
 
  880            Session.Log(
"Loading manifest file.");
 
  882            XmlDocument Manifest = 
new XmlDocument()
 
  884                PreserveWhitespace = 
true 
  886            Manifest.Load(ManifestFile);
 
  888            XmlElement Module = Manifest[
"Module"];
 
  889            string SourceFolder = Path.GetDirectoryName(ManifestFile);
 
  890            string AppFolder = Path.GetDirectoryName(ServerApplication);
 
  891            string DestManifestFileName = Path.Combine(AppFolder, Path.GetFileName(ManifestFile));
 
  893            CopyFileIfNewer(Session, ManifestFile, DestManifestFileName, 
null, 
false);
 
  895            Session.Log(
"Source folder: " + SourceFolder);
 
  896            Session.Log(
"App folder: " + AppFolder);
 
  898            foreach (XmlNode N 
in Module.ChildNodes)
 
  900                if (N is XmlElement E && E.LocalName == 
"Assembly")
 
  902                    KeyValuePair<string, string> FileNames = GetFileName(E, SourceFolder);
 
  903                    string FileName = FileNames.Key;
 
  904                    string SourceFileName = FileNames.Value;
 
  906                    if (CopyFileIfNewer(Session, SourceFileName, Path.Combine(AppFolder, FileName), 
null, 
true))
 
  908                        if (FileName.EndsWith(
".dll", StringComparison.CurrentCultureIgnoreCase))
 
  910                            string PdbFileName = FileName.Substring(0, FileName.Length - 4) + 
".pdb";
 
  911                            if (File.Exists(PdbFileName))
 
  912                                CopyFileIfNewer(Session, Path.Combine(SourceFolder, PdbFileName), Path.Combine(AppFolder, PdbFileName), 
null, 
true);
 
  916                    Assembly A = Assembly.LoadFrom(SourceFileName);
 
  917                    AssemblyName AN = A.GetName();
 
  919                    if (!(Deps is 
null) && Deps.TryGetValue(
"targets", out 
object Obj) && Obj is Dictionary<string, object> Targets)
 
  921                        foreach (KeyValuePair<string, object> P 
in Targets)
 
  923                            if (P.Value is Dictionary<string, object> Target)
 
  925                                foreach (KeyValuePair<string, object> P2 
in Target)
 
  927                                    if (P2.Key.StartsWith(ServerName.Name + 
"/") &&
 
  928                                        P2.Value is Dictionary<string, object> App &&
 
  929                                        App.TryGetValue(
"dependencies", out 
object Obj2) &&
 
  930                                        Obj2 is Dictionary<string, object> Dependencies)
 
  932                                        Dependencies[AN.Name] = AN.Version.ToString();
 
  937                                Dictionary<string, object> Dependencies2 = 
new Dictionary<string, object>();
 
  939                                foreach (AssemblyName Dependency 
in A.GetReferencedAssemblies())
 
  940                                    Dependencies2[Dependency.Name] = Dependency.Version.ToString();
 
  942                                Dictionary<string, object> Runtime = 
new Dictionary<string, object>()
 
  944                                        { Path.GetFileName(SourceFileName), 
new Dictionary<string,object>() }
 
  947                                Target[AN.Name + 
"/" + AN.Version.ToString()] = 
new Dictionary<string, object>()
 
  949                                        { 
"dependencies", Dependencies2 },
 
  950                                        { 
"runtime", Runtime }
 
  956                    if (!(Deps is 
null) && Deps.TryGetValue(
"libraries", out 
object Obj3) && Obj3 is Dictionary<string, object> Libraries)
 
  958                        foreach (KeyValuePair<string, object> P 
in Libraries)
 
  960                            if (P.Key.StartsWith(AN.Name + 
"/"))
 
  962                                Libraries.Remove(P.Key);
 
  967                        Libraries[AN.Name + 
"/" + AN.Version.ToString()] = 
new Dictionary<string, object>()
 
  969                                { 
"type", 
"project" },
 
  970                                { 
"serviceable", 
false },
 
  971                                { 
"sha512", string.Empty }
 
  978            CopyContent(Session, SourceFolder, AppFolder, ProgramDataFolder, Module);
 
  980            Session.Log(
"Encoding JSON");
 
  986                    typeof(
JSON).Assembly);
 
  991            Session.Log(
"Writing " + DepsJsonFileName);
 
  992            File.WriteAllText(DepsJsonFileName, s, Encoding.UTF8);
 
  995        private static bool CopyFileIfNewer(Session Session, 
string From, 
string To, 
string To2, 
bool OnlyIfNewer)
 
  997            if (!File.Exists(From))
 
  998                throw new FileNotFoundException(
"File not found: " + From);
 
 1000            bool Copy1 = From != To;
 
 1002            if (Copy1 && OnlyIfNewer && File.Exists(To))
 
 1004                DateTime ToTP = File.GetLastWriteTimeUtc(To);
 
 1005                DateTime FromTP = File.GetLastWriteTimeUtc(From);
 
 1009                    Session.Log(
"Skipping file. Destination folder contains newer version: " + From);
 
 1016                Session.Log(
"Copying " + From + 
" to " + To);
 
 1017                File.Copy(From, To, 
true);
 
 1020            if (!
string.IsNullOrEmpty(To2))
 
 1022                bool Copy2 = From != To2;
 
 1024                if (Copy2 && OnlyIfNewer && File.Exists(To2))
 
 1026                    DateTime ToTP = File.GetLastWriteTimeUtc(To2);
 
 1027                    DateTime FromTP = File.GetLastWriteTimeUtc(From);
 
 1031                        Session.Log(
"Skipping file. Destination folder contains newer version: " + From);
 
 1038                    Session.Log(
"Copying " + From + 
" to " + To2);
 
 1039                    File.Copy(From, To2, 
true);
 
 1046        private enum CopyOptions
 
 1052        private static void CopyContent(Session Session, 
string SourceFolder, 
string AppFolder, 
string DataFolder, XmlElement Parent)
 
 1054            foreach (XmlNode N 
in Parent.ChildNodes)
 
 1056                if (N is XmlElement E)
 
 1058                    switch (E.LocalName)
 
 1061                            KeyValuePair<string, string> FileNames;
 
 1065                                FileNames = GetFileName(E, SourceFolder);
 
 1067                            catch (FileNotFoundException)
 
 1073                            string FileName = FileNames.Key;
 
 1074                            string SourceFileName = FileNames.Value;
 
 1075                            CopyOptions CopyOptions = 
XML.
Attribute(E, 
"copy", CopyOptions.IfNewer);
 
 1077                            Session.Log(
"Content file: " + FileName);
 
 1079                            if (!
string.IsNullOrEmpty(DataFolder) && !Directory.Exists(DataFolder))
 
 1081                                Session.Log(
"Creating folder " + DataFolder + 
".");
 
 1082                                Directory.CreateDirectory(DataFolder);
 
 1085                            if (!
string.IsNullOrEmpty(AppFolder) && !Directory.Exists(AppFolder))
 
 1087                                Session.Log(
"Creating folder " + AppFolder + 
".");
 
 1088                                Directory.CreateDirectory(AppFolder);
 
 1093                                CopyFileIfNewer(Session, SourceFileName,
 
 1094                                    Path.Combine(DataFolder, FileName),
 
 1095                                    Path.Combine(AppFolder, FileName),
 
 1096                                    CopyOptions == CopyOptions.IfNewer);
 
 1098                            catch (FileNotFoundException)
 
 1107                            string SourceFolder2 = Path.Combine(SourceFolder, Name);
 
 1108                            string AppFolder2 = Path.Combine(AppFolder, Name);
 
 1109                            string DataFolder2 = Path.Combine(DataFolder, Name);
 
 1111                            Session.Log(
"Folder: " + Name,
 
 1112                                new KeyValuePair<string, object>(
"Source", SourceFolder2),
 
 1113                                new KeyValuePair<string, object>(
"App", AppFolder2),
 
 1114                                new KeyValuePair<string, object>(
"Data", DataFolder2));
 
 1116                            CopyContent(Session, SourceFolder2, AppFolder2, DataFolder2, E);
 
 1122                                FileNames = GetFileName(E, SourceFolder);
 
 1124                            catch (FileNotFoundException)
 
 1130                            FileName = FileNames.Key;
 
 1131                            SourceFileName = FileNames.Value;
 
 1133                            Session.Log(
"External program file: " + FileName);
 
 1135                            if (!
string.IsNullOrEmpty(AppFolder) && !Directory.Exists(AppFolder))
 
 1137                                Session.Log(
"Creating folder " + AppFolder + 
".");
 
 1138                                Directory.CreateDirectory(AppFolder);
 
 1143                                CopyFileIfNewer(Session, SourceFileName, Path.Combine(AppFolder, FileName), 
null, 
false);
 
 1145                            catch (FileNotFoundException)
 
 1152                            Environment.SpecialFolder SpecialFolder = 
XML.
Attribute(E, 
"folder", Environment.SpecialFolder.ProgramFiles);
 
 1155                            SourceFolder2 = Path.Combine(SourceFolder, Name);
 
 1156                            AppFolder2 = GetFolderPath(SpecialFolder, Name);
 
 1157                            DataFolder2 = Path.Combine(DataFolder, Name);
 
 1159                            Session.Log(
"Folder: " + Name,
 
 1160                                new KeyValuePair<string, object>(
"Source", SourceFolder2),
 
 1161                                new KeyValuePair<string, object>(
"App", AppFolder2),
 
 1162                                new KeyValuePair<string, object>(
"Data", DataFolder2));
 
 1164                            CopyContent(Session, SourceFolder2, AppFolder2, DataFolder2, E);
 
 1171        private static string GetFolderPath(SpecialFolder SpecialFolder, 
string Name)
 
 1173            string s = Environment.GetFolderPath(SpecialFolder);
 
 1174            string Result = Path.Combine(s, Name);
 
 1176            if (Directory.Exists(Result))
 
 1179            if (s.EndsWith(
"(x86)"))
 
 1181                s = s.Substring(0, s.Length - 5).TrimEnd();
 
 1182                string Result2 = Path.Combine(s, Name);
 
 1184                if (Directory.Exists(Result2))
 
 1191        private static void Uninstall(Session Session, 
string ManifestFile, 
string ServerApplication, 
string ProgramDataFolder, 
bool Remove)
 
 1197            if (
string.IsNullOrEmpty(ManifestFile))
 
 1198                throw new Exception(
"Missing manifest file.");
 
 1200            if (
string.IsNullOrEmpty(ServerApplication))
 
 1201                throw new Exception(
"Missing server application.");
 
 1203            if (
string.IsNullOrEmpty(ProgramDataFolder))
 
 1205                ProgramDataFolder = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), 
"IoT Gateway");
 
 1209                Session.Log(
"Using default program data folder: " + ProgramDataFolder);
 
 1212            if (!File.Exists(ServerApplication))
 
 1213                throw new Exception(
"Server application not found: " + ServerApplication);
 
 1215            Session.Log(
"Getting assembly name of server.");
 
 1216            AssemblyName ServerName = GetAssemblyName(ServerApplication);
 
 1217            Session.Log(
"Server assembly name: " + ServerName.ToString());
 
 1219            string DepsJsonFileName;
 
 1221            int i = ServerApplication.LastIndexOf(
'.');
 
 1223                DepsJsonFileName = ServerApplication;
 
 1225                DepsJsonFileName = ServerApplication.Substring(0, i);
 
 1227            DepsJsonFileName += 
".deps.json";
 
 1229            Session.Log(
"deps.json file name: " + DepsJsonFileName);
 
 1231            if (!File.Exists(DepsJsonFileName))
 
 1232                throw new Exception(
"Invalid server executable. No corresponding deps.json file found.");
 
 1234            Session.Log(
"Opening " + DepsJsonFileName);
 
 1236            string s = File.ReadAllText(DepsJsonFileName);
 
 1238            Session.Log(
"Parsing " + DepsJsonFileName);
 
 1240            if (!(
JSON.
Parse(s) is Dictionary<string, object> Deps))
 
 1241                throw new Exception(
"Invalid deps.json file. Unable to install.");
 
 1243            Session.Log(
"Loading manifest file.");
 
 1245            XmlDocument Manifest = 
new XmlDocument();
 
 1246            Manifest.Load(ManifestFile);
 
 1248            XmlElement Module = Manifest[
"Module"];
 
 1249            string AppFolder = Path.GetDirectoryName(ServerApplication);
 
 1251            Session.Log(
"App folder: " + AppFolder);
 
 1253            foreach (XmlNode N 
in Module.ChildNodes)
 
 1255                if (N is XmlElement E && E.LocalName == 
"Assembly")
 
 1257                    KeyValuePair<string, string> FileNames = GetFileName(E, AppFolder);
 
 1258                    string FileName = FileNames.Key;
 
 1259                    string AppFileName = FileNames.Value;
 
 1261                    Assembly A = Assembly.LoadFrom(AppFileName);
 
 1262                    AssemblyName AN = A.GetName();
 
 1263                    string Key = AN.Name + 
"/" + AN.Version.ToString();
 
 1265                    if (!(Deps is 
null) && Deps.TryGetValue(
"targets", out 
object Obj) && Obj is Dictionary<string, object> Targets)
 
 1267                        Targets.Remove(Key);
 
 1269                        foreach (KeyValuePair<string, object> P 
in Targets)
 
 1271                            if (P.Value is Dictionary<string, object> Target)
 
 1273                                foreach (KeyValuePair<string, object> P2 
in Target)
 
 1275                                    if (P2.Key.StartsWith(ServerName.Name + 
"/") &&
 
 1276                                        P2.Value is Dictionary<string, object> App &&
 
 1277                                        App.TryGetValue(
"dependencies", out 
object Obj2) &&
 
 1278                                        Obj2 is Dictionary<string, object> Dependencies)
 
 1280                                        Dependencies.Remove(AN.Name);
 
 1288                    if (!(Deps is 
null) && Deps.TryGetValue(
"libraries", out 
object Obj3) && Obj3 is Dictionary<string, object> Libraries)
 
 1290                        foreach (KeyValuePair<string, object> P 
in Libraries)
 
 1292                            if (P.Key.StartsWith(AN.Name + 
"/"))
 
 1294                                Libraries.Remove(P.Key);
 
 1302                        RemoveFile(Session, AppFileName);
 
 1303                        if (FileName.EndsWith(
".dll", StringComparison.CurrentCultureIgnoreCase))
 
 1305                            string PdbFileName = FileName.Substring(0, FileName.Length - 4) + 
".pdb";
 
 1306                            RemoveFile(Session, PdbFileName);
 
 1312            Session.Log(
"Encoding JSON");
 
 1318                    typeof(
JSON).Assembly);
 
 1323            Session.Log(
"Writing " + DepsJsonFileName);
 
 1324            File.WriteAllText(DepsJsonFileName, s, Encoding.UTF8);
 
 1326            if (Path.GetDirectoryName(ManifestFile) == AppFolder)
 
 1327                RemoveFile(Session, ManifestFile);
 
 1330        private static bool RemoveFile(Session Session, 
string FileName)
 
 1332            if (!File.Exists(FileName))
 
 1335            Session.Log(
"Deleting " + FileName);
 
 1338                File.Delete(FileName);
 
 1340            catch (Exception ex)
 
 1342                Session.Log(
"Unable to delete file. Error reported: " + ex.Message);
 
 1348        private static KeyValuePair<string, string> GetFileName(XmlElement E, 
string ReferenceFolder)
 
 1351            string AbsFileName = Path.Combine(ReferenceFolder, FileName);
 
 1352            if (File.Exists(AbsFileName))
 
 1353                return new KeyValuePair<string, string>(FileName, AbsFileName);
 
 1356            if (
string.IsNullOrEmpty(AltFolder))
 
 1357                throw new FileNotFoundException(
"File not found: " + AbsFileName);
 
 1359            AbsFileName = Path.Combine(AltFolder, FileName);
 
 1360            if (File.Exists(AbsFileName))
 
 1361                return new KeyValuePair<string, string>(FileName, AbsFileName);
 
 1363            throw new FileNotFoundException(
"File not found: " + AbsFileName);
 
Helps with common JSON-related tasks.
 
static object Parse(string Json)
Parses a JSON string.
 
static string Encode(string s)
Encodes a string for inclusion in JSON.
 
Helps with common XML-related tasks.
 
static string Attribute(XmlElement E, string Name)
Gets the value of an XML attribute.
 
Static class that dynamically manages types and interfaces available in the runtime environment.
 
static bool IsInitialized
If the inventory has been initialized.
 
static void Initialize(params Assembly[] Assemblies)
Initializes the inventory engine, registering types and interfaces available in Assemblies .