mirror of
https://github.com/LBPUnion/ProjectLighthouse.git
synced 2025-07-30 08:48:39 +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;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Net.Mail;
|
using System.Net.Mail;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
using LBPUnion.ProjectLighthouse.Configuration;
|
using LBPUnion.ProjectLighthouse.Configuration;
|
||||||
|
using LBPUnion.ProjectLighthouse.Logging;
|
||||||
|
|
||||||
namespace LBPUnion.ProjectLighthouse.Helpers;
|
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;
|
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,
|
EnableSsl = ServerConfiguration.Instance.Mail.UseSSL,
|
||||||
Credentials = new NetworkCredential(ServerConfiguration.Instance.Mail.Username, ServerConfiguration.Instance.Mail.Password),
|
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)
|
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,
|
Subject = subject,
|
||||||
Body = body,
|
Body = body,
|
||||||
};
|
};
|
||||||
|
|
||||||
try
|
this.emailQueue.Enqueue(new EmailEntry(message, resultTask));
|
||||||
{
|
this.emailSemaphore.Release();
|
||||||
client.Send(message);
|
|
||||||
}
|
|
||||||
catch(Exception e)
|
|
||||||
{
|
|
||||||
Console.WriteLine(e);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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,
|
Score,
|
||||||
RateLimit,
|
RateLimit,
|
||||||
Deserialization,
|
Deserialization,
|
||||||
|
Email,
|
||||||
}
|
}
|
|
@ -73,6 +73,11 @@ public class Logger
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private readonly ConcurrentQueue<LogLine> logQueue = new();
|
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>
|
/// <summary>
|
||||||
/// Adds a <see cref="LogLine"/> to the queue. Only used internally.
|
/// Adds a <see cref="LogLine"/> to the queue. Only used internally.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -86,17 +91,12 @@ public class Logger
|
||||||
public Logger() // Start queue thread on first Logger access
|
public Logger() // Start queue thread on first Logger access
|
||||||
{
|
{
|
||||||
Task.Factory.StartNew
|
Task.Factory.StartNew
|
||||||
(
|
(async () =>
|
||||||
() =>
|
|
||||||
{
|
{
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
bool logged = this.queueLoop();
|
await this.logSemaphore.WaitAsync();
|
||||||
Thread.Sleep(logged ? 10 : 100);
|
this.queueLoop();
|
||||||
// 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.
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -133,16 +133,14 @@ public class Logger
|
||||||
/// A function used by the queue thread
|
/// A function used by the queue thread
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns></returns>
|
/// <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)
|
foreach (ILogger logger in this.loggers)
|
||||||
{
|
{
|
||||||
logger.Log(line);
|
logger.Log(line);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
@ -215,6 +213,7 @@ public class Logger
|
||||||
Area = area,
|
Area = area,
|
||||||
Trace = getTrace(extraTraceLines),
|
Trace = getTrace(extraTraceLines),
|
||||||
});
|
});
|
||||||
|
this.logSemaphore.Release();
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
Loading…
Add table
Add a link
Reference in a new issue