Namespace: ITHit.WebDAV.Server.Synchronization
Task<DavChanges> GetChangesAsync( IList<PropertyName> propNames, string syncToken, bool deep, Nullable<long> limit = null )
The code below is part of 'WebDAVServer.FileSystemSynchronization.AspNetCore' C# & VB samples provided with the SDK.
public async Task<DavChanges> GetChangesAsync(IList<PropertyName> propNames, string syncToken, bool deep, long? limit = null) { // In this sample we use item's USN as a sync token. // USN increases on every item update, move, creation and deletion. DavChanges changes = new DavChanges(); long syncId = string.IsNullOrEmpty(syncToken) ? 0 : long.Parse(syncToken); // Get all file system entries with usn. List<(IChangedItem HierarchyItem, long SyncId)> childrenList = new List<(IChangedItem HierarchyItem, long SyncId)>(); foreach ((string Path, long SyncId) item in await GetSyncIdsAsync(syncId, deep)) { IChangedItem child = (IChangedItem)await GetChildAsync(item.Path); if (child != null) { childrenList.Add((child, item.SyncId)); } } // If limit==0 this is a sync-token request, no need to return any changes. bool isSyncTokenRequest = limit.HasValue && limit.Value == 0; if (isSyncTokenRequest) { changes.NewSyncToken = childrenList.Max(p => p.SyncId).ToString(); return changes; } IEnumerable<(IChangedItem HierarchyItem, long SyncId)> children = childrenList; // If syncId == 0 this is a full sync request. // We do not want to return deleted items in this case, removing them from the list. if (syncId == 0) { children = children.Where(item => item.HierarchyItem.ChangeType != Change.Deleted); } // Truncate results if limit is specified. if (limit.HasValue) { // Order children by sync ID, so we can truncate results. children = children.OrderBy(p => p.SyncId); // Truncate results. children = children.Take((int)limit.Value); // Specify if more changes can be returned. changes.MoreResults = limit.Value < childrenList.Count; } // Return new sync token. changes.NewSyncToken = children.Count() != 0 ? children.Max(p => p.SyncId).ToString() : syncToken; // Return changes. changes.AddRange(children.Select(p => p.HierarchyItem)); return changes; } private async Task<IHierarchyItem> GetChildAsync(string childPath) { string childRelPath = childPath.Substring(dirInfo.FullName.Length).Replace(System.IO.Path.DirectorySeparatorChar.ToString(), "/").TrimStart('/'); IEnumerable<string> encodedParts = childRelPath.Split('/').Select(EncodeUtil.EncodeUrlPart); string childRelUrl = Path.TrimEnd('/') + "/" + string.Join("/", encodedParts); DavHierarchyItem child = await DavFolder.GetFolderAsync(context, childRelUrl); if (child == null) { child = await DavFile.GetFileAsync(context, childRelUrl); } return child; } private async Task<IEnumerable<(string Path, long SyncId)>> GetSyncIdsAsync(long minSyncId, bool deep) { // First we must read max existing USN. However, in this sample, // for the sake of simplicity, we just read all changes under this folder. SearchOption searchOptions = deep ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly; ConcurrentBag<(string Path, long Usn)> list = new ConcurrentBag<(string Path, long Usn)>(); string[] decendants = Directory.GetFileSystemEntries(dirInfo.FullName, "*", searchOptions); ParallelOptions parallelOptions = new() { MaxDegreeOfParallelism = 1000 }; await Parallel.ForEachAsync(decendants, parallelOptions, async (path, token) => { long syncId = await new FileSystemItem(path).GetUsnAsync(); if (syncId > minSyncId) { list.Add(new(path, syncId)); } }); return list; }