Beispiel #1
0
        /// <summary>
        /// Touches up any existing tutorial assets or downloads missing ones.
        /// </summary>
        public static void TouchupTutorial()
        {
            var fileRootPath = Utilities.GetTutorialServiceCache();

            foreach (var step in App.TutorialService)
            {
                var  imagePath = Path.Combine(fileRootPath, step.imagename);
                bool download  = !File.Exists(imagePath) || Utilities.CalculateMD5(imagePath) != step.imagemd5;
                if (download)
                {
                    foreach (var endpoint in StaticFilesBaseEndpoints)
                    {
                        Uri    myUri = new Uri(endpoint);
                        string host  = myUri.Host;

                        var fullurl = endpoint + "tutorial/" + step.imagename;
                        Log.Information($"Downloading {step.imagename} from endpoint {host}");
                        var downloadedImage = OnlineContent.DownloadToMemory(fullurl, null, step.imagemd5);
                        if (downloadedImage.errorMessage == null)
                        {
                            downloadedImage.result.WriteToFile(imagePath);
                            break;
                        }
                        else
                        {
                            Log.Error($@"Unable to download {step.imagename} from endpoint {host}: {downloadedImage.errorMessage}");
                        }
                    }
                }
            }
        }
Beispiel #2
0
        private static void LoadLocalBasegameIdentificationService()
        {
            if (LocalBasegameFileIdentificationService != null)
            {
                return;
            }

            var file = Utilities.GetLocalBasegameIdentificationServiceFile();

            if (File.Exists(file))
            {
                try
                {
                    LocalBasegameFileIdentificationService =
                        JsonConvert
                        .DeserializeObject <
                            Dictionary <string, CaseInsensitiveDictionary <
                                            List <BasegameFileIdentificationService.BasegameCloudDBFile> > > >(
                            File.ReadAllText(file));
                    Log.Information(@"Loaded Local Basegame File Identification Service");
                }
                catch (Exception e)
                {
                    Log.Error($@"Error loading local BGFIS: {e.Message}");
                    LocalBasegameFileIdentificationService = OnlineContent.getBlankBGFIDB();
                }
            }
            else
            {
                Log.Information(@"Loaded blank Local Basegame File Identification Service");
                LocalBasegameFileIdentificationService = OnlineContent.getBlankBGFIDB();
            }
        }
        private static bool DownloadLocalization(string lang)
        {
            var livelocmd5 = App.ServerManifest[$@"livelocalization-{lang}"]; // this was checked previously
            var url        = LocalizationEndpoint + $@"?lang={lang}&build={App.BuildNumber}";
            var result     = OnlineContent.DownloadToMemory(url, hash: livelocmd5);

            if (result.errorMessage == null)
            {
                // OK!
                result.result.WriteToFile(getCachedLocalizationFile(lang));
                Log.Information($@"Wrote updated cached localization file for {lang}");
                return(true);
            }
            // RIP
            Log.Error($@"Error download updated localization file {lang}: {result.result}");
            return(false);
        }
Beispiel #4
0
        public static Dictionary <string, CaseInsensitiveDictionary <List <BasegameFileIdentificationService.BasegameCloudDBFile> > > FetchBasegameFileIdentificationServiceManifest(bool overrideThrottling = false)
        {
            Log.Information(@"Fetching basegame file identification manifest");

            //read cached first.
            string cached = null;

            if (File.Exists(Utilities.GetBasegameIdentificationCacheFile()))
            {
                try
                {
                    cached = File.ReadAllText(Utilities.GetBasegameIdentificationCacheFile());
                }
                catch (Exception e)
                {
                    var    attachments = new List <ErrorAttachmentLog>();
                    string log         = LogCollector.CollectLatestLog(true);
                    if (log != null && log.Length < ByteSizeLib.ByteSize.BytesInMegaByte * 7)
                    {
                        attachments.Add(ErrorAttachmentLog.AttachmentWithText(log, @"applog.txt"));
                    }
                    Crashes.TrackError(e, new Dictionary <string, string>()
                    {
                        { @"Error type", @"Error reading cached online content" },
                        { @"Service", @"Basegame File Identification Service" },
                        { @"Message", e.Message }
                    }, attachments.ToArray());
                }
            }


            if (!File.Exists(Utilities.GetBasegameIdentificationCacheFile()) || overrideThrottling || OnlineContent.CanFetchContentThrottleCheck())
            {
                var urls = new[] { BasegameFileIdentificationServiceURL, BasegameFileIdentificationServiceBackupURL };
                foreach (var staticurl in urls)
                {
                    Uri    myUri = new Uri(staticurl);
                    string host  = myUri.Host;
                    try
                    {
                        using var wc = new ShortTimeoutWebClient();

                        string json = wc.DownloadStringAwareOfEncoding(staticurl);
                        File.WriteAllText(Utilities.GetBasegameIdentificationCacheFile(), json);
                        return(JsonConvert.DeserializeObject <Dictionary <string, CaseInsensitiveDictionary <List <BasegameFileIdentificationService.BasegameCloudDBFile> > > >(json));
                    }
                    catch (Exception e)
                    {
                        //Unable to fetch latest help.
                        Log.Error($"Error fetching online basegame file identification service from endpoint {host}: {e.Message}");
                    }
                }

                if (cached == null)
                {
                    Log.Error("Unable to load basegame file identification service and local file doesn't exist. Returning a blank copy.");
                    Dictionary <string, CaseInsensitiveDictionary <List <BasegameFileIdentificationService.BasegameCloudDBFile> > > d = new Dictionary <string, CaseInsensitiveDictionary <List <BasegameFileIdentificationService.BasegameCloudDBFile> > >
                    {
                        ["ME1"] = new CaseInsensitiveDictionary <List <BasegameFileIdentificationService.BasegameCloudDBFile> >(),
                        ["ME2"] = new CaseInsensitiveDictionary <List <BasegameFileIdentificationService.BasegameCloudDBFile> >(),
                        ["ME3"] = new CaseInsensitiveDictionary <List <BasegameFileIdentificationService.BasegameCloudDBFile> >()
                    };
                    return(d);
                }
            }
            Log.Information("Using cached BGFIS instead");

            try
            {
                return(JsonConvert.DeserializeObject <Dictionary <string, CaseInsensitiveDictionary <List <BasegameFileIdentificationService.BasegameCloudDBFile> > > >(cached));
            }
            catch (Exception e)
            {
                Log.Error("Could not parse cached basegame file identification service file. Returning blank BFIS data instead. Reason: " + e.Message);
                return(new Dictionary <string, CaseInsensitiveDictionary <List <BasegameFileIdentificationService.BasegameCloudDBFile> > >
                {
                    ["ME1"] = new CaseInsensitiveDictionary <List <BasegameFileIdentificationService.BasegameCloudDBFile> >(),
                    ["ME2"] = new CaseInsensitiveDictionary <List <BasegameFileIdentificationService.BasegameCloudDBFile> >(),
                    ["ME3"] = new CaseInsensitiveDictionary <List <BasegameFileIdentificationService.BasegameCloudDBFile> >()
                });
            }
        }
Beispiel #5
0
        public static Dictionary <long, List <ThirdPartyServices.ThirdPartyImportingInfo> > FetchThirdPartyImportingService(bool overrideThrottling = false)
        {
            string cached = null;

            if (File.Exists(Utilities.GetThirdPartyImportingCachedFile()))
            {
                try
                {
                    cached = File.ReadAllText(Utilities.GetThirdPartyImportingCachedFile());
                }
                catch (Exception e)
                {
                    var    attachments = new List <ErrorAttachmentLog>();
                    string log         = LogCollector.CollectLatestLog(true);
                    if (log != null && log.Length < ByteSizeLib.ByteSize.BytesInMegaByte * 7)
                    {
                        attachments.Add(ErrorAttachmentLog.AttachmentWithText(log, "applog.txt"));
                    }
                    Crashes.TrackError(e, new Dictionary <string, string>()
                    {
                        { "Error type", "Error reading cached online content" },
                        { "Service", "Third Party Importing Service" },
                        { "Message", e.Message }
                    }, attachments.ToArray());
                }
            }

            if (!File.Exists(Utilities.GetThirdPartyImportingCachedFile()) || overrideThrottling || OnlineContent.CanFetchContentThrottleCheck())
            {
                try
                {
                    using var wc = new ShortTimeoutWebClient();

                    string json = wc.DownloadStringAwareOfEncoding(ThirdPartyImportingServiceURL);
                    File.WriteAllText(Utilities.GetThirdPartyImportingCachedFile(), json);
                    return(JsonConvert.DeserializeObject <Dictionary <long, List <ThirdPartyServices.ThirdPartyImportingInfo> > >(json));
                }
                catch (Exception e)
                {
                    //Unable to fetch latest help.
                    Log.Error("Error fetching latest importing service file: " + e.Message);

                    if (cached != null)
                    {
                        Log.Warning("Using cached third party importing service file instead");
                    }
                    else
                    {
                        Log.Error("Unable to fetch latest third party importing service file from server and local file doesn't exist. Returning a blank copy.");
                        return(new Dictionary <long, List <ThirdPartyServices.ThirdPartyImportingInfo> >());
                    }
                }
            }
            try
            {
                return(JsonConvert.DeserializeObject <Dictionary <long, List <ThirdPartyServices.ThirdPartyImportingInfo> > >(cached));
            }
            catch (Exception e)
            {
                Log.Error("Unable to parse cached importing service file: " + e.Message);
                return(new Dictionary <long, List <ThirdPartyServices.ThirdPartyImportingInfo> >());
            }
        }
Beispiel #6
0
        public static bool UpdateMod(ModUpdateInfo updateInfo, string stagingDirectory, Action <string> errorMessageCallback)
        {
            Log.Information(@"Updating mod: " + updateInfo.mod.ModName + @" from " + updateInfo.LocalizedLocalVersionString + @" to " + updateInfo.LocalizedServerVersionString);
            string modPath           = updateInfo.mod.ModPath;
            string serverRoot        = UpdateStorageRoot + updateInfo.serverfolder + '/';
            bool   cancelDownloading = false;
            var    stagedFileMapping = new ConcurrentDictionary <string, string>();

            foreach (var sf in updateInfo.applicableUpdates)
            {
                sf.AmountDownloaded = 0; //reset in the event this is a second attempt
            }
            Parallel.ForEach(updateInfo.applicableUpdates, new ParallelOptions {
                MaxDegreeOfParallelism = 4
            }, (sourcefile) =>
            {
                if (!cancelDownloading)
                {
                    void downloadProgressCallback(long received, long totalToReceived)
                    {
                        sourcefile.AmountDownloaded = received;
                        updateInfo.RecalculateAmountDownloaded();
                    }

                    string fullurl     = serverRoot + sourcefile.relativefilepath.Replace('\\', '/') + @".lzma";
                    var downloadedFile = OnlineContent.DownloadToMemory(fullurl, downloadProgressCallback, sourcefile.lzmahash, true);
                    if (downloadedFile.errorMessage != null && !cancelDownloading)
                    {
                        errorMessageCallback?.Invoke(downloadedFile.errorMessage);
                        cancelDownloading = true;
                        return;
                    }


                    if (cancelDownloading)
                    {
                        return; //Concurrency for long running download to memory
                    }
                    //Hash OK
                    string stagingFile = Path.Combine(stagingDirectory, sourcefile.relativefilepath);
                    Directory.CreateDirectory(Directory.GetParent(stagingFile).FullName);

                    //Decompress file
                    MemoryStream decompressedStream = new MemoryStream();
                    SevenZipHelper.LZMA.DecompressLZMAStream(downloadedFile.result, decompressedStream);
                    //SevenZipExtractor.DecompressStream(downloadedFile.result, decompressedStream, null, null);

                    //Hash check output
                    if (decompressedStream.Length != sourcefile.size)
                    {
                        Log.Error($@"Decompressed file ({sourcefile.relativefilepath}) is not of correct size. Expected: {sourcefile.size}, got: {decompressedStream.Length}");
                        errorMessageCallback?.Invoke(M3L.GetString(M3L.string_interp_decompressedFileNotCorrectSize, sourcefile.relativefilepath, sourcefile.size, decompressedStream.Length)); //force localize
                        cancelDownloading = true;
                        return;
                    }

                    var decompressedMD5 = Utilities.CalculateMD5(decompressedStream);
                    if (decompressedMD5 != sourcefile.hash)
                    {
                        Log.Error($@"Decompressed file ({sourcefile.relativefilepath}) has the wrong hash. Expected: {sourcefile.hash}, got: {decompressedMD5}");
                        errorMessageCallback?.Invoke(M3L.GetString(M3L.string_interp_decompressedFileWrongHash, sourcefile.relativefilepath, sourcefile.hash, decompressedMD5)); //force localize
                        cancelDownloading = true;
                        return;
                    }

                    File.WriteAllBytes(stagingFile, decompressedStream.ToArray());
                    if (sourcefile.timestamp != 0)
                    {
                        File.SetLastWriteTimeUtc(stagingFile, new DateTime(sourcefile.timestamp));
                    }
                    Log.Information(@"Wrote updater staged file: " + stagingFile);
                    stagedFileMapping[stagingFile] = Path.Combine(modPath, sourcefile.relativefilepath);
                }
            });
            if (cancelDownloading)
            {
                //callback already should have occured
                return(false);
            }

            //All files have been downloaded successfully.
            updateInfo.DownloadButtonText = M3L.GetString(M3L.string_applying);
            //Apply update
            if (stagedFileMapping.Count > 0)
            {
                Log.Information(@"Applying staged update to mod directory");
                foreach (var file in stagedFileMapping)
                {
                    Log.Information($@"Applying update file: {file.Key} => {file.Value}");
                    Directory.CreateDirectory(Directory.GetParent(file.Value).FullName);
                    File.Copy(file.Key, file.Value, true);
                }
            }

            //Delete files no longer in manifest
            foreach (var file in updateInfo.filesToDelete)
            {
                var fileToDelete = Path.Combine(modPath, file);
                Log.Information(@"Deleting file for mod update: " + fileToDelete);
                File.Delete(fileToDelete);
            }

            //Delete empty subdirectories
            Utilities.DeleteEmptySubdirectories(modPath);
            Utilities.DeleteFilesAndFoldersRecursively(stagingDirectory);
            //We're done!
            return(true);
        }
Beispiel #7
0
        //private static readonly string LatestHelpFileLink = StaticFilesBaseURL_Github + "dynamichelp/latesthelp-localized.xml";
        //internal static readonly string HelpResourcesBaseURL = StaticFilesBaseURL_Github + "dynamichelp/resources";

        public static List <SortableHelpElement> FetchLatestHelp(string language, bool preferLocal, bool overrideThrottling = false)
        {
            var    localHelpExists = File.Exists(Utilities.GetLocalHelpFile());
            string cached          = null;

            if (localHelpExists)
            {
                try
                {
                    cached = File.ReadAllText(Utilities.GetLocalHelpFile());
                }
                catch (Exception e)
                {
                    var    attachments = new List <ErrorAttachmentLog>();
                    string log         = LogCollector.CollectLatestLog(false);
                    if (log.Length < ByteSizeLib.ByteSize.BytesInMegaByte * 7)
                    {
                        attachments.Add(ErrorAttachmentLog.AttachmentWithText(log, "applog.txt"));
                    }
                    Crashes.TrackError(e, new Dictionary <string, string>()
                    {
                        { "Error type", "Error reading cached online content" },
                        { "Service", "Dynamic Help" },
                        { "Message", e.Message }
                    }, attachments.ToArray());
                }
            }

            if (localHelpExists && preferLocal)
            {
                return(ParseLocalHelp(cached, language));
            }


            if (!localHelpExists || overrideThrottling || OnlineContent.CanFetchContentThrottleCheck())
            {
                foreach (var staticendpoint in StaticFilesBaseEndpoints)
                {
                    using var wc = new System.Net.WebClient();
                    try
                    {
                        string xml = wc.DownloadStringAwareOfEncoding(staticendpoint + @"dynamichelp/latesthelp-localized.xml");
                        File.WriteAllText(Utilities.GetLocalHelpFile(), xml);
                        return(ParseLocalHelp(xml, language));
                    }
                    catch (Exception e)
                    {
                        Log.Error($"Error fetching online help from endpoint {staticendpoint}: {e.Message}");
                    }
                }
                if (cached != null)
                {
                    Log.Warning("Using cached help instead");
                }
                else
                {
                    Log.Error("Unable to display dynamic help: Could not fetch online asset and cached help asset does not exist.");
                    return(null);
                }
            }

            try
            {
                return(ParseLocalHelp(cached, language));
            }
            catch (Exception e)
            {
                Log.Error("Unable to parse local dynamic help file: " + e.Message);
                return(null);
            }
        }
Beispiel #8
0
        public static List <IntroTutorial.TutorialStep> FetchTutorialManifest(bool overrideThrottling = false)
        {
            Log.Information(@"Fetching tutorial manifest");
            string cached = null;

            // Read cached first.
            if (File.Exists(Utilities.GetTutorialServiceCacheFile()))
            {
                try
                {
                    cached = File.ReadAllText(Utilities.GetTutorialServiceCacheFile());
                }
                catch (Exception e)
                {
                    var    attachments = new List <ErrorAttachmentLog>();
                    string log         = LogCollector.CollectLatestLog(true);
                    if (log != null && log.Length < FileSize.MebiByte * 7)
                    {
                        attachments.Add(ErrorAttachmentLog.AttachmentWithText(log, @"applog.txt"));
                    }
                    Crashes.TrackError(e, new Dictionary <string, string>()
                    {
                        { @"Error type", @"Error reading cached online content" },
                        { @"Service", @"Tutorial Service" },
                        { @"Message", e.Message }
                    }, attachments.ToArray());
                }
            }

            if (!File.Exists(Utilities.GetTutorialServiceCacheFile()) || overrideThrottling || OnlineContent.CanFetchContentThrottleCheck())
            {
                string[] urls = new[] { TutorialServiceURL, TutorialServiceBackupURL };
                foreach (var staticurl in urls)
                {
                    Uri    myUri = new Uri(staticurl);
                    string host  = myUri.Host;

                    try
                    {
                        using var wc = new ShortTimeoutWebClient();
                        string json = wc.DownloadStringAwareOfEncoding(staticurl);
                        File.WriteAllText(Utilities.GetTutorialServiceCacheFile(), json);
                        return(JsonConvert.DeserializeObject <List <IntroTutorial.TutorialStep> >(json));
                    }
                    catch (Exception e)
                    {
                        //Unable to fetch latest help.
                        Log.Error($@"Error fetching latest tutorial service file from endpoint {host}: {e.Message}");
                    }
                }

                if (cached == null)
                {
                    Log.Error(@"Unable to fetch latest tutorial service file from server and local file doesn't exist. Returning a blank copy.");
                    return(new List <IntroTutorial.TutorialStep>());
                }
            }

            Log.Information(@"Using cached tutorial service file");

            try
            {
                return(JsonConvert.DeserializeObject <List <IntroTutorial.TutorialStep> >(cached));
            }
            catch (Exception e)
            {
                Log.Error(@"Unable to parse cached importing service file: " + e.Message);
                return(new List <IntroTutorial.TutorialStep>());
            }
        }
Beispiel #9
0
        public static Dictionary <string, CaseInsensitiveDictionary <ThirdPartyServices.ThirdPartyModInfo> > FetchThirdPartyIdentificationManifest(bool overrideThrottling = false)
        {
            string cached = null;

            if (File.Exists(Utilities.GetThirdPartyIdentificationCachedFile()))
            {
                try
                {
                    cached = File.ReadAllText(Utilities.GetThirdPartyIdentificationCachedFile());
                }
                catch (Exception e)
                {
                    var    attachments = new List <ErrorAttachmentLog>();
                    string log         = LogCollector.CollectLatestLog(true);
                    if (log != null && log.Length < FileSize.MebiByte * 7)
                    {
                        attachments.Add(ErrorAttachmentLog.AttachmentWithText(log, @"applog.txt"));
                    }
                    Crashes.TrackError(e, new Dictionary <string, string>()
                    {
                        { @"Error type", @"Error reading cached online content" },
                        { @"Service", @"Third Party Identification Service" },
                        { @"Message", e.Message }
                    }, attachments.ToArray());
                }
            }


            if (!File.Exists(Utilities.GetThirdPartyIdentificationCachedFile()) || overrideThrottling || OnlineContent.CanFetchContentThrottleCheck())
            {
                try
                {
                    using var wc = new ShortTimeoutWebClient();

                    string json = wc.DownloadStringAwareOfEncoding(ThirdPartyIdentificationServiceURL);
                    File.WriteAllText(Utilities.GetThirdPartyIdentificationCachedFile(), json);
                    return(JsonConvert.DeserializeObject <Dictionary <string, CaseInsensitiveDictionary <ThirdPartyServices.ThirdPartyModInfo> > >(json));
                }
                catch (Exception e)
                {
                    //Unable to fetch latest help.
                    Log.Error(@"Error fetching online third party identification service: " + e.Message);

                    if (cached != null)
                    {
                        Log.Warning(@"Using cached third party identification service  file instead");
                    }
                    else
                    {
                        Log.Error(@"Unable to load third party identification service and local file doesn't exist. Returning a blank copy.");
                        Dictionary <string, CaseInsensitiveDictionary <ThirdPartyServices.ThirdPartyModInfo> > d = new Dictionary <string, CaseInsensitiveDictionary <ThirdPartyServices.ThirdPartyModInfo> >
                        {
                            [@"ME1"] = new CaseInsensitiveDictionary <ThirdPartyServices.ThirdPartyModInfo>(),
                            [@"ME2"] = new CaseInsensitiveDictionary <ThirdPartyServices.ThirdPartyModInfo>(),
                            [@"ME3"] = new CaseInsensitiveDictionary <ThirdPartyServices.ThirdPartyModInfo>()
                        };
                        return(d);
                    }
                }
            }

            try
            {
                return(JsonConvert.DeserializeObject <Dictionary <string, CaseInsensitiveDictionary <ThirdPartyServices.ThirdPartyModInfo> > >(cached));
            }
            catch (Exception e)
            {
                Log.Error(@"Could not parse cached third party identification service file. Returning blank TPMI data instead. Reason: " + e.Message);
                return(new Dictionary <string, CaseInsensitiveDictionary <ThirdPartyServices.ThirdPartyModInfo> >
                {
                    [@"ME1"] = new CaseInsensitiveDictionary <ThirdPartyServices.ThirdPartyModInfo>(),
                    [@"ME2"] = new CaseInsensitiveDictionary <ThirdPartyServices.ThirdPartyModInfo>(),
                    [@"ME3"] = new CaseInsensitiveDictionary <ThirdPartyServices.ThirdPartyModInfo>()
                });
            }
        }