Пример #1
0
 public DriveHive(IDriveProxy remoteDrive, IDriveProxy localDrive, string remoteDrivePath, string localDrivePath)
 {
     this.RemoteDrive     = remoteDrive;
     this.LocalDrive      = localDrive;
     this.RemoteDrivePath = remoteDrivePath;
     this.LocalDrivePath  = localDrivePath;
 }
Пример #2
0
        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();
            };
        }
Пример #3
0
        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);
        }
Пример #4
0
        /* 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);
        }
Пример #5
0
        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);
        }
Пример #6
0
        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);
                    }
                }
            }
        }