/// <summary> /// Commits pre-release to GitHub converting it to Latest Release. /// </summary> /// <param name="settings">Zombie Settings.</param> public async void PushReleaseToGitHub(ZombieSettings settings) { try { var client = new GitHubClient(new ProductHeaderValue("Zombie")); var tokenAuth = new Credentials(settings.AccessToken); client.Credentials = tokenAuth; var segments = GitHubUtils.ParseUrl(settings.Address); var unused = await client.Repository.Release.Edit(segments["owner"], segments["repo"], settings.LatestRelease.Id, new ReleaseUpdate { Body = settings.LatestRelease.Body, Draft = false, Name = settings.LatestRelease.Name, Prerelease = false, TagName = settings.LatestRelease.TagName, TargetCommitish = "master" }); Messenger.Default.Send(new UpdateStatus { Message = "Zombie changed your Release!" }); } catch (Exception e) { _logger.Fatal(e.Message); Messenger.Default.Send(new UpdateStatus { Message = "Failed to push updates to your release!" }); } }
public ZombieViewModel(ZombieSettings settings, ZombieModel model) { Settings = settings; Model = model; WindowClosing = new RelayCommand <CancelEventArgs>(OnWindowClosing); WindowLoaded = new RelayCommand <Window>(OnWindowLoaded); var gitHub = new TabItem { Content = new GitHubView { DataContext = new GitHubViewModel(Settings, model) }, Header = "GitHub" }; var mappings = new TabItem { Content = new MappingsView { DataContext = new MappingsViewModel(Settings, model) }, Header = "Mappings" }; var general = new TabItem { Content = new GeneralView { DataContext = new GeneralViewModel(Settings, model) }, Header = "General" }; TabItems = new ObservableCollection <TabItem> { gitHub, mappings, general }; Messenger.Default.Register <StoreSettings>(this, OnStoreSettings); Messenger.Default.Register <ChangeFrequency>(this, OnChangeFrequency); Messenger.Default.Register <UpdateStatus>(this, OnUpdateStatus); }
private void SpawnZombie(Transform spawnPoint) { var controller = _zombiePool.GetZombieController(); if (controller == null) { return; } ZombieSettings settings = _config.GetZombieSettings(_currentZombieToSpawn.Type, _currentZombieToSpawn.IsBoss); if (settings == null) { Debug.LogError("ZombieFactory SpawnZombie ZOMBIE SETTINGS IS NULL!!!"); return; } _currentZombieToSpawn.SetSpeed(settings.GetSpeed()); ZombieAnimationQueue queue = controller.HasAnimationQueue() ? null : _animationQueueFactory.Create(); controller.UpdateInfo(_currentZombieToSpawn, spawnPoint.position, queue, _collection); _currentZombieToSpawn = null; _collection.OnGOCreated(controller); }
public ZombieStateMashine(Animator animator, ZombieSettings zombieSettings, NavMeshAgent agent, LayerMask playerLayer) { this.animator = animator; this.zombieSettings = zombieSettings; this.agent = agent; this.playerLayer = playerLayer; currentState = new WalkingState(this, agent); }
public GeneralViewModel(ZombieSettings settings, ZombieModel model) { Settings = settings; Model = model; SaveSettingsLocal = new RelayCommand(OnSaveSettingsLocal); SaveSettingsRemote = new RelayCommand(OnSaveSettingsRemote); FrequencyChanged = new RelayCommand(OnFrequencyChanged); }
public GitHubViewModel(ZombieSettings settings, ZombieModel model) { Settings = settings; Model = model; Update = new RelayCommand(OnUpdate); Messenger.Default.Register <ReleaseDownloaded>(this, OnReleaseDownloaded); }
void Awake() { if (Instance != null) { Destroy(gameObject); } else { DontDestroyOnLoad(gameObject); Instance = this; } }
/// <summary> /// /// </summary> /// <param name="settings"></param> /// <param name="asset"></param> /// <param name="destinationDir"></param> /// <param name="type"></param> /// <param name="streams"></param> /// <returns></returns> private static bool LockAllContents(ZombieSettings settings, AssetObject asset, string destinationDir, LocationType type, out Dictionary <string, FileStream> streams) { streams = new Dictionary <string, FileStream>(); var dir = FileUtils.GetZombieDownloadsDirectory(); string filePath; if (type == LocationType.Trash) { filePath = Path.Combine(dir, Path.GetFileNameWithoutExtension(asset.Name) + "_old" + Path.GetExtension(asset.Name)); if (!File.Exists(filePath)) { if (!GitHubUtils.DownloadAssets(settings, asset.Url, filePath)) { return(false); } } } else { filePath = Path.Combine(dir, asset.Name); } try { using (var zip = ZipFile.Open(filePath, ZipArchiveMode.Read)) { foreach (var file in zip.Entries) { var completeFileName = Path.Combine(destinationDir, file.FullName); if (file.Name == string.Empty || !Directory.Exists(Path.GetDirectoryName(completeFileName)) || !File.Exists(completeFileName)) { continue; } var fs = new FileStream(completeFileName, FileMode.Open, FileAccess.ReadWrite, FileShare.None); streams.Add(completeFileName, fs); } } } catch (Exception e) { _logger.Fatal(e.Message); return(false); } return(true); }
/// <summary> /// /// </summary> /// <param name="settings"></param> private void ProcessUpToDate(ZombieSettings settings) { Locations.Clear(); SourceLocations.Clear(); Model.Settings = settings; // (Konrad) Populate UI with stored settings PopulateSourceFromSettings(settings); if (settings.DestinationAssets.Any()) { PopulateDestinationFromSettings(settings); } }
public static void InitializeWithScene() { var settingsGO = GameObject.Find("ZombieSettings"); Settings = settingsGO?.GetComponent <ZombieSettings>(); if (!Settings) { return; } HumanLook = GetLookFromPrototype("HumanRenderPrototype"); ZombieLook = GetLookFromPrototype("ZombieRenderPrototype"); NewGame(); }
/// <summary> /// Sets DestinationAssets from a Zombie Settings. /// </summary> /// <param name="settings">Zombie Settings.</param> private void PopulateDestinationFromSettings(ZombieSettings settings) { foreach (var loc in settings.DestinationAssets) { var newLocation = new LocationsViewModel(loc); var assets = new ObservableCollection <AssetViewModel>(loc.Assets.Select(x => new AssetViewModel(x) { Parent = newLocation })); newLocation.Assets = assets; Locations.Add(newLocation); } }
public bool SetSettings(ZombieSettings settings) { // (Konrad) Update Service Settings but only if they are local // We should never override remote settings from the GUI. if (settings.StoreSettings) { Program.Settings = settings; } // (Konrad) Update Registry var assemblyLocation = Assembly.GetExecutingAssembly().Location; RegistryUtils.SetImagePath(settings, assemblyLocation); // (Konrad) This flag is true for local settings only. return(!settings.StoreSettings || SettingsUtils.StoreSettings(settings)); }
public UpdateRunner(ZombieSettings settings, ZombieModel model) { // (Konrad) We can launch the updater immediately. var interval = FrequencyUtils.TimeSpanFromFrequency(settings.CheckFrequency); Timer = new Timer(x => { try { model.GetLatestRelease(settings); } catch (Exception e) { _logger.Fatal(e.Message); } }, null, TimeSpan.Zero, interval); }
/// <summary> /// Downloads latest pre-release from GitHub. /// </summary> /// <param name="settings">Zombie Settings.</param> public async void DownloadPreRelease(ZombieSettings settings) { var segments = GitHubUtils.ParseUrl(settings.Address); var client = new GitHubClient(new ProductHeaderValue("Zombie")); var tokenAuth = new Credentials(settings.AccessToken); client.Credentials = tokenAuth; Release prerelease = null; try { var releases = await client.Repository.Release.GetAll(segments["owner"], segments["repo"], ApiOptions.None); if (releases.Any()) { prerelease = releases.OrderBy(x => x.PublishedAt).FirstOrDefault(x => x.Prerelease); } if (prerelease == null) { Messenger.Default.Send(new PrereleaseDownloaded { Status = PrereleaseStatus.Failed, Settings = null }); return; } } catch (Exception e) { _logger.Fatal("Failed to retrieve Pre-Release from GitHub. " + e.Message); return; } settings.LatestRelease = new ReleaseObject(prerelease); Messenger.Default.Send(new PrereleaseDownloaded { Status = PrereleaseStatus.Found, Settings = settings }); }
public MappingsViewModel(ZombieSettings settings, ZombieModel model) { Settings = settings; Model = model; BindingOperations.EnableCollectionSynchronization(_sourceLocations, _sourceLock); BindingOperations.EnableCollectionSynchronization(_locations, _lock); AddLocation = new RelayCommand(OnAddLocation); Messenger.Default.Register <LocationRemoved>(this, OnLocationRemoved); Messenger.Default.Register <ReleaseDownloaded>(this, OnReleaseDownloaded); // (Konrad) Populate UI with stored settings PopulateSourceFromSettings(settings); if (settings.DestinationAssets.Any()) { PopulateDestinationFromSettings(settings); } }
/// <summary> /// Sets Source Assets from a Zombie Settings. /// </summary> /// <param name="settings">Zombie Settings.</param> private void PopulateSourceFromSettings(ZombieSettings settings) { var loc = new LocationsViewModel(new Location { LocationType = LocationType.Source }, !settings.SourceAssets.Any()); foreach (var asset in settings.SourceAssets) { var vm = new AssetViewModel(asset) { Parent = loc }; if (!loc.Assets.Contains(vm)) { loc.Assets.Add(vm); } } SourceLocations.Add(loc); }
/// <summary> /// Utility method that publishes a GUI update to ZombieGUI. /// </summary> /// <param name="settings">Latest ZombieSettings file that GUI will be updated to.</param> /// <param name="status">Message status type.</param> /// <param name="message">String message to be displayed in the GUI.</param> private static void PublishGuiUpdate(ZombieSettings settings, Status status, string message) { var msg = "Status: " + status + " Message: " + message; if (string.IsNullOrWhiteSpace(Program.RecentLog) || msg != Program.RecentLog) { _logger.Info(msg); Program.RecentLog = msg; } var update = new GuiUpdate { Settings = settings, Status = status, Message = message }; new Thread(() => new ZombieMessenger().Broadcast(update)) { Priority = ThreadPriority.BelowNormal, IsBackground = true }.Start(); }
/// <summary> /// /// </summary> /// <param name="settings"></param> /// <param name="filePath"></param> /// <param name="shouldSerialize"></param> public bool StoreSettings(ZombieSettings settings, string filePath, bool shouldSerialize = false) { try { var jsonSettings = new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore, MissingMemberHandling = MissingMemberHandling.Ignore, CheckAdditionalContent = true, Formatting = Formatting.Indented }; settings.ShouldSerialize = shouldSerialize; var json = JsonConvert.SerializeObject(settings, jsonSettings); File.WriteAllText(filePath, json); } catch (Exception e) { _logger.Fatal(e.Message); } return(File.Exists(filePath)); }
/// <summary> /// /// </summary> /// <param name="settings"></param> public async void GetLatestRelease(ZombieSettings settings) { if (string.IsNullOrEmpty(settings?.AccessToken) || string.IsNullOrEmpty(settings.Address)) { UpdateUI("Connection failed!", ConnectionResult.Failure); return; } var response = await GetLatestReleaseFromGitHub(settings); if (response.StatusCode != HttpStatusCode.OK) { UpdateUI("Connection failed!", ConnectionResult.Failure); return; } var release = response.Data; var currentVersion = Properties.Settings.Default["CurrentVersion"].ToString(); if (!release.Assets.Any() || new Version(release.TagName).CompareTo(new Version(currentVersion)) <= 0) { UpdateUI("Your release is up to date!", ConnectionResult.UpToDate, release); return; } var dir = FileUtils.GetZombieDownloadsDirectory(); var downloaded = 0; foreach (var asset in release.Assets) { var filePath = Path.Combine(dir, asset.Name); if (GitHubUtils.DownloadAssets(settings, asset.Url, filePath)) { downloaded++; } } if (downloaded != release.Assets.Count) { UpdateUI("Failed to download assets!", ConnectionResult.Failure); return; } // (Konrad) Let's get updated settings, they might be local, or remote. // We need latest settings since there might be changes to the target locations. ZombieSettings newSettings; if (File.Exists(settings.SettingsLocation)) { if (!SettingsUtils.TryGetStoredSettings(settings.SettingsLocation, out newSettings)) { UpdateUI("Could not get latest local Zombie Settings!", ConnectionResult.Failure); return; } } else { if (!SettingsUtils.TryGetRemoteSettings(settings.SettingsLocation, out newSettings)) { UpdateUI("Could not get latest remote Zombie Settings!", ConnectionResult.Failure); return; } } // (Konrad) Let's make sure that we own the files that we are trying to override var fileStreams = new Dictionary <string, FileStream>(); foreach (var loc in newSettings.DestinationAssets) { foreach (var asset in loc.Assets) { if (asset.IsArchive()) { if (LockAllContents(settings, asset, loc.DirectoryPath, out var zippedStreams)) { fileStreams = fileStreams.Concat(zippedStreams).GroupBy(x => x.Key) .ToDictionary(x => x.Key, x => x.First().Value); continue; } UpdateUI("Could not get access to all ZIP contents!", ConnectionResult.Failure); return; } var to = Path.Combine(FilePathUtils.CreateUserSpecificPath(loc.DirectoryPath), asset.Name); try { var fs = new FileStream(to, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None); fileStreams.Add(to, fs); } catch (Exception e) { UpdateUI(e.Message, ConnectionResult.Failure); return; } } } // (Konrad) Move assets to target locations foreach (var loc in newSettings.DestinationAssets) { foreach (var asset in loc.Assets) { if (asset.IsArchive()) { if (ExtractToDirectory(asset, loc.DirectoryPath, fileStreams)) { continue; } UpdateUI("Could not override existing ZIP contents!", ConnectionResult.Failure); return; } var from = Path.Combine(dir, asset.Name); var to = Path.Combine(FilePathUtils.CreateUserSpecificPath(loc.DirectoryPath), asset.Name); // make sure that file is not locked var stream = fileStreams[to]; stream?.Close(); if (FileUtils.Copy(@from, @to)) { continue; } UpdateUI("Could not override existing file!", ConnectionResult.Failure); return; } } // (Konrad) Remove temporary assets if (!FileUtils.DeleteDirectory(dir)) { UpdateUI("Could not remove temporary download assets!", ConnectionResult.Failure); return; } // (Konrad) Update UI and save current version Properties.Settings.Default.CurrentVersion = release.TagName; Properties.Settings.Default.Save(); _logger.Info("Successfully updated to version: " + release.TagName); Messenger.Default.Send(new UpdateStatus { Status = "Successfully updated to version: " + release.TagName }); Messenger.Default.Send(new ReleaseDownloaded { Release = release, Result = ConnectionResult.Success }); }
/// <summary> /// /// </summary> /// <param name="settings"></param> /// <returns></returns> private static async Task <IRestResponse <ReleaseObject> > GetLatestReleaseFromGitHub(ZombieSettings settings) { // (Konrad) Apparently it's possible that new Windows updates change the standard // SSL protocol to SSL3. RestSharp uses whatever current one is while GitHub server // is not ready for it yet, so we have to use TLS1.2 explicitly. ServicePointManager.Expect100Continue = true; ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12; var client = new RestClient(BaseUrl); var repoAddress = settings.Address.Replace("https://github.com", ""); var requestString = "/repos" + repoAddress + "/releases/latest"; var request = new RestRequest(requestString, Method.GET) { OnBeforeDeserialization = x => { x.ContentType = "application/json"; } }; request.AddHeader("Content-type", "application/json"); request.AddHeader("Authorization", "Token " + settings.AccessToken); request.RequestFormat = DataFormat.Json; var response = await client.ExecuteTaskAsync <ReleaseObject>(request); return(response); }
/// <summary> /// Commits Zombie Settings to GitHub overriding existing file. /// </summary> /// <param name="settings">Zombie Settings.</param> public async void PushSettingsToGitHub(ZombieSettings settings) { try { var segments = GitHubUtils.ParseUrl(settings.SettingsLocation); var client = new GitHubClient(new ProductHeaderValue("Zombie")); var tokenAuth = new Credentials(settings.AccessToken); client.Credentials = tokenAuth; var contents = await client.Repository.Content.GetAllContents(segments["owner"], segments["repo"], segments["file"]); if (!contents.Any()) { Messenger.Default.Send(new UpdateStatus { Message = "Could not get contents of the repo!" }); return; } var sha = string.Empty; foreach (var rc in contents) { if (rc.Name != segments["file"]) { continue; } sha = rc.Sha; break; } if (string.IsNullOrEmpty(sha)) { Messenger.Default.Send(new UpdateStatus { Message = "Could not get valid SHA for the ZombieSettings!" }); return; } var jsonSettings = new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore, MissingMemberHandling = MissingMemberHandling.Ignore, CheckAdditionalContent = true, Formatting = Formatting.Indented }; settings.ShouldSerialize = false; var json = JsonConvert.SerializeObject(settings, jsonSettings); var unused = await client.Repository.Content.UpdateFile(segments["owner"], segments["repo"], segments["file"], new UpdateFileRequest("Zombie changed you!", json, sha, "master", true)); Messenger.Default.Send(new UpdateStatus { Message = "Zombie changed your settings!" }); } catch (Exception e) { _logger.Fatal(e.Message); Messenger.Default.Send(new UpdateStatus { Message = "Failed to push update to your Zombie Settings!" }); } }
private void Application_Startup(object sender, StartupEventArgs e) { var arg1 = GetRemoteSettingsPath(e.Args); var local = File.Exists(arg1); if (!string.IsNullOrEmpty(arg1) && !local) { // (Konrad) Arg1 is a path that doesn't exist locally so it is likely // a remote file location (HTTP). if (SettingsUtils.TryGetRemoteSettings(arg1, out var settings)) { Settings = settings; Settings.AccessToken = GetAccessToken(e.Args); Settings.SettingsLocation = arg1; Settings.StoreSettings = false; } else { // (Konrad) We have a path in the Arg1 that doesn't exist or failed to // deserialize so we can treat it as if it didn't exist and override it on close. Settings = new ZombieSettings { SettingsLocation = arg1, StoreSettings = true }; } } else if (!string.IsNullOrEmpty(arg1) && local) { // (Konrad) Arg1 exists on a user drive or network drive. Settings = SettingsUtils.TryGetStoredSettings(arg1, out var settings) ? settings : new ZombieSettings(); Settings.SettingsLocation = arg1; // (Konrad) If AccessToken was in the Settings file we can skip this. // If it wasn't it should be set with the Arg2 if (string.IsNullOrEmpty(Settings.AccessToken)) { Settings.AccessToken = GetAccessToken(e.Args); } } else { Settings = new ZombieSettings { SettingsLocation = Path.Combine(Directory.GetCurrentDirectory(), "ZombieSettings.json"), StoreSettings = true }; } // Create the startup window var m = new ZombieModel(); var vm = new ZombieViewModel(Settings, m); var wnd = new ZombieView { DataContext = vm }; wnd.ShowInTaskbar = true; vm.Startup(wnd); }
public ZombieModel(ZombieSettings settings) { Settings = settings; }
public bool SetSettings(ZombieSettings settings) { return(Channel.SetSettings(settings)); }
/// <summary> /// Method that retrieves the latest release from GitHub. /// </summary> /// <param name="settings">Zombie Settings to be used to retrieve latest Release.</param> public static async void GetLatestRelease(ZombieSettings settings) { if (IsProcessRunning("Revit")) { _logger.Error("Update failed. Revit is running."); // (Konrad) Since release was not up to date. Let's show a notification to user that update is in progress. PublishGuiUpdate(Program.Settings, Status.Notification, "Update failed. Revit is running."); return; } if (string.IsNullOrWhiteSpace(settings?.AccessToken) || string.IsNullOrWhiteSpace(settings.Address)) { var a = string.IsNullOrWhiteSpace(settings.Address) ? "Not found" : "Exists"; _logger.Error($"Connection failed! Address: {a}"); return; } var segments = GitHubUtils.ParseUrl(settings.Address); var client = new GitHubClient(new ProductHeaderValue("Zombie")); var tokenAuth = new Credentials(settings.AccessToken); client.Credentials = tokenAuth; Release release; try { release = await client.Repository.Release.GetLatest(segments["owner"], segments["repo"]); var currentVersion = RegistryUtils.GetZombieVersion(); if (!release.Assets.Any() || new Version(release.TagName).CompareTo(new Version(currentVersion)) <= 0) { PublishGuiUpdate(Program.Settings, Status.UpToDate, "Your release is up to date! Version: " + currentVersion); return; } } catch (Exception e) { _logger.Fatal("Failed to retrieve Release from GitHub. " + e.Message); return; } // (Konrad) Since release was not up to date. Let's show a notification to user that update is in progress. PublishGuiUpdate(Program.Settings, Status.Notification, "Update in progress. Please do not launch Revit."); var dir = FileUtils.GetZombieDownloadsDirectory(); var downloaded = 0; foreach (var asset in release.Assets) { var filePath = Path.Combine(dir, asset.Name); if (GitHubUtils.DownloadAssets(settings, asset.Url, filePath)) { downloaded++; } } if (downloaded != release.Assets.Count) { _logger.Error("Failed to download assets!"); // (Konrad) Since release was not up to date. Let's show a notification to user that update is in progress. PublishGuiUpdate(Program.Settings, Status.Notification, "Update failed. Check your internet connection and try again."); return; } // (Konrad) Let's get updated settings, they might be local, or remote. // We need latest settings since there might be changes to the target locations. ZombieSettings newSettings; if (File.Exists(settings.SettingsLocation)) { if (!SettingsUtils.TryGetStoredSettings(settings.SettingsLocation, out newSettings)) { _logger.Error("Could not get latest local Zombie Settings!"); // (Konrad) Since release was not up to date. Let's show a notification to user that update is in progress. PublishGuiUpdate(Program.Settings, Status.Notification, "Update failed. Zombie Settings not found."); return; } } else { if (!SettingsUtils.TryGetRemoteSettings(settings.SettingsLocation, out newSettings)) { _logger.Error("Could not get latest remote Zombie Settings!"); // (Konrad) Since release was not up to date. Let's show a notification to user that update is in progress. PublishGuiUpdate(Program.Settings, Status.Notification, "Update failed. Zombie Settings not found."); return; } } // (Konrad) Let's make sure that we own the files that we are trying to override var fileStreams = new Dictionary <string, FileStream>(); foreach (var loc in newSettings.DestinationAssets.OrderByDescending(x => (int)x.LocationType)) { foreach (var asset in loc.Assets) { if (asset.IsArchive()) { // (Konrad) Use old settings if (LockAllContents(loc.LocationType == LocationType.Trash ? settings : newSettings, asset, loc.DirectoryPath, loc.LocationType, out var zippedStreams)) { fileStreams = fileStreams .Concat(zippedStreams) .GroupBy(x => x.Key) .ToDictionary(x => x.Key, x => x.First().Value); continue; } ReleaseStreams(fileStreams); // (Konrad) Since release was not up to date. Let's show a notification to user that update is in progress. PublishGuiUpdate(Program.Settings, Status.Notification, "Update failed. Revit is potentially running preventing an update."); return; } if (loc.LocationType != LocationType.Trash) { // (Konrad) Make sure that destination folder exists. if (!Directory.Exists(loc.DirectoryPath)) { FileUtils.CreateDirectory(loc.DirectoryPath); } } var to = Path.Combine(loc.DirectoryPath, asset.Name); if (!File.Exists(to)) { continue; } try { var fs = new FileStream(to, FileMode.Open, FileAccess.ReadWrite, FileShare.None); fileStreams.Add(to, fs); } catch (Exception e) { _logger.Fatal(e.Message); ReleaseStreams(fileStreams); // (Konrad) Since release was not up to date. Let's show a notification to user that update is in progress. PublishGuiUpdate(Program.Settings, Status.Notification, "Update failed...due to unknown reasons. Sorry about that."); return; } } } // (Konrad) Move assets to target locations. // We sort the locations list so that Trash (3) is first. // This should make sure that we delete first, then move. // Could be important with Zipped contents and overriding. foreach (var loc in newSettings.DestinationAssets.OrderByDescending(x => (int)x.LocationType)) { if (loc.LocationType == LocationType.Trash) { // (Konrad) Let's remove these files. foreach (var asset in loc.Assets) { if (asset.IsArchive()) { if (DeleteZipContents(asset, loc.DirectoryPath, fileStreams)) { continue; } ReleaseStreams(fileStreams); // (Konrad) Since release was not up to date. Let's show a notification to user that update is in progress. PublishGuiUpdate(Program.Settings, Status.Notification, "Update failed. Revit is potentially running preventing an update."); return; } var to = Path.Combine(loc.DirectoryPath, asset.Name); if (fileStreams.ContainsKey(to)) { // make sure that file is not locked var stream = fileStreams[to]; stream?.Close(); } if (FileUtils.DeleteFile(to)) { continue; } ReleaseStreams(fileStreams); // (Konrad) Since release was not up to date. Let's show a notification to user that update is in progress. PublishGuiUpdate(Program.Settings, Status.Notification, "Update failed. Revit is potentially running preventing an update."); return; } } else { // (Konrad) Let's copy these files. foreach (var asset in loc.Assets) { if (asset.IsArchive()) { if (ExtractToDirectory(asset, loc.DirectoryPath, fileStreams)) { continue; } ReleaseStreams(fileStreams); // (Konrad) Since release was not up to date. Let's show a notification to user that update is in progress. PublishGuiUpdate(Program.Settings, Status.Notification, "Update failed. Revit is potentially running preventing an update."); return; } var from = Path.Combine(dir, asset.Name); var to = Path.Combine(loc.DirectoryPath, asset.Name); if (fileStreams.ContainsKey(to)) { // make sure that file is not locked var stream = fileStreams[to]; stream?.Close(); } // (Konrad) Make sure that directory exists. if (!Directory.Exists(Path.GetDirectoryName(to))) { FileUtils.CreateDirectory(Path.GetDirectoryName(to)); } if (FileUtils.Copy(from, to)) { continue; } ReleaseStreams(fileStreams); // (Konrad) Since release was not up to date. Let's show a notification to user that update is in progress. PublishGuiUpdate(Program.Settings, Status.Notification, "Update failed. Revit is potentially running preventing an update."); return; } } } // (Konrad) Remove temporary assets if (!FileUtils.DeleteDirectory(dir)) { // (Konrad) Cleanup failed but we can continue. _logger.Error("Could not remove temporary download assets!"); } // (Konrad) This is important! ReleaseStreams(fileStreams); // (Konrad) We need to store the current version for comparison on next update RegistryUtils.SetZombieVersion(release.TagName); // (Konrad) Settings need to be updated with the latest one just downloaded newSettings.LatestRelease = new ReleaseObject(release); if (!newSettings.StoreSettings) { newSettings.AccessToken = Program.Settings.AccessToken; newSettings.SettingsLocation = Program.Settings.SettingsLocation; } Program.Settings = newSettings; // (Konrad) Publish to any open GUIs PublishGuiUpdate(newSettings, Status.Succeeded, "Successfully updated to Version: " + release.TagName); // (Konrad) Since release was not up to date. Let's show a notification to user that update is in progress. PublishGuiUpdate(Program.Settings, Status.Notification, "Update succeeded. Go ahead and launch Revit to see what's new."); }
/// <summary> /// /// </summary> /// <param name="settings"></param> private void ProcessSucceeded(ZombieSettings settings) { Model.Settings = settings; // (Konrad) Get all allocated assets. They would be allocated if they were // previously deserialized from Settings, or set on previous cycle. var allocated = new HashSet <AssetObject>(); foreach (var l in SourceLocations) { foreach (var a in l.Assets) { allocated.Add(a.Asset); } } Locations = Locations.Where(x => x.LocationObject.LocationType != LocationType.Trash).ToObservableCollection(); foreach (var l in Locations) { foreach (var a in l.Assets) { allocated.Add(a.Asset); } } // (Konrad) Find out if there are any new assets downloaded that were not accounted for. // These would be added to the SourceLocations collection. var added = new HashSet <AssetObject>(); foreach (var a in settings.LatestRelease.Assets) { if (allocated.Contains(a)) { allocated.Remove(a); continue; } added.Add(a); } // (Konrad) Whatever is left in allocated needs to be deleted. var trashLocations = new ObservableCollection <LocationsViewModel>(); foreach (var l in Locations) { var remain = new ObservableCollection <AssetViewModel>(); var trashLoc = new LocationsViewModel(new Location { LocationType = LocationType.Trash, DirectoryPath = l.LocationObject.DirectoryPath }, false); foreach (var avm in l.Assets) { if (!allocated.Contains(avm.Asset)) { remain.Add(avm); } else { if (trashLoc.Assets.Contains(avm)) { continue; } avm.IsPlaceholder = true; trashLoc.Assets.Add(avm); } } l.Assets = remain; trashLocations.Add(trashLoc); } // (Konrad) Let's put these deleted assets into new deleted locations foreach (var lvm in trashLocations) { Locations.Add(lvm); } // (Konrad) If any location is now empty let's remove it. Locations = Locations.Where(x => x.Assets.Any()).ToObservableCollection(); // (Konrad) Add all new assets to source locations. // Since we are calling this from another thread (Timer runs on a thread pool) // we need to make sure that the collection is locked. lock (_sourceLock) { SourceLocations.Clear(); var loc = new LocationsViewModel(new Location { LocationType = LocationType.Source }, !added.Any()); foreach (var asset in added) { var vm = new AssetViewModel(asset) { Parent = loc }; if (!loc.Assets.Contains(vm)) { loc.Assets.Add(vm); } } SourceLocations.Add(loc); } }