/// <summary> /// Notifies the kernal that a provider has completed refreshing /// </summary> /// <param name="provider">The provider.</param> /// <param name="item">The item.</param> public void OnProviderRefreshCompleted(BaseMetadataProvider provider, BaseItem item) { var key = item.Id + provider.GetType().Name; Tuple<BaseMetadataProvider, BaseItem, CancellationTokenSource> current; if (_currentlyRunningProviders.TryRemove(key, out current)) { current.Item3.Dispose(); } }
/// <summary> /// Notifies the kernal that a provider has begun refreshing /// </summary> /// <param name="provider">The provider.</param> /// <param name="item">The item.</param> /// <param name="cancellationTokenSource">The cancellation token source.</param> public void OnProviderRefreshBeginning(BaseMetadataProvider provider, BaseItem item, CancellationTokenSource cancellationTokenSource) { var key = item.Id + provider.GetType().Name; Tuple<BaseMetadataProvider, BaseItem, CancellationTokenSource> current; if (_currentlyRunningProviders.TryGetValue(key, out current)) { try { current.Item3.Cancel(); } catch (ObjectDisposedException) { } } var tuple = new Tuple<BaseMetadataProvider, BaseItem, CancellationTokenSource>(provider, item, cancellationTokenSource); _currentlyRunningProviders.AddOrUpdate(key, tuple, (k, v) => tuple); }
/// <summary> /// Fetches metadata and returns true or false indicating if any work that requires persistence was done /// </summary> /// <param name="provider">The provider.</param> /// <param name="item">The item.</param> /// <param name="providerInfo">The provider information.</param> /// <param name="force">if set to <c>true</c> [force].</param> /// <param name="cancellationToken">The cancellation token.</param> /// <returns>Task{System.Boolean}.</returns> /// <exception cref="System.ArgumentNullException">item</exception> private async Task<ItemUpdateType?> FetchAsync(BaseMetadataProvider provider, BaseItem item, BaseProviderInfo providerInfo, bool force, CancellationToken cancellationToken) { if (item == null) { throw new ArgumentNullException("item"); } cancellationToken.ThrowIfCancellationRequested(); // Don't clog up the log with these providers if (!(provider is IDynamicInfoProvider)) { _logger.Debug("Running {0} for {1}", provider.GetType().Name, item.Path ?? item.Name ?? "--Unknown--"); } try { var changed = await provider.FetchAsync(item, force, providerInfo, cancellationToken).ConfigureAwait(false); if (changed) { return provider.ItemUpdateType; } return null; } catch (OperationCanceledException ex) { _logger.Debug("{0} canceled for {1}", provider.GetType().Name, item.Name); // If the outer cancellation token is the one that caused the cancellation, throw it if (cancellationToken.IsCancellationRequested && ex.CancellationToken == cancellationToken) { throw; } return null; } catch (Exception ex) { _logger.ErrorException("{0} failed refreshing {1} {2}", ex, provider.GetType().Name, item.Name, item.Path ?? string.Empty); provider.SetLastRefreshed(item, DateTime.UtcNow, providerInfo, ProviderRefreshStatus.Failure); return ItemUpdateType.Unspecified; } }
/// <summary> /// Fetches metadata and returns true or false indicating if any work that requires persistence was done /// </summary> /// <param name="provider">The provider.</param> /// <param name="item">The item.</param> /// <param name="force">if set to <c>true</c> [force].</param> /// <param name="cancellationToken">The cancellation token.</param> /// <returns>Task{System.Boolean}.</returns> /// <exception cref="System.ArgumentNullException"></exception> private async Task<ItemUpdateType?> FetchAsync(BaseMetadataProvider provider, BaseItem item, bool force, CancellationToken cancellationToken) { if (item == null) { throw new ArgumentNullException(); } cancellationToken.ThrowIfCancellationRequested(); _logger.Debug("Running {0} for {1}", provider.GetType().Name, item.Path ?? item.Name ?? "--Unknown--"); // This provides the ability to cancel just this one provider var innerCancellationTokenSource = new CancellationTokenSource(); OnProviderRefreshBeginning(provider, item, innerCancellationTokenSource); try { var changed = await provider.FetchAsync(item, force, CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, innerCancellationTokenSource.Token).Token).ConfigureAwait(false); if (changed) { return provider.ItemUpdateType; } return null; } catch (OperationCanceledException ex) { _logger.Debug("{0} canceled for {1}", provider.GetType().Name, item.Name); // If the outer cancellation token is the one that caused the cancellation, throw it if (cancellationToken.IsCancellationRequested && ex.CancellationToken == cancellationToken) { throw; } return null; } catch (Exception ex) { _logger.ErrorException("{0} failed refreshing {1}", ex, provider.GetType().Name, item.Name); provider.SetLastRefreshed(item, DateTime.UtcNow, ProviderRefreshStatus.Failure); return ItemUpdateType.Unspecified; } finally { innerCancellationTokenSource.Dispose(); OnProviderRefreshCompleted(provider, item); } }
/// <summary> /// Providers the supports item. /// </summary> /// <param name="provider">The provider.</param> /// <param name="item">The item.</param> /// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns> private bool ProviderSupportsItem(BaseMetadataProvider provider, BaseItem item) { try { return provider.Supports(item); } catch (Exception ex) { _logger.ErrorException("{0} failed in Supports for type {1}", ex, provider.GetType().Name, item.GetType().Name); return false; } }