Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion SFTPSync/SFTPSync.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ static async Task Main(string[] args)
{
await remoteSyncWorkers[0].DoneMakingFolders;
}
remoteSyncWorkers.Add(new RemoteSync(args[0], args[1], args[2], args[3], args[4], pattern, remoteSyncWorkers.Count == 0, director, null));
remoteSyncWorkers.Add(new RemoteSync(args[0], args[1], args[2], args[3], args[4], pattern, remoteSyncWorkers.Count == 0, director, null, false, remoteSyncWorkers.Count == 0));

Logger.LogInfo($"Started sync worker {remoteSyncWorkers.Count} for pattern {pattern}");
}
Expand Down
435 changes: 416 additions & 19 deletions SFTPSyncLib/RemoteSync.cs

Large diffs are not rendered by default.

162 changes: 159 additions & 3 deletions SFTPSyncLib/SyncDirector.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,20 +7,37 @@ public class SyncDirector
{
FileSystemWatcher _fsw;
List<(Regex, Action<FileSystemEventArgs>)> callbacks = new List<(Regex, Action<FileSystemEventArgs>)>();
readonly List<Action<FileSystemEventArgs>> directoryDeleteCallbacks = new List<Action<FileSystemEventArgs>>();
readonly List<Action<FileSystemEventArgs>> directoryCreateCallbacks = new List<Action<FileSystemEventArgs>>();
readonly List<Action<RenamedEventArgs>> directoryRenameCallbacks = new List<Action<RenamedEventArgs>>();
readonly HashSet<string> knownDirectories = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
readonly object directoryLock = new object();
readonly bool deleteEnabled;
bool _disposed;

public SyncDirector(string rootFolder)
public SyncDirector(string rootFolder, bool deleteEnabled = false)
{
_fsw = new FileSystemWatcher(rootFolder, "*.*")
this.deleteEnabled = deleteEnabled;
_fsw = new FileSystemWatcher(rootFolder, "*")
{
IncludeSubdirectories = true,
NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.FileName,
NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.FileName | NotifyFilters.DirectoryName,
// Max allowed size; helps reduce missed events during bursts.
InternalBufferSize = 64 * 1024
};

if (deleteEnabled)
{
SeedKnownDirectories(rootFolder);
}

_fsw.Created += Fsw_Created;
_fsw.Changed += Fsw_Changed;
_fsw.Renamed += Fsw_Renamed;
if (deleteEnabled)
{
_fsw.Deleted += Fsw_Deleted;
}
_fsw.Error += Fsw_Error;

_fsw.EnableRaisingEvents = true;
Expand All @@ -34,8 +51,36 @@ public void AddCallback(string match, Action<FileSystemEventArgs> handler)
callbacks.Add((new Regex(regexPattern, RegexOptions.IgnoreCase), handler));
}

public void AddDirectoryDeleteCallback(Action<FileSystemEventArgs> handler)
{
directoryDeleteCallbacks.Add(handler);
}

public void AddDirectoryCreateCallback(Action<FileSystemEventArgs> handler)
{
directoryCreateCallbacks.Add(handler);
}

public void AddDirectoryRenameCallback(Action<RenamedEventArgs> handler)
{
directoryRenameCallbacks.Add(handler);
}

private void Fsw_Created(object sender, FileSystemEventArgs e)
{
if (deleteEnabled)
{
TrackDirectoryIfPresent(e.FullPath);
}

if (Directory.Exists(e.FullPath))
{
foreach (var callback in directoryCreateCallbacks)
{
callback(e);
}
}

var name = Path.GetFileName(e.FullPath);
foreach (var (regex, callback) in callbacks)
{
Expand All @@ -60,6 +105,43 @@ private void Fsw_Changed(object sender, FileSystemEventArgs e)

private void Fsw_Renamed(object sender, RenamedEventArgs e)
{
if (deleteEnabled)
{
HandleRenameForDirectoryTracking(e.OldFullPath, e.FullPath);
}

if (Directory.Exists(e.FullPath))
{
foreach (var callback in directoryRenameCallbacks)
{
callback(e);
}
}

var name = Path.GetFileName(e.FullPath);
foreach (var (regex, callback) in callbacks)
{
if (regex.IsMatch(name))
{
callback(e);
}
}
}

private void Fsw_Deleted(object sender, FileSystemEventArgs e)
{
if (!deleteEnabled)
return;

if (TryRemoveKnownDirectory(e.FullPath))
{
foreach (var callback in directoryDeleteCallbacks)
{
callback(e);
}
return;
}

var name = Path.GetFileName(e.FullPath);
foreach (var (regex, callback) in callbacks)
{
Expand All @@ -74,5 +156,79 @@ private void Fsw_Error(object sender, ErrorEventArgs e)
{
Logger.LogError($"FileSystemWatcher error: {e.GetException()?.Message}");
}

public void Dispose()
{
if (_disposed)
return;

_disposed = true;
_fsw.EnableRaisingEvents = false;
_fsw.Dispose();
}

private void SeedKnownDirectories(string rootFolder)
{
try
{
var directories = Directory.EnumerateDirectories(rootFolder, "*", SearchOption.AllDirectories)
.Select(NormalizePath)
.ToList();

lock (directoryLock)
{
knownDirectories.Add(NormalizePath(rootFolder));
foreach (var dir in directories)
{
knownDirectories.Add(dir);
}
}
}
catch (Exception ex)
{
Logger.LogError($"Failed to seed directory tracking. Exception: {ex.Message}");
}
}

private void TrackDirectoryIfPresent(string path)
{
if (!Directory.Exists(path))
return;

var normalized = NormalizePath(path);
lock (directoryLock)
{
knownDirectories.Add(normalized);
}
}

private void HandleRenameForDirectoryTracking(string oldPath, string newPath)
{
var oldNormalized = NormalizePath(oldPath);
bool wasDirectory;
lock (directoryLock)
{
wasDirectory = knownDirectories.Remove(oldNormalized);
}

if (wasDirectory)
{
TrackDirectoryIfPresent(newPath);
}
}

private bool TryRemoveKnownDirectory(string path)
{
var normalized = NormalizePath(path);
lock (directoryLock)
{
return knownDirectories.Remove(normalized);
}
}

private static string NormalizePath(string path)
{
return Path.TrimEndingDirectorySeparator(Path.GetFullPath(path));
}
}
}
2 changes: 1 addition & 1 deletion SFTPSyncSetup/Product.wxs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
Id="*"
Name="SFTPSync"
Language="1033"
Version="1.6"
Version="1.7"
Manufacturer="Synergex International Corporation"
UpgradeCode="6000f870-b811-4e22-b80b-5b8956317d09">

Expand Down
2 changes: 1 addition & 1 deletion SFTPSyncSetup/SFTPSyncSetup.wixproj
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<ProductVersion>3.10</ProductVersion>
<ProjectGuid>5074cbcb-641b-4a9c-b3bc-8dd0b78810a6</ProjectGuid>
<SchemaVersion>2.0</SchemaVersion>
<OutputName>SFTPSync-1.6</OutputName>
<OutputName>SFTPSync-1.7</OutputName>
<OutputType>Package</OutputType>
<Name>SFTPSyncSetup</Name>
</PropertyGroup>
Expand Down
20 changes: 19 additions & 1 deletion SFTPSyncUI/AppSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,25 @@ public bool AccessVerified
}
}

// Support delted files and folders

private bool deleteEnabled = false;
public bool DeleteEnabled
{
get => deleteEnabled;
set
{
if (deleteEnabled != value)
{
deleteEnabled = value;
if (!initialLoadSettings)
{
SaveToFile();
}
}
}
}

//Local path

private string localPath = String.Empty;
Expand Down Expand Up @@ -331,6 +350,5 @@ public List<string> ExcludedDirectories
}
}
}

}
}
Loading