FileRemover
using Polly;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
namespace Relativity.Transfer
{
internal class FileRemover : IFileRemover
{
private const string _UNAVAILABLE_FILE_MESSAGE_PATTERN = "The process cannot access the file '(.+)' because it is being used by another process";
private readonly ITransferLog log;
private readonly IFileSystemService fileSystemService;
private readonly Policy policy;
public FileRemover(ITransferLog log, IFileSystemService fileSystemService = null, Policy policy = null)
{
if (log == null)
throw new ArgumentNullException("log");
this.log = log;
this.fileSystemService = (fileSystemService ?? new FileSystemService());
this.policy = (policy ?? CreateDeleteFilePolicy(LogPolicyException));
}
public void RemoveFile(string path)
{
policy.Execute((Action)delegate {
fileSystemService.DeleteFile(path);
});
}
private Policy CreateDeleteFilePolicy(Action<Exception, TimeSpan, int, Context> onRetry)
{
return RetrySyntax.WaitAndRetry(Policy.Handle<IOException>(), 3, (Func<int, TimeSpan>)((int retryNumber) => TimeSpan.FromSeconds(Math.Pow(3, (double)retryNumber))), onRetry);
}
private void LogPolicyException(Exception exception, TimeSpan span, int retry, Context context)
{
if (IsCannotAccessFileException(exception)) {
List<object> list = new List<object>();
string text = UnavailableFilePath(exception.Message);
StringBuilder stringBuilder = new StringBuilder("Error deleting file '{Path}', retry #{Retry}.");
list.Add(text);
list.Add(retry);
IList<Process> processesUsingFiles = InUseDetection.GetProcessesUsingFiles(new string[1] {
text
});
stringBuilder.Append(" There are {ProcessCount} presses using it.");
list.Add(processesUsingFiles.Count);
for (int i = 0; i < processesUsingFiles.Count; i++) {
Process process = processesUsingFiles[i];
stringBuilder.Append(" Process #{ProcessNumber}:");
list.Add(i + 1);
stringBuilder.Append(" Name: {ProcessName}");
list.Add(process.ProcessName);
stringBuilder.Append(", Id: {ProcessId}");
list.Add(process.Id);
stringBuilder.Append(", Start time (UTC): {ProcessStartTime}");
list.Add(process.StartTime.ToUniversalTime());
stringBuilder.Append(", User name: {ProcessUser}");
list.Add(process.StartInfo.UserName);
stringBuilder.Append(", Process file: {ProcessFile}");
try {
list.Add(process.MainModule?.FileName);
} catch (Win32Exception) {
list.Add("INFORMATION UNAVAILABLE");
}
stringBuilder.Append(".");
}
log.LogError(stringBuilder.ToString(), list);
}
}
private static string (string exceptionMessage)
{
return Regex.Match(exceptionMessage, "The process cannot access the file '(.+)' because it is being used by another process").Groups[1].Value;
}
private static bool IsCannotAccessFileException(Exception exception)
{
if (exception != null && exception.Message != null)
return Regex.IsMatch(exception.Message, "The process cannot access the file '(.+)' because it is being used by another process");
return false;
}
}
}