130 lines
3.1 KiB
C#
130 lines
3.1 KiB
C#
using System.Collections.ObjectModel;
|
|
using System.Diagnostics;
|
|
using System.IO.Pipes;
|
|
using System.Text.Json;
|
|
using CommIpc;
|
|
|
|
namespace ParentWpf;
|
|
|
|
public sealed class ChildSession : NotifyBase, IAsyncDisposable
|
|
{
|
|
private readonly SemaphoreSlim _writeLock = new(1, 1);
|
|
private string _status = "Starting";
|
|
private double _progressPercent;
|
|
private string? _currentWorkId;
|
|
private bool _isConnected;
|
|
|
|
public int Id { get; }
|
|
public string PipeName { get; }
|
|
public string PipePath => CommIpc.PipeName.Describe(PipeName);
|
|
|
|
public NamedPipeServerStream Pipe { get; }
|
|
public Process Process { get; }
|
|
public CancellationTokenSource LifetimeCts { get; } = new();
|
|
|
|
public ObservableCollection<string> Logs { get; } = new();
|
|
|
|
public bool IsConnected
|
|
{
|
|
get => _isConnected;
|
|
set
|
|
{
|
|
if (SetField(ref _isConnected, value))
|
|
{
|
|
OnPropertyChanged(nameof(DisplayName));
|
|
OnPropertyChanged(nameof(StatusLine));
|
|
}
|
|
}
|
|
}
|
|
|
|
public string Status
|
|
{
|
|
get => _status;
|
|
set
|
|
{
|
|
if (SetField(ref _status, value))
|
|
{
|
|
OnPropertyChanged(nameof(DisplayName));
|
|
OnPropertyChanged(nameof(StatusLine));
|
|
}
|
|
}
|
|
}
|
|
|
|
public string DisplayName => $"Child {Id} ({(IsConnected ? "Connected" : "Disconnected")})";
|
|
public string StatusLine => $"{Status} | Work: {(_currentWorkId ?? "-")}";
|
|
|
|
public double ProgressPercent
|
|
{
|
|
get => _progressPercent;
|
|
set => SetField(ref _progressPercent, value);
|
|
}
|
|
|
|
public string? CurrentWorkId
|
|
{
|
|
get => _currentWorkId;
|
|
set
|
|
{
|
|
if (SetField(ref _currentWorkId, value))
|
|
{
|
|
OnPropertyChanged(nameof(StatusLine));
|
|
}
|
|
}
|
|
}
|
|
|
|
public ChildSession(int id, string pipeName, NamedPipeServerStream pipe, Process process)
|
|
{
|
|
Id = id;
|
|
PipeName = pipeName;
|
|
Pipe = pipe;
|
|
Process = process;
|
|
}
|
|
|
|
public async Task SendAsync(IpcFrame frame, CancellationToken cancellationToken)
|
|
{
|
|
await _writeLock.WaitAsync(cancellationToken);
|
|
try
|
|
{
|
|
await IpcProtocol.WriteFrameAsync(Pipe, frame, cancellationToken);
|
|
}
|
|
finally
|
|
{
|
|
_writeLock.Release();
|
|
}
|
|
}
|
|
|
|
public void AddLog(string line)
|
|
{
|
|
// keep it from growing without bounds during prototyping
|
|
if (Logs.Count > 2000)
|
|
{
|
|
Logs.RemoveAt(0);
|
|
}
|
|
Logs.Add(line);
|
|
}
|
|
|
|
public async ValueTask DisposeAsync()
|
|
{
|
|
try
|
|
{
|
|
LifetimeCts.Cancel();
|
|
}
|
|
catch { }
|
|
|
|
try
|
|
{
|
|
if (!Process.HasExited)
|
|
{
|
|
Process.Kill(entireProcessTree: true);
|
|
}
|
|
}
|
|
catch { }
|
|
|
|
try { Pipe.Dispose(); } catch { }
|
|
try { Process.Dispose(); } catch { }
|
|
try { LifetimeCts.Dispose(); } catch { }
|
|
try { _writeLock.Dispose(); } catch { }
|
|
|
|
await Task.CompletedTask;
|
|
}
|
|
}
|