Merge pull request #149 from Noggog/WorkQueue-Utils-Rx

WorkQueue and Utils Rx instead of callbacks
This commit is contained in:
Timothy Baldridge 2019-11-04 22:30:05 -07:00 committed by GitHub
commit 6a93e4eca7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 67 additions and 81 deletions

View File

@ -1,6 +1,7 @@
using System;
using Wabbajack.Common;
using Microsoft.Win32;
using System.Reactive;
namespace VirtualFileSystem.Test
{
@ -10,10 +11,8 @@ namespace VirtualFileSystem.Test
{
var result = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\7-zip\");
Utils.SetLoggerFn(s => Console.WriteLine(s));
Utils.SetStatusFn((s, i) => Console.Write(s + "\r"));
WorkQueue.Init((a, b, c) => { },
(a, b) => { });
Utils.LogMessages.Subscribe(s => Console.WriteLine(s));
Utils.StatusUpdates.Subscribe((i) => Console.Write(i.Message + "\r"));
VFS.VirtualFileSystem.VFS.AddRoot(@"D:\tmp\archivetests");
}
}

View File

@ -101,5 +101,10 @@
<Name>Wabbajack.Common</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<PackageReference Include="System.Reactive">
<Version>4.2.0</Version>
</PackageReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>

View File

@ -6,6 +6,7 @@ using System.IO;
using System.Linq;
using System.Net.Configuration;
using System.Net.Http;
using System.Reactive.Subjects;
using System.Reflection;
using System.Security.Cryptography;
using System.Text;
@ -43,22 +44,15 @@ namespace Wabbajack.Common
File.Delete(LogFile);
}
private static Action<string> _loggerFn;
private static Action<string, int> _statusFn;
private static readonly Subject<string> _loggerSubj = new Subject<string>();
public static IObservable<string> LogMessages => _loggerSubj;
private static readonly Subject<(string Message, int Progress)> _statusSubj = new Subject<(string Message, int Progress)>();
public static IObservable<(string Message, int Progress)> StatusUpdates => _statusSubj;
private static readonly string[] Suffix = {"B", "KB", "MB", "GB", "TB", "PB", "EB"}; // Longs run out around EB
public static void SetLoggerFn(Action<string> f)
{
_loggerFn = f;
}
public static void SetStatusFn(Action<string, int> f)
{
_statusFn = f;
}
private static object _lock = new object();
private static DateTime _startTime;
public static void Log(string msg)
@ -69,7 +63,7 @@ namespace Wabbajack.Common
File.AppendAllText(LogFile, msg + "\r\n");
}
_loggerFn?.Invoke(msg);
_loggerSubj.OnNext(msg);
}
public static void LogToFile(string msg)
@ -87,10 +81,9 @@ namespace Wabbajack.Common
if (WorkQueue.CustomReportFn != null)
WorkQueue.CustomReportFn(progress, msg);
else
_statusFn?.Invoke(msg, progress);
_statusSubj.OnNext((msg, progress));
}
/// <summary>
/// MurMur3 hashes the file pointed to by this string
/// </summary>

View File

@ -143,6 +143,9 @@
<PackageReference Include="System.Data.HashFunction.xxHash">
<Version>2.0.0</Version>
</PackageReference>
<PackageReference Include="System.Reactive">
<Version>4.2.0</Version>
</PackageReference>
<PackageReference Include="YamlDotNet">
<Version>8.0.0</Version>
</PackageReference>

View File

@ -2,6 +2,10 @@
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Reactive;
using System.Reactive.Concurrency;
using System.Reactive.Linq;
using System.Reactive.Subjects;
using System.Threading;
namespace Wabbajack.Common
@ -19,22 +23,17 @@ namespace Wabbajack.Common
public static int MaxQueueSize;
public static int CurrentQueueSize;
private static bool _inited;
public static Action<int, string, int> ReportFunction { get; private set; }
public static Action<int, int> ReportQueueSize { get; private set; }
public static int ThreadCount { get; private set; }
private readonly static Subject<CPUStatus> _Status = new Subject<CPUStatus>();
public static IObservable<CPUStatus> Status => _Status;
private readonly static Subject<(int Current, int Max)> _QueueSize = new Subject<(int Current, int Max)>();
public static IObservable<(int Current, int Max)> QueueSize => _QueueSize;
public static int ThreadCount { get; } = Environment.ProcessorCount;
public static List<Thread> Threads { get; private set; }
public static void Init(Action<int, string, int> report_function, Action<int, int> report_queue_size)
static WorkQueue()
{
ReportFunction = report_function;
ReportQueueSize = report_queue_size;
ThreadCount = Environment.ProcessorCount;
if (_inited) return;
StartThreads();
_inited = true;
}
private static void StartThreads()
@ -67,9 +66,19 @@ namespace Wabbajack.Common
public static void Report(string msg, int progress)
{
if (CustomReportFn != null)
{
CustomReportFn(progress, msg);
}
else
ReportFunction(CpuId, msg, progress);
{
_Status.OnNext(
new CPUStatus
{
Progress = progress,
Msg = msg,
ID = CpuId
});
}
}
public static void QueueTask(Action a)
@ -79,7 +88,14 @@ namespace Wabbajack.Common
internal static void ReportNow()
{
ReportQueueSize(MaxQueueSize, CurrentQueueSize);
_QueueSize.OnNext((MaxQueueSize, CurrentQueueSize));
}
}
public class CPUStatus
{
public int Progress { get; internal set; }
public string Msg { get; internal set; }
public int ID { get; internal set; }
}
}

View File

@ -23,9 +23,7 @@ namespace Wabbajack.Test
utils = new TestUtils();
utils.GameName = "Skyrim Special Edition";
Utils.SetStatusFn((f, idx) => { });
Utils.SetLoggerFn(f => TestContext.WriteLine(f));
WorkQueue.Init((x, y, z) => { }, (min, max) => { });
Utils.LogMessages.Subscribe(f => TestContext.WriteLine(f));
}

View File

@ -48,7 +48,6 @@ namespace Wabbajack.Test
[TestInitialize]
public void TestSetup()
{
WorkQueue.Init((x, y, z) => { }, (min, max) => { });
validate = new ValidateModlist();
validate.LoadAuthorPermissionsFromString(permissions);
validate.LoadServerWhitelist(server_whitelist);

View File

@ -30,9 +30,7 @@ namespace Wabbajack.Test
utils = new TestUtils();
utils.GameName = "Skyrim Special Edition";
Utils.SetStatusFn((f, idx) => { });
Utils.SetLoggerFn(f => TestContext.WriteLine(f));
WorkQueue.Init((x, y, z) => { }, (min, max) => { });
Utils.LogMessages.Subscribe(f => TestContext.WriteLine(f));
if (!Directory.Exists(DOWNLOAD_FOLDER))
Directory.CreateDirectory(DOWNLOAD_FOLDER);

View File

@ -17,7 +17,6 @@ namespace Wabbajack
AppDomain.CurrentDomain.UnhandledException += (sender, e) =>
{
// Don't do any special logging side effects
Utils.SetLoggerFn((s) => { });
Utils.Log("Uncaught error:");
Utils.Log(((Exception)e.ExceptionObject).ExceptionToString());
};

View File

@ -1,15 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Wabbajack
{
public class CPUStatus
{
public int Progress { get; internal set; }
public string Msg { get; internal set; }
public int ID { get; internal set; }
}
}

View File

@ -29,11 +29,9 @@ namespace Wabbajack
private readonly ObservableAsPropertyHelper<ViewModel> _ActivePane;
public ViewModel ActivePane => _ActivePane.Value;
[Reactive]
public int QueueProgress { get; set; }
private readonly ObservableAsPropertyHelper<int> _QueueProgress;
public int QueueProgress => _QueueProgress.Value;
private readonly Subject<CPUStatus> _statusSubject = new Subject<CPUStatus>();
public IObservable<CPUStatus> StatusObservable => _statusSubject;
public ObservableCollectionExtended<CPUStatus> StatusList { get; } = new ObservableCollectionExtended<CPUStatus>();
private Subject<string> _logSubj = new Subject<string>();
@ -53,7 +51,7 @@ namespace Wabbajack
this._Compiler = new Lazy<CompilerVM>(() => new CompilerVM(this, source));
// Set up logging
_logSubj
Utils.LogMessages
.ToObservableChangeSet()
.Buffer(TimeSpan.FromMilliseconds(250))
.Where(l => l.Count > 0)
@ -63,8 +61,9 @@ namespace Wabbajack
.Bind(this.Log)
.Subscribe()
.DisposeWith(this.CompositeDisposable);
Utils.SetLoggerFn(s => _logSubj.OnNext(s));
Utils.SetStatusFn((msg, progress) => WorkQueue.Report(msg, progress));
Utils.StatusUpdates
.Subscribe((i) => WorkQueue.Report(i.Message, i.Progress))
.DisposeWith(this.CompositeDisposable);
// Wire mode to drive the active pane.
// Note: This is currently made into a derivative property driven by mode,
@ -89,13 +88,8 @@ namespace Wabbajack
.Subscribe(vm => vm.ModListPath = source)
.DisposeWith(this.CompositeDisposable);
// Initialize work queue
WorkQueue.Init(
report_function: (id, msg, progress) => this._statusSubject.OnNext(new CPUStatus() { ID = id, Msg = msg, Progress = progress }),
report_queue_size: (max, current) => this.SetQueueSize(max, current));
// Compile progress updates and populate ObservableCollection
this._statusSubject
WorkQueue.Status
.ObserveOn(RxApp.TaskpoolScheduler)
.ToObservableChangeSet(x => x.ID)
.Batch(TimeSpan.FromMilliseconds(250))
@ -105,19 +99,17 @@ namespace Wabbajack
.Bind(this.StatusList)
.Subscribe()
.DisposeWith(this.CompositeDisposable);
}
private void SetQueueSize(int max, int current)
{
if (max == 0)
max = 1;
QueueProgress = current * 100 / max;
}
public override void Dispose()
{
base.Dispose();
Utils.SetLoggerFn(s => { });
this._QueueProgress = WorkQueue.QueueSize
.Select(progress =>
{
if (progress.Max == 0)
{
progress.Max = 1;
}
return progress.Current * 100 / progress.Max;
})
.ToProperty(this, nameof(this.QueueProgress));
}
}
}

View File

@ -182,7 +182,6 @@
<Compile Include="Views\InstallationView.xaml.cs">
<DependentUpon>InstallationView.xaml</DependentUpon>
</Compile>
<Compile Include="Util\CPUStatus.cs" />
<Compile Include="View Models\CompilerVM.cs" />
<Compile Include="View Models\MainWindowVM.cs" />
<Compile Include="Views\ModeSelectionWindow.xaml.cs">