protected async Task _UpdateFileIndexes(FolderAssociation association, List <BaseItem> items) { await SetExecutionStatus(ExecutionStatus.UpdatingIndex); var itemTableModel = ItemTableModel.GetDefault(); foreach (BaseItem t in items) { t.Association = association; var foundItem = itemTableModel.GetItem(t); if (foundItem == null) { itemTableModel.InsertItem(t); t.Id = itemTableModel.GetLastInsertItem().Id; } else { if (foundItem.ChangeKey != t.ChangeKey) { t.ChangeNumber = foundItem.ChangeNumber + 1; itemTableModel.UpdateItem(t, foundItem.Id); } t.Id = foundItem.Id; } } association.LastSync = DateTime.Now; FolderAssociationTableModel.GetDefault().UpdateItem(association, association.Id); }
private void AfterUpdate(BaseItem sourceItem, BaseItem targetItem) { if (targetItem.Association == null) { targetItem.Association = sourceItem.Association; } targetItem.ChangeNumber = sourceItem.ChangeNumber; var link = LinkStatusTableModel.GetDefault().GetItem(sourceItem); if (link != null) { link.ChangeNumber = sourceItem.ChangeNumber; LinkStatusTableModel.GetDefault().UpdateItem(link, link.Id); targetItem.Id = link.TargetItemId; ItemTableModel.GetDefault().UpdateItem(sourceItem, sourceItem.Id); ItemTableModel.GetDefault().UpdateItem(targetItem, targetItem.Id); } var historyEntry = new SyncHistoryEntry(); historyEntry.CreateDate = DateTime.Now; historyEntry.SourceItemId = sourceItem.Id; historyEntry.TargetItemId = targetItem.Id; historyEntry.Result = sourceItem.AdapterType == _sourceEntityAdapter.GetType() ? SyncResult.Sent : SyncResult.Received; SyncHistoryTableModel.GetDefault().InsertItem(historyEntry); }
public override async Task <List <BaseItem> > GetDeletedItemsAsync(FolderAssociation association) { List <BaseItem> result = new List <BaseItem>(); //get the storagefolder var localFolderItem = GetAssociatedItem(association.LocalFolderId); StorageFolder sFolder = await StorageFolder.GetFolderFromPathAsync(localFolderItem.EntityId); var sItems = new List <IStorageItem>(); var options = new QueryOptions(); options.FolderDepth = FolderDepth.Deep; options.IndexerOption = IndexerOption.UseIndexerWhenAvailable; var itemQuery = sFolder.CreateItemQueryWithOptions(options); var queryTask = itemQuery.GetItemsAsync(); //get all the files and folders from the db that were inside the folder at the last time var existingItems = ItemTableModel.GetDefault().GetFilesForFolder(association, this.GetType()); sItems.AddRange(await queryTask); var storageItems = new List <BaseItem>(); foreach (var storageItem in sItems) { storageItems.Add(new BaseItem { EntityId = storageItem.Path }); } var missingItems = existingItems.Except(storageItems, new EnityIdComparer()).ToList(); //var fixedPath = sFolder.Path.Replace("USERS", "Users"); foreach (var missingItem in missingItems) { if (missingItem.EntityId == sFolder.Path) { continue; } //additional check if the file really does not exist //for some reason the query seems to return wrong results sometimes if (!missingItem.IsCollection) { FileInfo fInfo = new FileInfo(missingItem.EntityId); if (!fInfo.Exists) { result.Add(missingItem); } } else { DirectoryInfo dInfo = new DirectoryInfo(missingItem.EntityId); if (!dInfo.Exists) { result.Add(missingItem); } } } return(result); }
public override async Task <List <BaseItem> > GetUpdatedItems(FolderAssociation association) { List <BaseItem> items = new List <BaseItem>(); var folder = ItemTableModel.GetDefault().GetItem(association.RemoteFolderId); await _CheckRemoteFolderRecursive(folder, items); return(items); }
public override async Task <List <BaseItem> > GetDeletedItemsAsync(FolderAssociation association) { List <BaseItem> items = new List <BaseItem>(); var folder = ItemTableModel.GetDefault().GetItem(association.RemoteFolderId); var existingItems = ItemTableModel.GetDefault().GetFilesForFolder(association, this.GetType()).ToList(); await _GetDeletedItemsAsync(folder, existingItems, items); return(items); }
public void RemoveInstantUploadAssociations() { foreach (var association in GetInstantUploadAssociations()) { FolderAssociationTableModel.GetDefault().DeleteItem(association.Id); LinkStatusTableModel.GetDefault().DeleteLinksFromAssociation(association); ItemTableModel.GetDefault().DeleteItem(association.RemoteFolderId); ItemTableModel.GetDefault().DeleteItem(association.LocalFolderId); ItemTableModel.GetDefault().DeleteItemsFromAssociation(association); } }
public async Task <FolderAssociation> AddFolderToSyncAsync(StorageFolder folder, DavItem remoteFolderItem, bool allowInstantUpload = false) { StorageApplicationPermissions.FutureAccessList.Add(folder); var properties = await folder.Properties.RetrievePropertiesAsync(new List <string> { "System.DateModified" }); FolderAssociation fa = new FolderAssociation { IsActive = true, LocalFolderId = 0, RemoteFolderId = 0, SyncDirection = SyncDirection.FullSync, LastSync = DateTime.MinValue }; if (allowInstantUpload) { fa.SyncDirection = SyncDirection.UploadOnly; fa.SupportsInstantUpload = true; } FolderAssociationTableModel.GetDefault().InsertItem(fa); fa = FolderAssociationTableModel.GetDefault().GetLastInsertItem(); BaseItem li = new LocalItem { IsCollection = true, LastModified = ((DateTimeOffset)properties["System.DateModified"]).LocalDateTime, EntityId = folder.Path, Association = fa, }; var testFolder = await StorageFolder.GetFolderFromPathAsync(folder.Path); if (testFolder.Path != folder.Path) { li.EntityId = testFolder.Path; } ItemTableModel.GetDefault().InsertItem(li); li = ItemTableModel.GetDefault().GetLastInsertItem(); remoteFolderItem.Association = fa; ItemTableModel.GetDefault().InsertItem(remoteFolderItem); var ri = ItemTableModel.GetDefault().GetLastInsertItem(); fa.RemoteFolderId = ri.Id; fa.LocalFolderId = li.Id; FolderAssociationTableModel.GetDefault().UpdateItem(fa, fa.Id); var link = new LinkStatus(li, ri); LinkStatusTableModel.GetDefault().InsertItem(link); return(fa); }
private async Task <List <BaseItem> > GetDeletedItemsRecursiveAsync(FolderAssociation association, List <BaseItem> result = null, StorageFolder folder = null) { if (result is null) { result = new List <BaseItem>(); } if (folder is null) { var localFolderItem = GetAssociatedItem(association.LocalFolderId); folder = await StorageFolder.GetFolderFromPathAsync(localFolderItem.EntityId); } var queryItems = ItemTableModel.GetDefault().GetFilesForFolder(folder.Path + "\\"); var dataBaseItems = new List <BaseItem>(); //remove the items from subfolders foreach (var item in queryItems) { if (item.EntityId == folder.Path) { continue; } var path = item.EntityId.Replace(folder.Path, "").Substring(1); if (!path.Contains('\\')) { dataBaseItems.Add(item); } } var folderContent = await folder.GetItemsAsync(); foreach (var item in folderContent) { if (item.IsOfType(StorageItemTypes.Folder) && item.Path != folder.Path) { result = await GetDeletedItemsRecursiveAsync(association, result, item as StorageFolder); } } var folderItems = new List <BaseItem>(); foreach (var storageItem in folderContent) { folderItems.Add(new BaseItem { EntityId = storageItem.Path }); } var missingItems = dataBaseItems.Except(folderItems, new EnityIdComparer()).ToList(); result.AddRange(missingItems); return(result); }
//some users reported that the sync does not find any files //this workaround is used if the SearchIndexer does not yield any results, but it's quite slow private async Task _GetChangedFilesRecursive(StorageFolder folder, FolderAssociation association, List <BaseItem> result) { var items = await folder.GetItemsAsync(); foreach (var storageItem in items) { Debug.WriteLine(storageItem.Path); BasicProperties propertyResult = null; if (storageItem.IsOfType(StorageItemTypes.File)) { propertyResult = await((StorageFile)storageItem).GetBasicPropertiesAsync(); } else if (storageItem.IsOfType(StorageItemTypes.Folder)) { propertyResult = await((StorageFolder)storageItem).GetBasicPropertiesAsync(); } var existingItem = ItemTableModel.GetDefault().GetItemFromEntityId(storageItem.Path); DateTime date; if (existingItem != null && DateTime.TryParse(existingItem.ChangeKey, out date)) { int i = date.CompareTo(propertyResult.DateModified.UtcDateTime); if (i <= 0) { if (propertyResult.Size != existingItem.Size) { var item = new LocalItem(association, storageItem, propertyResult); result.Add(item); } } else { continue; } } else if (existingItem == null) { var item = new LocalItem(association, storageItem, propertyResult); result.Add(item); } if (storageItem.IsOfType(StorageItemTypes.Folder)) { await _GetChangedFilesRecursive((StorageFolder)storageItem, association, result); } } }
protected override async Task ProcessItems() { if (Configuration.Configuration.UploadViaWifiOnly) { var internetConnectionProfile = Windows.Networking.Connectivity.NetworkInformation.GetInternetConnectionProfile(); if (internetConnectionProfile != null && !internetConnectionProfile.IsWlanConnectionProfile) { return; } } List <dynamic> itemsToUpdate = new List <dynamic>(); if (_itemsToUpdate.Count != 0) { var links = LinkStatusTableModel.GetDefault().GetAllItems(); foreach (var baseItem in _itemsToUpdate) { var existingItem = ItemTableModel.GetDefault().GetItem(baseItem); if (existingItem == null) { _itemsToAdd.Add(baseItem); } else { var itemsToProcess = (from link in links .Where(x => x.SourceItemId == existingItem.Id || x.TargetItemId == existingItem.Id) .DefaultIfEmpty() select new { LinkStatus = link, BaseItem = existingItem }).ToList(); _itemsToAdd.AddRange((from item in itemsToProcess where item.LinkStatus == null select item.BaseItem).ToList()); itemsToUpdate.AddRange((from item in itemsToProcess where item.LinkStatus != null select item).ToList()); } } } await ProcessAdds(_itemsToAdd); await ProcessUpdates(itemsToUpdate); }
public async Task <FolderAssociation> AddFolderToSyncAsync(StorageFolder folder, DavItem remoteFolderItem, SyncDirection direction = SyncDirection.FullSync) { StorageApplicationPermissions.FutureAccessList.Add(folder); var properties = await folder.Properties.RetrievePropertiesAsync(new List <string> { "System.DateModified" }); FolderAssociation fa = new FolderAssociation { IsActive = true, LocalFolderId = 0, RemoteFolderId = 0, SyncDirection = direction, LastSync = DateTime.MinValue }; FolderAssociationTableModel.GetDefault().InsertItem(fa); fa = FolderAssociationTableModel.GetDefault().GetLastInsertItem(); var path = folder.Path.Replace("\\USERS\\", "\\Users\\"); BaseItem li = new LocalItem { IsCollection = true, LastModified = ((DateTimeOffset)properties["System.DateModified"]).LocalDateTime, EntityId = path, Association = fa, }; ItemTableModel.GetDefault().InsertItem(li); li = ItemTableModel.GetDefault().GetLastInsertItem(); remoteFolderItem.Association = fa; ItemTableModel.GetDefault().InsertItem(remoteFolderItem); var ri = ItemTableModel.GetDefault().GetLastInsertItem(); fa.RemoteFolderId = ri.Id; fa.LocalFolderId = li.Id; FolderAssociationTableModel.GetDefault().UpdateItem(fa, fa.Id); var link = new LinkStatus(li, ri); LinkStatusTableModel.GetDefault().InsertItem(link); return(fa); }
public override async Task DeleteItem(BaseItem item) { long fileId; var link = LinkStatusTableModel.GetDefault().GetItem(item); if (link == null) { await LogHelper.Write($"LinkStatus could not be found: EntityId: {item.EntityId} Id: {item.Id}"); return; } fileId = item.Id == link.SourceItemId ? link.TargetItemId : link.SourceItemId; var fileItem = ItemTableModel.GetDefault().GetItem(fileId); if (fileItem == null) { return; } if (item.IsCollection) { if (new DirectoryInfo(fileItem.EntityId).Exists) { var folder = await StorageFolder.GetFolderFromPathAsync(fileItem.EntityId); await folder.DeleteAsync(StorageDeleteOption.PermanentDelete); } } else { if (new FileInfo(fileItem.EntityId).Exists) { var file = await StorageFile.GetFileFromPathAsync(fileItem.EntityId); await file.DeleteAsync(StorageDeleteOption.PermanentDelete); } } }
public override async Task DeleteItem(BaseItem item) { var link = LinkStatusTableModel.GetDefault().GetItem(item); if (link == null) { await LogHelper.Write($"LinkStatus could not be found: EntityId: {item.EntityId} Id: {item.Id}"); return; } var davId = item.Id == link.SourceItemId ? link.TargetItemId : link.SourceItemId; var davItem = ItemTableModel.GetDefault().GetItem(davId); if (davItem == null) { return; } if (await _davClient.Exists(new Uri(davItem.EntityId, UriKind.RelativeOrAbsolute))) { await _davClient.Delete(new Uri(davItem.EntityId, UriKind.RelativeOrAbsolute)); } }
private void AfterInsert(BaseItem sourceItem, BaseItem targetItem) { if (targetItem.Association == null) { targetItem.Association = sourceItem.Association; } //check if item with same path already exists var existingItem = ItemTableModel.GetDefault().GetItem(targetItem); if (existingItem != null) { ItemTableModel.GetDefault().UpdateItem(targetItem, existingItem.Id); targetItem.Id = existingItem.Id; } else { ItemTableModel.GetDefault().InsertItem(targetItem); targetItem = ItemTableModel.GetDefault().GetLastInsertItem(); } if (LinkStatusTableModel.GetDefault().GetItem(sourceItem) == null) { var link = new LinkStatus(sourceItem, targetItem); LinkStatusTableModel.GetDefault().InsertItem(link); } var historyEntry = new SyncHistoryEntry(); historyEntry.CreateDate = DateTime.Now; historyEntry.SourceItemId = sourceItem.Id; historyEntry.TargetItemId = targetItem.Id; historyEntry.Result = sourceItem.AdapterType == _sourceEntityAdapter.GetType() ? SyncResult.Sent : SyncResult.Received; SyncHistoryTableModel.GetDefault().InsertItem(historyEntry); }
protected virtual async Task ProcessItems() { await LogHelper.Write($"Starting Sync.. BackgroundTask: {_isBackgroundTask}"); await SetExecutionStatus(ExecutionStatus.Active); var items = ItemTableModel.GetDefault().GetAllItems().ToList(); var links = LinkStatusTableModel.GetDefault().GetAllItems().ToList(); var itemsToProcess = (from baseItem in items .Where(i => i.Association.SyncDirection == SyncDirection.DownloadOnly && i.AdapterType == _targetEntityAdapter.GetType() || i.Association.SyncDirection == SyncDirection.UploadOnly && i.AdapterType == _sourceEntityAdapter.GetType() || i.Association.SyncDirection == SyncDirection.FullSync) from link in links .Where(x => x.SourceItemId == baseItem.Id || x.TargetItemId == baseItem.Id) .DefaultIfEmpty() select new { LinkStatus = link, BaseItem = baseItem }).ToList(); var itemsToAdd = (from item in itemsToProcess where item.LinkStatus == null select item.BaseItem).ToList(); var itemsToUpdate = (from item in itemsToProcess where item.BaseItem.ChangeNumber > item.LinkStatus?.ChangeNumber select item).ToList(); _totalCount += itemsToUpdate.Count + itemsToAdd.Count; await ProcessAdds(itemsToAdd); await ProcessUpdates(itemsToUpdate); }
protected override async Task ProcessItems() { List <dynamic> itemsToUpdate = new List <dynamic>(); if (_itemsToUpdate.Count != 0) { var links = LinkStatusTableModel.GetDefault().GetAllItems(); foreach (var baseItem in _itemsToUpdate) { var existingItem = ItemTableModel.GetDefault().GetItem(baseItem); if (existingItem == null) { _itemsToAdd.Add(baseItem); } else { var itemsToProcess = (from link in links .Where(x => x.SourceItemId == existingItem.Id || x.TargetItemId == existingItem.Id) .DefaultIfEmpty() select new { LinkStatus = link, BaseItem = existingItem }).ToList(); _itemsToAdd.AddRange((from item in itemsToProcess where item.LinkStatus == null select item.BaseItem).ToList()); itemsToUpdate.AddRange((from item in itemsToProcess where item.LinkStatus != null select item).ToList()); } } } await ProcessAdds(_itemsToAdd); await ProcessUpdates(itemsToUpdate); }
public async Task <List <BaseItem> > GetChangesFromChangeTracker(KnownLibraryId libraryId, FolderAssociation association, List <StorageLibraryChangeType> supportedChangeTypes) { var result = new List <BaseItem>(); var library = await StorageLibrary.GetLibraryAsync(libraryId); library.ChangeTracker.Enable(); _changeReader = library.ChangeTracker.GetChangeReader(); var changes = await _changeReader.ReadBatchAsync(); foreach (var change in changes) { if (change.ChangeType == StorageLibraryChangeType.ChangeTrackingLost) { await LogHelper.Write($"Changetracking lost: {change.Path}"); library.ChangeTracker.Reset(); return(null); } try { if (supportedChangeTypes.Contains(change.ChangeType)) { Debug.WriteLine($"File: {change.Path} ChangeType: {change.ChangeType}"); if (change.Path.EndsWith("thumb")) { continue; } var file = await change.GetStorageItemAsync(); if (file == null && change.ChangeType == StorageLibraryChangeType.Deleted) { var localItem = new LocalItem(); localItem.Association = association; localItem.EntityId = change.Path; result.Add(localItem); } else if (file == null || file.IsOfType(StorageItemTypes.Folder)) { await LogHelper.Write($"Skipping {change.Path}"); } else { try { //check if the file is currently in use, for example a video currently being recorded var stream = await((StorageFile)file).OpenStreamForWriteAsync(); stream.Dispose(); } catch (Exception) { continue; } var props = await file.GetBasicPropertiesAsync(); var item = new LocalItem(association, file, props); if (change.ChangeType == StorageLibraryChangeType.ContentsChanged) { //for some reason something is writing to the files after the upload, but without making changes var existingItem = ItemTableModel.GetDefault().GetItem(item); if (existingItem?.Size == item.Size) { continue; } } result.Add(item); } } } catch (Exception e) { await LogHelper.Write($"InstantUpload: {e.Message} File: {change.Path} ChangeType: {change.ChangeType}"); await LogHelper.Write(e.StackTrace); } } return(result); }
protected async Task ProcessAdds(IEnumerable <BaseItem> itemsToAdd) { var baseItems = itemsToAdd as IList <BaseItem> ?? itemsToAdd.ToList(); foreach (var item in baseItems) { try { await SetExectuingFileName(item.EntityId); if (ExecutionContext.Instance.Status == ExecutionStatus.Stopped) { break; } //the root item of an association should not be created again if (item.Id == item.Association.LocalFolderId || item.Id == item.Association.RemoteFolderId) { continue; } //skip files bigger than 50MB, these will have to be synced manually //otherwise the upload/download could take too long and task would be terminated //TODO make this configurable if (item.Size > (50 * 1024 * 1024) & _isBackgroundTask) { item.SyncPostponed = true; ItemTableModel.GetDefault().UpdateItem(item, item.Id); continue; } string targetEntitiyId = null; if (item.AdapterType == _targetEntityAdapter.GetType()) { targetEntitiyId = _sourceEntityAdapter.BuildEntityId(item); } if (item.AdapterType == _sourceEntityAdapter.GetType()) { targetEntitiyId = _targetEntityAdapter.BuildEntityId(item); } //if a new item is added which already exists on the other side we just assume //that they both have the same content and just create a link but do not upload/download anything //this the could be the case at the initial sync. The initial sync should never update //items on one side because we can not compare the contents of files var foundItem = ItemTableModel.GetDefault().GetItemFromEntityId(targetEntitiyId); var result = foundItem ?? await Insert(item); AfterInsert(item, result); if (await TimeIsOver()) { break; } } catch (Exception e) { ToastHelper.SendToast(string.Format("Message: {0}, EntitityId: {1}", e.Message, item.EntityId)); await LogHelper.Write(string.Format("Message: {0}, EntitityId: {1} StackTrace:\r\n{2}", e.Message, item.EntityId, e.StackTrace)); } } }
protected async Task ProcessUpdates(IEnumerable <dynamic> itemsToUpdate) { var toUpdate = itemsToUpdate as IList <dynamic> ?? itemsToUpdate.ToList(); await LogHelper.Write($"{toUpdate.Count} items to update"); foreach (var item in toUpdate) { try { await SetExectuingFileName(item.BaseItem.EntityId); if (ExecutionContext.Instance.Status == ExecutionStatus.Stopped) { break; } //the root item of an association should not be created again if (item.BaseItem.Id == item.BaseItem.Association.LocalFolderId || item.BaseItem.Id == item.BaseItem.Association.RemoteFolderId) { continue; } //skip files bigger than 50MB, these will have to be synced manually //otherwise the upload/download could take too long and task would be terminated //TODO make this configurable if (item.BaseItem.Size > (50 * 1024 * 1024) & _isBackgroundTask) { item.BaseItem.SyncPostponed = true; ItemTableModel.GetDefault().UpdateItem(item.BaseItem, item.BaseItem.Id); continue; } //get the linked item var linkedItem = ItemTableModel.GetDefault() .GetItem(item.BaseItem.Id == item.LinkStatus.SourceItemId ? item.LinkStatus.TargetItemId : item.LinkStatus.SourceItemId); //if both (item and the linkedItem) have a higher changenum than the link we have a conflict. //That means both item have been updated since the last time we checked. //so we check which one has the latest change and if it is the current item we update ititem.LinkStatus if (linkedItem != null && item.BaseItem.ChangeNumber > item.LinkStatus.ChangeNumber && linkedItem.ChangeNumber > item.LinkStatus.ChangeNumber) { if (item.BaseItem.LastModified > linkedItem.LastModified) { var result = await Update(item.BaseItem); AfterUpdate(item.BaseItem, result); } } else { var result = await Update(item.BaseItem); AfterUpdate(item.BaseItem, result); } if (await TimeIsOver()) { break; } } catch (Exception e) { var historyEntry = new SyncHistoryEntry(); historyEntry.CreateDate = DateTime.Now; historyEntry.SourceItemId = item.BaseItem.Id; historyEntry.Result = SyncResult.Failed; historyEntry.Message = e.Message; SyncHistoryTableModel.GetDefault().InsertItem(historyEntry); ToastHelper.SendToast(string.Format("Message: {0}, EntitityId: {1}", e.Message, item.BaseItem.EntityId)); await LogHelper.Write(string.Format("Message: {0}, EntitityId: {1} StackTrace:\r\n{2}", e.Message, item.BaseItem.EntityId, e.StackTrace)); } } }
public void RemoveFromSyncedFolders(FolderAssociation association) { ItemTableModel.GetDefault().DeleteItemsFromAssociation(association); LinkStatusTableModel.GetDefault().DeleteLinksFromAssociation(association); FolderAssociationTableModel.GetDefault().DeleteItem(association.Id); }
private bool ChangekeyHasChanged(BaseItem item) { var i = ItemTableModel.GetDefault().GetItem(item); return(i == null || i.ChangeKey != item.ChangeKey); }
private BaseItem GetAssociatedItem(long id) { return(ItemTableModel.GetDefault().GetItem(id)); }
protected async Task ProcessDeletions(List <BaseItem> deletedItems) { await SetExecutionStatus(ExecutionStatus.Deletions); foreach (var item in deletedItems) { try { if (item.AdapterType == _targetEntityAdapter.GetType() && item.Association.SyncDirection == SyncDirection.FullSync) { await _sourceEntityAdapter.DeleteItem(item); } if (item.AdapterType == _sourceEntityAdapter.GetType() && item.Association.SyncDirection == SyncDirection.FullSync) { await _targetEntityAdapter.DeleteItem(item); } var link = LinkStatusTableModel.GetDefault().GetItem(item); if (link != null && item.Association.SyncDirection == SyncDirection.FullSync) { //the linked item should only be deleted from the database if its a full sync //otherwise changes might not be tracked anymore if the user makes changes to the sync direction var linkedItem = ItemTableModel.GetDefault().GetItem(link.TargetItemId); if (linkedItem != null) { if (linkedItem.IsCollection) { var childItems = ItemTableModel.GetDefault().GetFilesForFolder(linkedItem.EntityId); foreach (var childItem in childItems) { var childLink = LinkStatusTableModel.GetDefault().GetItem(childItem); if (childLink != null) { LinkStatusTableModel.GetDefault().DeleteItem(childLink.Id); } ItemTableModel.GetDefault().DeleteItem(childItem.Id); } } ItemTableModel.GetDefault().DeleteItem(linkedItem.Id); var historyEntry = new SyncHistoryEntry(); historyEntry.CreateDate = DateTime.Now; historyEntry.Result = SyncResult.Deleted; historyEntry.OldItemDisplayName = item.DisplayName; SyncHistoryTableModel.GetDefault().InsertItem(historyEntry); } } if (link != null) { LinkStatusTableModel.GetDefault().DeleteItem(link.Id); } if (item.IsCollection) { var childItems = ItemTableModel.GetDefault().GetFilesForFolder(item.EntityId); foreach (var childItem in childItems) { ItemTableModel.GetDefault().DeleteItem(childItem.Id); _deletedCount++; } } ItemTableModel.GetDefault().DeleteItem(item.Id); _deletedCount++; } catch (Exception e) { ToastHelper.SendToast(string.Format("Message: {0}, EntitityId: {1}", e.Message, item.EntityId)); await LogHelper.Write(string.Format("Message: {0}, EntitityId: {1} StackTrace:\r\n{2}", e.Message, item.EntityId, e.StackTrace)); } } }
private async Task _GetChangesFromSearchIndex(StorageFolder folder, long associationId, List <BaseItem> result) { var association = FolderAssociationTableModel.GetDefault().GetItem(associationId); var files = new List <IStorageItem>(); var options = new QueryOptions(); options.FolderDepth = FolderDepth.Deep; options.IndexerOption = IndexerOption.UseIndexerWhenAvailable; //details about filesystem queries using the indexer //https://msdn.microsoft.com/en-us/magazine/mt620012.aspx string timeFilter = "System.Search.GatherTime:>=" + association.LastSync; options.ApplicationSearchFilter = timeFilter; var prefetchedProperties = new List <string> { "System.DateModified", "System.Size" }; options.SetPropertyPrefetch(PropertyPrefetchOptions.BasicProperties, prefetchedProperties); if (!folder.AreQueryOptionsSupported(options)) { throw new Exception($"Windows Search Index has to be enabled for {folder.Path}"); } var queryResult = folder.CreateItemQueryWithOptions(options); queryResult.ApplyNewQueryOptions(options); files.AddRange(await queryResult.GetItemsAsync()); foreach (var file in files) { try { IDictionary <string, object> propertyResult = null; if (file.IsOfType(StorageItemTypes.File)) { propertyResult = await((StorageFile)file).Properties.RetrievePropertiesAsync(prefetchedProperties); } else if (file.IsOfType(StorageItemTypes.Folder)) { propertyResult = await((StorageFolder)file).Properties.RetrievePropertiesAsync(prefetchedProperties); } var item = new LocalItem(new FolderAssociation { Id = associationId }, file, propertyResult); var existingItem = ItemTableModel.GetDefault().GetItem(item); if (existingItem != null) { if (!item.IsCollection) { //additional check if the file has changed: //even though the size not the best way to make sure if a file has changed //its very unlikely that after a change they have the exact same byte count //so its the best option we have if ((ulong)propertyResult["System.Size"] == existingItem.Size) { continue; } } } result.Add(item); } catch (Exception) { Debug.WriteLine(file); throw; } } if (files.Count == 0) { await _GetChangedFilesRecursive(folder, association, result); } if (!IsBackgroundSync) { var unsynced = ItemTableModel.GetDefault() .GetPostponedItems() .Where(x => x.AdapterType == typeof(FileSystemAdapter)); foreach (var abstractItem in unsynced) { abstractItem.SyncPostponed = false; } result.AddRange(unsynced); } }