diff --git a/Wino.Core/Integration/ImapClientPool.cs b/Wino.Core/Integration/ImapClientPool.cs index b0f6ea09..f72e07e4 100644 --- a/Wino.Core/Integration/ImapClientPool.cs +++ b/Wino.Core/Integration/ImapClientPool.cs @@ -9,6 +9,7 @@ using MailKit; using MailKit.Net.Imap; using MailKit.Net.Proxy; using MailKit.Security; +using MoreLinq; using Serilog; using Wino.Core.Domain.Entities; using Wino.Core.Domain.Enums; @@ -39,10 +40,10 @@ namespace Wino.Core.Integration Vendor = "Wino" }; - private const int MaxPoolSize = 5; + private readonly int MinimumPoolSize = 5; - private readonly ConcurrentBag _clients = []; - private readonly SemaphoreSlim _semaphore = new(MaxPoolSize); + private readonly ConcurrentStack _clients = []; + private readonly SemaphoreSlim _semaphore; private readonly CustomServerInformation _customServerInformation; private readonly Stream _protocolLogStream; private readonly ILogger _logger = Log.ForContext(); @@ -51,6 +52,9 @@ namespace Wino.Core.Integration { _customServerInformation = customServerInformation; _protocolLogStream = protocolLogStream; + + // Set the maximum pool size to 5 or the custom value if it's greater. + _semaphore = new(Math.Max(MinimumPoolSize, customServerInformation.MaxConcurrentClients)); } private async Task EnsureConnectivityAsync(ImapClient client, bool isCreatedNew) @@ -126,7 +130,7 @@ namespace Wino.Core.Integration { await _semaphore.WaitAsync(); - if (_clients.TryTake(out ImapClient item)) + if (_clients.TryPop(out ImapClient item)) { await EnsureConnectivityAsync(item, false); @@ -140,16 +144,37 @@ namespace Wino.Core.Integration return client; } - public void Release(ImapClient item) + public void Release(ImapClient item, bool destroyClient = false) { if (item != null) { - _clients.Add(item); + if (destroyClient) + { + lock (item.SyncRoot) + { + item.Disconnect(true); + } + + item.Dispose(); + } + else + { + _clients.Push(item); + } + _semaphore.Release(); } } - public ImapClient CreateNewClient() + public void DestroyClient(ImapClient client) + { + if (client == null) return; + + client.Disconnect(true); + client.Dispose(); + } + + private ImapClient CreateNewClient() { ImapClient client = null; @@ -232,11 +257,20 @@ namespace Wino.Core.Integration public void Dispose() { - foreach (var client in _clients) + _clients.ForEach(client => + { + lock (client.SyncRoot) + { + client.Disconnect(true); + } + }); + + _clients.ForEach(client => { - client.Disconnect(true); client.Dispose(); - } + }); + + _clients.Clear(); if (_protocolLogStream != null) { diff --git a/Wino.Core/Services/ImapTestService.cs b/Wino.Core/Services/ImapTestService.cs index a073ffef..b9cc54bf 100644 --- a/Wino.Core/Services/ImapTestService.cs +++ b/Wino.Core/Services/ImapTestService.cs @@ -45,8 +45,7 @@ namespace Wino.Core.Services // This call will make sure that everything is authenticated + connected successfully. var client = await clientPool.GetClientAsync(); - await client.DisconnectAsync(true); - client.Dispose(); + clientPool.Release(client); } } }