Generalize worker operations

This commit is contained in:
Ben Olden-Cooligan 2018-08-08 11:25:03 -04:00
parent 66eb4f018f
commit 89795c946f
6 changed files with 93 additions and 29 deletions

View File

@ -64,20 +64,13 @@ namespace NAPS2.ImportExport.Pdf
{ {
try try
{ {
if (UseWorker) Status.Success = DoWork(new SavePdfWorkArgs
{ {
using (var worker = WorkerServiceFactory.Create()) SubFileName = subFileName,
{ Snapshots = snapshots.Export(),
worker.Service.SetRecoveryFolder(RecoveryImage.RecoveryFolder.FullName); PdfSettings = pdfSettings,
worker.Callback.OnProgress += OnProgress; OcrLanguageCode = ocrLanguageCode
worker.Service.ExportPdf(subFileName, snapshots.Export(), pdfSettings, ocrLanguageCode); });
Status.Success = worker.Callback.WaitForFinish();
}
}
else
{
Status.Success = pdfExporter.Export(subFileName, snapshots, pdfSettings, ocrLanguageCode, OnProgress);
}
} }
catch (UnauthorizedAccessException ex) catch (UnauthorizedAccessException ex)
{ {
@ -114,9 +107,24 @@ namespace NAPS2.ImportExport.Pdf
return true; return true;
} }
protected internal override bool DoWorkInternal(WorkArgs args)
{
var a = (SavePdfWorkArgs)args;
return pdfExporter.Export(a.SubFileName, a.Snapshots.Import(), a.PdfSettings, a.OcrLanguageCode, OnProgress);
}
public override void WaitUntilFinished() public override void WaitUntilFinished()
{ {
thread.Join(); thread.Join();
} }
[Serializable]
internal class SavePdfWorkArgs : WorkArgs
{
public string SubFileName { get; set; }
public List<ScannedImage.SnapshotExport> Snapshots { get; set; }
public PdfSettings PdfSettings { get; set; }
public string OcrLanguageCode { get; set; }
}
} }
} }

View File

@ -5282,13 +5282,13 @@
<Content Include="Icons\contrast_with_sun.ico" /> <Content Include="Icons\contrast_with_sun.ico" />
<Content Include="Icons\control_play_blue-small.png" /> <Content Include="Icons\control_play_blue-small.png" />
<Content Include="Icons\email.ico" /> <Content Include="Icons\email.ico" />
<None Include="Icons\email.png" />
<None Include="Icons\email_setting.png" /> <None Include="Icons\email_setting.png" />
<Content Include="Icons\file_extension_pdf.ico" /> <Content Include="Icons\file_extension_pdf.ico" />
<None Include="Icons\gmail.png" /> <None Include="Icons\gmail.png" />
<Content Include="Icons\image_edit.png" /> <Content Include="Icons\image_edit.png" />
<None Include="Icons\outlookweb.png" /> <None Include="Icons\outlookweb.png" />
<None Include="Icons\mail_yellow.png" /> <None Include="Icons\mail_yellow.png" />
<Content Include="Icons\key.ico" />
<Content Include="Icons\picture.ico" /> <Content Include="Icons\picture.ico" />
<Content Include="Icons\pictures.png" /> <Content Include="Icons\pictures.png" />
<Content Include="Icons\picture_edit.png" /> <Content Include="Icons\picture_edit.png" />

View File

@ -46,8 +46,9 @@ namespace NAPS2.Operation
Error?.Invoke(this, args); Error?.Invoke(this, args);
} }
protected bool OnProgress(int current, int max) protected virtual bool OnProgress(int current, int max)
{ {
// TODO: Maybe don't make this virtual. Instead, clone the status object, and project event invocations back to the client.
Status.CurrentProgress = current; Status.CurrentProgress = current;
Status.MaxProgress = max; Status.MaxProgress = max;
InvokeStatusChanged(); InvokeStatusChanged();

View File

@ -1,19 +1,59 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Reflection;
using System.Runtime.Serialization;
using NAPS2.Recovery;
using NAPS2.Util;
using NAPS2.Worker; using NAPS2.Worker;
namespace NAPS2.Operation namespace NAPS2.Operation
{ {
public abstract class WorkerOperation : OperationBase public abstract class WorkerOperation : OperationBase
{ {
private readonly IWorkerServiceFactory workerServiceFactory;
protected WorkerOperation(IWorkerServiceFactory workerServiceFactory) protected WorkerOperation(IWorkerServiceFactory workerServiceFactory)
{ {
WorkerServiceFactory = workerServiceFactory; this.workerServiceFactory = workerServiceFactory;
} }
protected bool UseWorker => !Environment.Is64BitProcess; protected virtual bool UseWorker => !Environment.Is64BitProcess;
protected IWorkerServiceFactory WorkerServiceFactory { get; } public ProgressHandler ProgressProxy { get; set; }
protected bool DoWork(WorkArgs args)
{
if (UseWorker)
{
using (var worker = workerServiceFactory.Create())
{
worker.Service.SetRecoveryFolder(RecoveryImage.RecoveryFolder.FullName);
worker.Callback.OnProgress += OnProgress;
worker.Service.DoOperationWork(GetType().FullName, args);
return worker.Callback.WaitForFinish();
}
}
return DoWorkInternal(args);
}
protected internal abstract bool DoWorkInternal(WorkArgs args);
protected override bool OnProgress(int current, int max)
{
return ProgressProxy?.Invoke(current, max) ?? base.OnProgress(current, max);
}
[KnownType("DerivedTypes")]
[Serializable]
public class WorkArgs
{
// ReSharper disable once UnusedMember.Local
private static Type[] DerivedTypes()
{
return Assembly.GetExecutingAssembly().GetTypes().Where(x => x.IsSubclassOf(typeof(WorkArgs))).ToArray();
}
}
} }
} }

View File

@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.ServiceModel; using System.ServiceModel;
using NAPS2.ImportExport.Pdf; using NAPS2.ImportExport.Pdf;
using NAPS2.Operation;
using NAPS2.Recovery; using NAPS2.Recovery;
using NAPS2.Scan; using NAPS2.Scan;
using NAPS2.Scan.Images; using NAPS2.Scan.Images;
@ -25,6 +26,6 @@ namespace NAPS2.Worker
List<RecoveryIndexImage> TwainScan(int recoveryFileNumber, ScanDevice scanDevice, ScanProfile scanProfile, ScanParams scanParams); List<RecoveryIndexImage> TwainScan(int recoveryFileNumber, ScanDevice scanDevice, ScanProfile scanProfile, ScanParams scanParams);
[OperationContract(IsOneWay = true)] [OperationContract(IsOneWay = true)]
void ExportPdf(string subFileName, List<ScannedImage.SnapshotExport> snapshots, PdfSettings pdfSettings, string ocrLanguageCode); void DoOperationWork(string operationTypeName, WorkerOperation.WorkArgs args);
} }
} }

View File

@ -2,15 +2,18 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Reflection;
using System.Runtime.Serialization; using System.Runtime.Serialization;
using System.ServiceModel; using System.ServiceModel;
using System.Windows.Forms; using System.Windows.Forms;
using NAPS2.ImportExport.Pdf; using NAPS2.ImportExport.Pdf;
using NAPS2.Operation;
using NAPS2.Recovery; using NAPS2.Recovery;
using NAPS2.Scan; using NAPS2.Scan;
using NAPS2.Scan.Images; using NAPS2.Scan.Images;
using NAPS2.Scan.Images.Transforms; using NAPS2.Scan.Images.Transforms;
using NAPS2.Scan.Twain; using NAPS2.Scan.Twain;
using NAPS2.Util;
namespace NAPS2.Worker namespace NAPS2.Worker
{ {
@ -21,13 +24,15 @@ namespace NAPS2.Worker
{ {
private readonly TwainWrapper twainWrapper; private readonly TwainWrapper twainWrapper;
private readonly IPdfExporter pdfExporter; private readonly IPdfExporter pdfExporter;
private readonly IOperationFactory operationFactory;
public Form ParentForm { get; set; } public Form ParentForm { get; set; }
public WorkerService(TwainWrapper twainWrapper, IPdfExporter pdfExporter) public WorkerService(TwainWrapper twainWrapper, IPdfExporter pdfExporter, IOperationFactory operationFactory)
{ {
this.twainWrapper = twainWrapper; this.twainWrapper = twainWrapper;
this.pdfExporter = pdfExporter; this.pdfExporter = pdfExporter;
this.operationFactory = operationFactory;
} }
public void Init() public void Init()
@ -56,22 +61,31 @@ namespace NAPS2.Worker
{ {
} }
public void ExportPdf(string subFileName, List<ScannedImage.SnapshotExport> snapshots, PdfSettings pdfSettings, string ocrLanguageCode) public void DoOperationWork(string operationTypeName, WorkerOperation.WorkArgs args)
{ {
// TODO: Make a type for a serializable snapshot // TODO: Make a type for a serializable snapshot
// TODO: Other operations. Import. Recovery. Save images. Password and ghostscript callbacks. // TODO: Other operations. Import. Recovery. Save images. Password and ghostscript callbacks.
// Figure out ghostscript operation in general. // Figure out ghostscript operation in general.
// Also - consider off-process thumbnail rendering. That's probably IO bound though, right? // Also - consider off-process thumbnail rendering. That's probably IO bound though, right?
// So parellization doesn't help. The only benefit would be memory. Which is not a bad benefit. // So parellization doesn't help. The only benefit would be memory. Which is not a bad benefit.
WrapOperation(() => pdfExporter.Export(subFileName, snapshots.Import(), pdfSettings, ocrLanguageCode, Callback.Progress)); var operationType = Type.GetType(operationTypeName);
if (operationType == null)
{
Log.Error($"Operation type not available: {operationTypeName}");
return;
}
var op = (WorkerOperation)typeof(IOperationFactory).GetMethod("Create")?.MakeGenericMethod(operationType).Invoke(operationFactory, new object[0]);
if (op == null)
{
Log.Error($"Could not create operation: {operationTypeName}");
return;
} }
private void WrapOperation(Func<bool> op)
{
bool success = false; bool success = false;
try try
{ {
success = op(); op.ProgressProxy = Callback.Progress;
success = op.DoWorkInternal(args);
} }
catch (Exception e) catch (Exception e)
{ {