mirror of
https://github.com/LBPUnion/ProjectLighthouse.git
synced 2025-07-28 16:08:38 +00:00
Improve logging and rewrite email helper
This commit is contained in:
parent
dc26766b8a
commit
fb90371ad1
3 changed files with 89 additions and 31 deletions
|
@ -1,48 +1,106 @@
|
|||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Net;
|
||||
using System.Net.Mail;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using LBPUnion.ProjectLighthouse.Configuration;
|
||||
using LBPUnion.ProjectLighthouse.Logging;
|
||||
|
||||
namespace LBPUnion.ProjectLighthouse.Helpers;
|
||||
|
||||
public static class SMTPHelper
|
||||
public class SMTPHelper
|
||||
{
|
||||
private static readonly SmtpClient client;
|
||||
private static readonly MailAddress fromAddress;
|
||||
|
||||
static SMTPHelper()
|
||||
internal static readonly SMTPHelper Instance = new();
|
||||
|
||||
private readonly SmtpClient client;
|
||||
private readonly MailAddress fromAddress;
|
||||
|
||||
private readonly ConcurrentQueue<EmailEntry> emailQueue = new();
|
||||
|
||||
private readonly SemaphoreSlim emailSemaphore = new(0);
|
||||
|
||||
private bool stopSignal;
|
||||
|
||||
private readonly Task emailThread;
|
||||
|
||||
private SMTPHelper()
|
||||
{
|
||||
if (!ServerConfiguration.Instance.Mail.MailEnabled) return;
|
||||
|
||||
client = new SmtpClient(ServerConfiguration.Instance.Mail.Host, ServerConfiguration.Instance.Mail.Port)
|
||||
this.client = new SmtpClient(ServerConfiguration.Instance.Mail.Host, ServerConfiguration.Instance.Mail.Port)
|
||||
{
|
||||
EnableSsl = ServerConfiguration.Instance.Mail.UseSSL,
|
||||
Credentials = new NetworkCredential(ServerConfiguration.Instance.Mail.Username, ServerConfiguration.Instance.Mail.Password),
|
||||
};
|
||||
this.fromAddress = new MailAddress(ServerConfiguration.Instance.Mail.FromAddress, ServerConfiguration.Instance.Mail.FromName);
|
||||
|
||||
fromAddress = new MailAddress(ServerConfiguration.Instance.Mail.FromAddress, ServerConfiguration.Instance.Mail.FromName);
|
||||
this.stopSignal = false;
|
||||
this.emailThread = Task.Factory.StartNew(this.EmailQueue);
|
||||
}
|
||||
|
||||
private async void EmailQueue()
|
||||
{
|
||||
while (!this.stopSignal)
|
||||
{
|
||||
await this.emailSemaphore.WaitAsync();
|
||||
if (!this.emailQueue.TryDequeue(out EmailEntry entry)) continue;
|
||||
|
||||
try
|
||||
{
|
||||
this.client.Send(entry.Message);
|
||||
entry.Result.SetResult(true);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.Error($"Failed to send email: {e}", LogArea.Email);
|
||||
entry.Result.SetResult(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void Dispose()
|
||||
{
|
||||
Instance.stopSignal = true;
|
||||
Instance.emailThread.Wait();
|
||||
Instance.emailThread.Dispose();
|
||||
}
|
||||
|
||||
public static bool SendEmail(string recipientAddress, string subject, string body)
|
||||
{
|
||||
if (!ServerConfiguration.Instance.Mail.MailEnabled) return false;
|
||||
TaskCompletionSource<bool> resultTask = new();
|
||||
Instance.SendEmail(recipientAddress, subject, body, resultTask);
|
||||
return resultTask.Task.Result;
|
||||
}
|
||||
|
||||
MailMessage message = new(fromAddress, new MailAddress(recipientAddress))
|
||||
public void SendEmail(string recipientAddress, string subject, string body, TaskCompletionSource<bool> resultTask)
|
||||
{
|
||||
if (!ServerConfiguration.Instance.Mail.MailEnabled)
|
||||
{
|
||||
resultTask.SetResult(false);
|
||||
return;
|
||||
}
|
||||
|
||||
MailMessage message = new(Instance.fromAddress, new MailAddress(recipientAddress))
|
||||
{
|
||||
Subject = subject,
|
||||
Body = body,
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
client.Send(message);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
Console.WriteLine(e);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
this.emailQueue.Enqueue(new EmailEntry(message, resultTask));
|
||||
this.emailSemaphore.Release();
|
||||
}
|
||||
|
||||
internal class EmailEntry
|
||||
{
|
||||
public MailMessage Message { get; set; }
|
||||
public TaskCompletionSource<bool> Result { get; set; }
|
||||
|
||||
public EmailEntry(MailMessage message, TaskCompletionSource<bool> result)
|
||||
{
|
||||
this.Message = message;
|
||||
this.Result = result;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -26,4 +26,5 @@ public enum LogArea
|
|||
Score,
|
||||
RateLimit,
|
||||
Deserialization,
|
||||
Email,
|
||||
}
|
|
@ -73,6 +73,11 @@ public class Logger
|
|||
/// </summary>
|
||||
private readonly ConcurrentQueue<LogLine> logQueue = new();
|
||||
|
||||
/// <summary>
|
||||
/// Used to signal the logging loop that a new message has arrived
|
||||
/// </summary>
|
||||
private readonly SemaphoreSlim logSemaphore = new(0);
|
||||
|
||||
/// <summary>
|
||||
/// Adds a <see cref="LogLine"/> to the queue. Only used internally.
|
||||
/// </summary>
|
||||
|
@ -86,17 +91,12 @@ public class Logger
|
|||
public Logger() // Start queue thread on first Logger access
|
||||
{
|
||||
Task.Factory.StartNew
|
||||
(
|
||||
() =>
|
||||
(async () =>
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
bool logged = this.queueLoop();
|
||||
Thread.Sleep(logged ? 10 : 100);
|
||||
// We wait 100ms if we dont log since it's less likely that the program logged again.
|
||||
// If we did log, wait 10ms before looping again.
|
||||
|
||||
// This is all so we use as little CPU as possible. This is an endless while loop, after all.
|
||||
await this.logSemaphore.WaitAsync();
|
||||
this.queueLoop();
|
||||
}
|
||||
}
|
||||
);
|
||||
|
@ -133,16 +133,14 @@ public class Logger
|
|||
/// A function used by the queue thread
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private bool queueLoop()
|
||||
private void queueLoop()
|
||||
{
|
||||
if (!this.logQueue.TryDequeue(out LogLine line)) return false;
|
||||
if (!this.logQueue.TryDequeue(out LogLine line)) return;
|
||||
|
||||
foreach (ILogger logger in this.loggers)
|
||||
{
|
||||
logger.Log(line);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
@ -215,6 +213,7 @@ public class Logger
|
|||
Area = area,
|
||||
Trace = getTrace(extraTraceLines),
|
||||
});
|
||||
this.logSemaphore.Release();
|
||||
}
|
||||
#endregion
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue