LumaTunnel
【WinUI】LumaTunnel 是一个面向个人多设备的 Windows 代理系统。客户端在本机提供 HTTP/HTTPS CONNECT 与 SOCKS5 TCP 代理,并通过一个受信任 TLS 证书保护的 WSS 会话,将多个 TCP 流复用到自建 Windows Server 节点。
关注
0
Fork
0
Star
0
using System.Collections.Concurrent;
namespace LumaTunnel.Server;
internal sealed class RollingFileLoggerProvider(string directory) : ILoggerProvider
{
private readonly ConcurrentDictionary<string, RollingFileLogger> _loggers = new(StringComparer.Ordinal);
private readonly SharedWriter _writer = new(directory);
public ILogger CreateLogger(string categoryName) => _loggers.GetOrAdd(categoryName, category => new RollingFileLogger(category, _writer));
public void Dispose()
{
_writer.Dispose();
_loggers.Clear();
GC.SuppressFinalize(this);
}
private sealed class RollingFileLogger(string category, SharedWriter writer) : ILogger
{
public IDisposable? BeginScope<TState>(TState state) where TState : notnull => null;
public bool IsEnabled(LogLevel logLevel) => logLevel >= LogLevel.Information;
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception? exception, Func<TState, Exception?, string> formatter)
{
if (!IsEnabled(logLevel)) return;
var message = formatter(state, exception).Replace("\r", " ", StringComparison.Ordinal).Replace("\n", " ", StringComparison.Ordinal);
writer.Write($"{DateTimeOffset.Now:O} [{logLevel}] {category}: {message}{(exception is null ? string.Empty : " | " + exception.GetType().Name)}");
}
}
private sealed class SharedWriter : IDisposable
{
private readonly object _gate = new();
private readonly string _directory;
private DateOnly _date;
private StreamWriter? _writer;
private int _segment;
public SharedWriter(string directory)
{
_directory = directory;
Directory.CreateDirectory(directory);
}
public void Write(string line)
{
lock (_gate)
{
EnsureWriter();
_writer!.WriteLine(line);
_writer.Flush();
}
}
public void Dispose()
{
lock (_gate) { _writer?.Dispose(); _writer = null; }
}
private void EnsureWriter()
{
var today = DateOnly.FromDateTime(DateTime.Today);
if (_writer is null || today != _date || _writer.BaseStream.Length >= 10 * 1024 * 1024)
{
_writer?.Dispose();
if (today != _date) _segment = 0; else _segment++;
_date = today;
var suffix = _segment == 0 ? string.Empty : $"-{_segment}";
var path = Path.Combine(_directory, $"lumatunnel-{today:yyyyMMdd}{suffix}.log");
_writer = new StreamWriter(new FileStream(path, FileMode.Append, FileAccess.Write, FileShare.Read), System.Text.Encoding.UTF8);
foreach (var old in Directory.GetFiles(_directory, "lumatunnel-*.log").OrderByDescending(static item => item, StringComparer.OrdinalIgnoreCase).Skip(10))
File.Delete(old);
}
}
}
}
using System.Collections.Concurrent;
namespace LumaTunnel.Server;
internal sealed class RollingFileLoggerProvider(string directory) : ILoggerProvider
{
private readonly ConcurrentDictionary<string, RollingFileLogger> _loggers = new(StringComparer.Ordinal);
private readonly SharedWriter _writer = new(directory);
public ILogger CreateLogger(string categoryName) => _loggers.GetOrAdd(categoryName, category => new RollingFileLogger(category, _writer));
public void Dispose()
{
_writer.Dispose();
_loggers.Clear();
GC.SuppressFinalize(this);
}
private sealed class RollingFileLogger(string category, SharedWriter writer) : ILogger
{
public IDisposable? BeginScope<TState>(TState state) where TState : notnull => null;
public bool IsEnabled(LogLevel logLevel) => logLevel >= LogLevel.Information;
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception? exception, Func<TState, Exception?, string> formatter)
{
if (!IsEnabled(logLevel)) return;
var message = formatter(state, exception).Replace("\r", " ", StringComparison.Ordinal).Replace("\n", " ", StringComparison.Ordinal);
writer.Write($"{DateTimeOffset.Now:O} [{logLevel}] {category}: {message}{(exception is null ? string.Empty : " | " + exception.GetType().Name)}");
}
}
private sealed class SharedWriter : IDisposable
{
private readonly object _gate = new();
private readonly string _directory;
private DateOnly _date;
private StreamWriter? _writer;
private int _segment;
public SharedWriter(string directory)
{
_directory = directory;
Directory.CreateDirectory(directory);
}
public void Write(string line)
{
lock (_gate)
{
EnsureWriter();
_writer!.WriteLine(line);
_writer.Flush();
}
}
public void Dispose()
{
lock (_gate) { _writer?.Dispose(); _writer = null; }
}
private void EnsureWriter()
{
var today = DateOnly.FromDateTime(DateTime.Today);
if (_writer is null || today != _date || _writer.BaseStream.Length >= 10 * 1024 * 1024)
{
_writer?.Dispose();
if (today != _date) _segment = 0; else _segment++;
_date = today;
var suffix = _segment == 0 ? string.Empty : $"-{_segment}";
var path = Path.Combine(_directory, $"lumatunnel-{today:yyyyMMdd}{suffix}.log");
_writer = new StreamWriter(new FileStream(path, FileMode.Append, FileAccess.Write, FileShare.Read), System.Text.Encoding.UTF8);
foreach (var old in Directory.GetFiles(_directory, "lumatunnel-*.log").OrderByDescending(static item => item, StringComparer.OrdinalIgnoreCase).Skip(10))
File.Delete(old);
}
}
}
}