FubarDevelopment / FtpServer

Portable FTP server written in .NET
http://fubardevelopment.github.io/FtpServer/
MIT License
472 stars 161 forks source link

Enables the underlying TCP Listener to be configured and run by the c… #115

Closed robeving closed 2 years ago

robeving commented 3 years ago

This PR enables the caller to have greater control of the underlying TCPListener implementation by specifying an interface to use. It also makes PausableFtpService public. PausableFtpService is used by a number of classes already and it does a lot of the heavy lifting so callers should make use of it.

In my case I have my own server implementation that I want to use which provides diagnostics, management etc. I can now use a very small class like this to pass through individual TCP connections.

    internal class InternalListener : PausableFtpService, IListenerService
    {
        private readonly Channel<TcpClient> channels = System.Threading.Channels.Channel.CreateBounded<TcpClient>(1);
        private CancellationTokenSource cts;
        private TcpClient client;

        public InternalListener(CancellationTokenSource cts, TcpClient client) : base(cts.Token)
        {
            this.cts = cts;
            this.client = client;
        }

        public ChannelReader<TcpClient> Channel => channels;
        public CancellationToken Token => cts.Token;
        public bool IsCancellationRequested => cts.IsCancellationRequested;
        public event EventHandler<ListenerStartedEventArgs> ListenerStarted;

        public void Cancel(bool throwOnFirstException)
        {
            cts.Cancel(throwOnFirstException);
        }

        public void Dispose()
        {
            cts.Cancel();
            cts.Dispose();
        }

        protected override async Task ExecuteAsync(CancellationToken cancellationToken)
        {
            try
            {
                ListenerStarted?.Invoke(this, new ListenerStartedEventArgs((client.Client.LocalEndPoint as IPEndPoint).Port));
                await channels.Writer.WriteAsync(client, cancellationToken).ConfigureAwait(false);
            }
            catch (Exception ex) when (ex is OperationCanceledException)
            {
                // Ignore - everything is fine
            }
        }
    }

Fixes https://github.com/FubarDevelopment/FtpServer/issues/114

fubar-coder commented 3 years ago

This looks good. I'll take a look why some of the checks failed.