示例#1
0
        /// <summary>
        /// Gets the list of categories from the upstream server and adds them to the specified metadata collection.
        /// </summary>
        /// <param name="destination">Metadata collection where to add the results. If the collection implements <see cref="IMetadataSource"/>, only delta changes are retrieved and added to the destination.</param>
        public async Task GetCategories(IMetadataSink destination)
        {
            var deltaMetadataSource = destination as IMetadataSource;
            var progress            = new MetadataQueryProgress();

            if (AccessToken == null || AccessToken.ExpiresIn(TimeSpan.FromMinutes(2)))
            {
                await RefreshAccessToken(deltaMetadataSource?.UpstreamAccountName, deltaMetadataSource?.UpstreamAccountGuid);
            }

            // If no configuration is known, query it now
            if (ConfigData == null)
            {
                await RefreshServerConfigData();
            }

            // Query IDs for all categories known to the upstream server
            progress.CurrentTask = MetadataQueryStage.GetRevisionIdsStart;
            MetadataQueryProgress?.Invoke(this, progress);

            var categoriesAnchor    = deltaMetadataSource?.CategoriesAnchor;
            var categoryQueryResult = await GetCategoryIds(categoriesAnchor);

            progress.CurrentTask = MetadataQueryStage.GetRevisionIdsEnd;
            MetadataQueryProgress?.Invoke(this, progress);

            var cachedCategories = deltaMetadataSource?.CategoriesIndex;

            // Find all updates that did not change
            var unchangedUpdates = GetUnchangedUpdates(cachedCategories, categoryQueryResult.identities);

            // Create the list of updates to query data for. Remove those updates that were reported as "new"
            // but for which we already have metadata
            var updatesToRetrieveDataFor = categoryQueryResult.identities.Where(
                newUpdateId => !unchangedUpdates.ContainsKey(newUpdateId));

            // Retrieve metadata for all new categories
            progress.CurrentTask = MetadataQueryStage.GetUpdateMetadataStart;
            progress.Maximum     = updatesToRetrieveDataFor.Count();
            progress.Current     = 0;
            MetadataQueryProgress?.Invoke(this, progress);

            destination.SetCategoriesAnchor(categoryQueryResult.anchor);

            GetUpdateDataForIds(
                updatesToRetrieveDataFor.Select(id => id.Raw).ToList(), destination);

            progress.CurrentTask = MetadataQueryStage.GetUpdateMetadataEnd;
            MetadataQueryProgress?.Invoke(this, progress);
        }
示例#2
0
        /// <summary>
        /// Performs authentication with an upstream update server, using a previously issued service access token.
        /// </summary>
        /// <remarks>
        /// Refreshing an old token with this method is faster than obtaining a new token as it requires fewer server roundtrips.
        ///
        /// If the access cookie does not expire within 30 minutes, the function succeeds and the old token is returned.
        /// </remarks>
        /// <param name="cachedAccessToken">The previously issued access token.</param>
        /// <returns>The new ServiceAccessToken</returns>
        public async Task <ServiceAccessToken> Authenticate(ServiceAccessToken cachedAccessToken)
        {
            if (cachedAccessToken == null)
            {
                return(await Authenticate());
            }

            ServiceAccessToken newAccessToken = new ServiceAccessToken()
            {
                AuthCookie         = cachedAccessToken.AuthCookie,
                AccessCookie       = cachedAccessToken.AccessCookie,
                AuthenticationInfo = cachedAccessToken.AuthenticationInfo
            };

            // Check if the cached access cookie expires in the next 30 minutes; if not, return the new token
            // with this cookie
            if (!newAccessToken.ExpiresIn(TimeSpan.FromMinutes(30)))
            {
                return(newAccessToken);
            }

            bool restartAuthenticationRequired = false;

            // Get a new access cookie
            try
            {
                newAccessToken.AccessCookie = await GetServerAccessCookie(newAccessToken.AuthCookie);
            }
            catch (UpstreamServerException ex)
            {
                if (ex.ErrorCode == UpstreamServerErrorCode.InvalidAuthorizationCookie)
                {
                    // The authorization cookie is expired or invalid. Restart the authentication protocol
                    restartAuthenticationRequired = true;
                }
                else
                {
                    throw ex;
                }
            }

            return(restartAuthenticationRequired ? await Authenticate() : newAccessToken);
        }