Ejemplo n.º 1
0
 internal void StartDownload(IEnumerable <DependencyObject> download, DownloadStart downloadStart = null,
                             DownloadProgress downloadProgress = null, DownloadFailed downloadFail = null, DownloadFinish downloadFinish = null,
                             InstallFailed installFail         = null, InstallFinish installFinish = null)
 {
     foreach (var item in download)
     {
         StartCoroutine(UpdateModCoroutine(item, downloadStart, downloadProgress, downloadFail, downloadFinish, installFail, installFinish));
     }
 }
Ejemplo n.º 2
0
        private static IEnumerator UpdateModCoroutine(DependencyObject item, DownloadStart downloadStart,
                                                      DownloadProgress progress, DownloadFailed dlFail, DownloadFinish finish,
                                                      InstallFailed installFail, InstallFinish installFinish)
        { // (3.2)
            Logger.updater.Debug($"Release: {BeatSaber.ReleaseType}");

            var mod = new Ref <ApiEndpoint.Mod>(null);

            yield return(GetModInfo(item.Name, item.ResolvedVersion.ToString(), mod));

            try { mod.Verify(); }
            catch (Exception e)
            {
                Logger.updater.Error($"Error occurred while trying to get information for {item}");
                Logger.updater.Error(e);
                yield break;
            }

            var releaseName = BeatSaber.ReleaseType == BeatSaber.Release.Steam
                ? ApiEndpoint.Mod.DownloadsObject.TypeSteam : ApiEndpoint.Mod.DownloadsObject.TypeOculus;
            var platformFile = mod.Value.Downloads.First(f => f.Type == ApiEndpoint.Mod.DownloadsObject.TypeUniversal || f.Type == releaseName);

            string url = ApiEndpoint.BeatModBase + platformFile.Path;

            Logger.updater.Debug($"URL = {url}");

            const int maxTries = 3;
            int       tries    = maxTries;

            while (tries > 0)
            {
                if (tries-- != maxTries)
                {
                    Logger.updater.Debug("Re-trying download...");
                }

                using (var stream = new MemoryStream())
                    using (var request = UnityWebRequest.Get(url))
                        using (var taskTokenSource = new CancellationTokenSource())
                        {
                            var dlh = new StreamDownloadHandler(stream, (int i1, int i2, double d) => progress?.Invoke(item, i1, i2, d));
                            request.downloadHandler = dlh;

                            downloadStart?.Invoke(item);

                            Logger.updater.Debug("Sending request");
                            //Logger.updater.Debug(request?.downloadHandler?.ToString() ?? "DLH==NULL");
                            yield return(request.SendWebRequest());

                            Logger.updater.Debug("Download finished");

                            if (request.isNetworkError)
                            {
                                Logger.updater.Error("Network error while trying to update mod");
                                Logger.updater.Error(request.error);
                                dlFail?.Invoke(item, request.error);
                                taskTokenSource.Cancel();
                                continue;
                            }
                            if (request.isHttpError)
                            {
                                Logger.updater.Error("Server returned an error code while trying to update mod");
                                Logger.updater.Error(request.error);
                                dlFail?.Invoke(item, request.error);
                                taskTokenSource.Cancel();
                                continue;
                            }

                            finish?.Invoke(item);

                            stream.Seek(0, SeekOrigin.Begin); // reset to beginning

                            var downloadTask = Task.Run(() =>
                            { // use slightly more multi threaded approach than co-routines
                                // ReSharper disable once AccessToDisposedClosure
                                ExtractPluginAsync(stream, item, platformFile);
                            }, taskTokenSource.Token);

                            while (!(downloadTask.IsCompleted || downloadTask.IsCanceled || downloadTask.IsFaulted))
                            {
                                yield return(null); // pause co-routine until task is done
                            }
                            if (downloadTask.IsFaulted)
                            {
                                if (downloadTask.Exception != null && downloadTask.Exception.InnerExceptions.Any(e => e is BeatmodsInterceptException))
                                { // any exception is an intercept exception
                                    Logger.updater.Error($"BeatMods did not return expected data for {item.Name}");
                                }

                                Logger.updater.Error($"Error downloading mod {item.Name}");
                                Logger.updater.Error(downloadTask.Exception);

                                installFail?.Invoke(item, downloadTask.Exception);
                                continue;
                            }

                            break;
                        }
            }

            if (tries == 0)
            {
                Logger.updater.Warn($"Plugin download failed {maxTries} times, not re-trying");

                installFinish?.Invoke(item, true);
            }
            else
            {
                Logger.updater.Debug("Download complete");
                installFinish?.Invoke(item, false);
            }
        }