private Task ExecuteBackgroundCommandAsync(
            FtpContext context,
            IFtpCommandBase handler,
            CancellationToken cancellationToken)
        {
            var backgroundTaskFeature = _connection.Features.Get <IBackgroundTaskLifetimeFeature?>();

            if (backgroundTaskFeature == null)
            {
                backgroundTaskFeature = new BackgroundTaskLifetimeFeature(
                    handler,
                    context.Command,
                    ct =>
                {
                    var executionContext = new FtpExecutionContext(context, handler, ct);
                    return(_executionDelegate(executionContext));
                },
                    cancellationToken);
                _connection.Features.Set(backgroundTaskFeature);
                return(Task.CompletedTask);
            }

            return(SendResponseAsync(
                       new FtpResponse(503, T("Parallel commands aren't allowed.")),
                       cancellationToken));
        }
Exemple #2
0
 /// <summary>
 /// Initializes a new instance of the <see cref="FtpCommandSelection"/> class.
 /// </summary>
 /// <param name="handler">The FTP command handler.</param>
 /// <param name="handlerInformation">The FTP command handler information.</param>
 public FtpCommandSelection(
     IFtpCommandBase handler,
     IFtpCommandInformation handlerInformation)
 {
     Handler     = handler;
     Information = handlerInformation;
 }
 /// <summary>
 /// Initializes a new instance of the <see cref="FtpCommandSelection"/> class.
 /// </summary>
 /// <param name="handler">The FTP command handler.</param>
 /// <param name="handlerInformation">The FTP command handler information.</param>
 public FtpCommandSelection(
     [NotNull] IFtpCommandBase handler,
     [NotNull] IFtpCommandInformation handlerInformation)
 {
     Handler     = handler;
     Information = handlerInformation;
 }
 /// <summary>
 /// Initializes a new instance of the <see cref="FtpExecutionContext"/> class.
 /// </summary>
 /// <param name="ftpContext">The FTP context.</param>
 /// <param name="commandHandler">The FTP command handler.</param>
 /// <param name="commandAborted">The cancellation token signalling an aborted command.</param>
 public FtpExecutionContext(
     [NotNull] FtpContext ftpContext,
     [NotNull] IFtpCommandBase commandHandler,
     CancellationToken commandAborted)
     : base(ftpContext.Command, ftpContext.ServerCommandWriter, ftpContext.Connection)
 {
     CommandHandler = commandHandler;
     CommandAborted = commandAborted;
 }
 /// <summary>
 /// Initializes a new instance of the <see cref="BackgroundTaskLifetimeFeature"/> class.
 /// </summary>
 /// <param name="command">The FTP command to be run in the background.</param>
 /// <param name="commandHandler">The FTP command handler.</param>
 /// <param name="backgroundTask">The task that gets run in the background.</param>
 /// <param name="cancellationToken">The cancellation token.</param>
 public BackgroundTaskLifetimeFeature(
     [NotNull] IFtpCommandBase commandHandler,
     [NotNull] FtpCommand command,
     [NotNull] Func <CancellationToken, Task> backgroundTask,
     CancellationToken cancellationToken)
 {
     Command = command;
     Handler = commandHandler;
     Task    = Task.Run(
         async() =>
     {
         var registration = cancellationToken.Register(() => _taskCts.Cancel());
         try
         {
             await backgroundTask(_taskCts.Token)
             .ConfigureAwait(false);
         }
         finally
         {
             registration.Dispose();
         }
     });
 }
Exemple #6
0
        /// <inheritdoc />
        public Task <FtpResponse> Execute(IFtpCommandBase handler, FtpCommand command)
        {
            lock (_syncRoot)
            {
                if (_handlerTask != null)
                {
                    return(null);
                }

                _cancellationTokenSource = new CancellationTokenSource();
                _handlerTask             = handler.Process(command, _cancellationTokenSource.Token);
            }

            var taskCanceled = _handlerTask
                               .ContinueWith(
                t =>
            {
                var response = new FtpResponse(426, "Connection closed; transfer aborted.");
                Debug.WriteLine($"Background task cancelled with response {response}");
                return(response);
            },
                TaskContinuationOptions.OnlyOnCanceled);

            var taskCompleted = _handlerTask
                                .ContinueWith(
                t =>
            {
                var response = t.Result;
                Debug.WriteLine($"{DateTimeOffset.UtcNow} Background task finished successfully with response {response}");
                return(response);
            },
                TaskContinuationOptions.OnlyOnRanToCompletion);

            var taskFaulted = _handlerTask
                              .ContinueWith(
                t =>
            {
                var ex = t.Exception;
                _connection.Log?.LogError(ex, "Error while processing background command {0}", command);
                var response = new FtpResponse(501, "Syntax error in parameters or arguments.");
                Debug.WriteLine($"Background task failed with response {response}");
                return(response);
            },
                TaskContinuationOptions.OnlyOnFaulted);

            taskFaulted.ContinueWith(t => { }, TaskContinuationOptions.OnlyOnCanceled);
            taskCompleted.ContinueWith(t => { }, TaskContinuationOptions.OnlyOnCanceled);
            taskCanceled.ContinueWith(t => { }, TaskContinuationOptions.OnlyOnCanceled);

            return(Task.Run(
                       () =>
            {
                var tasks = new List <Task <FtpResponse> > {
                    taskCompleted, taskCanceled, taskFaulted
                };

                do
                {
                    try
                    {
                        var waitTasks = tasks.Where(x => !x.IsCompleted).Cast <Task>().ToArray();
                        if (waitTasks.Length != 0)
                        {
                            Debug.WriteLine($"Waiting for {waitTasks.Length} background tasks");
                            Task.WaitAll(waitTasks);
                        }
                    }
                    catch (AggregateException ex)
                    {
                        ex.Handle(e => e is TaskCanceledException);
                    }
                }while (tasks.Any(t => !t.IsCompleted));

                var response = tasks.Single(x => x.Status == TaskStatus.RanToCompletion).Result;
                Debug.WriteLine($"{DateTimeOffset.UtcNow} Background task finished with response {response}");

                lock (_syncRoot)
                {
                    _handlerTask = null;
                }

                return response;
            }));
        }