public DriveHive(IDriveProxy remoteDrive, IDriveProxy localDrive, string remoteDrivePath, string localDrivePath) { this.RemoteDrive = remoteDrive; this.LocalDrive = localDrive; this.RemoteDrivePath = remoteDrivePath; this.LocalDrivePath = localDrivePath; }
public CryptoDriveSyncEngine(IDriveProxy remoteDrive, IDriveProxy localDrive, SyncMode syncMode, ILogger logger) { _remoteDrive = remoteDrive; _localDrive = localDrive; _syncMode = syncMode; _logger = logger; _context = new CryptoDriveContext(); _syncId = 0; _regex_conflict = new Regex(@".*\s\(Conflicted Copy [0-9]{4}-[0-9]{2}-[0-9]{2}\s[0-9]{6}\)"); _regex_replace = new Regex(@"\s\(Conflicted Copy [0-9]{4}-[0-9]{2}-[0-9]{2}\s[0-9]{6}\)"); // changes _cts = new CancellationTokenSource(); _manualReset = new ManualResetEventSlim(); _changesQueue = new ConcurrentQueue <string>(); // handler _handler = (sender, e) => { _changesQueue.Enqueue(e); _manualReset.Set(); }; }
private async Task <DriveItem> InternalTransferDriveItem(IDriveProxy sourceDrive, IDriveProxy targetDrive, DriveItem driveItem) { DriveItem newDriveItem; try { newDriveItem = await targetDrive.CreateOrUpdateAsync(driveItem); } // retry if download link has expired catch (Exception) { _logger.LogWarning($"Download URI is null or has expired, requesting new one."); driveItem.SetUri(await sourceDrive.GetDownloadUriAsync(driveItem)); newDriveItem = await targetDrive.CreateOrUpdateAsync(driveItem); } await targetDrive.SetLastWriteTimeUtcAsync(driveItem); return(newDriveItem); }
/* low level */ private async Task <DriveItem> TransferDriveItem(IDriveProxy sourceDrive, IDriveProxy targetDrive, DriveItem driveItem) { (var itemName1, var itemName2) = this.GetItemNames(driveItem); var isLocal = sourceDrive == _localDrive; // item exists on target drive if (_syncMode == SyncMode.TwoWay && await targetDrive.ExistsAsync(driveItem)) { // item is unchanged on target drive // actions: do nothing if (await targetDrive.GetLastWriteTimeUtcAsync(driveItem) == driveItem.LastModified()) { _logger.LogDebug($"{itemName1} already exists and is unchanged on target drive '{targetDrive.Name}'. Action(s): do nothing."); } // item was modified on target drive else { if (!isLocal) { _logger.LogDebug($"{itemName1} already exists and was modified on target drive '{targetDrive.Name}'. Action(s): handle conflict."); await this.EnsureLocalConflict(driveItem); } } } // item does not exist on target drive // actions: transfer item else { _logger.LogInformation($"{itemName1} is not available on target drive '{targetDrive.Name}'. Action(s): transfer {itemName2}."); return(await this.InternalTransferDriveItem(sourceDrive, targetDrive, driveItem)); } return(driveItem); }
private async Task <(DriveItem UpdateDriveItem, WatcherChangeTypes ChangeType)> SyncDriveItem( IDriveProxy sourceDrive, IDriveProxy targetDrive, DriveItem oldDriveItem, DriveItem newDriveItem) { DriveItem updatedDriveItem; (var itemName1, var itemName2) = this.GetItemNames(newDriveItem); var changeType = newDriveItem.GetChangeType(oldDriveItem); switch (changeType) { case WatcherChangeTypes.Changed: case WatcherChangeTypes.Created: // Item was created or modified on source drive // actions: create or modify on target drive _logger.LogInformation($"{itemName1} was created or modified on drive '{sourceDrive.Name}'. Action(s): Create or modify {itemName2} on drive '{targetDrive.Name}'."); updatedDriveItem = await this.TransferDriveItem(sourceDrive, targetDrive, newDriveItem); break; case WatcherChangeTypes.Deleted: // item was deleted on source drive // actions: delete item on target drive _logger.LogInformation($"{itemName1} was deleted on drive '{sourceDrive.Name}'. Action(s): Delete {itemName2} on drive '{targetDrive.Name}'."); if (await targetDrive.ExistsAsync(newDriveItem)) { updatedDriveItem = await targetDrive.DeleteAsync(newDriveItem); } else { _logger.LogWarning($"Cannot delete {itemName2} because it does not exist on drive '{targetDrive.Name}'."); throw new InvalidOperationException($"Cannot delete {itemName2} because it does not exist on drive '{targetDrive.Name}'."); } break; case WatcherChangeTypes.Renamed: // item was renamed / moved on source drive // actions: rename / move item on target drive _logger.LogInformation($"{itemName1} was renamed / moved on drive '{sourceDrive.Name}'. Action(s): Rename / move {itemName2} on drive '{targetDrive.Name}'."); if (await targetDrive.ExistsAsync(newDriveItem)) { _logger.LogWarning($"Cannot move {itemName2} because the target {itemName2} already exists on drive '{targetDrive.Name}'."); throw new InvalidOperationException($"Cannot move {itemName2} because the target {itemName2} already exists on drive '{targetDrive.Name}'."); } else { updatedDriveItem = await targetDrive.MoveAsync(oldDriveItem, newDriveItem); } break; default: updatedDriveItem = newDriveItem; break; } return(updatedDriveItem, changeType); }
private async Task InternalSynchronize( IDriveProxy sourceDrive, IDriveProxy targetDrive, List <DriveItem> deltaPage) { var isLocal = sourceDrive == _localDrive; foreach (var newDriveItem in deltaPage) { using (_logger.BeginScope(new Dictionary <string, object> { ["ItemPath"] = newDriveItem.GetItemPath() })) { // if file is marked as conflicted copy if (isLocal && _regex_conflict.IsMatch(newDriveItem.Name)) { this.EnsureLocalConflictByConflictFile(conflictFilePath: newDriveItem.GetItemPath()); } // proceed else { RemoteState oldRemoteState; RemoteState newRemoteState; // find old remote state item if (isLocal) { oldRemoteState = _context.RemoteStates.FirstOrDefault(current => current.GetItemPath() == newDriveItem.GetItemPath()); } else { oldRemoteState = _context.RemoteStates.FirstOrDefault(current => current.Id == newDriveItem.Id); } var oldDriveItem = oldRemoteState?.ToDriveItem(); // file is tracked as conflict // action: do nothing, it will be handled by "CheckConflicts" later if (isLocal && _context.Conflicts.Any(conflict => conflict.OriginalFilePath == newDriveItem.GetItemPath())) { _logger.LogDebug($"File is tracked as conflict. Action(s): do nothing."); } // synchronize (var updatedDriveItem, var changeType) = await this.SyncDriveItem(sourceDrive, targetDrive, oldDriveItem, newDriveItem.MemberwiseClone()); // update database if (isLocal) { newRemoteState = updatedDriveItem.ToRemoteState(); newRemoteState.IsLocal = true; } else { if (updatedDriveItem.GetItemPath() == "root") { continue; } newRemoteState = newDriveItem.ToRemoteState(); } this.UpdateContext(oldRemoteState, newRemoteState: newRemoteState, changeType); } } } }