Esempio n. 1
0
        public async Task <T> DeserializePullAsync <T>(string uri, IStatus status)
        {
            var started             = DateTime.Now;
            var deserializePullTask = await statusController.CreateAsync(status, "Reading serialized data", false);

            T data = default(T);

            if (fileController.Exists(uri))
            {
                using (var readableStream = streamController.OpenReadable(uri))
                    data = Serializer.Deserialize <T>(readableStream);
            }

            await statusController.CompleteAsync(deserializePullTask, false);

            var completed = DateTime.Now;
            var duration  = (completed - started).TotalMilliseconds;

            traceDelegate?.Trace(
                "DePull",
                started.ToFileTimeUtc().ToString(),
                completed.ToFileTimeUtc().ToString(),
                duration.ToString(),
                uri);

            return(data);
        }
Esempio n. 2
0
        public async Task UpdateScreenshotsAsync(Product product, IStatus status)
        {
            var requestProductPageTask = await statusController.CreateAsync(status, "Request product page containing screenshots information");

            var productPageUri     = string.Format(getUpdateUriDelegate.GetUpdateUri(Entity.Screenshots), product.Url);
            var productPageContent = await networkController.GetResourceAsync(requestProductPageTask, productPageUri);

            await statusController.CompleteAsync(requestProductPageTask);

            var extractScreenshotsTask = await statusController.CreateAsync(status, "Exract screenshots from the page");

            var extractedProductScreenshots = itemizeScreenshotsDelegates.Itemize(productPageContent);

            if (extractedProductScreenshots == null)
            {
                return;
            }

            var productScreenshots = new ProductScreenshots
            {
                Id    = product.Id,
                Title = product.Title,
                Uris  = new List <string>(extractedProductScreenshots)
            };
            await statusController.CompleteAsync(extractScreenshotsTask);

            var updateProductScreenshotsTask = await statusController.CreateAsync(status, "Add product screenshots");

            await screenshotsDataController.UpdateAsync(productScreenshots, updateProductScreenshotsTask);

            await statusController.CompleteAsync(updateProductScreenshotsTask);
        }
        public async Task <IDictionary <long, IList <string> > > GetDownloadSourcesAsync(IStatus status)
        {
            var processUpdatesTask = await statusController.CreateAsync(status, "Process screenshots updates");

            var screenshotsSources = new Dictionary <long, IList <string> >();
            var current            = 0;
            var total = await screenshotsDataController.CountAsync(processUpdatesTask);

            var processProductsScreenshotsTask = await statusController.CreateAsync(processUpdatesTask, "Process product screenshots");

            foreach (var id in await screenshotsDataController.ItemizeAllAsync(processProductsScreenshotsTask))
            {
                var productScreenshots = await screenshotsDataController.GetByIdAsync(id, processProductsScreenshotsTask);

                if (productScreenshots == null)
                {
                    await statusController.WarnAsync(processProductsScreenshotsTask, $"Product {id} doesn't have screenshots");

                    continue;
                }

                await statusController.UpdateProgressAsync(
                    processUpdatesTask,
                    ++current,
                    total,
                    productScreenshots.Title);

                var currentProductScreenshotSources = new List <string>();

                foreach (var uri in productScreenshots.Uris)
                {
                    var sourceUri      = formatScreenshotsUriDelegate.Format(uri);
                    var destinationUri = Path.Combine(
                        screenshotsDirectoryDelegate.GetDirectory(string.Empty),
                        Path.GetFileName(sourceUri));

                    if (fileController.Exists(destinationUri))
                    {
                        continue;
                    }

                    currentProductScreenshotSources.Add(sourceUri);
                }

                if (currentProductScreenshotSources.Any())
                {
                    screenshotsSources.Add(id, currentProductScreenshotSources);
                }
            }

            await statusController.CompleteAsync(processProductsScreenshotsTask);

            await statusController.CompleteAsync(processUpdatesTask);

            return(screenshotsSources);
        }
Esempio n. 4
0
        public async Task <IEnumerable <string> > ItemizeAsync(GameDetails gameDetails, IStatus status)
        {
            var enumerateGameDetailsFilesStatus = await statusController.CreateAsync(status, "Enumerate game details files");

            var gameDetailsFiles = new List <string>();

            var gameDetailsManualUrls = await itemizeGameDetailsManualUrlsDelegate.ItemizeAsync(gameDetails, status);

            var gameDetailsManualUrlsCount = gameDetailsManualUrls.Count();
            var gameDetailsResolvedUris    = await routingController.TraceRoutesAsync(
                gameDetails.Id,
                gameDetailsManualUrls,
                enumerateGameDetailsFilesStatus);

            // that means that routes information is incomplete and
            // it's not possible to map manualUrls to resolvedUrls
            if (gameDetailsManualUrlsCount != gameDetailsResolvedUris.Count)
            {
                await statusController.CompleteAsync(enumerateGameDetailsFilesStatus);

                throw new ArgumentException($"Product {gameDetails.Id} resolvedUris count doesn't match manualUrls count");
            }

            for (var ii = 0; ii < gameDetailsResolvedUris.Count; ii++)
            {
                // since we don't download all languages and operating systems
                // we don't have routes for each and every gameDetails uri
                // however the ones we have should represent expected files for that product
                if (string.IsNullOrEmpty(gameDetailsResolvedUris[ii]))
                {
                    continue;
                }

                //var localFileUri = Path.Combine(
                //    getDirectoryDelegate.GetDirectory(gameDetailsManualUrls.ElementAt(ii)),
                //getFilenameDelegate.GetFilename(gameDetailsResolvedUris[ii]));

                var localFilePath = getPathDelegate.GetPath(
                    gameDetailsManualUrls.ElementAt(ii),
                    gameDetailsResolvedUris[ii]);

                gameDetailsFiles.Add(localFilePath);
            }

            await statusController.CompleteAsync(enumerateGameDetailsFilesStatus);

            if (gameDetailsManualUrlsCount != gameDetailsFiles.Count)
            {
                throw new ArgumentException($"Product {gameDetails.Id} files count doesn't match manualUrls count");
            }

            return(gameDetailsFiles);
        }
Esempio n. 5
0
        public async Task <string> TraceRouteAsync(long id, string source, IStatus status)
        {
            var traceRouteStatus = await statusController.CreateAsync(status, "Trace route");

            var productRoutes = await productRoutesDataController.GetByIdAsync(id, traceRouteStatus);

            if (productRoutes == null)
            {
                return(string.Empty);
            }

            await statusController.CompleteAsync(traceRouteStatus);

            return(TraceProductRoute(productRoutes.Routes, source));
        }
        public async Task DownloadProductFileAsync(long id, string title, string sourceUri, string destination, IStatus status)
        {
            if (string.IsNullOrEmpty(sourceUri))
            {
                return;
            }

            var sourceUriSansSession = formatUriRemoveSessionDelegate.Format(sourceUri);
            var destinationUri       = formatValidationFileDelegate.Format(sourceUriSansSession);

            // return early if validation is not expected for this file
            if (!confirmValidationExpectedDelegate.Confirm(sourceUriSansSession))
            {
                return;
            }

            if (fileController.Exists(destinationUri))
            {
                await statusController.InformAsync(status, "Validation file already exists, will not be redownloading");

                return;
            }

            var validationSourceUri = formatValidationUriDelegate.Format(sourceUri);

            var downloadValidationFileTask = await statusController.CreateAsync(status, "Download validation file");

            await downloadFromUriAsyncDelegate.DownloadFromUriAsync(
                validationSourceUri,
                validationDirectoryDelegate.GetDirectory(string.Empty),
                downloadValidationFileTask);

            await statusController.CompleteAsync(downloadValidationFileTask);
        }
        public async Task ConstrainAsync(string uri, IStatus status)
        {
            var prefix = collectionController.Reduce(uriPrefixes, uri.StartsWith).SingleOrDefault();

            if (string.IsNullOrEmpty(prefix))
            {
                return;
            }

            // don't limit rate for the first N requests, even if they match rate limit prefix
            if (++rateLimitRequestsCount <= passthroughCount)
            {
                return;
            }

            var now     = DateTime.UtcNow;
            var elapsed = (int)(now - lastRequestToUriPrefix[prefix]).TotalSeconds;

            if (elapsed < requestIntervalSeconds)
            {
                var limitRateTask = await statusController.CreateAsync(status, "Limit request rate to avoid temporary server block");

                await constrainExecutionAsyncDelegate.ConstrainAsync(requestIntervalSeconds - elapsed, status);

                await statusController.CompleteAsync(limitRateTask);
            }

            lastRequestToUriPrefix[prefix] = now;
        }
Esempio n. 8
0
        public async Task <IEnumerable <string> > ItemizeAllAsync(IStatus status)
        {
            var enumerateGameDetailsDirectoriesTask = await statusController.CreateAsync(status, "Enumerate gameDetails directories");

            var directories    = new List <string>();
            var current        = 0;
            var gameDetailsIds = await gameDetailsDataController.ItemizeAllAsync(enumerateGameDetailsDirectoriesTask);

            var gameDetailsCount = await gameDetailsDataController.CountAsync(enumerateGameDetailsDirectoriesTask);

            foreach (var id in gameDetailsIds)
            {
                var gameDetails = await gameDetailsDataController.GetByIdAsync(id, enumerateGameDetailsDirectoriesTask);

                await statusController.UpdateProgressAsync(
                    enumerateGameDetailsDirectoriesTask,
                    ++current,
                    gameDetailsCount,
                    gameDetails.Title);

                directories.AddRange(
                    await itemizeGameDetailsDirectoriesAsyncDelegate.ItemizeAsync(
                        gameDetails,
                        enumerateGameDetailsDirectoriesTask));
            }

            await statusController.CompleteAsync(enumerateGameDetailsDirectoriesTask);

            return(directories);
        }
Esempio n. 9
0
        public async Task LoadAsync(IStatus status)
        {
            var loadStatus = await statusController.CreateAsync(status, "Load stored data", false);

            var storedDataUri = getPathDelegate.GetPath(string.Empty, string.Empty);

            storedData = await serializedStorageController.DeserializePullAsync <ModelType>(storedDataUri, loadStatus);

            if (storedData == null)
            {
                storedData = new ModelType();
            }

            DataAvailable = true;

            await statusController.CompleteAsync(loadStatus, false);
        }
Esempio n. 10
0
        public async Task CommitAsync(IStatus status)
        {
            var commitTask = await statusController.CreateAsync(status, "Commit updated data");

            // commit records controller
            if (recordsController != null)
            {
                var commitRecordsTask = await statusController.CreateAsync(commitTask, "Commit records");

                await recordsController.CommitAsync(status);

                await statusController.CompleteAsync(commitRecordsTask);
            }

            var commitDataTask = await statusController.CreateAsync(commitTask, "Commit items");

            await stashController.SaveAsync(commitDataTask);

            await statusController.CompleteAsync(commitDataTask);

            var additionalCommitsTask = await statusController.CreateAsync(commitTask, "Additional commit dependencies");

            var current = 0;

            foreach (var commitDelegate in additionalCommitDelegates)
            {
                await statusController.UpdateProgressAsync(
                    additionalCommitsTask,
                    ++current,
                    additionalCommitDelegates.Length,
                    "Commit delegate");

                await commitDelegate.CommitAsync(additionalCommitsTask);
            }

            await statusController.CompleteAsync(additionalCommitsTask);

            await statusController.CompleteAsync(commitTask);
        }
        public async Task <IEnumerable <string> > ItemizeAllAsync(IStatus status)
        {
            var enumerateProductFilesDirectoriesTask = await statusController.CreateAsync(
                status,
                "Enumerate productFiles directories");

            var directories = new List <string>();

            var productFilesDirectory = productFilesDirectoryDelegate.GetDirectory(string.Empty);

            directories.AddRange(directoryController.EnumerateDirectories(productFilesDirectory));

            await statusController.CompleteAsync(enumerateProductFilesDirectoriesTask);

            return(directories);
        }
Esempio n. 12
0
        public async Task <IDictionary <long, IList <string> > > GetDownloadSourcesAsync(IStatus status)
        {
            var getDownloadSourcesStatus = await statusController.CreateAsync(status, "Get download sources");

            var productImageSources = new Dictionary <long, IList <string> >();
            var productIds          = await itemizeAllProductsAsyncDelegate.ItemizeAllAsync(getDownloadSourcesStatus);

            var current = 0;

            foreach (var id in productIds)
            {
                await statusController.UpdateProgressAsync(
                    getDownloadSourcesStatus,
                    ++current,
                    productIds.Count(),
                    id.ToString());

                var productCore = await dataController.GetByIdAsync(id, getDownloadSourcesStatus);

                // not all updated products can be found with all dataControllers
                if (productCore == null)
                {
                    continue;
                }

                var imageSources = new List <string> {
                    formatImagesUriDelegate.Format(
                        getImageUriDelegate.GetImageUri(productCore))
                };

                if (!productImageSources.ContainsKey(id))
                {
                    productImageSources.Add(id, new List <string>());
                }

                foreach (var source in imageSources)
                {
                    productImageSources[id].Add(source);
                }
            }

            await statusController.CompleteAsync(getDownloadSourcesStatus);

            return(productImageSources);
        }
Esempio n. 13
0
        public async Task DownloadFromUriAsync(string sourceUri, string destination, IStatus status)
        {
            var downloadEntryTask = await statusController.CreateAsync(status, "Download from source");

            try
            {
                using (var response = await requestResponseAsyncDelegate.RequestResponseAsync(downloadEntryTask, HttpMethod.Get, sourceUri))
                    await downloadFromResponseAsyncDelegate.DownloadFromResponseAsync(response, destination, downloadEntryTask);
            }
            catch (Exception ex)
            {
                await statusController.WarnAsync(downloadEntryTask, $"{sourceUri}: {ex.Message}");
            }
            finally
            {
                await statusController.CompleteAsync(downloadEntryTask);
            }
        }
Esempio n. 14
0
        public async Task ConstrainAsync(int delaySeconds, IStatus status)
        {
            var throttleTask = await statusController.CreateAsync(
                status,
                $"Sleeping {formatSecondsDelegate.Format(delaySeconds)} before next operation");

            for (var ii = 0; ii < delaySeconds; ii++)
            {
                await Task.Delay(1000);

                await statusController.UpdateProgressAsync(
                    throttleTask,
                    ii + 1,
                    delaySeconds,
                    "Countdown",
                    TimeUnits.Seconds);
            }

            await statusController.CompleteAsync(throttleTask);
        }
Esempio n. 15
0
        public async Task <Settings> CorrectAsync(Settings settings, IStatus status)
        {
            var correctSettingsStatus = await statusController.CreateAsync(status, "Correct settings");

            if (settings.DownloadsLanguages == null)
            {
                settings.DownloadsLanguages = new string[0];
            }
            if (settings.DownloadsOperatingSystems == null)
            {
                settings.DownloadsOperatingSystems = new string[0];
            }
            if (settings.Directories == null)
            {
                settings.Directories = new Dictionary <string, string>();
            }

            await statusController.CompleteAsync(correctSettingsStatus);

            return(settings);
        }
Esempio n. 16
0
        public async Task <bool> AuthorizedAsync(IStatus status)
        {
            var getUserDataTask = await statusController.CreateAsync(status, "Get userData.json");

            var userDataString = await networkController.GetResourceAsync(getUserDataTask, Uris.Paths.Authentication.UserData);

            if (string.IsNullOrEmpty(userDataString))
            {
                return(false);
            }

            var userData = serializationController.Deserialize <Models.UserData>(userDataString);

            await statusController.CompleteAsync(getUserDataTask);

            return(userData.IsLoggedIn);
        }
        public async Task <IDictionary <long, IList <string> > > GetDownloadSourcesAsync(IStatus status)
        {
            var getDownloadSourcesStatus = await statusController.CreateAsync(status, "Get download sources");

            var gameDetailsDownloadSources = new Dictionary <long, IList <string> >();
            var current = 0;

            foreach (var id in await updatedDataController.ItemizeAllAsync(getDownloadSourcesStatus))
            {
                await statusController.UpdateProgressAsync(
                    getDownloadSourcesStatus,
                    ++current,
                    await updatedDataController.CountAsync(getDownloadSourcesStatus),
                    id.ToString());

                var gameDetails = await gameDetailsDataController.GetByIdAsync(id, getDownloadSourcesStatus);

                if (!gameDetailsDownloadSources.ContainsKey(id))
                {
                    gameDetailsDownloadSources.Add(id, new List <string>());
                }

                foreach (var manualUrl in
                         await itemizeGameDetailsManualUrlsAsyncController.ItemizeAsync(gameDetails, status))
                {
                    if (!gameDetailsDownloadSources[id].Contains(manualUrl))
                    {
                        gameDetailsDownloadSources[id].Add(manualUrl);
                    }
                }
            }

            await statusController.CompleteAsync(getDownloadSourcesStatus);

            return(gameDetailsDownloadSources);
        }
        public async Task <IList <T> > GetPageResultsAsync(IStatus status)
        {
            // GOG.com quirk
            // Products, AccountProducts use server-side paginated results, similar to Wikipedia.
            // This class encapsulates requesting sequence of pages up to the total number of pages.
            // Additionally page requests are filtered using hashes, so if response has the same hash
            // we would not deserialize it again - no point passing around same data.
            // Please note that ealier app versions also used heuristic optimization when
            // some page was unchanged - stop requesting next pages. This leads to stale data as GOG.com
            // changes information all the time updating Products and AccountProducts. It's especially
            // important for AccountProducts as GOG.com can set Updates information on any AccountProduct.
            // Updated is used for driving updated.json - that in turn is used for all subsequent operations
            // as an optimization - we don't process all products all the time, just updated

            var pageResults = new List <T>();
            var currentPage = 1;
            var totalPages  = 1;
            T   pageResult  = null;

            var getPagesTask = await statusController.CreateAsync(status, $"Request {context}");

            do
            {
                var response = await requestPageAsyncDelegate.RequestPageAsync(
                    requestUri,
                    requestParameters,
                    currentPage,
                    getPagesTask);

                await statusController.UpdateProgressAsync(
                    getPagesTask,
                    currentPage,
                    totalPages,
                    requestUri,
                    PageUnits.Pages);

                var requestHash = await storedHashController.GetHashAsync(requestUri + currentPage, getPagesTask);

                var responseHash = await getStringHashDelegate.GetHashAsync(response, getPagesTask);

                pageResult = serializationController.Deserialize <T>(response);

                if (pageResult == null)
                {
                    continue;
                }

                totalPages = pageResult.TotalPages;

                if (responseHash == requestHash)
                {
                    continue;
                }

                var setHashTask = await statusController.CreateAsync(getPagesTask, "Set hash", false);

                await storedHashController.SetHashAsync(requestUri + currentPage, responseHash, setHashTask);

                await statusController.CompleteAsync(setHashTask, false);

                pageResults.Add(pageResult);
            } while (++currentPage <= totalPages);

            await statusController.CompleteAsync(getPagesTask);

            return(pageResults);
        }
Esempio n. 19
0
        public async Task DownloadProductFileAsync(long id, string title, string sourceUri, string destination, IStatus status)
        {
            var downloadTask = await statusController.CreateAsync(status, "Download game details manual url");

            HttpResponseMessage response;

            try
            {
                response = await networkController.RequestResponseAsync(downloadTask, HttpMethod.Get, sourceUri);
            }
            catch (HttpRequestException ex)
            {
                await statusController.FailAsync(
                    downloadTask,
                    $"Failed to get successful response for {sourceUri} for " +
                    $"product {id}: {title}, message: {ex.Message}");

                await statusController.CompleteAsync(downloadTask);

                return;
            }

            using (response)
            {
                var resolvedUri = response.RequestMessage.RequestUri.ToString();

                // GOG.com quirk
                // When resolving ManualUrl from GameDetails we get CDN Uri with the session key.
                // Storing this key is pointless - it expries after some time and needs to be updated.
                // So here we filter our this session key and store direct file Uri

                var uriSansSession = formatUriRemoveSessionDelegate.Format(resolvedUri);

                await routingController.UpdateRouteAsync(
                    id,
                    title,
                    sourceUri,
                    uriSansSession,
                    downloadTask);

                try
                {
                    await downloadFromResponseAsyncDelegate.DownloadFromResponseAsync(
                        response,
                        destination,
                        downloadTask);
                }
                catch (Exception ex)
                {
                    await statusController.FailAsync(
                        downloadTask,
                        $"Couldn't download {sourceUri}, resolved as {resolvedUri} to {destination} " +
                        $"for product {id}: {title}, error message: {ex.Message}");
                }

                // GOG.com quirk
                // Supplementary download is a secondary download to a primary driven by download scheduling
                // The example is validation file - while we can use the same pipeline, we would be
                // largerly duplicating all the work to establish the session, compute the name etc.
                // While the only difference validation files have - is additional extension.
                // So instead we'll do a supplementary download using primary download information

                await downloadValidationFileAsyncDelegate?.DownloadProductFileAsync(
                    id,
                    title,
                    resolvedUri,
                    destination,
                    downloadTask);
            }

            await statusController.CompleteAsync(downloadTask);
        }