Optimize and improve the Subject

pull/8024/head^2
2dust 2025-09-25 10:56:10 +08:00
parent faff8e4ea2
commit d86003df55
15 changed files with 93 additions and 62 deletions

View File

@ -0,0 +1,32 @@
using System.Reactive;
namespace ServiceLib.Events;
public static class AppEvents
{
public static readonly EventChannel<Unit> ReloadRequested = new();
public static readonly EventChannel<bool?> ShowHideWindowRequested = new();
public static readonly EventChannel<Unit> AddServerViaScanRequested = new();
public static readonly EventChannel<Unit> AddServerViaClipboardRequested = new();
public static readonly EventChannel<bool> SubscriptionsUpdateRequested = new();
public static readonly EventChannel<Unit> ProfilesRefreshRequested = new();
public static readonly EventChannel<Unit> SubscriptionsRefreshRequested = new();
public static readonly EventChannel<Unit> ProxiesReloadRequested = new();
public static readonly EventChannel<ServerSpeedItem> DispatcherStatisticsRequested = new();
public static readonly EventChannel<string> SendSnackMsgRequested = new();
public static readonly EventChannel<string> SendMsgViewRequested = new();
public static readonly EventChannel<Unit> AppExitRequested = new();
public static readonly EventChannel<bool> ShutdownRequested = new();
public static readonly EventChannel<Unit> AdjustMainLvColWidthRequested = new();
public static readonly EventChannel<string> SetDefaultServerRequested = new();
public static readonly EventChannel<Unit> RoutingsMenuRefreshRequested = new();
public static readonly EventChannel<Unit> TestServerRequested = new();
public static readonly EventChannel<Unit> InboundDisplayRequested = new();
public static readonly EventChannel<ESysProxyType> SysProxyChangeRequested = new();
}

View File

@ -0,0 +1,29 @@
using System.Reactive;
using System.Reactive.Linq;
using System.Reactive.Subjects;
namespace ServiceLib.Events;
public sealed class EventChannel<T>
{
private readonly ISubject<T> _subject = Subject.Synchronize(new Subject<T>());
public IObservable<T> AsObservable()
{
return _subject.AsObservable();
}
public void Publish(T value)
{
_subject.OnNext(value);
}
public void Publish()
{
if (typeof(T) != typeof(Unit))
{
throw new InvalidOperationException("Publish() without value is only valid for EventChannel<Unit>.");
}
_subject.OnNext((T)(object)Unit.Default);
}
}

View File

@ -1,6 +1,7 @@
global using ServiceLib.Base; global using ServiceLib.Base;
global using ServiceLib.Common; global using ServiceLib.Common;
global using ServiceLib.Enums; global using ServiceLib.Enums;
global using ServiceLib.Events;
global using ServiceLib.Handler; global using ServiceLib.Handler;
global using ServiceLib.Helper; global using ServiceLib.Helper;
global using ServiceLib.Manager; global using ServiceLib.Manager;

View File

@ -1,33 +0,0 @@
using System.Reactive;
using System.Reactive.Subjects;
namespace ServiceLib.Handler;
public static class AppEvents
{
public static readonly Subject<Unit> ReloadRequested = new();
public static readonly Subject<bool?> ShowHideWindowRequested = new();
public static readonly Subject<Unit> AddServerViaScanRequested = new();
public static readonly Subject<Unit> AddServerViaClipboardRequested = new();
public static readonly Subject<bool> SubscriptionsUpdateRequested = new();
public static readonly Subject<Unit> ProfilesRefreshRequested = new();
public static readonly Subject<Unit> SubscriptionsRefreshRequested = new();
public static readonly Subject<Unit> ProxiesReloadRequested = new();
public static readonly Subject<ServerSpeedItem> DispatcherStatisticsRequested = new();
public static readonly Subject<string> SendSnackMsgRequested = new();
public static readonly Subject<string> SendMsgViewRequested = new();
public static readonly Subject<Unit> AppExitRequested = new();
public static readonly Subject<bool> ShutdownRequested = new();
public static readonly Subject<Unit> AdjustMainLvColWidthRequested = new();
public static readonly Subject<string> SetDefaultServerRequested = new();
public static readonly Subject<Unit> RoutingsMenuRefreshRequested = new();
public static readonly Subject<Unit> TestServerRequested = new();
public static readonly Subject<Unit> InboundDisplayRequested = new();
public static readonly Subject<ESysProxyType> SysProxyChangeRequested = new();
}

View File

@ -96,7 +96,7 @@ public sealed class AppManager
Logging.SaveLog("AppExitAsync Begin"); Logging.SaveLog("AppExitAsync Begin");
await SysProxyHandler.UpdateSysProxy(_config, true); await SysProxyHandler.UpdateSysProxy(_config, true);
AppEvents.AppExitRequested.OnNext(Unit.Default); AppEvents.AppExitRequested.Publish();
await Task.Delay(50); //Wait for AppExitRequested to be processed await Task.Delay(50); //Wait for AppExitRequested to be processed
await ConfigHandler.SaveConfig(_config); await ConfigHandler.SaveConfig(_config);
@ -119,7 +119,7 @@ public sealed class AppManager
public void Shutdown(bool byUser) public void Shutdown(bool byUser)
{ {
AppEvents.ShutdownRequested.OnNext(byUser); AppEvents.ShutdownRequested.Publish(byUser);
} }
public async Task RebootAsAdmin() public async Task RebootAsAdmin()

View File

@ -11,7 +11,7 @@ public class NoticeManager
{ {
return; return;
} }
AppEvents.SendSnackMsgRequested.OnNext(content); AppEvents.SendSnackMsgRequested.Publish(content);
} }
public void SendMessage(string? content) public void SendMessage(string? content)
@ -20,7 +20,7 @@ public class NoticeManager
{ {
return; return;
} }
AppEvents.SendMsgViewRequested.OnNext(content); AppEvents.SendMsgViewRequested.Publish(content);
} }
public void SendMessageEx(string? content) public void SendMessageEx(string? content)

View File

@ -223,7 +223,7 @@ public class CheckUpdateViewModel : MyReactiveObject
{ {
if (blReload) if (blReload)
{ {
AppEvents.ReloadRequested.OnNext(Unit.Default); AppEvents.ReloadRequested.Publish();
} }
else else
{ {

View File

@ -292,7 +292,7 @@ public class MainWindowViewModel : MyReactiveObject
} }
if (_config.UiItem.EnableAutoAdjustMainLvColWidth) if (_config.UiItem.EnableAutoAdjustMainLvColWidth)
{ {
AppEvents.AdjustMainLvColWidthRequested.OnNext(Unit.Default); AppEvents.AdjustMainLvColWidthRequested.Publish();
} }
} }
} }
@ -303,7 +303,7 @@ public class MainWindowViewModel : MyReactiveObject
{ {
return; return;
} }
AppEvents.DispatcherStatisticsRequested.OnNext(update); AppEvents.DispatcherStatisticsRequested.Publish(update);
} }
#endregion Actions #endregion Actions
@ -312,14 +312,14 @@ public class MainWindowViewModel : MyReactiveObject
private async Task RefreshServers() private async Task RefreshServers()
{ {
AppEvents.ProfilesRefreshRequested.OnNext(Unit.Default); AppEvents.ProfilesRefreshRequested.Publish();
await Task.Delay(200); await Task.Delay(200);
} }
private void RefreshSubscriptions() private void RefreshSubscriptions()
{ {
AppEvents.SubscriptionsRefreshRequested.OnNext(Unit.Default); AppEvents.SubscriptionsRefreshRequested.Publish();
} }
#endregion Servers && Groups #endregion Servers && Groups
@ -451,7 +451,7 @@ public class MainWindowViewModel : MyReactiveObject
var ret = await _updateView?.Invoke(EViewAction.OptionSettingWindow, null); var ret = await _updateView?.Invoke(EViewAction.OptionSettingWindow, null);
if (ret == true) if (ret == true)
{ {
AppEvents.InboundDisplayRequested.OnNext(Unit.Default); AppEvents.InboundDisplayRequested.Publish();
await Reload(); await Reload();
} }
} }
@ -462,7 +462,7 @@ public class MainWindowViewModel : MyReactiveObject
if (ret == true) if (ret == true)
{ {
await ConfigHandler.InitBuiltinRouting(_config); await ConfigHandler.InitBuiltinRouting(_config);
AppEvents.RoutingsMenuRefreshRequested.OnNext(Unit.Default); AppEvents.RoutingsMenuRefreshRequested.Publish();
await Reload(); await Reload();
} }
} }
@ -530,12 +530,12 @@ public class MainWindowViewModel : MyReactiveObject
await SysProxyHandler.UpdateSysProxy(_config, false); await SysProxyHandler.UpdateSysProxy(_config, false);
await Task.Delay(1000); await Task.Delay(1000);
}); });
AppEvents.TestServerRequested.OnNext(Unit.Default); AppEvents.TestServerRequested.Publish();
var showClashUI = _config.IsRunningCore(ECoreType.sing_box); var showClashUI = _config.IsRunningCore(ECoreType.sing_box);
if (showClashUI) if (showClashUI)
{ {
AppEvents.ProxiesReloadRequested.OnNext(Unit.Default); AppEvents.ProxiesReloadRequested.Publish();
} }
RxApp.MainThreadScheduler.Schedule(() => ReloadResult(showClashUI)); RxApp.MainThreadScheduler.Schedule(() => ReloadResult(showClashUI));
@ -565,7 +565,7 @@ public class MainWindowViewModel : MyReactiveObject
{ {
if (_config.UiItem.AutoHideStartup) if (_config.UiItem.AutoHideStartup)
{ {
AppEvents.ShowHideWindowRequested.OnNext(false); AppEvents.ShowHideWindowRequested.Publish(false);
} }
await Task.CompletedTask; await Task.CompletedTask;
} }
@ -578,7 +578,7 @@ public class MainWindowViewModel : MyReactiveObject
{ {
await ConfigHandler.ApplyRegionalPreset(_config, type); await ConfigHandler.ApplyRegionalPreset(_config, type);
await ConfigHandler.InitRouting(_config); await ConfigHandler.InitRouting(_config);
AppEvents.RoutingsMenuRefreshRequested.OnNext(Unit.Default); AppEvents.RoutingsMenuRefreshRequested.Publish();
await ConfigHandler.SaveConfig(_config); await ConfigHandler.SaveConfig(_config);
await new UpdateService().UpdateGeoFileAll(_config, UpdateTaskHandler); await new UpdateService().UpdateGeoFileAll(_config, UpdateTaskHandler);

View File

@ -275,7 +275,7 @@ public class ProfilesViewModel : MyReactiveObject
private void Reload() private void Reload()
{ {
AppEvents.ReloadRequested.OnNext(Unit.Default); AppEvents.ReloadRequested.Publish();
} }
public async Task SetSpeedTestResult(SpeedTestResult result) public async Task SetSpeedTestResult(SpeedTestResult result)
@ -361,7 +361,7 @@ public class ProfilesViewModel : MyReactiveObject
public async Task RefreshServers() public async Task RefreshServers()
{ {
AppEvents.ProfilesRefreshRequested.OnNext(Unit.Default); AppEvents.ProfilesRefreshRequested.Publish();
await Task.Delay(200); await Task.Delay(200);
} }

View File

@ -148,17 +148,17 @@ public class StatusBarViewModel : MyReactiveObject
NotifyLeftClickCmd = ReactiveCommand.CreateFromTask(async () => NotifyLeftClickCmd = ReactiveCommand.CreateFromTask(async () =>
{ {
AppEvents.ShowHideWindowRequested.OnNext(null); AppEvents.ShowHideWindowRequested.Publish(null);
await Task.CompletedTask; await Task.CompletedTask;
}); });
ShowWindowCmd = ReactiveCommand.CreateFromTask(async () => ShowWindowCmd = ReactiveCommand.CreateFromTask(async () =>
{ {
AppEvents.ShowHideWindowRequested.OnNext(true); AppEvents.ShowHideWindowRequested.Publish(true);
await Task.CompletedTask; await Task.CompletedTask;
}); });
HideWindowCmd = ReactiveCommand.CreateFromTask(async () => HideWindowCmd = ReactiveCommand.CreateFromTask(async () =>
{ {
AppEvents.ShowHideWindowRequested.OnNext(false); AppEvents.ShowHideWindowRequested.Publish(false);
await Task.CompletedTask; await Task.CompletedTask;
}); });
@ -274,19 +274,19 @@ public class StatusBarViewModel : MyReactiveObject
private async Task AddServerViaClipboard() private async Task AddServerViaClipboard()
{ {
AppEvents.AddServerViaClipboardRequested.OnNext(Unit.Default); AppEvents.AddServerViaClipboardRequested.Publish();
await Task.Delay(1000); await Task.Delay(1000);
} }
private async Task AddServerViaScan() private async Task AddServerViaScan()
{ {
AppEvents.AddServerViaScanRequested.OnNext(Unit.Default); AppEvents.AddServerViaScanRequested.Publish();
await Task.Delay(1000); await Task.Delay(1000);
} }
private async Task UpdateSubscriptionProcess(bool blProxy) private async Task UpdateSubscriptionProcess(bool blProxy)
{ {
AppEvents.SubscriptionsUpdateRequested.OnNext(blProxy); AppEvents.SubscriptionsUpdateRequested.Publish(blProxy);
await Task.Delay(1000); await Task.Delay(1000);
} }
@ -348,7 +348,7 @@ public class StatusBarViewModel : MyReactiveObject
{ {
return; return;
} }
AppEvents.SetDefaultServerRequested.OnNext(SelectedServer.ID); AppEvents.SetDefaultServerRequested.Publish(SelectedServer.ID);
} }
public async Task TestServerAvailability() public async Task TestServerAvailability()
@ -449,7 +449,7 @@ public class StatusBarViewModel : MyReactiveObject
if (await ConfigHandler.SetDefaultRouting(_config, item) == 0) if (await ConfigHandler.SetDefaultRouting(_config, item) == 0)
{ {
NoticeManager.Instance.SendMessageEx(ResUI.TipChangeRouting); NoticeManager.Instance.SendMessageEx(ResUI.TipChangeRouting);
AppEvents.ReloadRequested.OnNext(Unit.Default); AppEvents.ReloadRequested.Publish();
_updateView?.Invoke(EViewAction.DispatcherRefreshIcon, null); _updateView?.Invoke(EViewAction.DispatcherRefreshIcon, null);
} }
} }
@ -496,7 +496,7 @@ public class StatusBarViewModel : MyReactiveObject
} }
} }
await ConfigHandler.SaveConfig(_config); await ConfigHandler.SaveConfig(_config);
AppEvents.ReloadRequested.OnNext(Unit.Default); AppEvents.ReloadRequested.Publish();
} }
private bool AllowEnableTun() private bool AllowEnableTun()

View File

@ -54,7 +54,7 @@ public partial class App : Application
{ {
if (desktop.MainWindow != null) if (desktop.MainWindow != null)
{ {
AppEvents.AddServerViaClipboardRequested.OnNext(Unit.Default); AppEvents.AddServerViaClipboardRequested.Publish();
await Task.Delay(1000); await Task.Delay(1000);
} }
} }

View File

@ -2,6 +2,7 @@ global using ServiceLib;
global using ServiceLib.Base; global using ServiceLib.Base;
global using ServiceLib.Common; global using ServiceLib.Common;
global using ServiceLib.Enums; global using ServiceLib.Enums;
global using ServiceLib.Events;
global using ServiceLib.Handler; global using ServiceLib.Handler;
global using ServiceLib.Manager; global using ServiceLib.Manager;
global using ServiceLib.Models; global using ServiceLib.Models;

View File

@ -253,7 +253,7 @@ public partial class MainWindow : WindowBase<MainWindowViewModel>
case EGlobalHotkey.SystemProxySet: case EGlobalHotkey.SystemProxySet:
case EGlobalHotkey.SystemProxyUnchanged: case EGlobalHotkey.SystemProxyUnchanged:
case EGlobalHotkey.SystemProxyPac: case EGlobalHotkey.SystemProxyPac:
AppEvents.SysProxyChangeRequested.OnNext((ESysProxyType)((int)e - 1)); AppEvents.SysProxyChangeRequested.Publish((ESysProxyType)((int)e - 1));
break; break;
} }
} }

View File

@ -2,6 +2,7 @@ global using ServiceLib;
global using ServiceLib.Base; global using ServiceLib.Base;
global using ServiceLib.Common; global using ServiceLib.Common;
global using ServiceLib.Enums; global using ServiceLib.Enums;
global using ServiceLib.Events;
global using ServiceLib.Handler; global using ServiceLib.Handler;
global using ServiceLib.Manager; global using ServiceLib.Manager;
global using ServiceLib.Models; global using ServiceLib.Models;

View File

@ -241,7 +241,7 @@ public partial class MainWindow
case EGlobalHotkey.SystemProxySet: case EGlobalHotkey.SystemProxySet:
case EGlobalHotkey.SystemProxyUnchanged: case EGlobalHotkey.SystemProxyUnchanged:
case EGlobalHotkey.SystemProxyPac: case EGlobalHotkey.SystemProxyPac:
AppEvents.SysProxyChangeRequested.OnNext((ESysProxyType)((int)e - 1)); AppEvents.SysProxyChangeRequested.Publish((ESysProxyType)((int)e - 1));
break; break;
} }
} }