Merge pull request #7321 from Bond-009/warn61

This commit is contained in:
Cody Robibero 2022-02-16 20:47:22 -07:00 committed by GitHub
commit 9930efec22
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
27 changed files with 194 additions and 93 deletions

View File

@ -150,7 +150,7 @@ namespace Emby.Server.Implementations
/// <param name="loggerFactory">Instance of the <see cref="ILoggerFactory"/> interface.</param>
/// <param name="options">Instance of the <see cref="IStartupOptions"/> interface.</param>
/// <param name="startupConfig">The <see cref="IConfiguration" /> interface.</param>
public ApplicationHost(
protected ApplicationHost(
IServerApplicationPaths applicationPaths,
ILoggerFactory loggerFactory,
IStartupOptions options,

View File

@ -39,7 +39,7 @@ namespace Emby.Server.Implementations.Channels
/// <summary>
/// The LiveTV channel manager.
/// </summary>
public class ChannelManager : IChannelManager
public class ChannelManager : IChannelManager, IDisposable
{
private readonly IUserManager _userManager;
private readonly IUserDataManager _userDataManager;
@ -52,6 +52,7 @@ namespace Emby.Server.Implementations.Channels
private readonly IMemoryCache _memoryCache;
private readonly SemaphoreSlim _resourcePool = new SemaphoreSlim(1, 1);
private readonly JsonSerializerOptions _jsonOptions = JsonDefaults.Options;
private bool _disposed = false;
/// <summary>
/// Initializes a new instance of the <see cref="ChannelManager"/> class.
@ -1213,5 +1214,31 @@ namespace Emby.Server.Implementations.Channels
return result;
}
/// <inheritdoc />
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
/// <summary>
/// Releases unmanaged and optionally managed resources.
/// </summary>
/// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
protected virtual void Dispose(bool disposing)
{
if (_disposed)
{
return;
}
if (disposing)
{
_resourcePool?.Dispose();
}
_disposed = true;
}
}
}

View File

@ -62,7 +62,7 @@ namespace Emby.Server.Implementations.Channels
public string Key => "RefreshInternetChannels";
/// <inheritdoc />
public async Task Execute(CancellationToken cancellationToken, IProgress<double> progress)
public async Task ExecuteAsync(IProgress<double> progress, CancellationToken cancellationToken)
{
var manager = (ChannelManager)_channelManager;

View File

@ -390,6 +390,7 @@ namespace Emby.Server.Implementations.Data
return userData;
}
#pragma warning disable CA2215
/// <inheritdoc/>
/// <remarks>
/// There is nothing to dispose here since <see cref="BaseSqliteRepository.WriteLock"/> and
@ -398,6 +399,10 @@ namespace Emby.Server.Implementations.Data
/// </remarks>
protected override void Dispose(bool dispose)
{
// The write lock and connection for the item repository are shared with the user data repository
// since they point to the same database. The item repo has responsibility for disposing these two objects,
// so the user data repo should not attempt to dispose them as well
}
#pragma warning restore CA2215
}
}

View File

@ -22,7 +22,7 @@ namespace Emby.Server.Implementations.Images
{
private readonly ILibraryManager _libraryManager;
public BaseFolderImageProvider(IFileSystem fileSystem, IProviderManager providerManager, IApplicationPaths applicationPaths, IImageProcessor imageProcessor, ILibraryManager libraryManager)
protected BaseFolderImageProvider(IFileSystem fileSystem, IProviderManager providerManager, IApplicationPaths applicationPaths, IImageProcessor imageProcessor, ILibraryManager libraryManager)
: base(fileSystem, providerManager, applicationPaths, imageProcessor)
{
_libraryManager = libraryManager;

View File

@ -1007,14 +1007,8 @@ namespace Emby.Server.Implementations.Library
return GetNewItemIdInternal(path, typeof(T), forceCaseInsensitiveId);
}
/// <summary>
/// Validate and refresh the People sub-set of the IBN.
/// The items are stored in the db but not loaded into memory until actually requested by an operation.
/// </summary>
/// <param name="cancellationToken">The cancellation token.</param>
/// <param name="progress">The progress.</param>
/// <returns>Task.</returns>
public Task ValidatePeople(CancellationToken cancellationToken, IProgress<double> progress)
/// <inheritdoc />
public Task ValidatePeopleAsync(IProgress<double> progress, CancellationToken cancellationToken)
{
// Ensure the location is available.
Directory.CreateDirectory(_configurationManager.ApplicationPaths.PeoplePath);

View File

@ -24,7 +24,7 @@ using Microsoft.Extensions.Logging;
namespace Emby.Server.Implementations.LiveTv.EmbyTV
{
public class EncodedRecorder : IRecorder
public class EncodedRecorder : IRecorder, IDisposable
{
private readonly ILogger _logger;
private readonly IMediaEncoder _mediaEncoder;
@ -36,6 +36,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
private Stream _logFileStream;
private string _targetPath;
private Process _process;
private bool _disposed = false;
public EncodedRecorder(
ILogger logger,
@ -323,5 +324,35 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
_logger.LogError(ex, "Error reading ffmpeg recording log");
}
}
/// <inheritdoc />
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
/// <summary>
/// Releases unmanaged and optionally managed resources.
/// </summary>
/// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
protected virtual void Dispose(bool disposing)
{
if (_disposed)
{
return;
}
if (disposing)
{
_logFileStream?.Dispose();
_process?.Dispose();
}
_logFileStream = null;
_process = null;
_disposed = true;
}
}
}

View File

@ -28,7 +28,7 @@ using Microsoft.Extensions.Logging;
namespace Emby.Server.Implementations.LiveTv.Listings
{
public class SchedulesDirect : IListingsProvider
public class SchedulesDirect : IListingsProvider, IDisposable
{
private const string ApiUrl = "https://json.schedulesdirect.org/20141201";
@ -39,6 +39,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings
private readonly ConcurrentDictionary<string, NameValuePair> _tokens = new ConcurrentDictionary<string, NameValuePair>();
private readonly JsonSerializerOptions _jsonOptions = JsonDefaults.Options;
private DateTime _lastErrorResponse;
private bool _disposed = false;
public SchedulesDirect(
ILogger<SchedulesDirect> logger,
@ -58,8 +59,8 @@ namespace Emby.Server.Implementations.LiveTv.Listings
{
var dates = new List<string>();
var start = new List<DateTime> { startDateUtc, startDateUtc.ToLocalTime() }.Min().Date;
var end = new List<DateTime> { endDateUtc, endDateUtc.ToLocalTime() }.Max().Date;
var start = new[] { startDateUtc, startDateUtc.ToLocalTime() }.Min().Date;
var end = new[] { endDateUtc, endDateUtc.ToLocalTime() }.Max().Date;
while (start <= end)
{
@ -822,5 +823,31 @@ namespace Emby.Server.Implementations.LiveTv.Listings
return list;
}
/// <inheritdoc />
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
/// <summary>
/// Releases unmanaged and optionally managed resources.
/// </summary>
/// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
protected virtual void Dispose(bool disposing)
{
if (_disposed)
{
return;
}
if (disposing)
{
_tokenSemaphore?.Dispose();
}
_disposed = true;
}
}
}

View File

@ -50,7 +50,7 @@ namespace Emby.Server.Implementations.LiveTv
public string Key => "RefreshGuide";
/// <inheritdoc />
public Task Execute(CancellationToken cancellationToken, IProgress<double> progress)
public Task ExecuteAsync(IProgress<double> progress, CancellationToken cancellationToken)
{
var manager = (LiveTvManager)_liveTvManager;

View File

@ -414,7 +414,7 @@ namespace Emby.Server.Implementations.ScheduledTasks
CurrentCancellationTokenSource.CancelAfter(TimeSpan.FromTicks(options.MaxRuntimeTicks.Value));
}
await ScheduledTask.Execute(CurrentCancellationTokenSource.Token, progress).ConfigureAwait(false);
await ScheduledTask.ExecuteAsync(progress, CurrentCancellationTokenSource.Token).ConfigureAwait(false);
status = TaskCompletionStatus.Completed;
}
@ -757,6 +757,10 @@ namespace Emby.Server.Implementations.ScheduledTasks
var trigger = triggerInfo.Item2;
trigger.Triggered -= OnTriggerTriggered;
trigger.Stop();
if (trigger is IDisposable disposable)
{
disposable.Dispose();
}
}
}
}

View File

@ -88,13 +88,8 @@ namespace Emby.Server.Implementations.ScheduledTasks.Tasks
};
}
/// <summary>
/// Returns the task to be executed.
/// </summary>
/// <param name="cancellationToken">The cancellation token.</param>
/// <param name="progress">The progress.</param>
/// <returns>Task.</returns>
public async Task Execute(CancellationToken cancellationToken, IProgress<double> progress)
/// <inheritdoc />
public async Task ExecuteAsync(IProgress<double> progress, CancellationToken cancellationToken)
{
var videos = _libraryManager.GetItemList(new InternalItemsQuery
{

View File

@ -57,12 +57,12 @@ namespace Emby.Server.Implementations.ScheduledTasks.Tasks
public bool IsLogged => true;
/// <inheritdoc />
public Task Execute(CancellationToken cancellationToken, IProgress<double> progress)
public Task ExecuteAsync(IProgress<double> progress, CancellationToken cancellationToken)
{
var retentionDays = _serverConfigurationManager.Configuration.ActivityLogRetentionDays;
if (!retentionDays.HasValue || retentionDays < 0)
{
throw new Exception($"Activity Log Retention days must be at least 0. Currently: {retentionDays}");
throw new InvalidOperationException($"Activity Log Retention days must be at least 0. Currently: {retentionDays}");
}
var startDate = DateTime.UtcNow.AddDays(-retentionDays.Value);

View File

@ -79,19 +79,14 @@ namespace Emby.Server.Implementations.ScheduledTasks.Tasks
};
}
/// <summary>
/// Returns the task to be executed.
/// </summary>
/// <param name="cancellationToken">The cancellation token.</param>
/// <param name="progress">The progress.</param>
/// <returns>Task.</returns>
public Task Execute(CancellationToken cancellationToken, IProgress<double> progress)
/// <inheritdoc />
public Task ExecuteAsync(IProgress<double> progress, CancellationToken cancellationToken)
{
var minDateModified = DateTime.UtcNow.AddDays(-30);
try
{
DeleteCacheFilesFromDirectory(cancellationToken, _applicationPaths.CachePath, minDateModified, progress);
DeleteCacheFilesFromDirectory(_applicationPaths.CachePath, minDateModified, progress, cancellationToken);
}
catch (DirectoryNotFoundException)
{
@ -104,7 +99,7 @@ namespace Emby.Server.Implementations.ScheduledTasks.Tasks
try
{
DeleteCacheFilesFromDirectory(cancellationToken, _applicationPaths.TempDirectory, minDateModified, progress);
DeleteCacheFilesFromDirectory(_applicationPaths.TempDirectory, minDateModified, progress, cancellationToken);
}
catch (DirectoryNotFoundException)
{
@ -117,11 +112,11 @@ namespace Emby.Server.Implementations.ScheduledTasks.Tasks
/// <summary>
/// Deletes the cache files from directory with a last write time less than a given date.
/// </summary>
/// <param name="cancellationToken">The task cancellation token.</param>
/// <param name="directory">The directory.</param>
/// <param name="minDateModified">The min date modified.</param>
/// <param name="progress">The progress.</param>
private void DeleteCacheFilesFromDirectory(CancellationToken cancellationToken, string directory, DateTime minDateModified, IProgress<double> progress)
/// <param name="cancellationToken">The task cancellation token.</param>
private void DeleteCacheFilesFromDirectory(string directory, DateTime minDateModified, IProgress<double> progress, CancellationToken cancellationToken)
{
var filesToDelete = _fileSystem.GetFiles(directory, true)
.Where(f => _fileSystem.GetLastWriteTimeUtc(f) < minDateModified)

View File

@ -69,13 +69,8 @@ namespace Emby.Server.Implementations.ScheduledTasks.Tasks
};
}
/// <summary>
/// Returns the task to be executed.
/// </summary>
/// <param name="cancellationToken">The cancellation token.</param>
/// <param name="progress">The progress.</param>
/// <returns>Task.</returns>
public Task Execute(CancellationToken cancellationToken, IProgress<double> progress)
/// <inheritdoc />
public Task ExecuteAsync(IProgress<double> progress, CancellationToken cancellationToken)
{
// Delete log files more than n days old
var minDateModified = DateTime.UtcNow.AddDays(-_configurationManager.CommonConfiguration.LogFileRetentionDays);

View File

@ -78,18 +78,13 @@ namespace Emby.Server.Implementations.ScheduledTasks.Tasks
};
}
/// <summary>
/// Returns the task to be executed.
/// </summary>
/// <param name="cancellationToken">The cancellation token.</param>
/// <param name="progress">The progress.</param>
/// <returns>Task.</returns>
public Task Execute(CancellationToken cancellationToken, IProgress<double> progress)
/// <inheritdoc />
public Task ExecuteAsync(IProgress<double> progress, CancellationToken cancellationToken)
{
var minDateModified = DateTime.UtcNow.AddDays(-1);
progress.Report(50);
DeleteTempFilesFromDirectory(cancellationToken, _configurationManager.GetTranscodePath(), minDateModified, progress);
DeleteTempFilesFromDirectory(_configurationManager.GetTranscodePath(), minDateModified, progress, cancellationToken);
return Task.CompletedTask;
}
@ -97,11 +92,11 @@ namespace Emby.Server.Implementations.ScheduledTasks.Tasks
/// <summary>
/// Deletes the transcoded temp files from directory with a last write time less than a given date.
/// </summary>
/// <param name="cancellationToken">The task cancellation token.</param>
/// <param name="directory">The directory.</param>
/// <param name="minDateModified">The min date modified.</param>
/// <param name="progress">The progress.</param>
private void DeleteTempFilesFromDirectory(CancellationToken cancellationToken, string directory, DateTime minDateModified, IProgress<double> progress)
/// <param name="cancellationToken">The task cancellation token.</param>
private void DeleteTempFilesFromDirectory(string directory, DateTime minDateModified, IProgress<double> progress, CancellationToken cancellationToken)
{
var filesToDelete = _fileSystem.GetFiles(directory, true)
.Where(f => _fileSystem.GetLastWriteTimeUtc(f) < minDateModified)

View File

@ -69,13 +69,8 @@ namespace Emby.Server.Implementations.ScheduledTasks.Tasks
};
}
/// <summary>
/// Returns the task to be executed.
/// </summary>
/// <param name="cancellationToken">The cancellation token.</param>
/// <param name="progress">The progress.</param>
/// <returns>Task.</returns>
public Task Execute(CancellationToken cancellationToken, IProgress<double> progress)
/// <inheritdoc />
public Task ExecuteAsync(IProgress<double> progress, CancellationToken cancellationToken)
{
_logger.LogInformation("Optimizing and vacuuming jellyfin.db...");

View File

@ -62,15 +62,10 @@ namespace Emby.Server.Implementations.ScheduledTasks.Tasks
};
}
/// <summary>
/// Returns the task to be executed.
/// </summary>
/// <param name="cancellationToken">The cancellation token.</param>
/// <param name="progress">The progress.</param>
/// <returns>Task.</returns>
public Task Execute(CancellationToken cancellationToken, IProgress<double> progress)
/// <inheritdoc />
public Task ExecuteAsync(IProgress<double> progress, CancellationToken cancellationToken)
{
return _libraryManager.ValidatePeople(cancellationToken, progress);
return _libraryManager.ValidatePeopleAsync(progress, cancellationToken);
}
}
}

View File

@ -68,13 +68,8 @@ namespace Emby.Server.Implementations.ScheduledTasks.Tasks
yield return new TaskTriggerInfo { Type = TaskTriggerInfo.TriggerInterval, IntervalTicks = TimeSpan.FromHours(24).Ticks };
}
/// <summary>
/// Update installed plugins.
/// </summary>
/// <param name="cancellationToken">The cancellation token.</param>
/// <param name="progress">The progress.</param>
/// <returns><see cref="Task" />.</returns>
public async Task Execute(CancellationToken cancellationToken, IProgress<double> progress)
/// <inheritdoc />
public async Task ExecuteAsync(IProgress<double> progress, CancellationToken cancellationToken)
{
progress.Report(0);

View File

@ -58,13 +58,8 @@ namespace Emby.Server.Implementations.ScheduledTasks.Tasks
};
}
/// <summary>
/// Executes the internal.
/// </summary>
/// <param name="cancellationToken">The cancellation token.</param>
/// <param name="progress">The progress.</param>
/// <returns>Task.</returns>
public Task Execute(CancellationToken cancellationToken, IProgress<double> progress)
/// <inheritdoc />
public Task ExecuteAsync(IProgress<double> progress, CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();

View File

@ -8,10 +8,11 @@ namespace Emby.Server.Implementations.ScheduledTasks.Triggers
/// <summary>
/// Represents a task trigger that fires everyday.
/// </summary>
public sealed class DailyTrigger : ITaskTrigger
public sealed class DailyTrigger : ITaskTrigger, IDisposable
{
private readonly TimeSpan _timeOfDay;
private Timer? _timer;
private bool _disposed = false;
/// <summary>
/// Initializes a new instance of the <see cref="DailyTrigger"/> class.
@ -71,6 +72,7 @@ namespace Emby.Server.Implementations.ScheduledTasks.Triggers
private void DisposeTimer()
{
_timer?.Dispose();
_timer = null;
}
/// <summary>
@ -80,5 +82,18 @@ namespace Emby.Server.Implementations.ScheduledTasks.Triggers
{
Triggered?.Invoke(this, EventArgs.Empty);
}
/// <inheritdoc />
public void Dispose()
{
if (_disposed)
{
return;
}
DisposeTimer();
_disposed = true;
}
}
}

View File

@ -9,11 +9,12 @@ namespace Emby.Server.Implementations.ScheduledTasks.Triggers
/// <summary>
/// Represents a task trigger that runs repeatedly on an interval.
/// </summary>
public sealed class IntervalTrigger : ITaskTrigger
public sealed class IntervalTrigger : ITaskTrigger, IDisposable
{
private readonly TimeSpan _interval;
private DateTime _lastStartDate;
private Timer? _timer;
private bool _disposed = false;
/// <summary>
/// Initializes a new instance of the <see cref="IntervalTrigger"/> class.
@ -89,6 +90,7 @@ namespace Emby.Server.Implementations.ScheduledTasks.Triggers
private void DisposeTimer()
{
_timer?.Dispose();
_timer = null;
}
/// <summary>
@ -104,5 +106,18 @@ namespace Emby.Server.Implementations.ScheduledTasks.Triggers
Triggered(this, EventArgs.Empty);
}
}
/// <inheritdoc />
public void Dispose()
{
if (_disposed)
{
return;
}
DisposeTimer();
_disposed = true;
}
}
}

View File

@ -8,11 +8,12 @@ namespace Emby.Server.Implementations.ScheduledTasks.Triggers
/// <summary>
/// Represents a task trigger that fires on a weekly basis.
/// </summary>
public sealed class WeeklyTrigger : ITaskTrigger
public sealed class WeeklyTrigger : ITaskTrigger, IDisposable
{
private readonly TimeSpan _timeOfDay;
private readonly DayOfWeek _dayOfWeek;
private Timer? _timer;
private bool _disposed = false;
/// <summary>
/// Initializes a new instance of the <see cref="WeeklyTrigger"/> class.
@ -94,6 +95,7 @@ namespace Emby.Server.Implementations.ScheduledTasks.Triggers
private void DisposeTimer()
{
_timer?.Dispose();
_timer = null;
}
/// <summary>
@ -103,5 +105,18 @@ namespace Emby.Server.Implementations.ScheduledTasks.Triggers
{
Triggered?.Invoke(this, EventArgs.Empty);
}
/// <inheritdoc />
public void Dispose()
{
if (_disposed)
{
return;
}
DisposeTimer();
_disposed = true;
}
}
}

View File

@ -138,10 +138,10 @@ namespace MediaBrowser.Controller.Library
/// Validate and refresh the People sub-set of the IBN.
/// The items are stored in the db but not loaded into memory until actually requested by an operation.
/// </summary>
/// <param name="cancellationToken">The cancellation token.</param>
/// <param name="progress">The progress.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task.</returns>
Task ValidatePeople(CancellationToken cancellationToken, IProgress<double> progress);
Task ValidatePeopleAsync(IProgress<double> progress, CancellationToken cancellationToken);
/// <summary>
/// Reloads the root media folder.

View File

@ -36,10 +36,10 @@ namespace MediaBrowser.Model.Tasks
/// <summary>
/// Executes the task.
/// </summary>
/// <param name="cancellationToken">The cancellation token.</param>
/// <param name="progress">The progress.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task.</returns>
Task Execute(CancellationToken cancellationToken, IProgress<double> progress);
Task ExecuteAsync(IProgress<double> progress, CancellationToken cancellationToken);
/// <summary>
/// Gets the default triggers that define when the task will run.

View File

@ -63,7 +63,8 @@ namespace MediaBrowser.Providers.MediaInfo
return _config.GetConfiguration<SubtitleOptions>("subtitles");
}
public async Task Execute(CancellationToken cancellationToken, IProgress<double> progress)
/// <inheritdoc />
public async Task ExecuteAsync(IProgress<double> progress, CancellationToken cancellationToken)
{
var options = GetOptions();
@ -210,6 +211,7 @@ namespace MediaBrowser.Providers.MediaInfo
return true;
}
/// <inheritdoc />
public IEnumerable<TaskTriggerInfo> GetDefaultTriggers()
{
return new[]

View File

@ -57,6 +57,10 @@
</Rules>
<Rules AnalyzerId="Microsoft.CodeAnalysis.NetAnalyzers" RuleNamespace="Microsoft.Design">
<!-- error on CA1001: Types that own disposable fields should be disposable -->
<Rule Id="CA1001" Action="Error" />
<!-- error on CA1012: Abstract types should not have public constructors -->
<Rule Id="CA1012" Action="Error" />
<!-- error on CA1063: Implement IDisposable correctly -->
<Rule Id="CA1063" Action="Error" />
<!-- error on CA1305: Specify IFormatProvider -->
@ -80,6 +84,8 @@
<!-- error on CA2016: Forward the CancellationToken parameter to methods that take one
or pass in 'CancellationToken.None' explicitly to indicate intentionally not propagating the token -->
<Rule Id="CA2016" Action="Error" />
<!-- error on CA2215: Dispose methods should call base class dispose -->
<Rule Id="CA2215" Action="Error" />
<!-- error on CA2254: Template should be a static expression -->
<Rule Id="CA2254" Action="Error" />

View File

@ -51,7 +51,7 @@ public class KeyframeExtractionScheduledTask : IScheduledTask
public string Category => _localizationManager.GetLocalizedString("TasksLibraryCategory");
/// <inheritdoc />
public Task Execute(CancellationToken cancellationToken, IProgress<double> progress)
public Task ExecuteAsync(IProgress<double> progress, CancellationToken cancellationToken)
{
var query = new InternalItemsQuery
{