Prechádzať zdrojové kódy

Add async Begin/End Close methods.
Avoid waiting for async method to complete when its already completed.

Gert Driesen 8 rokov pred
rodič
commit
768d1c9a68

+ 1 - 0
src/Renci.SshNet/Renci.SshNet.csproj

@@ -415,6 +415,7 @@
     <Compile Include="Sftp\Responses\SftpResponse.cs" />
     <Compile Include="Sftp\Responses\SftpStatusResponse.cs" />
     <Compile Include="Sftp\Responses\SftpVersionResponse.cs" />
+    <Compile Include="Sftp\SftpCloseAsyncResult.cs" />
     <Compile Include="Sftp\SftpDownloadAsyncResult.cs" />
     <Compile Include="Sftp\SftpFile.cs" />
     <Compile Include="Sftp\SftpFileAttributes.cs" />

+ 18 - 0
src/Renci.SshNet/Sftp/ISftpSession.cs

@@ -301,6 +301,24 @@ namespace Renci.SshNet.Sftp
         /// <param name="handle">The handle.</param>
         void RequestClose(byte[] handle);
 
+        /// <summary>
+        /// Performs SSH_FXP_CLOSE request.
+        /// </summary>
+        /// <param name="handle">The handle.</param>
+        /// <param name="callback">The <see cref="AsyncCallback"/> delegate that is executed when <see cref="BeginClose(byte[], AsyncCallback, object)"/> completes.</param>
+        /// <param name="state">An object that contains any additional user-defined data.</param>
+        /// <returns>
+        /// A <see cref="SftpCloseAsyncResult"/> that represents the asynchronous call.
+        /// </returns>
+        SftpCloseAsyncResult BeginClose(byte[] handle, AsyncCallback callback, object state);
+
+        /// <summary>
+        /// Handles the end of an asynchronous close.
+        /// </summary>
+        /// <param name="asyncResult">An <see cref="SftpCloseAsyncResult"/> that represents an asynchronous call.</param>
+        /// <exception cref="ArgumentNullException"><paramref name="asyncResult"/> is <c>null</c>.</exception>
+        void EndClose(SftpCloseAsyncResult asyncResult);
+
         /// <summary>
         /// Calculates the optimal size of the buffer to read data from the channel.
         /// </summary>

+ 12 - 0
src/Renci.SshNet/Sftp/SftpCloseAsyncResult.cs

@@ -0,0 +1,12 @@
+using Renci.SshNet.Common;
+using System;
+
+namespace Renci.SshNet.Sftp
+{
+    internal class SftpCloseAsyncResult : AsyncResult
+    {
+        public SftpCloseAsyncResult(AsyncCallback asyncCallback, object state) : base(asyncCallback, state)
+        {
+        }
+    }
+}

+ 67 - 2
src/Renci.SshNet/Sftp/SftpSession.cs

@@ -407,7 +407,7 @@ namespace Renci.SshNet.Sftp
         }
 
         /// <summary>
-        /// Handles the end of an asynchronous read.
+        /// Handles the end of an asynchronous open.
         /// </summary>
         /// <param name="asyncResult">An <see cref="SftpOpenAsyncResult"/> that represents an asynchronous call.</param>
         /// <returns>
@@ -426,6 +426,9 @@ namespace Renci.SshNet.Sftp
             if (asyncResult.EndInvokeCalled)
                 throw new InvalidOperationException("EndOpen has already been called.");
 
+            if (asyncResult.IsCompleted)
+                return asyncResult.EndInvoke();
+
             using (var waitHandle = asyncResult.AsyncWaitHandle)
             {
                 WaitOnHandle(waitHandle, OperationTimeout);
@@ -461,6 +464,56 @@ namespace Renci.SshNet.Sftp
             }
         }
 
+        /// <summary>
+        /// Performs SSH_FXP_CLOSE request.
+        /// </summary>
+        /// <param name="handle">The handle.</param>
+        /// <param name="callback">The <see cref="AsyncCallback"/> delegate that is executed when <see cref="BeginClose(byte[], AsyncCallback, object)"/> completes.</param>
+        /// <param name="state">An object that contains any additional user-defined data.</param>
+        /// <returns>
+        /// A <see cref="SftpCloseAsyncResult"/> that represents the asynchronous call.
+        /// </returns>
+        public SftpCloseAsyncResult BeginClose(byte[] handle, AsyncCallback callback, object state)
+        {
+            var asyncResult = new SftpCloseAsyncResult(callback, state);
+
+            var request = new SftpCloseRequest(ProtocolVersion, NextRequestId, handle,
+                response =>
+                {
+                    asyncResult.SetAsCompleted(GetSftpException(response), false);
+                });
+            SendRequest(request);
+
+            return asyncResult;
+        }
+
+        /// <summary>
+        /// Handles the end of an asynchronous close.
+        /// </summary>
+        /// <param name="asyncResult">An <see cref="SftpCloseAsyncResult"/> that represents an asynchronous call.</param>
+        /// <exception cref="ArgumentNullException"><paramref name="asyncResult"/> is <c>null</c>.</exception>
+        public void EndClose(SftpCloseAsyncResult asyncResult)
+        {
+            if (asyncResult == null)
+                throw new ArgumentNullException("asyncResult");
+
+            if (asyncResult.EndInvokeCalled)
+                throw new InvalidOperationException("EndClose has already been called.");
+
+            if (asyncResult.IsCompleted)
+            {
+                asyncResult.EndInvoke();
+            }
+            else
+            {
+                using (var waitHandle = asyncResult.AsyncWaitHandle)
+                {
+                    WaitOnHandle(waitHandle, OperationTimeout);
+                    asyncResult.EndInvoke();
+                }
+            }
+        }
+
         /// <summary>
         /// Begins an asynchronous read using a SSH_FXP_READ request.
         /// </summary>
@@ -517,6 +570,9 @@ namespace Renci.SshNet.Sftp
             if (asyncResult.EndInvokeCalled)
                 throw new InvalidOperationException("EndRead has already been called.");
 
+            if (asyncResult.IsCompleted)
+                return asyncResult.EndInvoke();
+
             using (var waitHandle = asyncResult.AsyncWaitHandle)
             {
                 WaitOnHandle(waitHandle, OperationTimeout);
@@ -697,6 +753,9 @@ namespace Renci.SshNet.Sftp
             if (asyncResult.EndInvokeCalled)
                 throw new InvalidOperationException("EndLStat has already been called.");
 
+            if (asyncResult.IsCompleted)
+                return asyncResult.EndInvoke();
+
             using (var waitHandle = asyncResult.AsyncWaitHandle)
             {
                 WaitOnHandle(waitHandle, OperationTimeout);
@@ -1050,6 +1109,9 @@ namespace Renci.SshNet.Sftp
             if (asyncResult.EndInvokeCalled)
                 throw new InvalidOperationException("EndRealPath has already been called.");
 
+            if (asyncResult.IsCompleted)
+                return asyncResult.EndInvoke();
+
             using (var waitHandle = asyncResult.AsyncWaitHandle)
             {
                 WaitOnHandle(waitHandle, OperationTimeout);
@@ -1126,7 +1188,7 @@ namespace Renci.SshNet.Sftp
         }
 
         /// <summary>
-        /// Handles the end of an asynchronous read.
+        /// Handles the end of an asynchronous stat.
         /// </summary>
         /// <param name="asyncResult">An <see cref="SFtpStatAsyncResult"/> that represents an asynchronous call.</param>
         /// <returns>
@@ -1141,6 +1203,9 @@ namespace Renci.SshNet.Sftp
             if (asyncResult.EndInvokeCalled)
                 throw new InvalidOperationException("EndStat has already been called.");
 
+            if (asyncResult.IsCompleted)
+                return asyncResult.EndInvoke();
+
             using (var waitHandle = asyncResult.AsyncWaitHandle)
             {
                 WaitOnHandle(waitHandle, OperationTimeout);