using System.Text;
using MailKit;
using Microsoft.Extensions.Logging;
namespace Dpz.Core.Hangfire;
public sealed class SerilogProtocolLogger(ILogger<SerilogProtocolLogger> logger) : IProtocolLogger
{
private readonly EventId _eventId = new(10001, "邮件日志");
private static readonly byte[] Secret = "********"u8.ToArray();
private static readonly byte[] DefaultClientPrefix = "Client: "u8.ToArray();
private static readonly byte[] DefaultServerPrefix = "Server: "u8.ToArray();
private bool _clientMidline;
private bool _serverMidline;
private readonly MemoryStream _stream = new();
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
private bool _disposed;
private void Dispose(bool disposing)
{
if (!_disposed)
{
if (disposing)
{
_stream.Position = 0;
using var reader = new StreamReader(_stream);
var message = reader.ReadToEnd();
logger.LogInformation(_eventId, "{Message}", message);
_stream.Dispose();
}
_disposed = true;
}
}
~SerilogProtocolLogger() => Dispose(false);
public void LogConnect(Uri uri)
{
var bytes = Encoding.ASCII.GetBytes($"{DateTime.Now} Connected to {uri}\r\n");
if (_clientMidline || _serverMidline)
{
_clientMidline = false;
_serverMidline = false;
}
_stream.Write(bytes, 0, bytes.Length);
_stream.Flush();
}
public void LogClient(byte[]? buffer, int offset, int count)
{
if (buffer == null)
{
logger.LogError(_eventId, "buffer is null");
return;
}
if (offset < 0 || offset > buffer.Length)
{
logger.LogError(_eventId, "offset less than 0 or offset greater than {Offset}", buffer.Length);
return;
}
if (count < 0 || count > buffer.Length - offset)
{
logger.LogError(_eventId, "count less than 0 or count greater than {Offset}", buffer.Length - offset);
return;
}
Log(DefaultClientPrefix, ref _clientMidline, buffer, offset, count, true);
}
public void LogServer(byte[]? buffer, int offset, int count)
{
if (buffer == null)
{
logger.LogError(_eventId, "buffer is null");
return;
}
if (offset < 0 || offset > buffer.Length)
{
logger.LogError(_eventId, "offset less than 0 or offset greater than {Offset}", buffer.Length);
return;
}
if (count < 0 || count > buffer.Length - offset)
{
logger.LogError(_eventId, "count less than 0 or count greater than {Offset}", buffer.Length - offset);
return;
}
Log(DefaultServerPrefix, ref _serverMidline, buffer, offset, count, false);
}
private void Log(
byte[] prefix,
ref bool midline,
byte[] buffer,
int offset,
int count,
bool isClient)
{
var number = offset + count;
var index = offset;
while (index < number)
{
var offset1 = index;
while (index < number && buffer[index] != 10)
++index;
if (!midline)
{
_stream.Write(prefix, 0, prefix.Length);
}
if (index < number && buffer[index] == 10)
{
midline = false;
++index;
}
else
midline = true;
if (isClient)
{
var authenticationSecrets =
AuthenticationSecretDetector?.DetectSecrets(buffer, offset1, index - offset1);
if (authenticationSecrets != null)
{
foreach (var detectSecret in authenticationSecrets)
{
if (detectSecret.StartIndex > offset1)
_stream.Write(buffer, offset1, detectSecret.StartIndex - offset1);
offset1 = detectSecret.StartIndex + detectSecret.Length;
_stream.Write(Secret, 0, Secret.Length);
}
}
}
_stream.Write(buffer, offset1, index - offset1);
}
_stream.Flush();
}
public IAuthenticationSecretDetector? AuthenticationSecretDetector { get; set; }
}