You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Zero/ZeroLevel/Services/FileSystem/PeriodicFileSystemWatcher.cs

236 lines
8.8 KiB

6 years ago
using System;
using System.Collections.Generic;
6 years ago
using System.Globalization;
using System.IO;
using System.Linq;
6 years ago
namespace ZeroLevel.Services.FileSystem
{
public sealed class PeriodicFileSystemWatcher :
IDisposable
{
private long _updateSourceTaskKey;
private readonly string _sourceFolder;
private readonly string _temporaryFolder;
private readonly TimeSpan _period;
5 years ago
private readonly Action<FileMeta> _callback;
private readonly HashSet<string> _extensions;
6 years ago
public event Action<int> OnStartMovingFilesToTemporary = delegate { };
public event Action<string, string> OnMovingFileToTemporary = delegate { };
public event Action OnCompleteMovingFilesToTemporary = delegate { };
private readonly bool _autoRemoveTempFileAfterCallback = false;
private readonly bool _useSubdirectories = false;
public PeriodicFileSystemWatcher(TimeSpan period, string watch_folder, string temp_folder, Action<FileMeta> callback
, IEnumerable<string> extensions = null
, bool removeTempFileAfterCallback = false
, bool useSubdirectories = false)
{
6 years ago
if (string.IsNullOrWhiteSpace(watch_folder))
{
throw new ArgumentNullException(nameof(watch_folder));
}
if (callback == null)
{
throw new ArgumentNullException(nameof(callback));
}
_extensions = new HashSet<string>(extensions?.Select(e => e.ToLowerInvariant()) ?? Enumerable.Empty<string>());
_useSubdirectories = useSubdirectories;
_autoRemoveTempFileAfterCallback = removeTempFileAfterCallback;
6 years ago
_callback = callback;
_sourceFolder = watch_folder;
_temporaryFolder = temp_folder;
_period = period;
if (Path.IsPathRooted(_temporaryFolder) == false)
6 years ago
{
_temporaryFolder = Path.Combine(Configuration.BaseDirectory, _temporaryFolder);
}
if (false == Directory.Exists(_temporaryFolder))
{
Directory.CreateDirectory(_temporaryFolder);
}
}
public void Start()
{
5 years ago
_updateSourceTaskKey = Sheduller.RemindEvery(_period, CheckSourceFolder);
6 years ago
}
public void Stop()
{
5 years ago
Sheduller.Remove(_updateSourceTaskKey);
6 years ago
}
5 years ago
private void CheckSourceFolder()
6 years ago
{
4 years ago
string[] files = null;
6 years ago
try
{
4 years ago
files = GetFilesFromSource();
}
catch (Exception ex)
{
Log.SystemError(ex, $"[PeriodicFileSystemWatcher.CheckSourceFolder] Failed to process input directory '{_sourceFolder}'");
}
if (files == null || files.Length == 0)
{
return;
}
3 years ago
foreach (Action<int> startFilesMoveingCallback in OnStartMovingFilesToTemporary.GetInvocationList())
startFilesMoveingCallback.BeginInvoke(files.Length, null, null);
4 years ago
foreach (var file in files)
{
if (!File.Exists(file))
{
Log.Warning($"[PeriodicFileSystemWatcher.CheckSourceFolder] Find '{file}' does not exists");
continue;
}
Log.Debug($"[PeriodicFileSystemWatcher.CheckSourceFolder] Find new file {file}");
if (FSUtils.IsFileLocked(new FileInfo(file)))
{
continue;
}
string tempFile;
4 years ago
try
6 years ago
{
tempFile = MoveToTemporary(file);
if (string.IsNullOrWhiteSpace(tempFile))
6 years ago
{
Log.SystemWarning($"[PeriodicFileSystemWatcher.CheckSourceFolder] Failed to move file '{file}' to temporary directory '{_temporaryFolder}'. Without system error!");
4 years ago
continue;
}
3 years ago
foreach (Action<string,string> moveFileToTempCallback in OnMovingFileToTemporary.GetInvocationList())
moveFileToTempCallback.BeginInvoke(file, tempFile, null, null);
}
catch (Exception ex)
{
Log.SystemError(ex, $"[PeriodicFileSystemWatcher.CheckSourceFolder] Failed to attempt to move file '{file}' to temporary directory '{_temporaryFolder}'");
continue;
}
Log.Debug($"[PeriodicFileSystemWatcher.CheckSourceFolder] Handle file {file}");
try
{
3 years ago
_callback.Invoke(new FileMeta(Path.GetFileName(file), tempFile));
}
catch (Exception ex)
{
Log.SystemError(ex, $"[PeriodicFileSystemWatcher.CheckSourceFolder] Fault callback for file '{tempFile}'");
}
try
{
4 years ago
if (_autoRemoveTempFileAfterCallback)
{
File.Delete(tempFile);
6 years ago
}
}
4 years ago
catch (Exception ex)
{
Log.SystemError(ex, $"[PeriodicFileSystemWatcher.CheckSourceFolder] Fault delete file {tempFile}");
4 years ago
}
6 years ago
}
3 years ago
foreach (Action completeFileMovingCallback in OnCompleteMovingFilesToTemporary.GetInvocationList())
completeFileMovingCallback.BeginInvoke(null, null);
6 years ago
}
/// <summary>
/// Moving a file to a temporary directory
6 years ago
/// </summary>
4 years ago
private string MoveToTemporary(string from)
6 years ago
{
if (from == null)
{
throw new ArgumentException("from");
}
string tempFile = Path.Combine(_temporaryFolder, Path.GetFileName(from));
if (File.Exists(tempFile))
{
tempFile = TrySolveCollision(tempFile);
}
File.Copy(from, tempFile, false);
4 years ago
if (File.Exists(tempFile))
{
File.Delete(from);
return tempFile;
}
return null;
6 years ago
}
6 years ago
/// <summary>
/// Resolving collisions in filenames in the temporary directory
6 years ago
/// </summary>
private static string TrySolveCollision(string file)
{
if (file == null)
{
throw new ArgumentNullException("file");
}
string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(file);
string extension = Path.GetExtension(file);
string directoryName = Path.GetDirectoryName(file);
if (directoryName != null)
{
int num = 0;
do
{
num++;
}
while (File.Exists(Path.Combine(directoryName,
fileNameWithoutExtension + "_" +
num.ToString(CultureInfo.CurrentCulture) +
extension)));
return Path.Combine(directoryName,
fileNameWithoutExtension + "_" +
num.ToString(CultureInfo.CurrentCulture) +
extension);
}
throw new ArgumentException("folder");
}
6 years ago
/// <summary>
/// Getting a list of files from the input directory
6 years ago
/// </summary>
4 years ago
private string[] GetFilesFromSource()
6 years ago
{
4 years ago
string[] files;
if (_extensions.Count > 0)
{
4 years ago
files = Directory.GetFiles(_sourceFolder, "*.*", _useSubdirectories ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly)
?.Where(f => _extensions.Contains(Path.GetExtension(f).ToLowerInvariant()))
?.ToArray();
}
else
{
4 years ago
files = Directory.GetFiles(_sourceFolder, "*.*", _useSubdirectories ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly);
}
if (files != null)
{
Array.Sort<string>(files, FileNameSortCompare);
}
4 years ago
return files;
6 years ago
}
6 years ago
/// <summary>
/// File Name Comparison
6 years ago
/// </summary>
private static int FileNameSortCompare(string x, string y)
{
int num;
int num2;
if (int.TryParse(Path.GetFileNameWithoutExtension(x), out num) &&
int.TryParse(Path.GetFileNameWithoutExtension(y), out num2))
{
return num - num2;
}
return string.Compare(x, y, StringComparison.InvariantCultureIgnoreCase);
}
public void Dispose()
{
Sheduller.Remove(_updateSourceTaskKey);
}
}
}

Powered by TurnKey Linux.