Skip to content

Commit e730189

Browse files
committed
Codex attempts to fix crashes.
1 parent 697f47b commit e730189

8 files changed

Lines changed: 198 additions & 79 deletions

File tree

.github/workflows/build.yml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ jobs:
4141
--configuration Release `
4242
--runtime win-x64 `
4343
--self-contained true `
44-
--output SFTPSync/bin/Release/net8.0-windows/publish/win-x64/ `
44+
--output SFTPSync/bin/Release/net8.0-windows `
4545
/p:PublishSingleFile=true `
4646
/p:PublishReadyToRun=true
4747
@@ -51,7 +51,7 @@ jobs:
5151
--configuration Release `
5252
--runtime win-x64 `
5353
--self-contained true `
54-
--output SFTPSyncStop/bin/Release/net8.0-windows/publish/win-x64/ `
54+
--output SFTPSyncStop/bin/Release/net8.0-windows `
5555
/p:PublishSingleFile=true `
5656
/p:PublishReadyToRun=true
5757
@@ -61,7 +61,7 @@ jobs:
6161
--configuration Release `
6262
--runtime win-x64 `
6363
--self-contained true `
64-
--output SFTPSyncUI/bin/Release/net8.0-windows/publish/win-x64/ `
64+
--output SFTPSyncUI/bin/Release/net8.0-windows `
6565
/p:PublishSingleFile=true `
6666
/p:PublishReadyToRun=true
6767
@@ -75,7 +75,7 @@ jobs:
7575
AZURE_CERT_NAME: ${{ secrets.AZURE_CERT_NAME }}
7676
shell: pwsh
7777
run: |
78-
$publishDirs = @("SFTPSync/bin/Release/net8.0-windows/publish/win-x64", "SFTPSyncStop/bin/Release/net8.0-windows/publish/win-x64", "SFTPSyncUI/bin/Release/net8.0-windows/publish/win-x64")
78+
$publishDirs = @("SFTPSync/bin/Release/net8.0-windows", "SFTPSyncStop/bin/Release/net8.0-windows", "SFTPSyncUI/bin/Release/net8.0-windows")
7979
foreach ($dir in $publishDirs) {
8080
if (Test-Path $dir) {
8181
$files = Get-ChildItem -Path $dir -Include *.exe, *.dll -Recurse

SFTPSync.chm-keep

1.32 MB
Binary file not shown.

SFTPSyncLib/RemoteSync.cs

Lines changed: 132 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ public class RemoteSync : IDisposable
1616
SftpClient _sftp;
1717
SyncDirector _director;
1818
HashSet<string> _activeDirSync = new HashSet<string>();
19+
readonly SemaphoreSlim _sftpLock = new SemaphoreSlim(1, 1);
20+
bool _disposed;
1921

2022

2123
public Task DoneMakingFolders { get; }
@@ -85,7 +87,7 @@ public static void SyncFile(SftpClient sftp, string sourcePath, string destinati
8587

8688
return;
8789
}
88-
catch (Exception ex) when (ex is IOException || ex is FileNotFoundException)
90+
catch (Exception ex)
8991
{
9092
retryCount++;
9193
if (retryCount >= maxRetries)
@@ -150,6 +152,9 @@ public async Task CreateDirectories(string localPath, string remotePath)
150152

151153
try
152154
{
155+
if (!EnsureConnectedSafe())
156+
return;
157+
153158
//Got local directories to sync
154159
var localDirectories = FilteredDirectories(localPath);
155160

@@ -194,6 +199,9 @@ public async Task InitialSync(string localPath, string remotePath)
194199
//Wait for the folders to be created before starting the initial sync
195200
await DoneMakingFolders;
196201

202+
if (!EnsureConnectedSafe())
203+
return;
204+
197205
//Get the local directories to sync
198206
var localDirectories = FilteredDirectories(localPath);
199207

@@ -256,65 +264,151 @@ public static bool IsFileReady(String sFilename)
256264
}
257265
}
258266

267+
private void EnsureConnected()
268+
{
269+
if (_disposed)
270+
throw new ObjectDisposedException(nameof(RemoteSync));
259271

260-
private async void Fsw_Changed(object? sender, FileSystemEventArgs arg)
272+
if (_sftp.IsConnected)
273+
return;
274+
275+
_sftp.Connect();
276+
}
277+
278+
private bool EnsureConnectedSafe()
261279
{
262-
if (arg.ChangeType == WatcherChangeTypes.Changed || arg.ChangeType == WatcherChangeTypes.Created
263-
|| arg.ChangeType == WatcherChangeTypes.Renamed)
280+
try
264281
{
265-
var changedPath = Path.GetDirectoryName(arg.FullPath);
266-
var relativePath = _localRootDirectory == changedPath ? "" : changedPath?.Substring(_localRootDirectory.Length).Replace('\\', '/');
267-
var fullRemotePath = _remoteRootDirectory + relativePath;
268-
await Task.Yield();
269-
bool makeDirectory = true;
270-
lock (_activeDirSync)
271-
{
272-
if (changedPath == null)
273-
return;
274-
if (_activeDirSync.Contains(changedPath))
275-
makeDirectory = false;
276-
else
277-
_activeDirSync.Add(changedPath);
278-
}
282+
EnsureConnected();
283+
return true;
284+
}
285+
catch (Exception ex)
286+
{
287+
Logger.LogError($"SFTP connection error: {ex.Message}");
288+
return false;
289+
}
290+
}
279291

280-
//check if we're a new directory
281-
if (makeDirectory && Directory.Exists(arg.FullPath) && !_sftp.Exists(arg.FullPath))
282-
{
283-
_sftp.CreateDirectory(fullRemotePath);
284-
}
285292

286-
if (makeDirectory)
293+
private async void Fsw_Changed(object? sender, FileSystemEventArgs arg)
294+
{
295+
try
296+
{
297+
if (arg.ChangeType == WatcherChangeTypes.Changed || arg.ChangeType == WatcherChangeTypes.Created
298+
|| arg.ChangeType == WatcherChangeTypes.Renamed)
287299
{
300+
var changedPath = Path.GetDirectoryName(arg.FullPath);
301+
var relativePath = _localRootDirectory == changedPath ? "" : changedPath?.Substring(_localRootDirectory.Length).Replace('\\', '/');
302+
var fullRemotePath = _remoteRootDirectory + relativePath;
303+
await Task.Yield();
304+
bool makeDirectory = true;
288305
lock (_activeDirSync)
289306
{
290-
_activeDirSync.Remove(changedPath);
307+
if (changedPath == null)
308+
return;
309+
if (_activeDirSync.Contains(changedPath))
310+
makeDirectory = false;
311+
else
312+
_activeDirSync.Add(changedPath);
291313
}
292-
}
293314

294-
while (!IsFileReady(arg.FullPath))
295-
await Task.Delay(25);
315+
bool connectionOk;
316+
await _sftpLock.WaitAsync();
317+
try
318+
{
319+
connectionOk = EnsureConnectedSafe();
320+
if (connectionOk)
321+
{
322+
//check if we're a new directory
323+
if (makeDirectory && Directory.Exists(arg.FullPath) && !_sftp.Exists(fullRemotePath))
324+
{
325+
_sftp.CreateDirectory(fullRemotePath);
326+
}
327+
}
328+
}
329+
finally
330+
{
331+
_sftpLock.Release();
332+
}
296333

334+
if (!connectionOk)
335+
{
336+
if (makeDirectory)
337+
{
338+
lock (_activeDirSync)
339+
{
340+
_activeDirSync.Remove(changedPath);
341+
}
342+
}
343+
return;
344+
}
297345

298-
lock (_activeDirSync)
299-
{
300-
if (_activeDirSync.Contains(arg.FullPath))
346+
if (makeDirectory)
347+
{
348+
lock (_activeDirSync)
349+
{
350+
_activeDirSync.Remove(changedPath);
351+
}
352+
}
353+
354+
if (Directory.Exists(arg.FullPath))
301355
return;
302-
else
303-
_activeDirSync.Add(arg.FullPath);
304-
}
305-
SyncFile(_sftp, arg.FullPath, fullRemotePath + "/" + Path.GetFileName(arg.FullPath) );
306356

307-
lock (_activeDirSync)
308-
{
309-
_activeDirSync.Remove(arg.FullPath);
357+
var waitStart = DateTime.UtcNow;
358+
while (!IsFileReady(arg.FullPath))
359+
{
360+
if (!File.Exists(arg.FullPath))
361+
return;
362+
if (DateTime.UtcNow - waitStart > TimeSpan.FromSeconds(30))
363+
{
364+
Logger.LogWarnig($"Timed out waiting for file to be ready: {arg.FullPath}");
365+
return;
366+
}
367+
await Task.Delay(25);
368+
}
369+
370+
lock (_activeDirSync)
371+
{
372+
if (_activeDirSync.Contains(arg.FullPath))
373+
return;
374+
else
375+
_activeDirSync.Add(arg.FullPath);
376+
}
377+
378+
bool fileConnectionOk;
379+
await _sftpLock.WaitAsync();
380+
try
381+
{
382+
fileConnectionOk = EnsureConnectedSafe();
383+
if (fileConnectionOk)
384+
{
385+
SyncFile(_sftp, arg.FullPath, fullRemotePath + "/" + Path.GetFileName(arg.FullPath));
386+
}
387+
}
388+
finally
389+
{
390+
_sftpLock.Release();
391+
lock (_activeDirSync)
392+
{
393+
_activeDirSync.Remove(arg.FullPath);
394+
}
395+
}
396+
397+
if (!fileConnectionOk)
398+
return;
310399
}
311400
}
401+
catch (Exception ex)
402+
{
403+
Logger.LogError($"Unhandled exception in file sync handler: {ex.Message}");
404+
}
312405
}
313406

314407
public void Dispose()
315408
{
316409
if (_sftp != null)
317410
{
411+
_disposed = true;
318412
_sftp.Dispose();
319413
}
320414
}

SFTPSyncLib/SyncDirector.cs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,15 @@ public SyncDirector(string rootFolder)
1313
_fsw = new FileSystemWatcher(rootFolder, "*.*")
1414
{
1515
IncludeSubdirectories = true,
16-
NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.FileName
16+
NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.FileName,
17+
// Max allowed size; helps reduce missed events during bursts.
18+
InternalBufferSize = 64 * 1024
1719
};
1820

1921
_fsw.Changed += Fsw_Changed;
2022
_fsw.Created += Fsw_Created;
2123
_fsw.Renamed += Fsw_Renamed;
24+
_fsw.Error += Fsw_Error;
2225

2326
_fsw.EnableRaisingEvents = true;
2427
}
@@ -61,5 +64,10 @@ private void Fsw_Changed(object sender, FileSystemEventArgs e)
6164
}
6265
}
6366
}
67+
68+
private void Fsw_Error(object sender, ErrorEventArgs e)
69+
{
70+
Logger.LogError($"FileSystemWatcher error: {e.GetException()?.Message}");
71+
}
6472
}
6573
}

0 commit comments

Comments
 (0)