Exemple #1
0
        /// <inheritdoc/>
        public async Task GetChildrenAsync(string pattern, IOperationContext operationContext, IFolderListingResultContext resultContext)
        {
            // This method has a 60 sec timeout.
            // To process longer requests and reset the timout timer call one of the following:
            // - IGetChildrenContext.ReturnChildren() method.
            // - IGetChildrenContext.ReportProgress() method.

            LogMessage($"IFolder.GetChildrenAsync({pattern})", this.FullPath);

            string remoreStoragePath = Mapping.MapPath(this.FullPath);

            IEnumerable <FileSystemInfo>    remoteStorageChildren  = new DirectoryInfo(remoreStoragePath).EnumerateFileSystemInfos(pattern);
            List <IFileSystemItemBasicInfo> userFileSystemChildren = new List <IFileSystemItemBasicInfo>();

            foreach (FileSystemInfo remoteStorageItem in remoteStorageChildren)
            {
                string userFileSystemPath = Path.Combine(this.FullPath, Path.GetFileName(remoteStorageItem.Name));
                if (!FsPath.Exists(userFileSystemPath))
                {
                    // Uncomment to simulate slow network access.
                    //Thread.Sleep(10000);
                    //resultContext.ReportProgress(remoteStorageChildren.Count(), userFileSystemChildren.Count());

                    LogMessage("Creating:", Path.GetFileName(remoteStorageItem.Name));
                    FileSystemItemBasicInfo userFileSystemItemInfo = Mapping.GetUserFileSysteItemInfo(remoteStorageItem);
                    userFileSystemChildren.Add(userFileSystemItemInfo);
                }
            }

            // To signal that the children enumeration is completed
            // always call this method in GetChildrenAsync(), even if the folder is empty.
            resultContext.ReturnChildren(userFileSystemChildren.ToArray(), userFileSystemChildren.Count());
        }
        /// <summary>
        /// Returns true if the remote storage ETag and user file system ETags are equal. False - otherwise.
        /// </summary>
        /// <param name="userFileSystemPath">User file system item.</param>
        /// <param name="remoteStorageItem">Remote storage item info.</param>
        /// <remarks>
        /// ETag is updated on the server during every document update and is sent to client with a file.
        /// During client->server update it is sent back to the remote storage together with a modified content.
        /// This ensures the changes on the server are not overwritten if the document on the server is modified.
        /// </remarks>
        internal static async Task <bool> ETagEqualsAsync(string userFileSystemPath, FileSystemItemBasicInfo remoteStorageItem)
        {
            string remoteStorageETag  = remoteStorageItem.ETag;
            string userFileSystemETag = await ETag.GetETagAsync(userFileSystemPath);

            if (string.IsNullOrEmpty(remoteStorageETag) && string.IsNullOrEmpty(userFileSystemETag))
            {
                // We assume the remote storage is not using ETags or no ETag is ssociated with this file/folder.
                return(true);
            }

            return(remoteStorageETag == userFileSystemETag);
        }
        /// <summary>
        /// Creates or updates folder in the remote storage.
        /// </summary>
        /// <param name="remoteStoragePath">Path of the folder to be created or updated in the remote storage.</param>
        /// <param name="newInfo">New information about the folder, such as modification date, attributes, custom data, etc.</param>
        /// <param name="mode">Specifies if a new folder should be created or existing folder should be updated.</param>
        /// <returns>New ETag returned from the remote storage.</returns>
        protected async Task <string> CreateOrUpdateFolderAsync(string remoteStoragePath, IFolderBasicInfo newInfo, FileMode mode)
        {
            // Get ETag and lock-token here and send it to the remote storage with the new item content/info if needed.
            if (mode == FileMode.Open)
            {
                // Get ETag.
                string eTag = await ETag.GetETagAsync(UserFileSystemPath);

                // Get lock-token.
                string lockToken = Lock?.LockToken;
            }

            DirectoryInfo remoteStorageItem = new DirectoryInfo(remoteStoragePath);

            try
            {
                Program.RemoteStorageMonitorInstance.Enabled = false; // Disable RemoteStorageMonitor to avoid circular calls.

                remoteStorageItem.Create();

                string userFileSystemPath = Mapping.ReverseMapPath(remoteStoragePath);
                if (mode == FileMode.Open)
                {
                    // Verify that the item in the remote storage is not modified since it was downloaded to the user file system.
                    // In your real-life application you will send the ETag to the server as part of the update request.
                    FileSystemItemBasicInfo itemInfo = Mapping.GetUserFileSysteItemBasicInfo(remoteStorageItem);
                    if (!(await ETag.ETagEqualsAsync(userFileSystemPath, itemInfo)))
                    {
                        throw new ConflictException(Modified.Server, "Item is modified in the remote storage, ETags not equal.");
                    }
                }

                // Update ETag/LastWriteTime in user file system, so the synchronyzation or remote storage monitor would not start the new update.
                // This is only required to avoid circular updates because of the simplicity of this sample.
                // In your real-life application you will receive a new ETag from server in the update response.
                string eTag = newInfo.LastWriteTime.ToBinary().ToString();
                await ETag.SetETagAsync(userFileSystemPath, eTag);

                remoteStorageItem.Attributes        = newInfo.Attributes;
                remoteStorageItem.CreationTimeUtc   = newInfo.CreationTime;
                remoteStorageItem.LastWriteTimeUtc  = newInfo.LastWriteTime;
                remoteStorageItem.LastAccessTimeUtc = newInfo.LastAccessTime;
                remoteStorageItem.LastWriteTimeUtc  = newInfo.LastWriteTime;

                return(eTag);
            }
            finally
            {
                Program.RemoteStorageMonitorInstance.Enabled = true;
            }
        }
Exemple #4
0
        /// <summary>
        /// Returns true if the remote storage ETag and user file system ETags are equal. False - otherwise.
        /// </summary>
        /// <param name="userFileSystemPath">User file system item.</param>
        /// <param name="remoteStorageItem">Remote storage item info.</param>
        /// <remarks>
        /// ETag is updated on the server during every document update and is sent to client with a file.
        /// During client->server update it is sent back to the remote storage together with a modified content.
        /// This ensures the changes on the server are not overwritten if the document on the server is modified.
        /// </remarks>
        internal static async Task <bool> ETagEqualsAsync(string userFileSystemPath, FileSystemItemBasicInfo remoteStorageItem)
        {
            string remoteStorageETag = remoteStorageItem.ETag;

            // Intstead of the real ETag we store remote storage LastWriteTime when
            // creating and updating files/folders.
            string userFileSystemETag = await ETag.GetETagAsync(userFileSystemPath);

            if (string.IsNullOrEmpty(userFileSystemETag))
            {
                // No ETag associated with the file. This is a new file created in user file system.
                return(false);
            }

            return(remoteStorageETag == userFileSystemETag);
        }
Exemple #5
0
        /// <summary>
        /// Gets list of files and folders in this folder in the remote storage.
        /// </summary>
        /// <param name="pattern">Search pattern.</param>
        /// <returns>
        /// List of files and folders located in this folder in the remote
        /// storage that correstonds with the provided search pattern.
        /// </returns>
        public async Task <IEnumerable <FileSystemItemBasicInfo> > EnumerateChildrenAsync(string pattern)
        {
            // This method has a 60 sec timeout.
            // To process longer requests modify the IFolder.GetChildrenAsync() implementation.

            IEnumerable <FileSystemInfo> remoteStorageChildren = new DirectoryInfo(RemoteStoragePath).EnumerateFileSystemInfos(pattern);

            List <FileSystemItemBasicInfo> userFileSystemChildren = new List <FileSystemItemBasicInfo>();

            foreach (FileSystemInfo remoteStorageItem in remoteStorageChildren)
            {
                FileSystemItemBasicInfo itemInfo = Mapping.GetUserFileSysteItemBasicInfo(remoteStorageItem);
                userFileSystemChildren.Add(itemInfo);
            }

            return(userFileSystemChildren);
        }
        /// <summary>
        /// Creates or updates file in the remote storage.
        /// </summary>
        /// <param name="remoteStoragePath">Path of the file to be created or updated in the remote storage.</param>
        /// <param name="newInfo">New information about the file, such as modification date, attributes, custom data, etc.</param>
        /// <param name="mode">Specifies if a new file should be created or existing file should be updated.</param>
        /// <param name="newContentStream">New file content or null if the file content is not modified.</param>
        /// <returns>New ETag returned from the remote storage.</returns>
        protected async Task <string> CreateOrUpdateFileAsync(string remoteStoragePath, IFileBasicInfo newInfo, FileMode mode, Stream newContentStream = null)
        {
            // Get ETag and lock-token here and send it to the remote storage with the new item content/info if needed.
            if (mode == FileMode.Open)
            {
                // Get ETag.
                string eTag = await ETag.GetETagAsync(UserFileSystemPath);

                // Get lock-token.
                string lockToken = Lock?.LockToken;
            }

            FileInfo remoteStorageItem = new FileInfo(remoteStoragePath);

            try
            {
                Program.RemoteStorageMonitorInstance.Enabled = false; // Disable RemoteStorageMonitor to avoid circular calls.

                // If another thread is trying to sync the same file, this call will fail in other threads.
                // In your implementation you must lock your remote storage file, or block it for reading and writing by other means.
                await using (FileStream remoteStorageStream = remoteStorageItem.Open(mode, FileAccess.Write, FileShare.None))
                {
                    string userFileSystemPath = Mapping.ReverseMapPath(remoteStoragePath);
                    if (mode == FileMode.Open)
                    {
                        // Verify that the item in the remote storage is not modified since it was downloaded to the user file system.
                        // In your real-life application you will send the ETag to the server as part of the update request.
                        FileSystemItemBasicInfo itemInfo = Mapping.GetUserFileSysteItemBasicInfo(remoteStorageItem);
                        if (!(await ETag.ETagEqualsAsync(userFileSystemPath, itemInfo)))
                        {
                            throw new ConflictException(Modified.Server, "Item is modified in the remote storage, ETags not equal.");
                        }
                    }

                    // Update ETag/LastWriteTime in user file system, so the synchronyzation or remote storage monitor would not start the new update.
                    // This is only required to avoid circular updates because of the simplicity of this sample.
                    // In your real-life application you will receive a new ETag from the server in the update response
                    // and return it from this method.
                    string eTag = newInfo.LastWriteTime.ToBinary().ToString();
                    await ETag.SetETagAsync(userFileSystemPath, eTag);

                    // Update remote storage file content.
                    if (newContentStream != null)
                    {
                        await newContentStream.CopyToAsync(remoteStorageStream);

                        remoteStorageStream.SetLength(newContentStream.Length);
                    }

                    // Update remote storage file basic info.
                    WindowsFileSystemItem.SetFileInformation(
                        remoteStorageStream.SafeFileHandle,
                        newInfo.Attributes,
                        newInfo.CreationTime,
                        newInfo.LastWriteTime,
                        newInfo.LastAccessTime,
                        newInfo.LastWriteTime);

                    return(eTag);
                }
            }
            finally
            {
                Program.RemoteStorageMonitorInstance.Enabled = true;
            }
        }