// // PacketLogViewModel.cs // // Copyright (c) František Boháček. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System; using System.Collections; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; using System.Reactive; using System.Reactive.Concurrency; using System.Reactive.Disposables; using System.Reactive.Linq; using Avalonia; using Avalonia.Collections; using DynamicData; using DynamicData.Binding; using PacketLogger.Models; using PacketLogger.Models.Filters; using PacketLogger.Models.Packets; using ReactiveUI; using Reloaded.Memory.Kernel32; namespace PacketLogger.ViewModels; /// public class PacketLogViewModel : ViewModelBase, IDisposable { private readonly ReadOnlyObservableCollection _packets; private readonly IDisposable _cleanUp; private bool _logReceived = true; private bool _logSent = true; /// /// Initializes a new instance of the class. /// /// The packet provider. public PacketLogViewModel(IPacketProvider packetProvider) { Provider = packetProvider; var dynamicFilter = this.WhenValueChanged(@this => @this.CurrentFilter) .Select ( filter => { return (Func)((pi) => { if (filter is null) { return true; } return filter.Match(pi); }); } ); var packetsSubscription = Provider.Packets.Connect() .Filter(dynamicFilter) .Sort(new PacketComparer()) .Bind(out _packets) .ObserveOn(RxApp.MainThreadScheduler) .DisposeMany() .Subscribe ( _ => { if (Scroll) { RxApp.MainThreadScheduler.Schedule ( DateTimeOffset.Now.AddMilliseconds(100), () => { if (FilteredPackets.Count > 0) { SelectedPacket = FilteredPackets[^1]; } } ); } } ); _cleanUp = packetsSubscription; CopyPackets = ReactiveCommand.CreateFromObservable ( list => Observable.StartAsync ( async () => { var clipboardString = string.Join ('\n', list.OfType().Select(x => x.PacketString)); await Application.Current!.Clipboard!.SetTextAsync(clipboardString); } ) ); TogglePane = ReactiveCommand.Create ( _ => PaneOpen = !PaneOpen ); Clear = ReactiveCommand.Create ( () => Provider.Clear() ); SendFilter = new(); RecvFilter = new(); SendFilter.PropertyChanged += (s, e) => { if (e.PropertyName is "Whitelist" or "Active") { CreateSendRecv(); } }; RecvFilter.PropertyChanged += (s, e) => { if (e.PropertyName is "Whitelist" or "Active") { CreateSendRecv(); } }; SendFilter.Filters.CollectionChanged += (s, e) => { CreateSendRecv(); }; RecvFilter.Filters.CollectionChanged += (s, e) => { CreateSendRecv(); }; } /// /// Gets the send filter model. /// public PacketLogFilterViewModel SendFilter { get; } /// /// Gets the receive filter model. /// public PacketLogFilterViewModel RecvFilter { get; } /// /// Gets the currently applied filter. /// public IFilter? CurrentFilter { get; private set; } /// /// Gets the filtered packets. /// public ReadOnlyObservableCollection FilteredPackets => _packets; /// /// Gets packet provider. /// public IPacketProvider Provider { get; } /// /// Gets whether the pane is open. /// public bool PaneOpen { get; private set; } = true; /// /// Gets the toggle pane command. /// public ReactiveCommand TogglePane { get; } /// /// Gets command to copy packets. /// public ReactiveCommand CopyPackets { get; } /// /// Gets the command for clearing. /// public ReactiveCommand Clear { get; } /// /// Gets or sets whether to log received packets. /// public bool LogReceived { get => _logReceived; set { Provider.LogReceived = value; _logReceived = value; } } /// /// Gets or sets whether to log sent packets. /// public bool LogSent { get => _logSent; set { Provider.LogSent = value; _logSent = value; } } /// /// Gets or sets whether to scroll to teh bottom of the grid. /// public bool Scroll { get; set; } = true; /// /// Gets or sets the currently selected packet. /// public object? SelectedPacket { get; set; } /// /// Gets empty string. /// public string Empty { get; } = string.Empty; /// /// Gets or sets whether the recv filter is selected. /// public bool RecvFilterSelected { get; set; } /// /// Gets or sets whether the send filter is selected. /// public bool SendFilterSelected { get; set; } private void CreateSendRecv() { IFilter recvFilter = CreateCompound(RecvFilter); IFilter sendFilter = CreateCompound(SendFilter); CurrentFilter = new SendRecvFilter(sendFilter, recvFilter); } private IFilter CreateCompound(PacketLogFilterViewModel packetLogFilter) { if (!packetLogFilter.Active) { return new CompoundFilter(true); } List filters = new List(); foreach (var filter in packetLogFilter.Filters) { filters.Add(FilterCreator.BuildFilter(filter.Type, filter.Value)); } return new CompoundFilter(!packetLogFilter.Whitelist, filters.ToArray()); } /// public void Dispose() { TogglePane.Dispose(); CopyPackets.Dispose(); Clear.Dispose(); Provider.Dispose(); (Provider as CommsPacketProvider)?.CustomDispose(); _cleanUp.Dispose(); SendFilter.Dispose(); RecvFilter.Dispose(); } }