Exemplo n.º 1
0
        /// <summary>
        /// Validates the children internal.
        /// </summary>
        /// <param name="progress">The progress.</param>
        /// <param name="cancellationToken">The cancellation token.</param>
        /// <param name="recursive">if set to <c>true</c> [recursive].</param>
        /// <param name="refreshChildMetadata">if set to <c>true</c> [refresh child metadata].</param>
        /// <param name="refreshOptions">The refresh options.</param>
        /// <param name="directoryService">The directory service.</param>
        /// <returns>Task.</returns>
        protected async virtual Task ValidateChildrenInternal(IProgress <double> progress, CancellationToken cancellationToken, bool recursive, bool refreshChildMetadata, MetadataRefreshOptions refreshOptions, IDirectoryService directoryService)
        {
            var locationType = LocationType;

            cancellationToken.ThrowIfCancellationRequested();

            var validChildren = new List <BaseItem>();

            if (locationType != LocationType.Remote && locationType != LocationType.Virtual)
            {
                IEnumerable <BaseItem> nonCachedChildren;

                try
                {
                    nonCachedChildren = GetNonCachedChildren(directoryService);
                }
                catch (IOException ex)
                {
                    nonCachedChildren = new BaseItem[] { };

                    Logger.ErrorException("Error getting file system entries for {0}", ex, Path);
                }

                if (nonCachedChildren == null)
                {
                    return;                            //nothing to validate
                }
                progress.Report(5);

                //build a dictionary of the current children we have now by Id so we can compare quickly and easily
                var currentChildren = GetActualChildrenDictionary();

                //create a list for our validated children
                var newItems = new List <BaseItem>();

                cancellationToken.ThrowIfCancellationRequested();

                foreach (var child in nonCachedChildren)
                {
                    BaseItem currentChild;

                    if (currentChildren.TryGetValue(child.Id, out currentChild))
                    {
                        if (IsValidFromResolver(currentChild, child))
                        {
                            var currentChildLocationType = currentChild.LocationType;
                            if (currentChildLocationType != LocationType.Remote &&
                                currentChildLocationType != LocationType.Virtual)
                            {
                                currentChild.DateModified = child.DateModified;
                            }

                            currentChild.IsOffline = false;
                            validChildren.Add(currentChild);
                        }
                        else
                        {
                            newItems.Add(child);
                            validChildren.Add(child);
                        }
                    }
                    else
                    {
                        // Brand new item - needs to be added
                        newItems.Add(child);
                        validChildren.Add(child);
                    }
                }

                // If any items were added or removed....
                if (newItems.Count > 0 || currentChildren.Count != validChildren.Count)
                {
                    // That's all the new and changed ones - now see if there are any that are missing
                    var itemsRemoved   = currentChildren.Values.Except(validChildren).ToList();
                    var actualRemovals = new List <BaseItem>();

                    foreach (var item in itemsRemoved)
                    {
                        if (item.LocationType == LocationType.Virtual ||
                            item.LocationType == LocationType.Remote)
                        {
                            // Don't remove these because there's no way to accurately validate them.
                            validChildren.Add(item);
                        }

                        else if (!string.IsNullOrEmpty(item.Path) && IsPathOffline(item.Path))
                        {
                            item.IsOffline = true;
                            validChildren.Add(item);
                        }
                        else
                        {
                            item.IsOffline = false;
                            actualRemovals.Add(item);
                        }
                    }

                    if (actualRemovals.Count > 0)
                    {
                        RemoveChildrenInternal(actualRemovals);

                        foreach (var item in actualRemovals)
                        {
                            LibraryManager.ReportItemRemoved(item);
                        }
                    }

                    await LibraryManager.CreateItems(newItems, cancellationToken).ConfigureAwait(false);

                    AddChildrenInternal(newItems);

                    await ItemRepository.SaveChildren(Id, ActualChildren.Select(i => i.Id).ToList(), cancellationToken).ConfigureAwait(false);
                }
            }

            progress.Report(10);

            cancellationToken.ThrowIfCancellationRequested();

            if (recursive)
            {
                await ValidateSubFolders(ActualChildren.OfType <Folder>().ToList(), directoryService, progress, cancellationToken).ConfigureAwait(false);
            }

            progress.Report(20);

            if (refreshChildMetadata)
            {
                var container = this as IMetadataContainer;

                var innerProgress = new ActionableProgress <double>();

                innerProgress.RegisterAction(p => progress.Report((.80 * p) + 20));

                if (container != null)
                {
                    await container.RefreshAllMetadata(refreshOptions, innerProgress, cancellationToken).ConfigureAwait(false);
                }
                else
                {
                    await RefreshMetadataRecursive(refreshOptions, recursive, innerProgress, cancellationToken);
                }
            }

            progress.Report(100);
        }
Exemplo n.º 2
0
        /// <summary>
        /// Compare our current children (presumably just read from the repo) with the current state of the file system and adjust for any changes
        /// ***Currently does not contain logic to maintain items that are unavailable in the file system***
        /// </summary>
        /// <param name="progress">The progress.</param>
        /// <param name="cancellationToken">The cancellation token.</param>
        /// <param name="recursive">if set to <c>true</c> [recursive].</param>
        /// <param name="forceRefreshMetadata">if set to <c>true</c> [force refresh metadata].</param>
        /// <returns>Task.</returns>
        protected async virtual Task ValidateChildrenInternal(IProgress <double> progress, CancellationToken cancellationToken, bool?recursive = null, bool forceRefreshMetadata = false)
        {
            var locationType = LocationType;

            // Nothing to do here
            if (locationType == LocationType.Remote || locationType == LocationType.Virtual)
            {
                return;
            }

            cancellationToken.ThrowIfCancellationRequested();

            IEnumerable <BaseItem> nonCachedChildren;

            try
            {
                nonCachedChildren = GetNonCachedChildren();
            }
            catch (IOException ex)
            {
                nonCachedChildren = new BaseItem[] { };

                Logger.ErrorException("Error getting file system entries for {0}", ex, Path);
            }

            if (nonCachedChildren == null)
            {
                return;                            //nothing to validate
            }
            progress.Report(5);

            //build a dictionary of the current children we have now by Id so we can compare quickly and easily
            var currentChildren = ActualChildren;

            //create a list for our validated children
            var validChildren = new ConcurrentBag <Tuple <BaseItem, bool> >();
            var newItems      = new ConcurrentBag <BaseItem>();

            cancellationToken.ThrowIfCancellationRequested();

            var options = new ParallelOptions
            {
                MaxDegreeOfParallelism = 20
            };

            Parallel.ForEach(nonCachedChildren, options, child =>
            {
                BaseItem currentChild;

                if (currentChildren.TryGetValue(child.Id, out currentChild))
                {
                    currentChild.ResolveArgs = child.ResolveArgs;

                    //existing item - check if it has changed
                    if (currentChild.HasChanged(child))
                    {
                        EntityResolutionHelper.EnsureDates(currentChild, child.ResolveArgs, false);

                        validChildren.Add(new Tuple <BaseItem, bool>(currentChild, true));
                    }
                    else
                    {
                        validChildren.Add(new Tuple <BaseItem, bool>(currentChild, false));
                    }

                    currentChild.IsOffline = false;
                }
                else
                {
                    //brand new item - needs to be added
                    newItems.Add(child);

                    validChildren.Add(new Tuple <BaseItem, bool>(child, true));
                }
            });

            // If any items were added or removed....
            if (!newItems.IsEmpty || currentChildren.Count != validChildren.Count)
            {
                var newChildren = validChildren.Select(c => c.Item1).ToList();

                //that's all the new and changed ones - now see if there are any that are missing
                var itemsRemoved = currentChildren.Values.Except(newChildren).ToList();

                foreach (var item in itemsRemoved)
                {
                    if (IsRootPathAvailable(item.Path))
                    {
                        item.IsOffline = false;

                        BaseItem removed;

                        if (!_children.TryRemove(item.Id, out removed))
                        {
                            Logger.Error("Failed to remove {0}", item.Name);
                        }
                        else
                        {
                            LibraryManager.ReportItemRemoved(item);
                        }
                    }
                    else
                    {
                        item.IsOffline = true;

                        validChildren.Add(new Tuple <BaseItem, bool>(item, false));
                    }
                }

                await LibraryManager.CreateItems(newItems, cancellationToken).ConfigureAwait(false);

                foreach (var item in newItems)
                {
                    if (!_children.TryAdd(item.Id, item))
                    {
                        Logger.Error("Failed to add {0}", item.Name);
                    }
                    else
                    {
                        Logger.Debug("** " + item.Name + " Added to library.");
                    }
                }

                await ItemRepository.SaveChildren(Id, _children.Values.ToList().Select(i => i.Id), cancellationToken).ConfigureAwait(false);

                //force the indexes to rebuild next time
                IndexCache.Clear();
            }

            progress.Report(10);

            cancellationToken.ThrowIfCancellationRequested();

            await RefreshChildren(validChildren, progress, cancellationToken, recursive, forceRefreshMetadata).ConfigureAwait(false);

            progress.Report(100);
        }