/// <summary> /// When overridden in the derived class, handles synchronizing the given version. /// </summary> /// <param name="fu">The <see cref="IFileUploader"/> to use.</param> /// <param name="v">The version to synchronize.</param> /// <param name="reEnqueue">True if the <paramref name="v"/> should be re-enqueued so it can be re-attempted. /// If the method throws an <see cref="Exception"/>, the <paramref name="v"/> will be re-enqueued no matter what.</param> /// <returns> /// The error string, or null if the synchronization was successful. /// </returns> protected override string DoSync(IFileUploader fu, int v, out bool reEnqueue) { reEnqueue = false; // Load the VersionFileList for the version to check var vflPath = VersionHelper.GetVersionFileListPath(v); if (!File.Exists(vflPath)) { // Version doesn't exist at all return null; } var vfl = VersionFileList.CreateFromFile(vflPath); // Try to download the version's file list hash var fileListHashPath = GetVersionRemoteFilePath(v, PathHelper.RemoteFileListHashFileName); var vflHash = fu.DownloadAsString(fileListHashPath); // Check if the hash file exists on the server if (vflHash != null) { // Check if the hash matches the current version's hash var expectedVflHash = File.ReadAllText(VersionHelper.GetVersionFileListHashPath(v)); if (vflHash != expectedVflHash) { // Delete the whole version folder first fu.DeleteDirectory(GetVersionRemoteFilePath(v, null)); } else { // Hash existed and was correct - good enough for us! return null; } } else { // Hash didn't exist at all, so we will have to update. As long as SkipIfExists is set to true, files // that already exist will be skipped, so we will only end up uploading the new files. In any case, its // the same process either way. } // Check the hashes of the local files foreach (var f in vfl.Files) { // Get the local file path var localPath = VersionHelper.GetVersionFile(v, f.FilePath); // Confirm the hash of the file var fileHash = Hasher.GetFileHash(localPath); if (fileHash != f.Hash) { const string errmsg = "The cached hash ({0}) of file `{1}` does not match the real hash ({2}) for version {3}." + " Possible version corruption."; return string.Format(errmsg, f.Hash, f.FilePath, fileHash, v); } } // Hashes check out, start uploading foreach (var f in vfl.Files) { // Get the local file path var localPath = VersionHelper.GetVersionFile(v, f.FilePath); var remotePath = GetVersionRemoteFilePath(v, f.FilePath); fu.UploadAsync(localPath, remotePath); } // Wait for uploads to finish while (fu.IsBusy) { Thread.Sleep(1000); } // All uploads have finished, so upload the VersionFileList hash fu.UploadAsync(VersionHelper.GetVersionFileListHashPath(v), fileListHashPath); // All done! That was easy enough, eh? *sigh* return null; }
/// <summary> /// When overridden in the derived class, handles synchronizing the given version. /// </summary> /// <param name="fu">The <see cref="IFileUploader"/> to use.</param> /// <param name="v">The version to synchronize.</param> /// <param name="reEnqueue">True if the <paramref name="v"/> should be re-enqueued so it can be re-attempted. /// If the method throws an <see cref="Exception"/>, the <paramref name="v"/> will be re-enqueued no matter what.</param> /// <returns> /// The error string, or null if the synchronization was successful. /// </returns> protected override string DoSync(IFileUploader fu, int v, out bool reEnqueue) { reEnqueue = false; // Load the VersionFileList for the version to check var vflPath = VersionHelper.GetVersionFileListPath(v); if (!File.Exists(vflPath)) { // Version doesn't exist at all return(null); } var vfl = VersionFileList.CreateFromFile(vflPath); // Try to download the version's file list hash var fileListHashPath = GetVersionRemoteFilePath(v, PathHelper.RemoteFileListHashFileName); var vflHash = fu.DownloadAsString(fileListHashPath); // Check if the hash file exists on the server if (vflHash != null) { // Check if the hash matches the current version's hash var expectedVflHash = File.ReadAllText(VersionHelper.GetVersionFileListHashPath(v)); if (vflHash != expectedVflHash) { // Delete the whole version folder first fu.DeleteDirectory(GetVersionRemoteFilePath(v, null)); } else { // Hash existed and was correct - good enough for us! return(null); } } else { // Hash didn't exist at all, so we will have to update. As long as SkipIfExists is set to true, files // that already exist will be skipped, so we will only end up uploading the new files. In any case, its // the same process either way. } // Check the hashes of the local files foreach (var f in vfl.Files) { // Get the local file path var localPath = VersionHelper.GetVersionFile(v, f.FilePath); // Confirm the hash of the file var fileHash = Hasher.GetFileHash(localPath); if (fileHash != f.Hash) { const string errmsg = "The cached hash ({0}) of file `{1}` does not match the real hash ({2}) for version {3}." + " Possible version corruption."; return(string.Format(errmsg, f.Hash, f.FilePath, fileHash, v)); } } // Hashes check out, start uploading foreach (var f in vfl.Files) { // Get the local file path var localPath = VersionHelper.GetVersionFile(v, f.FilePath); var remotePath = GetVersionRemoteFilePath(v, f.FilePath); fu.UploadAsync(localPath, remotePath); } // Wait for uploads to finish while (fu.IsBusy) { Thread.Sleep(1000); } // All uploads have finished, so upload the VersionFileList hash fu.UploadAsync(VersionHelper.GetVersionFileListHashPath(v), fileListHashPath); // All done! That was easy enough, eh? *sigh* return(null); }