@@ -17,7 +17,9 @@ public class RemoteSync : IDisposable
1717 SyncDirector _director ;
1818 HashSet < string > _activeDirSync = new HashSet < string > ( ) ;
1919
20+
2021 public Task DoneMakingFolders { get ; }
22+
2123 public Task DoneInitialSync { get ; }
2224
2325 public RemoteSync ( string host , string username , string password ,
@@ -35,23 +37,39 @@ public RemoteSync(string host, string username, string password,
3537 _sftp = new SftpClient ( host , username , password ) ;
3638 _sftp . Connect ( ) ;
3739
40+ //Our first instance is responsible for creating all of the the directories
41+ //Subsequent instances will not be created until this is done
3842 DoneMakingFolders = createFolders ? CreateDirectories ( _localRootDirectory , _remoteRootDirectory ) : Task . CompletedTask ;
3943
44+ //Now perform the initial sync for the pattern this instance is responsible for
4045 DoneInitialSync = InitialSync ( _localRootDirectory , _remoteRootDirectory ) ;
4146
47+ //Once the initial sync is done, we can start watching the file system for changes
4248 DoneInitialSync . ContinueWith ( ( tmp ) =>
4349 {
4450 _director . AddCallback ( searchPattern , ( args ) => Fsw_Changed ( null , args ) ) ;
4551 } ) ;
4652 }
4753
54+ /// <summary>
55+ /// Sync changes for a file. This is only used for changes AFTER the initial sync has completed.
56+ /// </summary>
57+ /// <param name="sftp">SFTP client</param>
58+ /// <param name="sourcePath">Path to the source file</param>
59+ /// <param name="destinationPath">Path to the destination file</param>
4860 public static void SyncFile ( SftpClient sftp , string sourcePath , string destinationPath )
4961 {
5062 Logger . LogInfo ( $ "Syncing { sourcePath } -> { destinationPath } ") ;
63+
64+ //Because the VMS SFTP server uses Posix not RMS, and some older servers do not correctly
65+ //handle truncating files when the content gets shorter (resulting in corruption at the end of the file),
66+ //we delete the file first if it exists, before writing new content.
5167 if ( sftp . Exists ( destinationPath ) )
5268 {
5369 sftp . DeleteFile ( destinationPath ) ;
5470 }
71+
72+ //Write the file content to the destination path
5573 sftp . WriteAllText ( destinationPath , File . ReadAllText ( sourcePath ) ) ;
5674 }
5775
@@ -105,8 +123,10 @@ public async Task CreateDirectories(string localPath, string remotePath)
105123
106124 try
107125 {
126+ //Got local directories to sync
108127 var localDirectories = FilteredDirectories ( localPath ) ;
109128
129+ //Get remote directories
110130 var remoteDirectories = ( await ListDirectoryAsync ( _sftp , remotePath ) ) . Where ( item => item . IsDirectory ) . ToDictionary ( item =>
111131 {
112132 if ( item . Name . Contains ( ".DIR" , StringComparison . OrdinalIgnoreCase ) )
@@ -115,13 +135,16 @@ public async Task CreateDirectories(string localPath, string remotePath)
115135 return item . Name ;
116136 } ) ;
117137
138+ //Compare local and remote directories, creating missing ones, and recurse for subdirectories
118139 foreach ( var item in localDirectories )
119140 {
120141 var directoryName = item . Split ( Path . DirectorySeparatorChar ) . Last ( ) ;
121142 if ( ! remoteDirectories . ContainsKey ( directoryName ) )
122143 {
144+ //Create new remote directory
123145 _sftp . CreateDirectory ( remotePath + "/" + directoryName ) ;
124146 }
147+ //And recurse for any subdirectories it may need
125148 await CreateDirectories ( localPath + "\\ " + directoryName , remotePath + "/" + directoryName ) ;
126149 }
127150 }
@@ -133,11 +156,21 @@ public async Task CreateDirectories(string localPath, string remotePath)
133156 }
134157 }
135158
159+ /// <summary>
160+ /// For the pattern we are responsible for, sync the files in the local directory to the remote directory.
161+ /// </summary>
162+ /// <param name="localPath">Local directory path</param>
163+ /// <param name="remotePath">Remote directory path</param>
164+ /// <returns></returns>
136165 public async Task InitialSync ( string localPath , string remotePath )
137166 {
167+ //Wait for the folders to be created before starting the initial sync
138168 await DoneMakingFolders ;
169+
170+ //Get the local directories to sync
139171 var localDirectories = FilteredDirectories ( localPath ) ;
140172
173+ //Get the remote directories to sync, removing the .DIR suffix if it exists
141174 var remoteDirectories = ( await ListDirectoryAsync ( _sftp , remotePath ) ) . Where ( item => item . IsDirectory ) . ToDictionary ( item =>
142175 {
143176 if ( item . Name . Contains ( ".DIR" , StringComparison . OrdinalIgnoreCase ) )
@@ -146,6 +179,7 @@ public async Task InitialSync(string localPath, string remotePath)
146179 return item . Name ;
147180 } ) ;
148181
182+ //
149183 foreach ( var item in localDirectories )
150184 {
151185 var directoryName = item . Split ( Path . DirectorySeparatorChar ) . Last ( ) ;
0 commit comments