M src/PacketLogger/Models/NostaleProcess.cs => src/PacketLogger/Models/NostaleProcess.cs +11 -0
@@ 56,12 56,23 @@ public class NostaleProcess : ObservableObject
public NosBrowserManager BrowserManager { get; init; }
/// <summary>
+ /// Gets whether the process has been closed.
+ /// </summary>
+ public bool Closed { get; private set; }
+
+ /// <summary>
/// Look for changes in the process, fire property changed.
/// </summary>
internal void ObserveChanges()
{
try
{
+ if (Process.HasExited)
+ {
+ Closed = true;
+ return;
+ }
+
if (BrowserManager.IsInGame.Get() != _wasInGame)
{
OnPropertyChanging(nameof(BrowserManager));
M src/PacketLogger/Models/NostaleProcesses.cs => src/PacketLogger/Models/NostaleProcesses.cs +20 -2
@@ 14,6 14,7 @@ using System.Reactive.Concurrency;
using System.Reactive.Linq;
using System.Runtime.InteropServices;
using System.Security.Principal;
+using System.Threading;
using System.Threading.Tasks;
using NosSmooth.Comms.Local;
using NosSmooth.Core.Extensions;
@@ 31,6 32,7 @@ namespace PacketLogger.Models;
public class NostaleProcesses : IDisposable
{
private readonly IDisposable? _cleanUp;
+ private readonly SemaphoreSlim _semaphore;
private readonly ManagementEventWatcher? _processStartWatcher;
private readonly ManagementEventWatcher? _processStopWatcher;
@@ 39,6 41,7 @@ public class NostaleProcesses : IDisposable
/// </summary>
public NostaleProcesses()
{
+ _semaphore = new SemaphoreSlim(1, 1);
Processes = new ObservableCollection<NostaleProcess>();
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
@@ 123,7 126,13 @@ public class NostaleProcesses : IDisposable
if (nosBrowserManager.IsModuleLoaded<PlayerManager>())
{
RxApp.MainThreadScheduler.Schedule
- (() => Processes.Add(new NostaleProcess(process, nosBrowserManager)));
+ (() =>
+ {
+ _semaphore.Wait();
+ Processes.Add(new NostaleProcess(process, nosBrowserManager));
+ _semaphore.Release();
+ }
+ );
}
else
{
@@ 143,7 152,14 @@ public class NostaleProcesses : IDisposable
if (process is not null)
{
RxApp.MainThreadScheduler.Schedule
- (() => Processes.Remove(process));
+ (() =>
+ {
+ process.ObserveChanges();
+ _semaphore.Wait();
+ Processes.Remove(process);
+ _semaphore.Release();
+ }
+ );
}
}
}
@@ 175,9 191,11 @@ public class NostaleProcesses : IDisposable
private void UpdateNames()
{
+ _semaphore.Wait();
foreach (var process in Processes)
{
process.ObserveChanges();
}
+ _semaphore.Release();
}
}=
\ No newline at end of file
M src/PacketLogger/Models/Packets/ClientPacketProvider.cs => src/PacketLogger/Models/Packets/ClientPacketProvider.cs +13 -1
@@ 6,6 6,8 @@
using System;
using System.ComponentModel;
+using System.Reactive.Disposables;
+using System.Reactive.Linq;
using System.Threading;
using System.Threading.Tasks;
using DynamicData;
@@ 42,11 44,16 @@ public abstract class ClientPacketProvider : ReactiveObject, IPacketProvider
_process = process;
_client = client;
Packets = new SourceList<PacketInfo>();
- _cleanUp = process.WhenPropertyChanged(x => x.CharacterString)
+ var cleanUp1 = process.WhenPropertyChanged(x => x.CharacterString)
.Subscribe
(
_ => this.RaisePropertyChanged(nameof(Name))
);
+
+ var cleanUp2 = process.WhenAnyValue(x => x.Closed)
+ .ObserveOn(RxApp.MainThreadScheduler)
+ .Subscribe(_ => this.RaisePropertyChanged(nameof(Closed)));
+ _cleanUp = new CompositeDisposable(cleanUp1, cleanUp2);
}
/// <inheritdoc />
@@ 55,6 62,11 @@ public abstract class ClientPacketProvider : ReactiveObject, IPacketProvider
: null) ?? $"Not in game ({_process.Process.Id})";
/// <summary>
+ /// Gets whether the process has been closed.
+ /// </summary>
+ public bool Closed => _process.Closed;
+
+ /// <summary>
/// Gets or sets title of document.
/// </summary>
public string DocumentTitle { get; set; } = string.Empty;
M src/PacketLogger/ViewModels/DocumentViewModel.cs => src/PacketLogger/ViewModels/DocumentViewModel.cs +23 -7
@@ 85,7 85,9 @@ public class DocumentViewModel : Document, INotifyPropertyChanged, IDisposable
);
_cleanUp = this.WhenAnyValue(x => x.Title)
- .Subscribe(title =>
+ .Subscribe
+ (
+ title =>
{
if (_packetProvider is not null)
{
@@ 207,7 209,8 @@ public class DocumentViewModel : Document, INotifyPropertyChanged, IDisposable
if (!runClientContractResult.IsDefined(out var runClientResponse))
{
repository.Remove(connection.Client);
- Error = "An error has occurred upon sending run client: " + runClientContractResult.ToFullString();
+ Error = "An error has occurred upon sending run client: "
+ + runClientContractResult.ToFullString();
Loading = false;
return;
}
@@ 220,7 223,8 @@ public class DocumentViewModel : Document, INotifyPropertyChanged, IDisposable
return;
}
- if (runClientResponse.BindingManagerResult is not null && !runClientResponse.BindingManagerResult.Value.IsSuccess)
+ if (runClientResponse.BindingManagerResult is not null
+ && !runClientResponse.BindingManagerResult.Value.IsSuccess)
{
Console.WriteLine("There was an error in binding initialization.");
Console.WriteLine(runClientResponse.BindingManagerResult.Value.ToFullString());
@@ 229,7 233,8 @@ public class DocumentViewModel : Document, INotifyPropertyChanged, IDisposable
if (!runClientResponse.InitializationResult.Value.IsSuccess)
{
repository.Remove(connection.Client);
- Error = "An error has occurred during starting client: " + runClientResponse.InitializationResult.ToFullString();
+ Error = "An error has occurred during starting client: "
+ + runClientResponse.InitializationResult.ToFullString();
Loading = false;
return;
}
@@ 239,7 244,14 @@ public class DocumentViewModel : Document, INotifyPropertyChanged, IDisposable
_titleHandle = titleGenerator.AddTitle
(
title => Title = title,
- provider.WhenAnyValue(x => x.Name).ObserveOn(RxApp.MainThreadScheduler),
+ provider
+ .WhenAnyValue(x => x.Name, x => x.Closed)
+ .ObserveOn(RxApp.MainThreadScheduler)
+ .Select
+ (
+ (x) => (x.Item2 ? "Closed (" : string.Empty) + x.Item1
+ + (x.Item2 ? ")" : string.Empty)
+ ),
provider.Name
);
@@ 276,9 288,13 @@ public class DocumentViewModel : Document, INotifyPropertyChanged, IDisposable
(
title => Title = title,
provider
- .WhenAnyValue(x => x.Name)
+ .WhenAnyValue(x => x.Name, x => x.Closed)
.ObserveOn(RxApp.MainThreadScheduler)
- .Select(x => x + " - sniff"),
+ .Select
+ (
+ (x) => (x.Item2 ? "Closed (" : string.Empty) + (x.Item1 + " - sniff")
+ + (x.Item2 ? ")" : string.Empty)
+ ),
provider.Name
);
await provider.Open();