Skip to content

Commit 5aa0134

Browse files
committed
WIP: Getting real-time sync working again.
1 parent 02d0318 commit 5aa0134

3 files changed

Lines changed: 113 additions & 67 deletions

File tree

SFTPSyncLib/RemoteSync.cs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,8 @@ public RemoteSync(string host, string username, string password,
3333
_username = username;
3434
_password = password;
3535
_searchPattern = searchPattern;
36-
_localRootDirectory = Path.GetFullPath(localRootDirectory)
37-
.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar);
36+
_localRootDirectory = Path.TrimEndingDirectorySeparator(
37+
Path.GetFullPath(localRootDirectory));
3838
_remoteRootDirectory = remoteRootDirectory.TrimEnd('/', '\\');
3939
_director = director;
4040
_excludedFolders = excludedFolders ?? new List<string>();
@@ -63,8 +63,8 @@ public RemoteSync(string host, string username, string password,
6363
_username = username;
6464
_password = password;
6565
_searchPattern = searchPattern;
66-
_localRootDirectory = Path.GetFullPath(localRootDirectory)
67-
.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar);
66+
_localRootDirectory = Path.TrimEndingDirectorySeparator(
67+
Path.GetFullPath(localRootDirectory));
6868
_remoteRootDirectory = remoteRootDirectory.TrimEnd('/', '\\');
6969
_director = director;
7070
_excludedFolders = excludedFolders ?? new List<string>();
@@ -197,7 +197,7 @@ public static Task<IEnumerable<FileInfo>> SyncDirectoryAsync(SftpClient sftp, st
197197
{
198198
if (new DirectoryInfo(sourcePath).EnumerateFiles(searchPattern, SearchOption.TopDirectoryOnly).Any())
199199
{
200-
Logger.LogInfo($"Sync started for {sourcePath}\\{searchPattern} -> {destinationPath}");
200+
Logger.LogInfo($"Sync started for {sourcePath}\\{searchPattern}");
201201

202202
return Task<IEnumerable<FileInfo>>.Factory.FromAsync(sftp.BeginSynchronizeDirectories,
203203
sftp.EndSynchronizeDirectories, sourcePath,
@@ -339,6 +339,7 @@ private static async Task CreateDirectoriesInternal(
339339
var directoryName = item.Split(Path.DirectorySeparatorChar).Last();
340340
if (!remoteDirectories.ContainsKey(directoryName))
341341
{
342+
Logger.LogInfo($"Creating remote directory {remotePath}{directoryName}");
342343
sftp.CreateDirectory(remotePath + "/" + directoryName);
343344
}
344345
await CreateDirectoriesInternal(sftp, localRootDirectory, localPath + "\\" + directoryName, remotePath + "/" + directoryName, excludedFolders);

SFTPSyncLib/SyncDirector.cs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,10 @@ public SyncDirector(string rootFolder)
2828

2929
private void Fsw_Renamed(object sender, RenamedEventArgs e)
3030
{
31+
var name = Path.GetFileName(e.FullPath);
3132
foreach (var (regex, callback) in callbacks)
3233
{
33-
if (regex.IsMatch(e.FullPath))
34+
if (regex.IsMatch(name))
3435
{
3536
callback(e);
3637
}
@@ -39,9 +40,10 @@ private void Fsw_Renamed(object sender, RenamedEventArgs e)
3940

4041
private void Fsw_Created(object sender, FileSystemEventArgs e)
4142
{
43+
var name = Path.GetFileName(e.FullPath);
4244
foreach (var (regex, callback) in callbacks)
4345
{
44-
if (regex.IsMatch(e.FullPath))
46+
if (regex.IsMatch(name))
4547
{
4648
callback(e);
4749
}
@@ -58,9 +60,10 @@ public void AddCallback(string match, Action<FileSystemEventArgs> handler)
5860

5961
private void Fsw_Changed(object sender, FileSystemEventArgs e)
6062
{
63+
var name = Path.GetFileName(e.FullPath);
6164
foreach (var (regex, callback) in callbacks)
6265
{
63-
if (regex.IsMatch(e.FullPath))
66+
if (regex.IsMatch(name))
6467
{
6568
callback(e);
6669
}

SFTPSyncUI/SFTPSyncUI.cs

Lines changed: 101 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -210,76 +210,118 @@ public static async void StartSync(Action<string> loggerAction)
210210
Logger.LogInfo("Starting sync workers...");
211211
mainForm?.SetStatusBarText("Performing initial sync...");
212212

213-
var director = new SyncDirector(settings.LocalPath);
214-
215-
var patterns = settings.LocalSearchPattern
216-
.Split(';', StringSplitOptions.RemoveEmptyEntries)
217-
.Select(pattern => pattern.Trim())
218-
.Where(pattern => pattern.Length > 0)
219-
.ToArray();
220-
221-
if (patterns.Length == 0)
213+
var capturedSettings = settings;
214+
var capturedMainForm = mainForm;
215+
var setStatus = (string text) =>
222216
{
223-
Logger.LogError("No valid search patterns were configured.");
224-
return;
225-
}
217+
if (capturedMainForm == null)
218+
return;
219+
capturedMainForm.BeginInvoke((Action)(() => capturedMainForm.SetStatusBarText(text)));
220+
};
226221

227-
Task initialSyncTask;
228222
try
229223
{
230-
initialSyncTask = RemoteSync.RunSharedInitialSyncAsync(
231-
settings.RemoteHost,
232-
settings.RemoteUsername,
233-
DPAPIEncryption.Decrypt(settings.RemotePassword),
234-
settings.LocalPath,
235-
settings.RemotePath,
236-
patterns,
237-
settings.ExcludedDirectories,
238-
patterns.Length);
239-
}
240-
catch (Exception ex)
241-
{
242-
Logger.LogError($"Failed to start initial sync. Exception: {ex.Message}");
243-
return;
244-
}
245-
246-
foreach (var pattern in patterns)
247-
{
248-
try
224+
await Task.Run(async () =>
249225
{
250-
RemoteSyncWorkers.Add(new RemoteSync(
251-
settings.RemoteHost,
252-
settings.RemoteUsername,
253-
DPAPIEncryption.Decrypt(settings.RemotePassword),
254-
settings.LocalPath,
255-
settings.RemotePath,
256-
pattern,
257-
director,
258-
settings.ExcludedDirectories,
259-
initialSyncTask));
260-
261-
Logger.LogInfo($"Started sync worker {RemoteSyncWorkers.Count} for pattern {pattern}");
262-
}
263-
catch (Exception)
264-
{
265-
Logger.LogError($"Failed to start sync worker for pattern {pattern}");
266-
}
267-
}
226+
var director = new SyncDirector(capturedSettings.LocalPath);
268227

269-
//Wait for all sync workers to finish initial sync then tell the user
270-
try
271-
{
272-
await initialSyncTask;
228+
var patterns = capturedSettings.LocalSearchPattern
229+
.Split(';', StringSplitOptions.RemoveEmptyEntries)
230+
.Select(pattern => pattern.Trim())
231+
.Where(pattern => pattern.Length > 0)
232+
.ToArray();
233+
234+
if (patterns.Length == 0)
235+
{
236+
Logger.LogError("No valid search patterns were configured.");
237+
setStatus("Invalid search patterns");
238+
return;
239+
}
240+
241+
var initialSyncTcs = new TaskCompletionSource<object?>();
242+
var initialSyncTask = initialSyncTcs.Task;
243+
244+
foreach (var pattern in patterns)
245+
{
246+
try
247+
{
248+
RemoteSyncWorkers.Add(new RemoteSync(
249+
capturedSettings.RemoteHost,
250+
capturedSettings.RemoteUsername,
251+
DPAPIEncryption.Decrypt(capturedSettings.RemotePassword),
252+
capturedSettings.LocalPath,
253+
capturedSettings.RemotePath,
254+
pattern,
255+
director,
256+
capturedSettings.ExcludedDirectories,
257+
initialSyncTask));
258+
259+
Logger.LogInfo($"Started sync worker {RemoteSyncWorkers.Count} for pattern {pattern}");
260+
}
261+
catch (Exception)
262+
{
263+
Logger.LogError($"Failed to start sync worker for pattern {pattern}");
264+
}
265+
}
266+
267+
Task runInitialSyncTask;
268+
try
269+
{
270+
runInitialSyncTask = RemoteSync.RunSharedInitialSyncAsync(
271+
capturedSettings.RemoteHost,
272+
capturedSettings.RemoteUsername,
273+
DPAPIEncryption.Decrypt(capturedSettings.RemotePassword),
274+
capturedSettings.LocalPath,
275+
capturedSettings.RemotePath,
276+
patterns,
277+
capturedSettings.ExcludedDirectories,
278+
patterns.Length);
279+
}
280+
catch (Exception ex)
281+
{
282+
Logger.LogError($"Failed to start initial sync. Exception: {ex.Message}");
283+
setStatus("Initial sync failed");
284+
return;
285+
}
286+
287+
runInitialSyncTask.ContinueWith(t =>
288+
{
289+
if (t.IsFaulted && t.Exception != null)
290+
{
291+
initialSyncTcs.TrySetException(t.Exception.InnerExceptions);
292+
}
293+
else if (t.IsCanceled)
294+
{
295+
initialSyncTcs.TrySetCanceled();
296+
}
297+
else
298+
{
299+
initialSyncTcs.TrySetResult(null);
300+
}
301+
}, TaskScheduler.Default);
302+
303+
//Wait for all sync workers to finish initial sync then tell the user
304+
try
305+
{
306+
await runInitialSyncTask;
307+
}
308+
catch (Exception ex)
309+
{
310+
Logger.LogError($"Initial sync failed. Exception: {ex.Message}");
311+
setStatus("Initial sync failed");
312+
return;
313+
}
314+
315+
Logger.LogInfo("Initial sync complete, real-time sync active");
316+
setStatus("Real time sync active");
317+
});
273318
}
274319
catch (Exception ex)
275320
{
276-
Logger.LogError($"Initial sync failed. Exception: {ex.Message}");
277-
mainForm?.SetStatusBarText("Initial sync failed");
321+
Logger.LogError($"Failed to start sync. Exception: {ex.Message}");
322+
mainForm?.SetStatusBarText("Sync failed");
278323
return;
279324
}
280-
281-
Logger.LogInfo("Initial sync complete, real-time sync active");
282-
mainForm?.SetStatusBarText("Real time sync active");
283325
}
284326

285327
/// <summary>

0 commit comments

Comments
 (0)