Example #1
0
        internal void UpdateWithLocalInfo(ConflictHandling conflictHandling, Guid correlationId)
        {
            Logger.LogDebug(correlationId, Id, "(UpdateWithLocalInfo) Name={0}, LocalFolder={1}, Type={2}", Name, LocalFolder, Type);
            if (Type == ItemType.File)
            {
                var mod = File.GetLastWriteTimeUtc(Path.Combine(LocalFolder, Name));
                if (mod == LastModified)
                {
                    // means something went wrong on initial sync, so reset status to updatedlocal
                    if (SharePointId == -1)
                    {
                        Logger.LogDebug(correlationId, Id, "(UpdateWithLocalInfo) Possibly error: LastWriteTime=LastModified but SharePointId=-1");
                        Status = ItemStatus.UpdatedLocal;
                    }
                    else
                    {
                        Logger.LogDebug(correlationId, Id, "(UpdateWithLocalInfo) Nothing to do");
                    }

                    return;
                }

                if (mod > LastModified)
                {
                    Logger.LogDebug(correlationId, Id, "(UpdateWithLocalInfo) File is greater than metadata LastModified. Status={0}", Status);
                    if (Status == ItemStatus.UpdatedRemote || Status == ItemStatus.Conflict)
                    {
                        switch (conflictHandling)
                        {
                        case ConflictHandling.ManualConflictHandling:
                            ConflictData = new ConflictData()
                            {
                                LocalLastModified  = mod,
                                RemoteLastModified = LastModified
                            };
                            Logger.LogDebug(correlationId, Id, "(UpdateWithLocalInfo) Set status to 'Conflict'");
                            Status = ItemStatus.Conflict;
                            return;

                        case ConflictHandling.OverwriteLocalChanges:
                            Logger.LogDebug(correlationId, Id, "(UpdateWithLocalInfo) Set status to 'UpdatedRemote'");
                            Status = ItemStatus.UpdatedRemote;
                            return;

                        case ConflictHandling.OverwriteRemoteChanges:
                            break;
                        }
                    }

                    Logger.LogDebug(correlationId, Id, "(UpdateWithLocalInfo) Set status to 'UpdatedLocal' and LastModified to {0}", mod);
                    LastModified = mod;
                    Status       = ItemStatus.UpdatedLocal;
                }
                else
                {
                    Logger.LogDebug(correlationId, Id, "(UpdateWithLocalInfo) File is older than metadata LastModified. Status set to 'UpdatedRemote'");
                    Status = ItemStatus.UpdatedRemote;
                }
            }
        }
Example #2
0
        private void buttonTest_Click(object sender, RoutedEventArgs e)
        {
            ConflictHandling ch = new ConflictHandling(obj1, obj2);

            ch.analyzeObjects();
            ch.printConflicts();
        }
Example #3
0
        public void DeleteItem(string tableName, TableItem tableItem, ConflictHandling conflictHandling)
        {
            var genericTableEntity = GenericTableEntity.HydrateFrom(tableItem);

            if (ShouldForceOverwrite(conflictHandling, genericTableEntity))
            {
                genericTableEntity.ETag = "*";
            }
            Action <MemoryStorageAccount> action = tables => tables.GetTable(tableName).GetPartition(tableItem.PartitionKey).Delete(genericTableEntity);

            _pendingActions.Enqueue(new TableAction(action, tableItem.PartitionKey, tableItem.RowKey, tableName));
        }
        public void DeleteItem(string tableName, TableItem tableItem, ConflictHandling conflictHandling)
        {
            var genericTableEntity = GenericTableEntity.HydrateFrom(tableItem);

            if (ShouldForceOverwrite(conflictHandling, genericTableEntity))
            {
                genericTableEntity.ETag = "*";
            }
            var operation = TableOperation.Delete(genericTableEntity);

            _operations.Enqueue(new ExecutableTableOperation(tableName, operation, TableOperationType.Delete, tableItem.PartitionKey, tableItem.RowKey));
        }
Example #5
0
        /// <summary>
        /// Remove the instance from table storage
        /// </summary>
        /// <param name="tableName">Name of the table</param>
        /// <param name="instance">the instance to delete</param>
        /// <param name="conflictHandling">Method for handling ETag conflicts</param>
        public void Delete(string tableName, dynamic instance, ConflictHandling conflictHandling)
        {
            TableItem tableItem = TableItem.Create(instance, _reservedPropertyBehavior);

            if (tableItem.ETag == null)
            {
                Delete(tableName, tableItem.PartitionKey, tableItem.RowKey);
            }
            else
            {
                _context.DeleteItem(tableName, tableItem, conflictHandling);
            }
        }
Example #6
0
 /// <summary>
 /// Merge the entity
 /// </summary>
 /// <param name="tableName">Name of the table</param>
 /// <param name="instance">the instance to merge</param>
 /// <param name="conflictHandling">Method for handling ETag conflicts</param>
 public void Merge(string tableName, dynamic instance, ConflictHandling conflictHandling)
 {
     _context.Merge(tableName, TableItem.Create(instance, _reservedPropertyBehavior), conflictHandling);
 }
Example #7
0
 /// <summary>
 /// Update the entity with specified partition key and row key in table storage
 /// </summary>
 /// <param name="tableName">Name of the table</param>
 /// <param name="instance">the instance to update</param>
 /// <param name="partitionKey">The partition key to use when storing the entity</param>
 /// <param name="rowKey">The row key to use when storing the entity</param>
 /// <param name="conflictHandling">Method for handling ETag conflicts</param>
 public void Update(string tableName, dynamic instance, string partitionKey, string rowKey, ConflictHandling conflictHandling)
 {
     _context.Update(tableName, TableItem.Create(instance, partitionKey, rowKey, _reservedPropertyBehavior), conflictHandling);
 }
Example #8
0
        internal void UpdateWithRemoteInfo(int sharePointId, int etag, DateTime lastModified, ConflictHandling conflictHandling, Guid correlationId)
        {
            Logger.LogDebug(correlationId, Id, "(UpdateWithRemoteInfo) SharePointId={0}, ETag={1}, Name={2}, LocalFolder={3}, Type={4}, CurrentStatus={5}", sharePointId, etag, Name, LocalFolder, Type, Status);

            if (Type == ItemType.File)
            {
                Logger.LogDebug(correlationId, Id, "(UpdateWithRemoteInfo) SharePointId old={0}, SharePointId new={1}", SharePointId, sharePointId);
                SharePointId = sharePointId;

                if (ETag == -1)
                {
                    Logger.LogDebug(correlationId, Id, "(UpdateWithRemoteInfo) Current ETag=-1, new ETag={0}", etag);
                    ETag = etag;
                    if (lastModified > LastModified)
                    {
                        Logger.LogDebug(correlationId, Id, "(UpdateWithRemoteInfo) RemoteLastModified is greater than current LastModified. Status={0}", Status);
                        if (Status == ItemStatus.UpdatedLocal || Status == ItemStatus.Conflict)
                        {
                            switch (conflictHandling)
                            {
                            case ConflictHandling.ManualConflictHandling:
                                ConflictData = new ConflictData()
                                {
                                    LocalLastModified  = LastModified,
                                    RemoteLastModified = lastModified
                                };
                                Logger.LogDebug(correlationId, Id, "(UpdateWithRemoteInfo) Set status to 'Conflict'");
                                Status = ItemStatus.Conflict;
                                return;

                            case ConflictHandling.OverwriteRemoteChanges:
                                Logger.LogDebug(correlationId, Id, "(UpdateWithRemoteInfo) Set status to 'UpdatedLocal'");
                                Status = ItemStatus.UpdatedLocal;
                                return;

                            case ConflictHandling.OverwriteLocalChanges:
                                break;
                            }
                        }

                        Logger.LogDebug(correlationId, Id, "(UpdateWithRemoteInfo) Set status to 'UpdatedRemote' and LastModified to {0}", lastModified);
                        LastModified = lastModified;
                        Status       = ItemStatus.UpdatedRemote;
                        return;
                    }
                    if (lastModified < LastModified)
                    {
                        Logger.LogDebug(correlationId, Id, "(UpdateWithRemoteInfo) RemoteLastModified is less than current LasModified. Set status to 'UpdatedLocal'");
                        Status = ItemStatus.UpdatedLocal;
                        return;
                    }
                    Logger.LogDebug(correlationId, Id, "(UpdateWithRemoteInfo) LastModified dates are equal");
                    Status = ItemStatus.Unchanged;
                    return;
                }

                if (File.Exists(Path.Combine(LocalFolder, Name) + ".spsync"))
                {
                    Status = ItemStatus.Unchanged;
                    return;
                }

                if (ETag < etag)
                {
                    Logger.LogDebug(correlationId, Id, "(UpdateWithRemoteInfo) Current ETag is less than remote etag. Status={0}", Status);
                    if (Status == ItemStatus.UpdatedLocal || Status == ItemStatus.Conflict)
                    {
                        switch (conflictHandling)
                        {
                        case ConflictHandling.ManualConflictHandling:
                            ConflictData = new ConflictData()
                            {
                                LocalLastModified  = LastModified,
                                RemoteLastModified = lastModified
                            };
                            Logger.LogDebug(correlationId, Id, "(UpdateWithRemoteInfo) Set status to 'Conflict'");
                            Status = ItemStatus.Conflict;
                            return;

                        case ConflictHandling.OverwriteRemoteChanges:
                            Logger.LogDebug(correlationId, Id, "(UpdateWithRemoteInfo) Set status to 'UpdatedLocal'");
                            Status = ItemStatus.UpdatedLocal;
                            return;

                        case ConflictHandling.OverwriteLocalChanges:
                            break;
                        }
                    }

                    Logger.LogDebug(correlationId, Id, "(UpdateWithRemoteInfo) Set status to 'UpdatedRemote' and ETag to {0}", etag);
                    ETag   = etag;
                    Status = ItemStatus.UpdatedRemote;
                    return;
                }
                if (ETag > etag)
                {
                    Logger.LogDebug(correlationId, Id, "(UpdateWithRemoteInfo) Current ETag is greater than remote etag. Set Status to 'UpdatedLocal'");
                    Status = ItemStatus.UpdatedLocal;
                    return;
                }
                Logger.LogDebug(correlationId, Id, "(UpdateWithRemoteInfo) ETags are equal.");
            }
        }
Example #9
0
        private int SyncMetadataStore(bool doNotSave, ConflictHandling conflictHandling, out bool moreChangesFound, bool rescanLocalFiles = true)
        {
            var sumWatch = Stopwatch.StartNew();

            var correlationId = Guid.NewGuid();

            //reset item status for all items except the ones with errors
            _metadataStore.Items.Where(p => p.Status != ItemStatus.Conflict).ToList().ForEach(p => { p.Status = ItemStatus.Unchanged; p.HasError = false; });

            var watch = Stopwatch.StartNew();

            var remoteFileList = _sharePointManager.GetChangedFiles(_metadataStore, (percent, currentFile) =>
            {
                OnSyncProgress(percent, ProgressStatus.Analyzing, $"Processing remote changes... '{currentFile}'");
            });

            watch.Stop();

            var syncToRemote = (_configuration.Direction == SyncDirection.LocalToRemote || _configuration.Direction == SyncDirection.Both);
            var syncToLocal  = _configuration.Direction == SyncDirection.RemoteToLocal || _configuration.Direction == SyncDirection.Both;

            var searchOption = SearchOption.AllDirectories;

            if (rescanLocalFiles)
            {
                OnSyncProgress(0, ProgressStatus.Analyzing, "Processing local changes");

                #region Iterate local files/folders

                watch = Stopwatch.StartNew();

                Parallel.ForEach(Directory.EnumerateDirectories(_localFolder, "*", searchOption), localFolder =>
                {
                    if (!syncToRemote)
                    {
                        return;
                    }

                    if (!_configuration.ShouldFileSync(localFolder))
                    {
                        return;
                    }

                    if (File.GetAttributes(localFolder).HasFlag(FileAttributes.Hidden))
                    {
                        return;
                    }

                    if (Path.GetDirectoryName(localFolder) == MetadataStore.STOREFOLDER)
                    {
                        return;
                    }

                    var item = _metadataStore.GetByFileName(localFolder);
                    if (item == null)
                    {
                        _metadataStore.Add(new MetadataItem(localFolder, ItemType.Folder));
                    }
                    else
                    {
                        item.UpdateWithLocalInfo(conflictHandling, correlationId);
                        if (item.Status == ItemStatus.Conflict)
                        {
                            item.Status = OnItemConflict(item);
                        }
                    }
                });

                watch.Stop();
                watch = Stopwatch.StartNew();

                // update store for local files
                Parallel.ForEach(Directory.EnumerateFiles(_localFolder, "*.*", searchOption), localFile =>
                                 //foreach (var localFile in Directory.EnumerateFiles(_localFolder, "*.*", searchOption))
                {
                    if (!syncToRemote)
                    {
                        return;
                    }

                    if (!_configuration.ShouldFileSync(localFile))
                    {
                        return;
                    }

                    var localExtension = Path.GetExtension(localFile);
                    if (localExtension == ".spsync")
                    {
                        return;
                    }

                    if (File.GetAttributes(localFile).HasFlag(FileAttributes.Hidden))
                    {
                        return;
                    }

                    if (Directory.GetParent(localFile).Name == MetadataStore.STOREFOLDER)
                    {
                        return;
                    }

                    var item = _metadataStore.GetByFileName(localFile);
                    if (item == null)
                    {
                        _metadataStore.Add(new MetadataItem(localFile, ItemType.File));
                    }
                    else
                    {
                        item.UpdateWithLocalInfo(conflictHandling, correlationId);
                        if (item.Status == ItemStatus.Conflict)
                        {
                            item.Status = OnItemConflict(item);
                        }
                    }
                });

                watch.Stop();

                #endregion
            }

            #region Iterate remote files/folders

            // update store for remote files/folders
            foreach (var remoteItem in remoteFileList)
            {
                if (!syncToLocal)
                {
                    continue;
                }

                var localFile = new DirectoryInfo(Path.Combine(_localFolder, remoteItem.FullFileName)).FullName;

                if (!_configuration.ShouldFileSync(localFile))
                {
                    continue;
                }

                string fn = localFile;
                if (remoteItem.Type == ItemType.Folder)
                {
                    fn = Path.Combine(localFile, remoteItem.Name);
                }

                var item = _metadataStore.GetByItemId(remoteItem.Id);
                if (remoteItem.ChangeType == Microsoft.SharePoint.Client.ChangeType.Add)
                {
                    // new
                    if (item == null)
                    {
                        _metadataStore.Add(new MetadataItem(remoteItem.Id, remoteItem.ETag, remoteItem.Name, Path.GetDirectoryName(localFile), remoteItem.LastModified, remoteItem.Type));
                    }
                    // remote and local change
                    else
                    {
                        item.UpdateWithRemoteInfo(remoteItem.Id, remoteItem.ETag, remoteItem.LastModified, conflictHandling, correlationId);
                        if (item.Status == ItemStatus.Conflict)
                        {
                            item.Status = OnItemConflict(item);
                        }
                    }
                }
                if (remoteItem.ChangeType == Microsoft.SharePoint.Client.ChangeType.DeleteObject)
                {
                    if (item != null)
                    {
                        item.Status = ItemStatus.DeletedRemote;
                    }
                }
                if (remoteItem.ChangeType == Microsoft.SharePoint.Client.ChangeType.Rename)
                {
                    if (item == null)
                    {
                        _metadataStore.Add(new MetadataItem(remoteItem.Id, remoteItem.ETag, remoteItem.Name, Path.GetDirectoryName(localFile), remoteItem.LastModified, remoteItem.Type));
                    }
                    else
                    {
                        if (item.Name != remoteItem.Name)
                        {
                            item.NewNameAfterRename = remoteItem.Name;
                            item.Status             = ItemStatus.RenamedRemote;

                            if (item.Type == ItemType.Folder)
                            {
                                foreach (var itemInFolder in _metadataStore.Items.Where(p => p.LocalFile.Contains(item.LocalFile)))
                                {
                                    if (itemInFolder.Id == item.Id)
                                    {
                                        continue;
                                    }
                                    var newFolder = _localFolder + remoteItem.FullFileName.Substring(1);
                                    itemInFolder.LocalFolder = itemInFolder.LocalFolder.Replace(item.LocalFile, newFolder);
                                    itemInFolder.HasError    = true;
                                }
                            }
                        }
                        else
                        {
                            item.Status = ItemStatus.Unchanged;
                        }
                    }
                }
                if (remoteItem.ChangeType == Microsoft.SharePoint.Client.ChangeType.Update)
                {
                    // new
                    if (item == null)
                    {
                        _metadataStore.Add(new MetadataItem(remoteItem.Id, remoteItem.ETag, remoteItem.Name, Path.GetDirectoryName(localFile), remoteItem.LastModified, remoteItem.Type));
                    }
                    else
                    {
                        item.UpdateWithRemoteInfo(remoteItem.Id, remoteItem.ETag, remoteItem.LastModified, conflictHandling, correlationId);
                        if (item.Status == ItemStatus.Conflict)
                        {
                            item.Status = OnItemConflict(item);
                        }
                    }
                }
            }

            #endregion

            #region Check for deleted files/folders

            var itemsToDelete = new List <Guid>();

            // update store: files
            foreach (var item in _metadataStore.Items.Where(p => p.Status == ItemStatus.Unchanged && p.Type == ItemType.File && !p.HasError))
            {
                var path = item.LocalFile;

                if (!_configuration.ShouldFileSync(path))
                {
                    continue;
                }

                if (!File.Exists(path) && !File.Exists(path + ".spsync"))
                {
                    item.Status = ItemStatus.DeletedLocal;
                }
                //if (remoteFileList.Count(p => p.Id == item.SharePointId) < 1)
                //{
                //    if (item.Status == ItemStatus.DeletedLocal)
                //    {
                //        itemsToDelete.Add(item.Id);
                //    }
                //    item.Status = ItemStatus.DeletedRemote;
                //}
            }

            // update store: folders
            foreach (var item in _metadataStore.Items.Where(p => p.Status == ItemStatus.Unchanged && p.Type == ItemType.Folder && !p.HasError))
            {
                var relFile = item.LocalFile.Replace(_localFolder, string.Empty).TrimStart('.', '\\');
                var path    = item.LocalFile;

                if (!_configuration.ShouldFileSync(path))
                {
                    continue;
                }

                if (!Directory.Exists(path))
                {
                    item.Status = ItemStatus.DeletedLocal;

                    // delete all dependend items
                    _metadataStore.Items.Where(p => p.LocalFolder == item.LocalFile).ToList().ForEach(p => { if (!itemsToDelete.Contains(p.Id))
                                                                                                             {
                                                                                                                 itemsToDelete.Add(p.Id);
                                                                                                             }
                                                                                                      });
                }
                //if (remoteFileList.Count(p => p.FullFileName.Replace(_localFolder, string.Empty).TrimStart('.', '\\') + p.Name == relFile) < 1)
                //{
                //    if (item.Status == ItemStatus.DeletedLocal)
                //    {
                //        if (!itemsToDelete.Contains(item.Id))
                //            itemsToDelete.Add(item.Id);
                //    }
                //    item.Status = ItemStatus.DeletedRemote;
                //}
            }

            #endregion

            itemsToDelete.ForEach(p => _metadataStore.Delete(p));

            var countChanged = _metadataStore.Items.Count(p => p.Status != ItemStatus.Unchanged);

            _metadataStore.Items.Where(p => p.Status != ItemStatus.Unchanged).ToList().ForEach(p =>
            {
                Logger.LogDebug(correlationId, p.Id, "(Result) Item Name={0}, Status={1}, HasError={2}, LastError={3}", p.Name, p.Status, p.HasError, p.LastError);
            });

            // reset error flag
            //_metadataStore.Items.Where(p => p.HasError && p.Status != ItemStatus.Unchanged).ToList().ForEach(p => p.HasError = false);

            if (!doNotSave)
            {
                _metadataStore.Save();
            }

            sumWatch.Stop();

            moreChangesFound = remoteFileList.Count > 0;

            return(countChanged);
        }
Example #10
0
 private static bool ShouldForceOverwrite(ConflictHandling conflictHandling, GenericTableEntity genericTableEntity)
 {
     return(string.IsNullOrEmpty(genericTableEntity.ETag) || conflictHandling.Equals(ConflictHandling.Overwrite));
 }