Files
v2rayN/v2rayN/ServiceLib/ViewModels/ClashConnectionsViewModel.cs
DHR60 9664ee380e ViewModel-First (#9621)
* Interaction

* Remove view action

* ViewModel-first

* MainGirdOrientation Hot Reload

* Fix avalonia preview

* Remove CloseWindowInteraction

* Fix

* Avoid threading issues

* Fix

* ProfilesSelect

* Try fix previewer

* Remove AppEvents.ProfilesRefreshRequested

* Remove AppEvents.SubscriptionsRefreshRequested

* Remove AppEvents.ProxiesReloadRequested

* Remove AppEvents.AdjustMainLvColWidthRequested

* Remove AppEvents.SetDefaultServerRequested

* Remove AppEvents.RoutingsMenuRefreshRequested

* Remove AppEvents.TestServerRequested

* Remove AppEvents.InboundDisplayRequested

* Remove AppEvents.SubscriptionsUpdateRequested

* Remove AppEvents.ShowHideWindowRequested

* Remove AppEvents.ReloadRequested

* Remove AppEvents.AddServerRequested

* Fix
2026-07-14 09:05:05 +08:00

151 lines
4.3 KiB
C#

namespace ServiceLib.ViewModels;
public class ClashConnectionsViewModel : MyReactiveObject
{
public IObservableCollection<ClashConnectionModel> ConnectionItems { get; } = new ObservableCollectionExtended<ClashConnectionModel>();
[Reactive]
public ClashConnectionModel SelectedSource { get; set; }
public ReactiveCommand<Unit, Unit> ConnectionCloseCmd { get; }
public ReactiveCommand<Unit, Unit> ConnectionCloseAllCmd { get; }
[Reactive]
public string HostFilter { get; set; }
[Reactive]
public bool AutoRefresh { get; set; }
public ClashConnectionsViewModel()
{
_config = AppManager.Instance.Config;
AutoRefresh = _config.ClashUIItem.ConnectionsAutoRefresh;
var canEditRemove = this.WhenAnyValue(
x => x.SelectedSource,
selectedSource => selectedSource != null && selectedSource.Id.IsNotEmpty());
this.WhenAnyValue(
x => x.AutoRefresh,
y => y == true)
.Subscribe(c => { _config.ClashUIItem.ConnectionsAutoRefresh = AutoRefresh; });
ConnectionCloseCmd = ReactiveCommand.CreateFromTask(async () =>
{
await ClashConnectionClose(false);
}, canEditRemove);
ConnectionCloseAllCmd = ReactiveCommand.CreateFromTask(async () =>
{
await ClashConnectionClose(true);
});
_ = Init();
}
private async Task Init()
{
await DelayTestTask();
}
private async Task GetClashConnections()
{
var ret = await ClashApiManager.Instance.GetClashConnectionsAsync();
if (ret == null)
{
return;
}
RxSchedulers.MainThreadScheduler.Schedule(ret?.connections, (scheduler, model) =>
{
_ = RefreshConnections(model);
return Disposable.Empty;
});
}
public async Task RefreshConnections(List<ConnectionItem>? connections)
{
ConnectionItems.Clear();
var dtNow = DateTime.Now;
var lstModel = new List<ClashConnectionModel>();
foreach (var item in connections ?? [])
{
var host = $"{(item.metadata.host.IsNullOrEmpty() ? item.metadata.destinationIP : item.metadata.host)}:{item.metadata.destinationPort}";
if (HostFilter.IsNotEmpty() && !host.Contains(HostFilter))
{
continue;
}
var model = new ClashConnectionModel
{
Id = item.id,
Network = item.metadata.network,
Type = item.metadata.type,
Host = host,
Time = (dtNow - item.start).TotalSeconds < 0 ? 1 : (dtNow - item.start).TotalSeconds,
Elapsed = (dtNow - item.start).ToString(@"hh\:mm\:ss"),
Chain = $"{item.rule} , {string.Join("->", item.chains ?? [])}"
};
lstModel.Add(model);
}
if (lstModel.Count <= 0)
{
return;
}
ConnectionItems.AddRange(lstModel);
await Task.CompletedTask;
}
public async Task ClashConnectionClose(bool all)
{
var id = string.Empty;
if (!all)
{
var item = SelectedSource;
if (item is null)
{
return;
}
id = item.Id;
}
else
{
ConnectionItems.Clear();
}
await ClashApiManager.Instance.ClashConnectionClose(id);
await GetClashConnections();
}
public async Task DelayTestTask()
{
_ = Task.Run(async () =>
{
var numOfExecuted = 1;
while (true)
{
await Task.Delay(1000 * 5);
numOfExecuted++;
if (!(AutoRefresh && AppManager.Instance.ShowInTaskbar && AppManager.Instance.IsRunningCore(ECoreType.sing_box)))
{
continue;
}
if (_config.ClashUIItem.ConnectionsRefreshInterval <= 0)
{
continue;
}
if (numOfExecuted % _config.ClashUIItem.ConnectionsRefreshInterval != 0)
{
continue;
}
await GetClashConnections();
}
});
await Task.CompletedTask;
}
}