コード例 #1
0
        public async Task <ScriptInstallStatus> InstallScript(ContentType contentType, FGORegion region, List <string> installPaths, string baseInstallPath, int installId, string assetStorageCheck = null,
                                                              ObservableCollection <InstallerPage.TranslationGUIObject> translationGuiObjects = null)
        {
            _cm.ClearCache();
            var gui       = translationGuiObjects != null;
            var guiObject = gui ? translationGuiObjects.First(w => w.BundleID == installId) : null;

            if (guiObject != null)
            {
                guiObject.Status =
                    UIFunctions.GetResourceString("InstallingFetchingHandshake");
                guiObject.ButtonInstallText = UIFunctions.GetResourceString("InstallingText");
                guiObject.TextColor         = Color.Chocolate;
            }
            // fetch new translation list to ensure it is up to date
            var restful         = new RestfulAPI();
            var translationList = await restful.GetHandshakeApiResponse(region, assetStorageCheck);

            if (!translationList.IsSuccessful || translationList.Data.Status != 200)
            {
                return(new ScriptInstallStatus()
                {
                    IsSuccessful = false,
                    ErrorMessage = String.Format(UIFunctions.GetResourceString("InstallHandshakeFailure"), translationList.StatusCode, translationList.Data?.Message)
                });
            }

            if (assetStorageCheck != null)
            {
                switch (translationList.Data.Response.AssetStatus)
                {
                case HandshakeAssetStatus.UpdateRequired:
                    return(new ScriptInstallStatus()
                    {
                        IsSuccessful = false,
                        ErrorMessage = String.Format("AssetStorage.txt out of date, skipping update.")
                    });

                default:
                    break;
                }
            }

            // download required scripts
            var groupToInstall = translationList.Data.Response.Translations.FirstOrDefault(w => w.Group == installId);

            if (groupToInstall?.Scripts == null)
            {
                return(new ScriptInstallStatus()
                {
                    IsSuccessful = false,
                    ErrorMessage = String.Format(UIFunctions.GetResourceString("InstallMissingScriptFailure"), installId)
                });
            }

            if (!gui && groupToInstall.Hidden)
            {
                return(new ScriptInstallStatus()
                {
                    IsSuccessful = false,
                    ErrorMessage = String.Format(UIFunctions.GetResourceString("InstallHiddenScriptFailure"), installId)
                });
            }

            var totalScripts = groupToInstall.Scripts.Count;

            if (guiObject != null)
            {
                guiObject.Status =
                    String.Format(UIFunctions.GetResourceString("InstallDownloadingScripts"), 1, totalScripts);
            }

            ConcurrentDictionary <string, byte[]> scriptDictionary = new ConcurrentDictionary <string, byte[]>();
            object lockObj = new Object();

            try
            {
                await groupToInstall.Scripts.ParallelForEachAsync(async script =>
                {
                    var name             = script.Key;
                    var downloadUrl      = script.Value.DownloadURL;
                    var downloadResponse = await restful.GetScript(downloadUrl);
                    var downloadedScript = downloadResponse.RawBytes;

                    if (!downloadResponse.IsSuccessful)
                    {
                        throw new EndEarlyException(String.Format(UIFunctions.GetResourceString("InstallScriptDownloadFailure"),
                                                                  installId, downloadUrl, downloadResponse.ErrorMessage));
                    }

                    if (downloadedScript == null)
                    {
                        throw new EndEarlyException(String.Format(UIFunctions.GetResourceString("InstallEmptyFileFailure"),
                                                                  installId, downloadUrl));
                    }

                    var scriptSha = ScriptUtil.Sha1(downloadedScript);

                    if (scriptSha != script.Value.TranslatedSHA1)
                    {
                        throw new EndEarlyException(String.Format(UIFunctions.GetResourceString("InstallChecksumFailure"),
                                                                  installId, downloadedScript.Length, downloadUrl));
                    }

                    scriptDictionary.TryAdd(name, downloadedScript);
                    lock (lockObj)
                    {
                        if (guiObject != null)
                        {
                            guiObject.Status =
                                String.Format(UIFunctions.GetResourceString("InstallDownloadingScripts"),
                                              Math.Min(scriptDictionary.Count, totalScripts), totalScripts);
                        }
                    }
                }, maxDegreeOfParallelism : 4);
            }
            catch (EndEarlyException ex)
            {
                return(new ScriptInstallStatus()
                {
                    IsSuccessful = false,
                    ErrorMessage = ex.ToString()
                });
            }

            if (guiObject != null)
            {
                guiObject.Status =
                    String.Format(UIFunctions.GetResourceString("InstallDownloadNewAssetStorage"));
            }

            Dictionary <string, byte[]> newAssetStorages = new Dictionary <string, byte[]>();

            // get new assetstorage.txt
            foreach (var game in installPaths)
            {
                var assetStoragePath = contentType != ContentType.DirectAccess ? $"data/{game}/files/data/d713/{InstallerPage._assetList}"
                    : $"{game}/files/data/d713/{InstallerPage._assetList}";

                var fileContents = await _cm.GetFileContents(contentType, assetStoragePath, baseInstallPath);

                if (!fileContents.Successful || fileContents.FileContents.Length == 0)
                {
                    return(new ScriptInstallStatus()
                    {
                        IsSuccessful = false,
                        ErrorMessage = String.Format(UIFunctions.GetResourceString("InstallEmptyAssetStorage"), installId, assetStoragePath, fileContents.Error)
                    });
                }


                // remove bom
                var base64 = "";
                await using var inputStream = new MemoryStream(fileContents.FileContents);
                using (var reader = new StreamReader(inputStream, Encoding.ASCII))
                {
                    base64 = await reader.ReadToEndAsync();
                }
                var newAssetList = await restful.SendAssetList(base64, installId, region);

                if (!newAssetList.IsSuccessful)
                {
                    return(new ScriptInstallStatus()
                    {
                        IsSuccessful = false,
                        ErrorMessage = string.Format(UIFunctions.GetResourceString("InstallAssetStorageAPIFailure"), installId, newAssetList.StatusCode, newAssetList.Data?.Message)
                    });
                }

                // add bom
                await using var outputStream = new MemoryStream();
                await using (var writer = new StreamWriter(outputStream, Encoding.ASCII))
                {
                    await writer.WriteAsync(newAssetList.Data.Response["data"]);
                }

                newAssetStorages.Add(assetStoragePath, outputStream.ToArray());
            }

            // prepare files

            Dictionary <string, byte[]> filesToWrite = newAssetStorages;

            foreach (var game in installPaths)
            {
                foreach (var asset in scriptDictionary)
                {
                    var assetInstallPath = contentType != ContentType.DirectAccess
                        ? $"data/{game}/files/data/d713/{asset.Key}"
                        : $"{game}/files/data/d713/{asset.Key}";

                    filesToWrite.Add(assetInstallPath, asset.Value);
                }
            }

            // write files
            int j   = 1;
            int tot = filesToWrite.Count;

            foreach (var file in filesToWrite)
            {
                if (file.Key.EndsWith(".bin"))
                {
                    await _cm.RemoveFileIfExists(contentType,
                                                 file.Key, baseInstallPath);
                }
            }
            _cm.ClearCache();

            foreach (var file in filesToWrite)
            {
                if (guiObject != null)
                {
                    guiObject.Status =
                        String.Format(UIFunctions.GetResourceString("InstallWriteFile"), j, tot);
                }

                await _cm.WriteFileContents(contentType, file.Key, baseInstallPath, file.Value);

                j += 1;
            }


            if (guiObject != null)
            {
                guiObject.Status =
                    String.Format(UIFunctions.GetResourceString("InstallFinished"));
                guiObject.TextColor = Color.LimeGreen;
            }
            Preferences.Set($"InstalledScript_{region}", JsonConvert.SerializeObject(groupToInstall));

            return(new ScriptInstallStatus()
            {
                IsSuccessful = true,
                ErrorMessage = ""
            });
        }
コード例 #2
0
        protected override async void OnActivityResult(int requestCode, Result resultCode, Intent intent)
        {
            base.OnActivityResult(requestCode, resultCode, intent);
            Log.Info("TranslateFGO", $"ActivityResult Code: {resultCode}, Result: {resultCode}, Data: {intent?.DataString}");

            if (resultCode == Result.Ok && requestCode == (int)RequestCodes.FolderIntentRequestCode)
            {
                var service = new ContentManager();

                var uri            = intent.Data;
                var selectedFolder = DocumentsContract.GetTreeDocumentId(uri);

                if (selectedFolder == null || !selectedFolder.EndsWith("Android"))
                {
                    var folderSplit  = selectedFolder?.Split(":").Last();
                    var infoText     = UIFunctions.GetResourceString("AndroidFolderNotSelected");
                    var errorMessage = String.Format(infoText, !string.IsNullOrEmpty(folderSplit) ? folderSplit : "none");
                    Toast.MakeText(this.Context, errorMessage, ToastLength.Long)?.Show();
                    return;
                }

                service.ClearCache();
                var dataChildren = service.GetFolderChildren(uri, "data/"); // Get list of children to find FGO folders

                if (dataChildren.Count == 0)
                {
                    var infoText = UIFunctions.GetResourceString("AndroidDataFolderEmpty");
                    Toast.MakeText(this.Context, infoText, ToastLength.Long)?.Show();
                    return;
                }

                var  appNamesList = ContentManager.ValidAppNames.ToList();
                bool found        = false;
                foreach (var folder in dataChildren)
                {
                    if (appNamesList.Contains(folder.Path.Split("/").Last()))
                    {
                        found = true;
                    }
                }

                if (!found)
                {
                    var infoText = UIFunctions.GetResourceString("NoFGOInstallationFoundToast");
                    Toast.MakeText(this.Context, infoText, ToastLength.Long)?.Show();
                    return;
                }

                // Save URL
                try
                {
                    this.ContentResolver.TakePersistableUriPermission(uri, intent.Flags & (ActivityFlags.GrantReadUriPermission | ActivityFlags.GrantWriteUriPermission));
                }
                catch (Exception ex)
                {
                    Log.Error("BetterFGO", $"Error thrown while persisting uri: {ex}");
                    var errorText    = UIFunctions.GetResourceString("UnknownError");
                    var errorMessage = String.Format(errorText, ex.ToString());
                    Toast.MakeText(this.Context, errorMessage, ToastLength.Long)?.Show();
                }

                // If we got this far, all is well
                var successText = UIFunctions.GetResourceString("Android11SetupSuccessful");
                Toast.MakeText(this.Context, successText, ToastLength.Long)?.Show();

                Log.Info("BetterFGO", $"Saving URI: {uri?.ToString()}");

                Preferences.Set("StorageType", (int)ContentType.StorageFramework);
                Preferences.Set("StorageLocation", uri?.ToString());

                MessagingCenter.Send(Xamarin.Forms.Application.Current, "return_to_main_page");
            }
        }