/// <summary>
        /// Installs the specific version of an ASI to the specified target
        /// </summary>
        /// <param name="modVersion"></param>
        /// <param name="target"></param>
        /// <param name="forceSource">Null to let application choose the source, true to force online, false to force local cache. This parameter is used for testing</param>
        /// <returns></returns>
        public static bool InstallASIToTarget(ASIModVersion asi, GameTarget target, bool?forceSource = null)
        {
            if (asi.Game != target.Game)
            {
                throw new Exception($@"ASI {asi.Name} cannot be installed to game {target.Game}");
            }
            Log.Information($@"Processing ASI installation request: {asi.Name} v{asi.Version} -> {target.TargetPath}");
            string destinationFilename  = $@"{asi.InstalledPrefix}-v{asi.Version}.asi";
            string cachedPath           = Path.Combine(CachedASIsFolder, destinationFilename);
            string destinationDirectory = MEDirectories.ASIPath(target);

            if (!Directory.Exists(destinationDirectory))
            {
                Log.Information(@"Creating ASI directory in game: " + destinationDirectory);
                Directory.CreateDirectory(destinationDirectory);
            }
            string finalPath = Path.Combine(destinationDirectory, destinationFilename);

            // Delete existing ASIs from the same group to ensure we don't install the same mod
            var  existingSameGroupMods            = target.GetInstalledASIs().OfType <KnownInstalledASIMod>().Where(x => x.AssociatedManifestItem.OwningMod == asi.OwningMod).ToList();
            bool hasExistingVersionOfModInstalled = false;

            if (existingSameGroupMods.Any())
            {
                foreach (var v in existingSameGroupMods)
                {
                    if (v.Hash == asi.Hash && !forceSource.HasValue && !hasExistingVersionOfModInstalled) //If we are forcing a source, we should always install. Delete duplicates past the first one
                    {
                        Log.Information($@"{v.AssociatedManifestItem.Name} is already installed. We will not remove the existing correct installed ASI for this install request");
                        hasExistingVersionOfModInstalled = true;
                        continue; //Don't delete this one. We are already installed. There is no reason to install it again.
                    }
                    Log.Information($@"Deleting existing ASI from same group: {v.InstalledPath}");
                    v.Uninstall();
                }
            }

            if (hasExistingVersionOfModInstalled && !forceSource.HasValue) //Let app decide
            {
                return(true);                                              // This asi was "Installed" (because it was already installed).
            }

            // Install the ASI
            if (forceSource == null || forceSource.Value == false)
            {
                Debug.WriteLine("Hit me");
            }
            string md5;
            bool   useLocal = forceSource.HasValue && !forceSource.Value; // false (forceLocal)

            if (!useLocal && !forceSource.HasValue)
            {
                useLocal = File.Exists(cachedPath);
            }
            if (useLocal)
            {
                //Check hash first
                md5 = Utilities.CalculateMD5(cachedPath);
                if (md5 == asi.Hash)
                {
                    Log.Information($@"Copying ASI from cached library to destination: {cachedPath} -> {finalPath}");

                    File.Copy(cachedPath, finalPath, true);
                    Log.Information($@"Installed ASI to {finalPath}");
                    Analytics.TrackEvent(@"Installed ASI", new Dictionary <string, string>()
                    {
                        { @"Filename", Path.GetFileNameWithoutExtension(finalPath) }
                    });
                    return(true);
                }
            }

            if (!forceSource.HasValue || forceSource.Value)
            {
                WebRequest request = WebRequest.Create(asi.DownloadLink);
                Log.Information(@"Fetching remote ASI from server");

                using WebResponse response = request.GetResponse();
                var memoryStream = new MemoryStream();
                response.GetResponseStream().CopyTo(memoryStream);
                //MD5 check on file for security
                md5 = Utilities.CalculateMD5(memoryStream);
                if (md5 != asi.Hash)
                {
                    //ERROR!
                    Log.Error(@"Downloaded ASI did not match the manifest! It has the wrong hash.");
                    return(false);
                }

                Log.Information(@"Fetched remote ASI from server. Installing ASI to " + finalPath);
                memoryStream.WriteToFile(finalPath);
                Log.Information(@"ASI successfully installed.");
                Analytics.TrackEvent(@"Installed ASI", new Dictionary <string, string>()
                {
                    { @"Filename", Path.GetFileNameWithoutExtension(finalPath) }
                });

                //Cache ASI
                if (!Directory.Exists(CachedASIsFolder))
                {
                    Log.Information(@"Creating cached ASIs folder");
                    Directory.CreateDirectory(CachedASIsFolder);
                }

                Log.Information(@"Caching ASI to local ASI library: " + cachedPath);
                memoryStream.WriteToFile(cachedPath);
                return(true);
            }

            // We could not install the ASI
            return(false);
        }
Esempio n. 2
0
 public KnownInstalledASIMod(string filepath, string hash, MEGame game, ASIModVersion mappedVersion) : base(filepath, hash, game)
 {
     AssociatedManifestItem = mappedVersion;
 }