Improved log message display

pull/5636/head
2dust 2024-09-03 16:03:26 +08:00
parent 82eb3fd6bd
commit d91b0afb9a
8 changed files with 192 additions and 169 deletions

View File

@ -39,6 +39,7 @@
DispatcherRefreshServersBiz, DispatcherRefreshServersBiz,
DispatcherRefreshIcon, DispatcherRefreshIcon,
DispatcherCheckUpdate, DispatcherCheckUpdate,
DispatcherCheckUpdateFinished, DispatcherCheckUpdateFinished,
DispatcherShowMsg,
} }
} }

View File

@ -124,20 +124,16 @@ namespace ServiceLib.Handler
mtu = 9000, mtu = 9000,
}; };
} }
if (config.guiItem == null) config.guiItem ??= new()
{ {
config.guiItem = new() enableStatistics = false,
{ };
enableStatistics = false, config.msgUIItem ??= new();
};
} config.uiItem ??= new UIItem()
if (config.uiItem == null)
{ {
config.uiItem = new UIItem() enableAutoAdjustMainLvColWidth = true
{ };
enableAutoAdjustMainLvColWidth = true
};
}
if (config.uiItem.mainColumnItem == null) if (config.uiItem.mainColumnItem == null)
{ {
config.uiItem.mainColumnItem = new(); config.uiItem.mainColumnItem = new();
@ -174,11 +170,11 @@ namespace ServiceLib.Handler
} }
config.mux4RayItem ??= new() config.mux4RayItem ??= new()
{ {
concurrency = 8, concurrency = 8,
xudpConcurrency = 16, xudpConcurrency = 16,
xudpProxyUDP443 = "reject" xudpProxyUDP443 = "reject"
}; };
if (config.mux4SboxItem == null) if (config.mux4SboxItem == null)
{ {

View File

@ -38,6 +38,7 @@
public GrpcItem grpcItem { get; set; } public GrpcItem grpcItem { get; set; }
public RoutingBasicItem routingBasicItem { get; set; } public RoutingBasicItem routingBasicItem { get; set; }
public GUIItem guiItem { get; set; } public GUIItem guiItem { get; set; }
public MsgUIItem msgUIItem { get; set; }
public UIItem uiItem { get; set; } public UIItem uiItem { get; set; }
public ConstItem constItem { get; set; } public ConstItem constItem { get; set; }
public SpeedTestItem speedTestItem { get; set; } public SpeedTestItem speedTestItem { get; set; }

View File

@ -107,6 +107,13 @@
public bool enableLog { get; set; } = true; public bool enableLog { get; set; } = true;
} }
[Serializable]
public class MsgUIItem
{
public string? mainMsgFilter { get; set; }
public bool? autoRefresh { get; set; }
}
[Serializable] [Serializable]
public class UIItem public class UIItem
{ {
@ -126,7 +133,6 @@
public bool enableDragDropSort { get; set; } public bool enableDragDropSort { get; set; }
public bool doubleClick2Activate { get; set; } public bool doubleClick2Activate { get; set; }
public bool autoHideStartup { get; set; } public bool autoHideStartup { get; set; }
public string mainMsgFilter { get; set; }
public List<ColumnItem> mainColumnItem { get; set; } public List<ColumnItem> mainColumnItem { get; set; }
public bool showInTaskbar { get; set; } public bool showInTaskbar { get; set; }
} }

View File

@ -0,0 +1,112 @@
using ReactiveUI;
using ReactiveUI.Fody.Helpers;
using Splat;
using System.Collections.Concurrent;
using System.Diagnostics;
using System.Text.RegularExpressions;
namespace ServiceLib.ViewModels
{
public class MsgViewModel : MyReactiveObject
{
private ConcurrentQueue<string> _queueMsg = new();
private int _numMaxMsg = 500;
private string _lastMsgFilter = string.Empty;
private bool _lastMsgFilterNotAvailable;
private bool _blLockShow = false;
[Reactive]
public string MsgFilter { get; set; }
[Reactive]
public bool AutoRefresh { get; set; }
public MsgViewModel(Func<EViewAction, object?, Task<bool>>? updateView)
{
_config = LazyConfig.Instance.Config;
_updateView = updateView;
_noticeHandler = Locator.Current.GetService<NoticeHandler>();
MessageBus.Current.Listen<string>(Global.CommandSendMsgView).Subscribe(async x => await AppendQueueMsg(x));
MsgFilter = _config.msgUIItem.mainMsgFilter ?? string.Empty;
AutoRefresh = _config.msgUIItem.autoRefresh ?? true;
this.WhenAnyValue(
x => x.MsgFilter)
.Subscribe(c => _config.msgUIItem.mainMsgFilter = MsgFilter);
this.WhenAnyValue(
x => x.AutoRefresh,
y => y == true)
.Subscribe(c => { _config.msgUIItem.autoRefresh = AutoRefresh; });
}
private async Task AppendQueueMsg(string msg)
{
//if (msg == Global.CommandClearMsg)
//{
// ClearMsg();
// return;
//}
if (AutoRefresh == false)
{
return;
}
_ = EnqueueQueueMsg(msg);
if (_blLockShow)
{
return;
}
_blLockShow = true;
await Task.Delay(100);
var txt = string.Join("", _queueMsg.ToArray());
await _updateView?.Invoke(EViewAction.DispatcherShowMsg, txt);
_blLockShow = false;
}
private async Task EnqueueQueueMsg(string msg)
{
//filter msg
if (MsgFilter != _lastMsgFilter) _lastMsgFilterNotAvailable = false;
if (!Utils.IsNullOrEmpty(MsgFilter) && !_lastMsgFilterNotAvailable)
{
try
{
if (!Regex.IsMatch(msg, MsgFilter))
{
return;
}
}
catch (Exception)
{
_lastMsgFilterNotAvailable = true;
}
}
_lastMsgFilter = MsgFilter;
//Enqueue
if (_queueMsg.Count > _numMaxMsg)
{
for (int k = 0; k < _queueMsg.Count - _numMaxMsg; k++)
{
_queueMsg.TryDequeue(out _);
}
}
_queueMsg.Enqueue(msg);
if (!msg.EndsWith(Environment.NewLine))
{
_queueMsg.Enqueue(Environment.NewLine);
}
}
public void ClearMsg()
{
_queueMsg.Clear();
}
}
}

View File

@ -1,104 +1,54 @@
using Avalonia.Controls;
using Avalonia.Interactivity; using Avalonia.Interactivity;
using Avalonia.ReactiveUI;
using Avalonia.Threading; using Avalonia.Threading;
using ReactiveUI; using ReactiveUI;
using System.Collections.Concurrent; using System.Reactive.Disposables;
using System.Text.RegularExpressions;
using v2rayN.Desktop.Common; using v2rayN.Desktop.Common;
namespace v2rayN.Desktop.Views namespace v2rayN.Desktop.Views
{ {
public partial class MsgView : UserControl public partial class MsgView : ReactiveUserControl<MsgViewModel>
{ {
private static Config? _config;
private ConcurrentQueue<string> _queueMsg = new();
private int _numMaxMsg = 500;
private string lastMsgFilter = string.Empty;
private bool lastMsgFilterNotAvailable;
public MsgView() public MsgView()
{ {
InitializeComponent(); InitializeComponent();
_config = LazyConfig.Instance.Config;
MessageBus.Current.Listen<string>(Global.CommandSendMsgView).Subscribe(x => DelegateAppendText(x)); ViewModel = new MsgViewModel(UpdateViewHandler);
//Global.PresetMsgFilters.ForEach(it =>
//{ this.WhenActivated(disposables =>
// cmbMsgFilter.Items.Add(it);
//});
if (!_config.uiItem.mainMsgFilter.IsNullOrEmpty())
{ {
cmbMsgFilter.Text = _config.uiItem.mainMsgFilter; this.Bind(ViewModel, vm => vm.MsgFilter, v => v.cmbMsgFilter.Text).DisposeWith(disposables);
} this.Bind(ViewModel, vm => vm.AutoRefresh, v => v.togAutoRefresh.IsChecked).DisposeWith(disposables);
cmbMsgFilter.TextChanged += (s, e) => });
{
_config.uiItem.mainMsgFilter = cmbMsgFilter.Text?.ToString();
};
} }
private void DelegateAppendText(string msg) private async Task<bool> UpdateViewHandler(EViewAction action, object? obj)
{ {
Dispatcher.UIThread.Post(() => AppendText(msg), DispatcherPriority.ApplicationIdle); switch (action)
{
case EViewAction.DispatcherShowMsg:
if (obj is null) return false;
Dispatcher.UIThread.Post(() =>
ShowMsg(obj),
DispatcherPriority.ApplicationIdle);
break;
}
return await Task.FromResult(true);
} }
public void AppendText(string msg) private void ShowMsg(object msg)
{ {
if (msg == Global.CommandClearMsg) txtMsg.Text = msg.ToString();
{
ClearMsg();
return;
}
if (togAutoRefresh.IsChecked == false)
{
return;
}
var MsgFilter = cmbMsgFilter.Text?.ToString();
if (MsgFilter != lastMsgFilter) lastMsgFilterNotAvailable = false;
if (!Utils.IsNullOrEmpty(MsgFilter) && !lastMsgFilterNotAvailable)
{
try
{
if (!Regex.IsMatch(msg, MsgFilter))
{
return;
}
}
catch (Exception)
{
lastMsgFilterNotAvailable = true;
}
}
lastMsgFilter = MsgFilter;
ShowMsg(msg);
if (togScrollToEnd.IsChecked ?? true) if (togScrollToEnd.IsChecked ?? true)
{ {
txtMsg.CaretIndex = int.MaxValue; txtMsg.CaretIndex = int.MaxValue;
} }
} }
private void ShowMsg(string msg)
{
if (_queueMsg.Count > _numMaxMsg)
{
for (int k = 0; k < _queueMsg.Count - _numMaxMsg; k++)
{
_queueMsg.TryDequeue(out _);
}
}
_queueMsg.Enqueue(msg);
if (!msg.EndsWith(Environment.NewLine))
{
_queueMsg.Enqueue(Environment.NewLine);
}
txtMsg.Text = string.Join("", _queueMsg.ToArray());
}
public void ClearMsg() public void ClearMsg()
{ {
_queueMsg.Clear(); ViewModel?.ClearMsg();
txtMsg.Clear(); txtMsg.Clear();
} }

View File

@ -1,13 +1,16 @@
<UserControl <reactiveui:ReactiveUserControl
x:Class="v2rayN.Views.MsgView" x:Class="v2rayN.Views.MsgView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes" xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:reactiveui="http://reactiveui.net"
xmlns:resx="clr-namespace:ServiceLib.Resx;assembly=ServiceLib" xmlns:resx="clr-namespace:ServiceLib.Resx;assembly=ServiceLib"
xmlns:vms="clr-namespace:ServiceLib.ViewModels;assembly=ServiceLib"
d:DesignHeight="450" d:DesignHeight="450"
d:DesignWidth="800" d:DesignWidth="800"
x:TypeArguments="vms:MsgViewModel"
mc:Ignorable="d"> mc:Ignorable="d">
<DockPanel Margin="2"> <DockPanel Margin="2">
<WrapPanel <WrapPanel
@ -23,8 +26,7 @@
materialDesign:HintAssist.Hint="{x:Static resx:ResUI.MsgFilterTitle}" materialDesign:HintAssist.Hint="{x:Static resx:ResUI.MsgFilterTitle}"
materialDesign:TextFieldAssist.HasClearButton="True" materialDesign:TextFieldAssist.HasClearButton="True"
IsEditable="True" IsEditable="True"
Style="{StaticResource DefComboBox}" Style="{StaticResource DefComboBox}" />
TextBoxBase.TextChanged="cmbMsgFilter_TextChanged" />
<Button <Button
x:Name="btnCopy" x:Name="btnCopy"
Width="24" Width="24"
@ -96,4 +98,4 @@
</TextBox.ContextMenu> </TextBox.ContextMenu>
</TextBox> </TextBox>
</DockPanel> </DockPanel>
</UserControl> </reactiveui:ReactiveUserControl>

View File

@ -1,25 +1,23 @@
using ReactiveUI; using ReactiveUI;
using System.Collections.Concurrent; using System.Reactive.Disposables;
using System.Reactive.Linq; using System.Windows;
using System.Text.RegularExpressions;
using System.Windows.Threading; using System.Windows.Threading;
namespace v2rayN.Views namespace v2rayN.Views
{ {
public partial class MsgView public partial class MsgView
{ {
private static Config? _config;
private ConcurrentQueue<string> _queueMsg = new();
private int _numMaxMsg = 500;
private string lastMsgFilter = string.Empty;
private bool lastMsgFilterNotAvailable;
public MsgView() public MsgView()
{ {
InitializeComponent(); InitializeComponent();
_config = LazyConfig.Instance.Config;
MessageBus.Current.Listen<string>(Global.CommandSendMsgView).Subscribe(x => DelegateAppendText(x)); ViewModel = new MsgViewModel(UpdateViewHandler);
this.WhenActivated(disposables =>
{
this.Bind(ViewModel, vm => vm.MsgFilter, v => v.cmbMsgFilter.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.AutoRefresh, v => v.togAutoRefresh.IsChecked).DisposeWith(disposables);
});
btnCopy.Click += menuMsgViewCopyAll_Click; btnCopy.Click += menuMsgViewCopyAll_Click;
btnClear.Click += menuMsgViewClear_Click; btnClear.Click += menuMsgViewClear_Click;
@ -32,75 +30,37 @@ namespace v2rayN.Views
{ {
cmbMsgFilter.Items.Add(it); cmbMsgFilter.Items.Add(it);
}); });
if (!_config.uiItem.mainMsgFilter.IsNullOrEmpty())
{
cmbMsgFilter.Text = _config.uiItem.mainMsgFilter;
}
} }
private void DelegateAppendText(string msg) private async Task<bool> UpdateViewHandler(EViewAction action, object? obj)
{ {
Dispatcher.BeginInvoke(AppendText, DispatcherPriority.ApplicationIdle, msg); switch (action)
}
public void AppendText(string msg)
{
if (msg == Global.CommandClearMsg)
{ {
ClearMsg(); case EViewAction.DispatcherShowMsg:
return; if (obj is null) return false;
} Application.Current?.Dispatcher.Invoke((() =>
if (togAutoRefresh.IsChecked == false)
{
return;
}
var MsgFilter = cmbMsgFilter.Text.TrimEx();
if (MsgFilter != lastMsgFilter) lastMsgFilterNotAvailable = false;
if (!Utils.IsNullOrEmpty(MsgFilter) && !lastMsgFilterNotAvailable)
{
try
{
if (!Regex.IsMatch(msg, MsgFilter)) // 如果不是正则表达式会异常
{ {
return; ShowMsg(obj);
} }), DispatcherPriority.ApplicationIdle);
} break;
catch (Exception)
{
lastMsgFilterNotAvailable = true;
}
} }
lastMsgFilter = MsgFilter; return await Task.FromResult(true);
}
ShowMsg(msg);
private void ShowMsg(object msg)
{
txtMsg.BeginChange();
txtMsg.Text = msg.ToString();
if (togScrollToEnd.IsChecked ?? true) if (togScrollToEnd.IsChecked ?? true)
{ {
txtMsg.ScrollToEnd(); txtMsg.ScrollToEnd();
} }
} txtMsg.EndChange();
private void ShowMsg(string msg)
{
if (_queueMsg.Count > _numMaxMsg)
{
for (int k = 0; k < _queueMsg.Count - _numMaxMsg; k++)
{
_queueMsg.TryDequeue(out _);
}
}
_queueMsg.Enqueue(msg);
if (!msg.EndsWith(Environment.NewLine))
{
_queueMsg.Enqueue(Environment.NewLine);
}
txtMsg.Text = string.Join("", _queueMsg.ToArray());
} }
public void ClearMsg() public void ClearMsg()
{ {
_queueMsg.Clear(); ViewModel?.ClearMsg();
txtMsg.Clear(); txtMsg.Clear();
} }
@ -126,10 +86,5 @@ namespace v2rayN.Views
{ {
ClearMsg(); ClearMsg();
} }
private void cmbMsgFilter_TextChanged(object sender, System.Windows.Controls.TextChangedEventArgs e)
{
_config.uiItem.mainMsgFilter = cmbMsgFilter.Text.TrimEx();
}
} }
} }