public PackageData AddPackage(string archiveFileName) { // uncompress and verify package content string tempFolder = Path.Combine(Utility.GetTmpFolder(), Path.GetFileNameWithoutExtension(archiveFileName)); Utility.FolderCleanUp(tempFolder); Utility.UncompressZip(archiveFileName, tempFolder); string packageJson = File.ReadAllText(Path.Combine(tempFolder, "package.json")); var packageData = JsonConvert.DeserializeObject <PackageData>(packageJson); // TODO: Data normalization and check string programsDatabase = Path.Combine(tempFolder, "programs.xml"); var serializer1 = new XmlSerializer(typeof(List <ProgramBlock>)); using (var reader = new StreamReader(programsDatabase)) { // verify if package data checksum matches the one in programs.xml file var programs = (List <ProgramBlock>)serializer1.Deserialize(reader); foreach (var prg in packageData.Programs) { // Get the program from programs.xml var p1 = programs.Find((p) => p.Address.ToString() == prg.Hid); if (p1 != null) { p1.PackageInfo.Checksum = Utility.GetObjectChecksum(new { setup = p1.ScriptSetup, source = p1.ScriptSource }); if (p1.PackageInfo.Checksum != prg.Checksum) { //TODO: Integrity check failed, should abort package importing //Console.WriteLine(p1.PackageInfo.Checksum); //Console.WriteLine(prg.Checksum); } } } } // copy the extracted package folder to the repository folder string repositoryFolder = Path.Combine(Utility.GetDataFolder(), "packages", packageData.Repository); if (!Directory.Exists(repositoryFolder)) { Directory.CreateDirectory(repositoryFolder); } string pkgFolder = Path.Combine(repositoryFolder, packageData.Id); if (Directory.Exists(pkgFolder)) { Directory.Delete(pkgFolder, true); } Directory.Move(tempFolder, pkgFolder); return(packageData); }
public bool UpdatePrograms(string file) { bool success = true; try { var serializer = new XmlSerializer(typeof(List <ProgramBlock>)); var reader = new StreamReader(file); var newProgramList = (List <ProgramBlock>)serializer.Deserialize(reader); reader.Close(); // if (newProgramList.Count > 0) { bool configChanged = false; foreach (var program in newProgramList) { // Only system programs are to be updated if (program.Address < ProgramManager.USERSPACE_PROGRAMS_START) { ProgramBlock oldProgram = homegenie.ProgramManager.Programs.Find(p => p.Address == program.Address); if (oldProgram != null) { // Check new program against old one to find out if they differ bool changed = ProgramsDiff(oldProgram, program); if (!changed) { continue; } // Preserve IsEnabled status if program already exist program.IsEnabled = oldProgram.IsEnabled; LogMessage("* Updating Automation Program: " + program.Name + " (" + program.Address + ")"); homegenie.ProgramManager.ProgramRemove(oldProgram); } else { LogMessage("+ Adding Automation Program: " + program.Name + " (" + program.Address + ")"); } // Try copying the new program files (binary dll or arduino sketch files) try { if (program.Type.ToLower() == "csharp") { File.Copy(Path.Combine(UpdateBaseFolder, "programs", program.Address + ".dll"), Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "programs", program.Address + ".dll"), true); } else if (program.Type.ToLower() == "arduino") { // copy arduino project files... // TODO: this is untested yet string sourceFolder = Path.Combine(UpdateBaseFolder, "programs", "arduino", program.Address.ToString()); string arduinoFolder = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "programs", "arduino", program.Address.ToString()); Utility.FolderCleanUp(arduinoFolder); foreach (string newPath in Directory.GetFiles(sourceFolder)) { File.Copy(newPath, newPath.Replace(sourceFolder, arduinoFolder), true); LogMessage("* Updating Automation Program: " + program.Name + " (" + program.Address + ") - " + Path.GetFileName(newPath)); } } } catch { } // Add the new program to the ProgramEngine homegenie.ProgramManager.ProgramAdd(program); if (!configChanged) { configChanged = true; } } } if (configChanged) { // Save new programs config homegenie.UpdateProgramsDatabase(); } } // File.Delete(file); if (Directory.Exists(Path.Combine(homegenie.UpdateChecker.UpdateBaseFolder, "programs"))) { Directory.Delete(Path.Combine(homegenie.UpdateChecker.UpdateBaseFolder, "programs"), true); } } catch { success = false; } if (!success) { LogMessage("+ ERROR updating Automation Programs"); } return(success); }
public InstallStatus InstallFiles() { var status = InstallStatus.Success; bool restartRequired = false; string oldFilesPath = Path.Combine("_update", "oldfiles"); string newFilesPath = Path.Combine("_update", "files", "HomeGenie_update"); string fullReleaseFolder = Path.Combine("_update", "files", "homegenie"); if (Directory.Exists(fullReleaseFolder)) { Directory.Move(fullReleaseFolder, newFilesPath); } Utility.FolderCleanUp(oldFilesPath); if (Directory.Exists(newFilesPath)) { LogMessage("= Copying new files..."); foreach (string file in Directory.EnumerateFiles(newFilesPath, "*", SearchOption.AllDirectories)) { bool doNotCopy = false; string destinationFolder = Path.GetDirectoryName(file).Replace(newFilesPath, "").TrimStart('/').TrimStart('\\'); string destinationFile = Path.Combine(destinationFolder, Path.GetFileName(file)).TrimStart(Directory.GetDirectoryRoot(Directory.GetCurrentDirectory()).ToArray()).TrimStart('/').TrimStart('\\'); // Update file only if different from local one bool processFile = false; if (File.Exists(destinationFile)) { using (var md5 = MD5.Create()) { string localHash, remoteHash = ""; try { // Try getting files' hash using (var stream = File.OpenRead(destinationFile)) { localHash = BitConverter.ToString(md5.ComputeHash(stream)); } using (var stream = File.OpenRead(file)) { remoteHash = BitConverter.ToString(md5.ComputeHash(stream)); } if (localHash != remoteHash) { processFile = true; //Console.WriteLine("CHANGED {0}", destinationFile); //Console.WriteLine(" - LOCAL {0}", localHash); //Console.WriteLine(" - REMOTE {0}", remoteHash); } } catch (Exception e) { // this mostly happen if the destinationFile is un use and cannot be opened, // file is then ignored if hash cannot be calculated } } } else { processFile = true; //Console.WriteLine("NEW FILE {0}", file); } if (!processFile) { continue; } // Some files needs to be handled differently than just copying if (destinationFile.EndsWith(".xml") && File.Exists(destinationFile)) { switch (destinationFile) { case "automationgroups.xml": doNotCopy = true; status = UpdateAutomationGroups(file) ? InstallStatus.Success : InstallStatus.Error;; break; case "groups.xml": doNotCopy = true; status = UpdateGroups(file) ? InstallStatus.Success : InstallStatus.Error; break; case "lircconfig.xml": doNotCopy = true; break; case "modules.xml": doNotCopy = true; break; case "programs.xml": doNotCopy = true; status = UpdatePrograms(file) ? InstallStatus.Success : InstallStatus.Error;; break; case "scheduler.xml": doNotCopy = true; status = UpdateScheduler(file) ? InstallStatus.Success : InstallStatus.Error;; break; case "systemconfig.xml": doNotCopy = true; status = UpdateSystemConfig(file) ? InstallStatus.Success : InstallStatus.Error;; break; } if (status == InstallStatus.Error) { break; } } else if (destinationFile.EndsWith("homegenie_stats.db")) { doNotCopy = true; } if (doNotCopy) { continue; } // Update the file if (destinationFile.EndsWith(".exe") || destinationFile.EndsWith(".dll") || destinationFile.EndsWith(".so")) { restartRequired = true; } if (!String.IsNullOrWhiteSpace(destinationFolder) && !Directory.Exists(destinationFolder)) { Directory.CreateDirectory(destinationFolder); } // backup current file before replacing it if (File.Exists(destinationFile)) { string oldFile = Path.Combine(oldFilesPath, destinationFile); Directory.CreateDirectory(Path.GetDirectoryName(oldFile)); LogMessage("+ Backup file '" + oldFile + "'"); // TODO: delete oldFilesPath before starting update //File.Delete(oldFile); if (destinationFile.EndsWith(".exe") || destinationFile.EndsWith(".dll")) { // this will allow replace of new exe and dll files File.Move(destinationFile, oldFile); } else { File.Copy(destinationFile, oldFile); } } try { LogMessage("+ Copying file '" + destinationFile + "'"); if (!string.IsNullOrWhiteSpace(Path.GetDirectoryName(destinationFile)) && !Directory.Exists(Path.GetDirectoryName(destinationFile))) { try { Directory.CreateDirectory(Path.GetDirectoryName(destinationFile)); LogMessage("+ Created folder '" + Path.GetDirectoryName(destinationFile) + "'"); } catch { } } File.Copy(file, destinationFile, true); } catch (Exception e) { LogMessage("! Error copying file '" + destinationFile + "' (" + e.Message + ")"); status = InstallStatus.Error; break; } } if (status == InstallStatus.Error) { // TODO: should revert! LogMessage("! ERROR update aborted."); } else if (restartRequired) { status = InstallStatus.RestartRequired; } } return(status); }
public bool InstallFiles() { bool success = true; string oldFilesPath = Path.Combine("_update", "oldfiles"); Utility.FolderCleanUp(oldFilesPath); if (Directory.Exists(Path.Combine("_update", "files", "HomeGenie"))) { LogMessage("= Copying new files..."); foreach (string file in Directory.EnumerateFiles(Path.Combine("_update", "files", "HomeGenie"), "*", SearchOption.AllDirectories)) { bool doNotCopy = false; string destinationFolder = Path.GetDirectoryName(file).Replace(Path.Combine("_update", "files", "HomeGenie"), "").TrimStart('/').TrimStart('\\'); if (!String.IsNullOrWhiteSpace(destinationFolder) && !Directory.Exists(destinationFolder)) { Directory.CreateDirectory(destinationFolder); } string destinationFile = Path.Combine(destinationFolder, Path.GetFileName(file)).TrimStart(Directory.GetDirectoryRoot(Directory.GetCurrentDirectory()).ToArray()).TrimStart('/').TrimStart('\\'); // backup current file before replacing it if (File.Exists(destinationFile)) { string oldFile = Path.Combine(oldFilesPath, destinationFile); Directory.CreateDirectory(Path.GetDirectoryName(oldFile)); LogMessage("+ Backup file '" + oldFile + "'"); // TODO: delete oldFilesPath before starting update //File.Delete(oldFile); if (destinationFile.EndsWith(".exe") || destinationFile.EndsWith(".dll")) { // this will allow replace of new exe and dll files File.Move(destinationFile, oldFile); } else { File.Copy(destinationFile, oldFile); } } if (destinationFile.EndsWith(".xml") && File.Exists(destinationFile)) { switch (destinationFile) { case "automationgroups.xml": doNotCopy = true; success = UpdateAutomationGroups(file); break; case "groups.xml": doNotCopy = true; success = UpdateGroups(file); break; case "lircconfig.xml": doNotCopy = true; break; case "modules.xml": doNotCopy = true; break; case "programs.xml": doNotCopy = true; success = UpdatePrograms(file); break; case "scheduler.xml": doNotCopy = true; success = UpdateScheduler(file); break; case "systemconfig.xml": doNotCopy = true; success = UpdateSystemConfig(file); break; } if (!success) { break; } } if (!doNotCopy) { try { LogMessage("+ Copying file '" + destinationFile + "'"); if (!String.IsNullOrWhiteSpace(Path.GetDirectoryName(destinationFile)) && !Directory.Exists(Path.GetDirectoryName(destinationFile))) { try { Directory.CreateDirectory(Path.GetDirectoryName(destinationFile)); LogMessage("+ Created folder '" + Path.GetDirectoryName(destinationFile) + "'"); } catch { } } File.Copy(file, destinationFile, true); } catch (Exception e) { LogMessage("! Error copying file '" + destinationFile + "' (" + e.Message + ")"); success = false; break; } } } if (!success) { // TODO: should revert! LogMessage("! ERROR update aborted."); } } return(success); }
public bool InstallPackage(string pkgFolderUrl, string tempFolderPath) { string installFolder = Path.Combine(tempFolderPath, "pkg"); dynamic pkgData = null; bool success = true; // Download package specs homegenie.RaiseEvent( Domains.HomeGenie_System, Domains.HomeGenie_PackageInstaller, SourceModule.Master, "HomeGenie Package Installer", Properties.InstallProgressMessage, "= Downloading: package.json" ); using (var client = new WebClient()) { try { string pkgJson = "[" + client.DownloadString(pkgFolderUrl + "/package.json") + "]"; pkgData = (JsonConvert.DeserializeObject(pkgJson) as JArray)[0]; } catch (Exception e) { homegenie.RaiseEvent( Domains.HomeGenie_System, Domains.HomeGenie_PackageInstaller, SourceModule.Master, "HomeGenie Package Installer", Properties.InstallProgressMessage, "= ERROR: '" + e.Message + "'" ); success = false; } client.Dispose(); } // Download and install package files if (success && pkgData != null) { // Import Automation Programs in package foreach (var program in pkgData.programs) { homegenie.RaiseEvent( Domains.HomeGenie_System, Domains.HomeGenie_PackageInstaller, SourceModule.Master, "HomeGenie Package Installer", Properties.InstallProgressMessage, "= Downloading: " + program.file.ToString() ); Utility.FolderCleanUp(installFolder); string programFile = Path.Combine(installFolder, program.file.ToString()); if (File.Exists(programFile)) { File.Delete(programFile); } using (var client = new WebClient()) { try { client.DownloadFile(pkgFolderUrl + "/" + program.file.ToString(), programFile); } catch (Exception e) { homegenie.RaiseEvent( Domains.HomeGenie_System, Domains.HomeGenie_PackageInstaller, SourceModule.Master, "HomeGenie Package Installer", Properties.InstallProgressMessage, "= ERROR: '" + e.Message + "'" ); success = false; } client.Dispose(); } if (success) { homegenie.RaiseEvent( Domains.HomeGenie_System, Domains.HomeGenie_PackageInstaller, SourceModule.Master, "HomeGenie Package Installer", Properties.InstallProgressMessage, "= Installing: " + program.name.ToString() ); int pid = int.Parse(program.uid.ToString()); // by default enable package programs after installing them var enabled = true; var oldProgram = homegenie.ProgramManager.ProgramGet(pid); if (oldProgram != null) { homegenie.RaiseEvent( Domains.HomeGenie_System, Domains.HomeGenie_PackageInstaller, SourceModule.Master, "HomeGenie Package Installer", Properties.InstallProgressMessage, "= Replacing: '" + oldProgram.Name + "' with pid " + pid ); // if the program was already installed, inherit IsEnabled enabled = oldProgram.IsEnabled; homegenie.ProgramManager.ProgramRemove(oldProgram); } var programBlock = ProgramImport(pid, programFile, program.group.ToString()); if (programBlock != null) { string groupName = programBlock.Group; if (!String.IsNullOrWhiteSpace(groupName)) { // Add automation program group if does not exist Group newGroup = new Group() { Name = groupName }; if (homegenie.AutomationGroups.Find(g => g.Name == newGroup.Name) == null) { homegenie.AutomationGroups.Add(newGroup); homegenie.UpdateGroupsDatabase("Automation"); } } programBlock.IsEnabled = enabled; homegenie.RaiseEvent( Domains.HomeGenie_System, Domains.HomeGenie_PackageInstaller, SourceModule.Master, "HomeGenie Package Installer", Properties.InstallProgressMessage, "= Installed: '" + program.name.ToString() + "' as pid " + pid ); } else { // TODO: report error and stop the package install procedure success = false; } } } // Import Widgets in package foreach (var widget in pkgData.widgets) { homegenie.RaiseEvent( Domains.HomeGenie_System, Domains.HomeGenie_PackageInstaller, SourceModule.Master, "HomeGenie Package Installer", Properties.InstallProgressMessage, "= Downloading: " + widget.file.ToString() ); Utility.FolderCleanUp(installFolder); string widgetFile = Path.Combine(installFolder, widget.file.ToString()); if (File.Exists(widgetFile)) { File.Delete(widgetFile); } using (var client = new WebClient()) { try { client.DownloadFile(pkgFolderUrl + "/" + widget.file.ToString(), widgetFile); } catch (Exception e) { homegenie.RaiseEvent( Domains.HomeGenie_System, Domains.HomeGenie_PackageInstaller, SourceModule.Master, "HomeGenie Package Installer", Properties.InstallProgressMessage, "= ERROR: '" + e.Message + "'" ); success = false; } client.Dispose(); } if (success && WidgetImport(widgetFile, installFolder)) { homegenie.RaiseEvent( Domains.HomeGenie_System, Domains.HomeGenie_PackageInstaller, SourceModule.Master, "HomeGenie Package Installer", Properties.InstallProgressMessage, "= Installed: '" + widget.name.ToString() + "'" ); } else { // TODO: report error and stop the package install procedure success = false; } } // Import MIG Interfaces in package foreach (var migface in pkgData.interfaces) { homegenie.RaiseEvent( Domains.HomeGenie_System, Domains.HomeGenie_PackageInstaller, SourceModule.Master, "HomeGenie Package Installer", Properties.InstallProgressMessage, "= Downloading: " + migface.file.ToString() ); Utility.FolderCleanUp(installFolder); string migfaceFile = Path.Combine(installFolder, migface.file.ToString()); if (File.Exists(migfaceFile)) { File.Delete(migfaceFile); } using (var client = new WebClient()) { try { client.DownloadFile(pkgFolderUrl + "/" + migface.file.ToString(), migfaceFile); Utility.UncompressZip(migfaceFile, installFolder); File.Delete(migfaceFile); } catch (Exception e) { homegenie.RaiseEvent( Domains.HomeGenie_System, Domains.HomeGenie_PackageInstaller, SourceModule.Master, "HomeGenie Package Installer", Properties.InstallProgressMessage, "= ERROR: '" + e.Message + "'" ); success = false; } client.Dispose(); } if (success && InterfaceInstall(installFolder)) { homegenie.RaiseEvent( Domains.HomeGenie_System, Domains.HomeGenie_PackageInstaller, SourceModule.Master, "HomeGenie Package Installer", Properties.InstallProgressMessage, "= Installed: '" + migface.name.ToString() + "'" ); } else { // TODO: report error and stop the package install procedure success = false; } } } else { success = false; } if (success) { pkgData.folder_url = pkgFolderUrl; pkgData.install_date = DateTime.UtcNow; AddInstalledPackage(pkgData); homegenie.RaiseEvent( Domains.HomeGenie_System, Domains.HomeGenie_PackageInstaller, SourceModule.Master, "HomeGenie Package Installer", Properties.InstallProgressMessage, "= Status: Package Install Successful" ); } else { homegenie.RaiseEvent( Domains.HomeGenie_System, Domains.HomeGenie_PackageInstaller, SourceModule.Master, "HomeGenie Package Installer", Properties.InstallProgressMessage, "= Status: Package Install Error" ); } return(success); }
public string CreatePackage(PackageData package) { string programsFile = Path.Combine(Utility.GetTmpFolder(), "programs.xml"); string modulesFile = Path.Combine(Utility.GetTmpFolder(), "modules.xml"); string groupsFile = Path.Combine(Utility.GetTmpFolder(), "groups.xml"); string schedulesFile = Path.Combine(Utility.GetTmpFolder(), "schedules.xml"); string packageFile = Path.Combine(Utility.GetTmpFolder(), "package.json"); string bundleFile = Path.Combine(Utility.GetTmpFolder(), package.Id + "-" + package.Version + ".zip"); try { // Clean-up File.Delete(programsFile); File.Delete(packageFile); File.Delete(bundleFile); // collect programs and modules bool saveProgramsRequired = false; var packagePrograms = new List <ProgramBlock>(); var packageModules = new List <Module>(); foreach (var item in package.Programs) { if (item.Repository != package.Repository || item.PackageId != package.Id) { // item is an external dependency belonging to some other repository/package continue; } var program = homegenie.ProgramManager.ProgramGet(int.Parse(item.Hid)); if (program != null) { saveProgramsRequired = true; //if (program.PackageInfo.Repository == null) { program.PackageInfo.Repository = package.Repository; } //if (program.PackageInfo.PackageId == null) { program.PackageInfo.PackageId = package.Id; } // update package version only if repository/package id match if (program.PackageInfo.Repository == package.Repository && program.PackageInfo.PackageId == package.Id) { program.PackageInfo.PackageVersion = package.Version; } if (program.PackageInfo.Id == null) { program.PackageInfo.Id = item.Id; } program.PackageInfo.Version = item.Version; program.PackageInfo.Required = item.Required; item.Checksum = program.PackageInfo.Checksum = Utility.GetObjectChecksum(new { setup = program.ScriptSetup, source = program.ScriptSource }); packagePrograms.Add(program); // lookup for modules belonging to this program packageModules.AddRange(homegenie.Modules.FindAll((m) => { var vm = Utility.ModuleParameterGet(m, Properties.VirtualModuleParentId); return((m.Domain == Domains.HomeAutomation_HomeGenie && m.Address == program.Address.ToString()) || (vm != null && vm.Value == program.Address.ToString())); })); } } Utility.UpdateXmlDatabase(packagePrograms, programsFile, null); Utility.UpdateXmlDatabase(packageModules, modulesFile, null); // collect control groups var packageGroups = new List <Group>(); foreach (var item in package.Groups) { var group = homegenie.GetGroups("Control").Find((g) => g.Name == item.Hid); if (group != null) { packageGroups.Add(group); } } Utility.UpdateXmlDatabase(packageGroups, groupsFile, null); // collect schedules var packageSchedules = new List <SchedulerItem>(); foreach (var item in package.Schedules) { var schedule = homegenie.ProgramManager.SchedulerService.Get(item.Hid); if (schedule != null) { packageSchedules.Add(schedule); } } Utility.UpdateXmlDatabase(packageSchedules, schedulesFile, null); // add files to zip bundle File.WriteAllText(packageFile, JsonConvert.SerializeObject(package)); Utility.AddFileToZip(bundleFile, packageFile, "package.json"); Utility.AddFileToZip(bundleFile, programsFile, "programs.xml"); Utility.AddFileToZip(bundleFile, modulesFile, "modules.xml"); Utility.AddFileToZip(bundleFile, groupsFile, "groups.xml"); Utility.AddFileToZip(bundleFile, schedulesFile, "schedules.xml"); // move files to package folder in data/packages string packageFolder = Path.Combine(Utility.GetDataFolder(), "packages", package.Repository, package.Id); Utility.FolderCleanUp(packageFolder); File.Move(packageFile, Path.Combine(packageFolder, "package.json")); File.Move(programsFile, Path.Combine(packageFolder, "programs.xml")); File.Move(modulesFile, Path.Combine(packageFolder, "modules.xml")); File.Move(groupsFile, Path.Combine(packageFolder, "groups.xml")); File.Move(schedulesFile, Path.Combine(packageFolder, "schedules.xml")); // update programs db if required if (saveProgramsRequired) { homegenie.UpdateProgramsDatabase(); } } catch (Exception e) { homegenie.RaiseEvent( Domains.HomeGenie_System, Domains.HomeGenie_PackageInstaller, SourceModule.Master, "HomeGenie Package Installer", Properties.InstallProgressMessage, "= Error: " + e.Message ); return(null); } // TODO: cleanup temp files and folders return(bundleFile); }