wasSharpNET

Subversion Repositories:
Compare Path: Rev
With Path: Rev
?path1? @ 1  →  ?path2? @ HEAD
/IO/FileSystemWatcher.cs
@@ -0,0 +1,73 @@
using System;
using System.IO;
using System.Runtime.Caching;
 
namespace wasSharpNET.IO
{
/// <summary>
/// Filesystem watcher that ensures events are not fired twice
/// </summary>
/// <remarks>derived from Ben Hall @ benhall.io</remarks>
public class FileSystemWatcher : IDisposable
{
public event FileSystemEventHandler FilesytemEvent;
private readonly CacheItemPolicy _cacheItemPolicy;
private readonly int _cacheTimeMilliseconds = 1000;
private readonly MemoryCache _memCache;
 
public FileSystemWatcher(string path, NotifyFilters notifyFilters, string filter)
{
_memCache = MemoryCache.Default;
 
var watcher = new System.IO.FileSystemWatcher
{
Path = path,
NotifyFilter = notifyFilters,
Filter = filter
};
 
_cacheItemPolicy = new CacheItemPolicy
{
RemovedCallback = OnRemovedFromCache
};
 
watcher.Changed += OnChanged;
watcher.EnableRaisingEvents = true;
}
 
public FileSystemWatcher(string path, NotifyFilters notifyFilters, string filter, int timeout) : this(path,
notifyFilters, filter)
{
_cacheTimeMilliseconds = timeout;
}
 
// Add file event to cache for CacheTimeMilliseconds
private void OnChanged(object source, FileSystemEventArgs e)
{
_cacheItemPolicy.AbsoluteExpiration =
DateTimeOffset.Now.AddMilliseconds(_cacheTimeMilliseconds);
 
// Only add if it is not there already (swallow others)
_memCache.AddOrGetExisting(e.Name, e, _cacheItemPolicy);
}
 
// Handle cache item expiring
private void OnRemovedFromCache(CacheEntryRemovedArguments args)
{
if (args.RemovedReason != CacheEntryRemovedReason.Expired) return;
 
// Now actually handle file event.
OnFileSystemEvent((FileSystemEventArgs)args.CacheItem.Value);
}
 
protected virtual void OnFileSystemEvent(FileSystemEventArgs e)
{
FilesytemEvent?.Invoke(this, e);
}
 
public void Dispose()
{
_memCache.Dispose();
}
}
}
/IO/SafeFileStream.cs
@@ -6,8 +6,6 @@
 
using System;
using System.IO;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;
using System.Threading;
 
namespace wasSharpNET.IO
@@ -22,7 +20,7 @@
 
public SafeFileStream(string path, FileMode mode, FileAccess access, FileShare share, uint milliscondsTimeout)
{
m_mutex = new Mutex(false, string.Format("Global\\{0}", path.Replace('\\', '/')));
m_mutex = new Mutex(false, $"Global\\{path.Replace('\\', '/')}");
m_path = path;
m_fileMode = mode;
m_fileAccess = access;
/IO/Utilities/IOExtensions.cs
@@ -0,0 +1,81 @@
///////////////////////////////////////////////////////////////////////////
// Copyright (C) Wizardry and Steamworks 2017 - License: GNU GPLv3 //
// Please see: http://www.gnu.org/licenses/gpl.html for legal details, //
// rights of fair usage, the disclaimer and warranty conditions. //
///////////////////////////////////////////////////////////////////////////
 
using System;
using System.Diagnostics;
using System.IO;
 
namespace wasSharpNET.IO.Utilities
{
public static class IOExtensions
{
/// <summary>
/// Attempt to obtain a filestream by polling a file till the handle becomes available.
/// </summary>
/// <param name="path">the path to the file</param>
/// <param name="mode">the file mode to use</param>
/// <param name="access">the level of access to the file</param>
/// <param name="share">the type of file share locking</param>
/// <param name="timeout">the timeout in milliseconds to fail opening the file</param>
/// <returns>a filestream if the file was opened successfully</returns>
public static FileStream GetWriteStream(string path, FileMode mode, FileAccess access, FileShare share,
int timeout)
{
var time = Stopwatch.StartNew();
while (time.ElapsedMilliseconds < timeout)
try
{
return new FileStream(path, mode, access, share);
}
catch (IOException e)
{
// access error
if (e.HResult != -2147024864)
throw;
}
 
throw new TimeoutException($"Failed to get a write handle to {path} within {timeout}ms.");
}
 
public static bool isRootedIn(this string path, string root)
{
// Path is empty and root is empty.
if (string.IsNullOrEmpty(path) && string.IsNullOrEmpty(root))
return true;
 
// Path is empty but the root path is not empty.
if (string.IsNullOrEmpty(path) && !string.IsNullOrEmpty(root))
return true;
 
// The supplied root path is empty.
if (string.IsNullOrEmpty(root))
return false;
 
// The path is empty and the root is not.
if (string.IsNullOrEmpty(path))
return true;
 
var p = new DirectoryInfo(path);
var r = new DirectoryInfo(root);
 
return string.Equals(p.Parent?.FullName, r.Parent?.FullName) || isRootedIn(p.Parent?.FullName, root);
}
 
public static void Empty(this string directory)
{
var dir = new DirectoryInfo(directory);
 
foreach (var fi in dir.GetFiles())
fi.Delete();
 
foreach (var di in dir.GetDirectories())
{
Empty(di.FullName);
di.Delete();
}
}
}
}