Files
speckle-sharp-connectors/DUI3/Speckle.Connectors.DUI/Bindings/OperationProgressManager.cs
T
Adam Hathcock 4e85a6cccc feat(Revit 2026) Add projects and fixes for Revit 2026 usage (#736)
* add base revit 26 projects

* fix up cef replacement

* fix up revit 2026 events

* add revit events

* fixes for revit 26

* use right version of DI for Revit26

* add Revit26 to local

* fmt

* use visual studio to fix slns

* Add revit to installer constants

* move webview stuff to 2026 specific area to avoid build issues

* update locks

* Revit 2026 wants to invoke scripts with RevitTask.  Abstract RevitTask

* fmt

* fix project copying

* use 3.2 SDK

* fix build

* Revit 2025 is now CEF vulnerable

* add SendProgress to not overload revit context

* update Revit 26 lock files

* update locks

---------

Co-authored-by: Oğuzhan Koral <45078678+oguzhankoral@users.noreply.github.com>
2025-05-14 12:55:00 +03:00

80 lines
2.5 KiB
C#

using System.Collections.Concurrent;
using Speckle.Connectors.Common.Operations;
using Speckle.Connectors.DUI.Bridge;
using Speckle.Connectors.DUI.Models.Card;
using Speckle.InterfaceGenerator;
namespace Speckle.Connectors.DUI.Bindings;
/// <summary>
/// Debouncing progress for every %1 update for UI.
/// This class requires a specific bridge in its binding, so registering it will create random bridge which we don't want to.
/// </summary>
[GenerateAutoInterface]
public class OperationProgressManager : IOperationProgressManager
{
private class NonUIThreadProgress<T>(Action<T> handler) : IProgress<T>
{
public void Report(T value) => handler(value);
}
private const string SET_MODEL_PROGRESS_UI_COMMAND_NAME = "setModelProgress";
private static readonly ConcurrentDictionary<string, (DateTime lastCallTime, string status)> s_lastProgressValues =
new();
private const int THROTTLE_INTERVAL_MS = 200;
public IProgress<CardProgress> CreateOperationProgressEventHandler(
IBrowserBridge bridge,
string modelCardId,
CancellationToken cancellationToken
)
{
var progress = new NonUIThreadProgress<CardProgress>(args =>
{
SetModelProgress(
bridge,
modelCardId,
new ModelCardProgress(modelCardId, args.Status, args.Progress),
cancellationToken
);
});
return progress;
}
public void SetModelProgress(
IBrowserBridge bridge,
string modelCardId,
ModelCardProgress progress,
CancellationToken cancellationToken
)
{
if (cancellationToken.IsCancellationRequested)
{
return;
}
if (!s_lastProgressValues.TryGetValue(modelCardId, out (DateTime, string) t))
{
t.Item1 = DateTime.Now;
s_lastProgressValues[modelCardId] = (t.Item1, progress.Status);
// Since it's the first time we get a call for this model card, we should send it out
SendProgress(bridge, modelCardId, progress);
return;
}
var currentTime = DateTime.Now;
var elapsedMs = (currentTime - t.Item1).Milliseconds;
if (elapsedMs < THROTTLE_INTERVAL_MS && t.Item2 == progress.Status)
{
return;
}
Console.WriteLine($"Progress: {progress.Status} - {progress.Progress}");
s_lastProgressValues[modelCardId] = (currentTime, progress.Status);
SendProgress(bridge, modelCardId, progress);
}
private static void SendProgress(IBrowserBridge bridge, string modelCardId, ModelCardProgress progress) =>
bridge.SendProgress(SET_MODEL_PROGRESS_UI_COMMAND_NAME, new { modelCardId, progress });
}