You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
203 lines
6.4 KiB
203 lines
6.4 KiB
using AuroraDesk.Presentation.ViewModels.Base;
|
|
using Microsoft.Extensions.Logging;
|
|
using ReactiveUI;
|
|
using System;
|
|
using System.Collections.ObjectModel;
|
|
using System.Collections.Specialized;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Reactive;
|
|
using System.Reactive.Disposables;
|
|
|
|
namespace AuroraDesk.Presentation.ViewModels.Pages;
|
|
|
|
public class TcpClientPageViewModel : RoutableViewModel
|
|
{
|
|
private readonly ILogger<TcpClientPageViewModel>? _logger;
|
|
private readonly ObservableCollection<TcpClientSessionViewModel> _sessions = new();
|
|
private readonly Dictionary<TcpClientSessionViewModel, IDisposable> _sessionSubscriptions = new();
|
|
|
|
private TcpClientSessionViewModel? _selectedSession;
|
|
private string _globalStatusMessage = "尚未创建会话";
|
|
private int _sessionCounter = 1;
|
|
|
|
public TcpClientPageViewModel(
|
|
IScreen hostScreen,
|
|
ILogger<TcpClientPageViewModel>? logger = null)
|
|
: base(hostScreen, "TcpClient")
|
|
{
|
|
_logger = logger;
|
|
|
|
Sessions = new ReadOnlyObservableCollection<TcpClientSessionViewModel>(_sessions);
|
|
|
|
AddSessionCommand = ReactiveCommand.Create(AddSession);
|
|
RemoveSessionCommand = ReactiveCommand.Create<TcpClientSessionViewModel?>(RemoveSession);
|
|
|
|
_sessions.CollectionChanged += SessionsOnCollectionChanged;
|
|
UpdateAggregates();
|
|
}
|
|
|
|
public ReadOnlyObservableCollection<TcpClientSessionViewModel> Sessions { get; }
|
|
|
|
public TcpClientSessionViewModel? SelectedSession
|
|
{
|
|
get => _selectedSession;
|
|
set => this.RaiseAndSetIfChanged(ref _selectedSession, value);
|
|
}
|
|
|
|
public string GlobalStatusMessage
|
|
{
|
|
get => _globalStatusMessage;
|
|
private set => this.RaiseAndSetIfChanged(ref _globalStatusMessage, value);
|
|
}
|
|
|
|
public int ActiveSessionCount => _sessions.Count(x => x.IsConnected);
|
|
|
|
public int TotalSentMessages => _sessions.Sum(x => x.SentMessages.Count);
|
|
|
|
public int TotalReceivedMessages => _sessions.Sum(x => x.ReceivedMessages.Count);
|
|
|
|
public ReactiveCommand<Unit, Unit> AddSessionCommand { get; }
|
|
|
|
public ReactiveCommand<TcpClientSessionViewModel?, Unit> RemoveSessionCommand { get; }
|
|
|
|
private void AddSession()
|
|
{
|
|
var name = $"会话 {_sessionCounter++}";
|
|
var session = new TcpClientSessionViewModel(name);
|
|
AttachSession(session);
|
|
_sessions.Add(session);
|
|
SelectedSession = session;
|
|
_logger?.LogInformation("已创建 TCP 会话 {Session}", name);
|
|
UpdateAggregates();
|
|
}
|
|
|
|
private void RemoveSession(TcpClientSessionViewModel? session)
|
|
{
|
|
if (session is null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (_sessions.Contains(session))
|
|
{
|
|
DetachSession(session);
|
|
_sessions.Remove(session);
|
|
session.Dispose();
|
|
_logger?.LogInformation("已移除 TCP 会话 {Session}", session.SessionName);
|
|
|
|
if (ReferenceEquals(SelectedSession, session))
|
|
{
|
|
SelectedSession = _sessions.LastOrDefault();
|
|
}
|
|
|
|
UpdateAggregates();
|
|
}
|
|
}
|
|
|
|
private void SessionsOnCollectionChanged(object? sender, NotifyCollectionChangedEventArgs e)
|
|
{
|
|
if (e.Action == NotifyCollectionChangedAction.Add && e.NewItems != null)
|
|
{
|
|
foreach (var item in e.NewItems.OfType<TcpClientSessionViewModel>())
|
|
{
|
|
AttachSession(item);
|
|
}
|
|
}
|
|
|
|
if (e.Action == NotifyCollectionChangedAction.Remove && e.OldItems != null)
|
|
{
|
|
foreach (var item in e.OldItems.OfType<TcpClientSessionViewModel>())
|
|
{
|
|
DetachSession(item);
|
|
}
|
|
}
|
|
|
|
if (e.Action == NotifyCollectionChangedAction.Reset)
|
|
{
|
|
foreach (var subscription in _sessionSubscriptions)
|
|
{
|
|
subscription.Value.Dispose();
|
|
}
|
|
_sessionSubscriptions.Clear();
|
|
}
|
|
|
|
UpdateAggregates();
|
|
}
|
|
|
|
private void AttachSession(TcpClientSessionViewModel session)
|
|
{
|
|
if (_sessionSubscriptions.ContainsKey(session))
|
|
{
|
|
return;
|
|
}
|
|
|
|
void OnPropertyChanged(object? _, System.ComponentModel.PropertyChangedEventArgs args)
|
|
{
|
|
if (string.IsNullOrEmpty(args.PropertyName) ||
|
|
args.PropertyName is nameof(TcpClientSessionViewModel.IsConnected) or
|
|
nameof(TcpClientSessionViewModel.SessionName) or
|
|
nameof(TcpClientSessionViewModel.StatusMessage))
|
|
{
|
|
UpdateAggregates();
|
|
}
|
|
}
|
|
|
|
void OnCollectionChanged(object? _, NotifyCollectionChangedEventArgs __) => UpdateAggregates();
|
|
void OnMetricsUpdated(object? _, EventArgs __) => UpdateAggregates();
|
|
|
|
session.PropertyChanged += OnPropertyChanged;
|
|
session.SentMessages.CollectionChanged += OnCollectionChanged;
|
|
session.ReceivedMessages.CollectionChanged += OnCollectionChanged;
|
|
session.MetricsUpdated += OnMetricsUpdated;
|
|
|
|
var disposer = Disposable.Create(() =>
|
|
{
|
|
session.PropertyChanged -= OnPropertyChanged;
|
|
session.SentMessages.CollectionChanged -= OnCollectionChanged;
|
|
session.ReceivedMessages.CollectionChanged -= OnCollectionChanged;
|
|
session.MetricsUpdated -= OnMetricsUpdated;
|
|
});
|
|
|
|
_sessionSubscriptions[session] = disposer;
|
|
}
|
|
|
|
private void DetachSession(TcpClientSessionViewModel session)
|
|
{
|
|
if (_sessionSubscriptions.TryGetValue(session, out var disposer))
|
|
{
|
|
disposer.Dispose();
|
|
_sessionSubscriptions.Remove(session);
|
|
}
|
|
}
|
|
|
|
private void UpdateAggregates()
|
|
{
|
|
this.RaisePropertyChanged(nameof(ActiveSessionCount));
|
|
this.RaisePropertyChanged(nameof(TotalSentMessages));
|
|
this.RaisePropertyChanged(nameof(TotalReceivedMessages));
|
|
|
|
GlobalStatusMessage = _sessions.Count switch
|
|
{
|
|
0 => "尚未创建任何会话",
|
|
_ => $"共 {_sessions.Count} 个会话,活动 {_sessions.Count(x => x.IsConnected)} 个"
|
|
};
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
foreach (var session in _sessions.ToList())
|
|
{
|
|
session.Dispose();
|
|
}
|
|
|
|
foreach (var subscription in _sessionSubscriptions)
|
|
{
|
|
subscription.Value.Dispose();
|
|
}
|
|
|
|
_sessionSubscriptions.Clear();
|
|
_sessions.Clear();
|
|
}
|
|
}
|
|
|
|
|