Reworked IMAP setup flow. Implemented easy way to share protocol log on failure if possible.

This commit is contained in:
Burak Kaan Köse
2024-06-17 02:16:06 +02:00
parent a788b1706b
commit 49afed7751
24 changed files with 1000 additions and 331 deletions

View File

@@ -1,7 +1,10 @@
using System;
using System.Collections.Concurrent;
using System.IO;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using MailKit;
using MailKit.Net.Imap;
using MailKit.Net.Proxy;
using MailKit.Security;
@@ -20,7 +23,7 @@ namespace Wino.Core.Integration
/// TODO: Listens to the Inbox folder for new messages.
/// </summary>
/// <param name="customServerInformation">Connection/Authentication info to be used to configure ImapClient.</param>
public class ImapClientPool
public class ImapClientPool : IDisposable
{
// Hardcoded implementation details for ID extension if the server supports.
// Some providers like Chinese 126 require Id to be sent before authentication.
@@ -40,11 +43,13 @@ namespace Wino.Core.Integration
private readonly ConcurrentBag<ImapClient> _clients = [];
private readonly SemaphoreSlim _semaphore = new(MaxPoolSize);
private readonly CustomServerInformation _customServerInformation;
private readonly Stream _protocolLogStream;
private readonly ILogger _logger = Log.ForContext<ImapClientPool>();
public ImapClientPool(CustomServerInformation customServerInformation)
public ImapClientPool(CustomServerInformation customServerInformation, Stream protocolLogStream = null)
{
_customServerInformation = customServerInformation;
_protocolLogStream = protocolLogStream;
}
private async Task EnsureConnectivityAsync(ImapClient client, bool isCreatedNew)
@@ -75,7 +80,7 @@ namespace Wino.Core.Integration
}
catch (Exception ex)
{
throw new ImapClientPoolException(ex);
throw new ImapClientPoolException(ex, GetProtocolLogContent());
}
finally
{
@@ -84,6 +89,18 @@ namespace Wino.Core.Integration
}
}
public string GetProtocolLogContent()
{
if (_protocolLogStream == null) return default;
// Set the position to the beginning of the stream in case it is not already at the start
if (_protocolLogStream.CanSeek)
_protocolLogStream.Seek(0, SeekOrigin.Begin);
using var reader = new StreamReader(_protocolLogStream, Encoding.UTF8, true, 1024, leaveOpen: true);
return reader.ReadToEnd();
}
public async Task<ImapClient> GetClientAsync()
{
await _semaphore.WaitAsync();
@@ -113,7 +130,17 @@ namespace Wino.Core.Integration
public ImapClient CreateNewClient()
{
var client = new ImapClient();
ImapClient client = null;
// Make sure to create a ImapClient with a protocol logger if enabled.
if (_protocolLogStream != null)
{
client = new ImapClient(new ProtocolLogger(_protocolLogStream));
}
else
{
client = new ImapClient();
}
HttpProxyClient proxyClient = null;
@@ -175,5 +202,20 @@ namespace Wino.Core.Integration
await client.AuthenticateAsync(_customServerInformation.IncomingServerUsername, _customServerInformation.IncomingServerPassword);
}
public void Dispose()
{
foreach (var client in _clients)
{
client.Disconnect(true);
client.Dispose();
}
if (_protocolLogStream != null)
{
_protocolLogStream.Flush();
_protocolLogStream.Dispose();
}
}
}
}