diff --git a/uSync.BackOffice/Hubs/uSyncCallbacks.cs b/uSync.BackOffice/Hubs/uSyncCallbacks.cs
index 6f6fdfaf..77b0bf36 100644
--- a/uSync.BackOffice/Hubs/uSyncCallbacks.cs
+++ b/uSync.BackOffice/Hubs/uSyncCallbacks.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using System.Threading.Tasks;
using uSync.BackOffice.Models;
@@ -11,26 +12,52 @@ namespace uSync.BackOffice;
public delegate void SyncEventCallback(SyncProgressSummary summary);
///
-/// callback delegate for SignalR messaging
+/// async callback delegate for SignalR messaging
+///
+public delegate Task SyncEventCallbackAsync(SyncProgressSummary summary);
+
+///
+/// callback delegate for SignalR messaging
///
public delegate void SyncUpdateCallback(string message, int count, int total);
+///
+/// async callback delegate for SignalR messaging
+///
+public delegate Task SyncUpdateCallbackAsync(string message, int count, int total);
+
///
/// callback delegate to set the start and end range for the update counters.
///
public delegate void SyncSetUpdateRange(int start, int end);
+///
+/// async callback delegate to set the start and end range for the update counters.
+///
+public delegate Task SyncSetUpdateRangeAsync(int start, int end);
+
///
/// callback to send a update message and increment the counter by one so moving the progress bar.
///
///
public delegate void SyncIncrementalUpdateCallback(string message);
+///
+/// async callback to send a update message and increment the counter by one so moving the progress bar.
+///
+///
+public delegate Task SyncIncrementalUpdateCallbackAsync(string message);
+
///
/// callback to signal that the sync is complete
///
public delegate void SyncCompleteCallBack(Guid id, string message, bool success, IEnumerable actions);
+///
+/// async callback to signal that the sync is complete
+///
+public delegate Task SyncCompleteCallBackAsync(Guid id, string message, bool success, IEnumerable actions);
+
///
/// Callback objects used to communicate via SignalR
@@ -42,29 +69,56 @@ public class uSyncCallbacks
///
public SyncEventCallback? Callback { get; private set; }
+ ///
+ /// Async add event callback. Set alongside (or instead of) when the
+ /// consumer needs to await the send (e.g. a SignalR hub push) rather than block on it.
+ ///
+ public SyncEventCallbackAsync? CallbackAsync { get; set; }
+
///
/// Update event callback
///
public SyncUpdateCallback? Update { get; private set; }
+ ///
+ /// Async update event callback. Set alongside (or instead of) when the
+ /// consumer needs to await the send rather than block on it.
+ ///
+ public SyncUpdateCallbackAsync? UpdateAsync { get; set; }
+
///
/// set a start and end range for the counter.
///
public SyncSetUpdateRange? SetRange { get; private set; }
+ ///
+ /// Async version of .
+ ///
+ public SyncSetUpdateRangeAsync? SetRangeAsync { get; set; }
+
///
/// update and increment callback.
///
public SyncIncrementalUpdateCallback? IncrementalUpdate { get; private set; }
+ ///
+ /// Async version of .
+ ///
+ public SyncIncrementalUpdateCallbackAsync? IncrementalUpdateAsync { get; set; }
+
///
/// callback to signal that the sync is complete
///
public SyncCompleteCallBack? Complete { get; private set; }
+ ///
+ /// Async version of .
+ ///
+ public SyncCompleteCallBackAsync? CompleteAsync { get; set; }
+
///
- /// generate a new callback object
+ /// generate a new callback object
///
public uSyncCallbacks(SyncEventCallback? callback, SyncUpdateCallback? update)
{
@@ -75,9 +129,9 @@ public uSyncCallbacks(SyncEventCallback? callback, SyncUpdateCallback? update)
///
/// generate a callback object with range and incremental update
///
- public uSyncCallbacks(SyncEventCallback? callback,
+ public uSyncCallbacks(SyncEventCallback? callback,
SyncUpdateCallback? update,
- SyncSetUpdateRange? updateRange,
+ SyncSetUpdateRange? updateRange,
SyncIncrementalUpdateCallback incrementalUpdate,
SyncCompleteCallBack? complete)
: this(callback, update)
@@ -86,4 +140,59 @@ public uSyncCallbacks(SyncEventCallback? callback,
this.IncrementalUpdate = incrementalUpdate;
this.Complete = complete;
}
+
+ ///
+ /// raise the / event, awaiting the async
+ /// version (if set) so callers no longer need to block on it.
+ ///
+ public async Task RaiseCallbackAsync(SyncProgressSummary summary)
+ {
+ Callback?.Invoke(summary);
+ if (CallbackAsync is not null)
+ await CallbackAsync(summary).ConfigureAwait(false);
+ }
+
+ ///
+ /// raise the / event, awaiting the async
+ /// version (if set) so callers no longer need to block on it.
+ ///
+ public async Task RaiseUpdateAsync(string message, int count, int total)
+ {
+ Update?.Invoke(message, count, total);
+ if (UpdateAsync is not null)
+ await UpdateAsync(message, count, total).ConfigureAwait(false);
+ }
+
+ ///
+ /// raise the / event, awaiting the async
+ /// version (if set) so callers no longer need to block on it.
+ ///
+ public async Task RaiseSetRangeAsync(int start, int end)
+ {
+ SetRange?.Invoke(start, end);
+ if (SetRangeAsync is not null)
+ await SetRangeAsync(start, end).ConfigureAwait(false);
+ }
+
+ ///
+ /// raise the / event, awaiting
+ /// the async version (if set) so callers no longer need to block on it.
+ ///
+ public async Task RaiseIncrementalUpdateAsync(string message)
+ {
+ IncrementalUpdate?.Invoke(message);
+ if (IncrementalUpdateAsync is not null)
+ await IncrementalUpdateAsync(message).ConfigureAwait(false);
+ }
+
+ ///
+ /// raise the / event, awaiting the async
+ /// version (if set) so callers no longer need to block on it.
+ ///
+ public async Task RaiseCompleteAsync(Guid id, string message, bool success, IEnumerable actions)
+ {
+ Complete?.Invoke(id, message, success, actions);
+ if (CompleteAsync is not null)
+ await CompleteAsync(id, message, success, actions).ConfigureAwait(false);
+ }
}
diff --git a/uSync.BackOffice/Services/SyncActionService.cs b/uSync.BackOffice/Services/SyncActionService.cs
index 91310959..afe499d6 100644
--- a/uSync.BackOffice/Services/SyncActionService.cs
+++ b/uSync.BackOffice/Services/SyncActionService.cs
@@ -124,7 +124,8 @@ public async Task ImportPostAsync(SyncFinalActionRequest reque
request.ActionOptions.GetSetOrDefault(_uSyncConfig.Settings.DefaultSet),
request.Actions);
- request.Callbacks?.Update?.Invoke("Post Import Complete", 1, 1);
+ if (request.Callbacks is not null)
+ await request.Callbacks.RaiseUpdateAsync("Post Import Complete", 1, 1);
return new SyncActionResult([.. actions.Where(x => x.Change > Core.ChangeType.NoChange)]);
}
@@ -218,7 +219,8 @@ public async Task FinishProcessAsync(SyncFinalActionRequest re
request.HandlerAction, request.Actions.CountChanges(), request.Actions.Count(), elapsed);
}
- request.Callbacks?.Update?.Invoke($"{request.HandlerAction} completed ({elapsed:#,#}ms)", 1, 1);
+ if (request.Callbacks is not null)
+ await request.Callbacks.RaiseUpdateAsync($"{request.HandlerAction} completed ({elapsed:#,#}ms)", 1, 1);
// for speed we return an empty list. the merge will just take
// what we where passed in, and we avoid a whole copy and compare step
diff --git a/uSync.BackOffice/Services/SyncService.cs b/uSync.BackOffice/Services/SyncService.cs
index bd0d31a0..0a2db748 100644
--- a/uSync.BackOffice/Services/SyncService.cs
+++ b/uSync.BackOffice/Services/SyncService.cs
@@ -198,7 +198,8 @@ public async Task> ImportAsync(string[] folders, bool f
summary.UpdateHandler(
handler.Name, HandlerStatus.Processing, $"Importing {handler.Name}", 0);
- callbacks?.Callback?.Invoke(summary);
+ if (callbacks is not null)
+ await callbacks.RaiseCallbackAsync(summary);
var handlerActions = await this.ImportHandlerAsync(handler.Alias, importOptions);
@@ -228,14 +229,18 @@ public async Task> ImportAsync(string[] folders, bool f
if (actions.ContainsErrors())
_logger.LogWarning("uSync Import: Errors detected in import : {count}", actions.CountErrors());
- callbacks?.Update?.Invoke($"Processed {actions.Count} items in {sw.ElapsedMilliseconds}ms", 1, 1);
+ if (callbacks is not null)
+ await callbacks.RaiseUpdateAsync($"Processed {actions.Count} items in {sw.ElapsedMilliseconds}ms", 1, 1);
summary.Message = "Completed";
summary.Total = handlers.Count() + 1;
var finalActions = actions.Select(x => x.AsActionView()).ToList();
- callbacks?.Callback?.Invoke(summary);
- callbacks?.Complete?.Invoke(requestId, "Sync complete", true, finalActions);
+ if (callbacks is not null)
+ {
+ await callbacks.RaiseCallbackAsync(summary);
+ await callbacks.RaiseCompleteAsync(requestId, "Sync complete", true, finalActions);
+ }
return actions;
}
@@ -392,7 +397,8 @@ public async Task> ExportAsync(string folder, IEnumerab
summary.UpdateHandler(
handler.Name, HandlerStatus.Processing, $"Exporting {handler.Name}", 0);
- callbacks?.Callback?.Invoke(summary);
+ if (callbacks is not null)
+ await callbacks.RaiseCallbackAsync(summary);
var handlerActions = await handler.ExportAllAsync([$"{folder}/{handler.DefaultFolder}"], configuredHandler.Settings, callbacks?.Update);
@@ -405,7 +411,8 @@ public async Task> ExportAsync(string folder, IEnumerab
summary.UpdateMessage("Export Completed");
- callbacks?.Callback?.Invoke(summary);
+ if (callbacks is not null)
+ await callbacks.RaiseCallbackAsync(summary);
await _mutexService.FireBulkCompleteAsync(new uSyncExportCompletedNotification(actions, null));
@@ -419,7 +426,8 @@ public async Task> ExportAsync(string folder, IEnumerab
sw.ElapsedMilliseconds);
}
- callbacks?.Update?.Invoke($"Processed {actions.Count} items in {sw.ElapsedMilliseconds}ms", 1, 1);
+ if (callbacks is not null)
+ await callbacks.RaiseUpdateAsync($"Processed {actions.Count} items in {sw.ElapsedMilliseconds}ms", 1, 1);
return actions;
}
diff --git a/uSync.BackOffice/Services/SyncService_Single.cs b/uSync.BackOffice/Services/SyncService_Single.cs
index f9b0b341..6f018838 100644
--- a/uSync.BackOffice/Services/SyncService_Single.cs
+++ b/uSync.BackOffice/Services/SyncService_Single.cs
@@ -59,8 +59,9 @@ public async Task> ReportPartialAsync(IList> ImportPartialAsync(IList> ImportPartialSecondPassAsync(IEnumer
continue;
}
- options.Callbacks?.Update?.Invoke($"Second Pass: {action.Name}",
- CalculateProgress(index, total, options.ProgressMin, options.ProgressMax), 100);
+ if (options.Callbacks is not null)
+ await options.Callbacks.RaiseUpdateAsync($"Second Pass: {action.Name}",
+ CalculateProgress(index, total, options.ProgressMin, options.ProgressMax), 100);
secondPassActions.AddRange(await handlerPair.Handler.ImportSecondPassAsync(action, handlerPair.Settings, options));
@@ -273,7 +276,8 @@ public async Task> ImportPartialPostImportAsync(IEnumer
{
if (handlerPair.Handler is ISyncPostImportHandler postImportHandler)
{
- options.Callbacks?.Update?.Invoke(actionItem.alias, index, folders.Count);
+ if (options.Callbacks is not null)
+ await options.Callbacks.RaiseUpdateAsync(actionItem.alias, index, folders.Count);
var handlerActions = actions.Where(x => x.HandlerAlias.InvariantEquals(handlerPair.Handler.Alias));
results.AddRange(await postImportHandler.ProcessPostImportAsync(handlerActions, handlerPair.Settings));
@@ -326,7 +330,8 @@ public async Task> ImportPostCleanFilesAsync(IEnumerabl
if (handlerPair.Handler is ISyncCleanEntryHandler cleanEntryHandler)
{
- options.Callbacks?.Update?.Invoke(actionItem.alias, index, cleans.Count);
+ if (options.Callbacks is not null)
+ await options.Callbacks.RaiseUpdateAsync(actionItem.alias, index, cleans.Count);
var handlerActions = actions.Where(x => x.HandlerAlias.InvariantEquals(handlerPair.Handler.Alias));
results.AddRange(await cleanEntryHandler.ProcessCleanActionsAsync(actionItem.folder, handlerActions, handlerPair.Settings));
diff --git a/uSync.BackOffice/SyncHandlers/SyncHandlerRoot.cs b/uSync.BackOffice/SyncHandlers/SyncHandlerRoot.cs
index d5b3f275..9be83d04 100644
--- a/uSync.BackOffice/SyncHandlers/SyncHandlerRoot.cs
+++ b/uSync.BackOffice/SyncHandlers/SyncHandlerRoot.cs
@@ -266,11 +266,13 @@ public async Task> ImportAllAsync(string[] folders, Han
var cacheKey = PrepCaches();
try
{
- options.Callbacks?.Update?.Invoke("Calculating import order", 1, 9);
+ if (options.Callbacks is not null)
+ await options.Callbacks.RaiseUpdateAsync("Calculating import order", 1, 9);
var items = await GetMergedItemsAsync(folders, new SyncMergeOptions(options.Callbacks?.Update));
- options.Callbacks?.Update?.Invoke($"Processing {items.Count} items", 2, 9);
+ if (options.Callbacks is not null)
+ await options.Callbacks.RaiseUpdateAsync($"Processing {items.Count} items", 2, 9);
// create the update list with items.count space. this is the max size we need this list.
List actions = new(items.Count);
@@ -280,7 +282,8 @@ public async Task> ImportAllAsync(string[] folders, Han
int count = 0;
int total = items.Count;
- options.Callbacks?.SetRange?.Invoke(count, total);
+ if (options.Callbacks is not null)
+ await options.Callbacks.RaiseSetRangeAsync(count, total);
foreach (var item in items)
{
@@ -326,7 +329,8 @@ public async Task> ImportAllAsync(string[] folders, Han
await PerformImportCleanAsync(cleanMarkers, actions, config, options.Callbacks?.Update);
}
- options.Callbacks?.Update?.Invoke("Done", 3, 3);
+ if (options.Callbacks is not null)
+ await options.Callbacks.RaiseUpdateAsync("Done", 3, 3);
if (logger.IsEnabled(LogLevel.Debug))
logger.LogDebug("ImportAll: {count} items imported", actions.Count);
@@ -458,7 +462,8 @@ virtual public async Task> ImportElementAsync(XElement
{
var actions = new List();
var elements = node.Elements().ToList();
- options.Callbacks?.SetRange?.Invoke(0, elements.Count);
+ if (options.Callbacks is not null)
+ await options.Callbacks.RaiseSetRangeAsync(0, elements.Count);
foreach (var item in elements)
{
actions.AddRange(await ImportSingleElementAsync(new XElement(item), filename, settings, options));
@@ -492,7 +497,8 @@ virtual protected async Task> ImportSingleElementAsync(
try
{
- options.Callbacks?.IncrementalUpdate?.Invoke(node.GetAlias());
+ if (options.Callbacks is not null)
+ await options.Callbacks.RaiseIncrementalUpdateAsync(node.GetAlias());
// merge the options from the handler and any import options into our serializer options.
var serializerOptions = new SyncSerializerOptions(options.Flags, settings.Settings, options.UserId);
diff --git a/uSync.Backoffice.Management.Api/Services/uSyncManagementService.cs b/uSync.Backoffice.Management.Api/Services/uSyncManagementService.cs
index 9ba186b7..c63dd893 100644
--- a/uSync.Backoffice.Management.Api/Services/uSyncManagementService.cs
+++ b/uSync.Backoffice.Management.Api/Services/uSyncManagementService.cs
@@ -269,7 +269,7 @@ await _syncActionService.StartProcessAsync(new SyncStartActionRequest
if (actionRequest.StepNumber >= handlers.Count)
{
var actions = await PerformFinalSteps(requestId, action, handlerOptions, callbacks, user?.Username);
- return SummerizeCompleteProcess(actionRequest, action, handlers, requestId, callbacks, actions);
+ return await SummerizeCompleteProcess(actionRequest, action, handlers, requestId, callbacks, actions);
}
@@ -282,7 +282,7 @@ await _syncActionService.StartProcessAsync(new SyncStartActionRequest
var allActions = _syncManagementCache.GetCachedActions(requestId);
var summaries = GetSummaries(action, handlers, actionRequest.StepNumber, allActions);
- callbacks.Callback?.Invoke(new SyncProgressSummary(summaries, "Processing " + action.ToString(), handlers.Count));
+ await callbacks.RaiseCallbackAsync(new SyncProgressSummary(summaries, "Processing " + action.ToString(), handlers.Count));
return new PerformActionResponse
{
@@ -293,15 +293,18 @@ await _syncActionService.StartProcessAsync(new SyncStartActionRequest
};
}
- private static PerformActionResponse SummerizeCompleteProcess(PerformActionRequest actionRequest, HandlerActions action, List handlers, Guid requestId, uSyncCallbacks callbacks, List actions)
+ private static async Task SummerizeCompleteProcess(PerformActionRequest actionRequest, HandlerActions action, List handlers, Guid requestId, uSyncCallbacks callbacks, List actions)
{
var finalSummary = GetSummaries(action, handlers, actionRequest.StepNumber + 1, actions);
var actionViews = actions.Select(x => x.AsActionView());
- callbacks?.Callback?.Invoke(new SyncProgressSummary(finalSummary, "Completed", handlers.Count));
- callbacks?.Complete?.Invoke(requestId, "Sync complete", true, actionViews);
+ if (callbacks is not null)
+ {
+ await callbacks.RaiseCallbackAsync(new SyncProgressSummary(finalSummary, "Completed", handlers.Count));
+ await callbacks.RaiseCompleteAsync(requestId, "Sync complete", true, actionViews);
+ }
- // finished.
+ // finished.
return new PerformActionResponse
{
RequestId = requestId.ToString(),