Example #1
0
        /// <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!"
                });
            }
        }
Example #2
0
        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);
        }
Example #3
0
    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);
    }
Example #4
0
 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);
 }
Example #5
0
        public GeneralViewModel(ZombieSettings settings, ZombieModel model)
        {
            Settings = settings;
            Model    = model;

            SaveSettingsLocal  = new RelayCommand(OnSaveSettingsLocal);
            SaveSettingsRemote = new RelayCommand(OnSaveSettingsRemote);
            FrequencyChanged   = new RelayCommand(OnFrequencyChanged);
        }
Example #6
0
        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;
     }
 }
Example #8
0
        /// <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);
        }
Example #9
0
        /// <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);
            }
        }
Example #10
0
    public static void InitializeWithScene()
    {
        var settingsGO = GameObject.Find("ZombieSettings");

        Settings = settingsGO?.GetComponent <ZombieSettings>();
        if (!Settings)
        {
            return;
        }

        HumanLook  = GetLookFromPrototype("HumanRenderPrototype");
        ZombieLook = GetLookFromPrototype("ZombieRenderPrototype");

        NewGame();
    }
Example #11
0
        /// <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);
            }
        }
Example #12
0
        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));
        }
Example #13
0
        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);
        }
Example #14
0
        /// <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
            });
        }
Example #15
0
        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);
            }
        }
Example #16
0
        /// <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);
        }
Example #17
0
        /// <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();
        }
Example #18
0
        /// <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));
        }
Example #19
0
        /// <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
            });
        }
Example #20
0
        /// <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);
        }
Example #21
0
        /// <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!"
                });
            }
        }
Example #22
0
        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);
        }
Example #23
0
 public ZombieModel(ZombieSettings settings)
 {
     Settings = settings;
 }
Example #24
0
 public bool SetSettings(ZombieSettings settings)
 {
     return(Channel.SetSettings(settings));
 }
Example #25
0
        /// <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.");
        }
Example #26
0
        /// <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);
            }
        }