Skip to content

Commit

Permalink
bjorn/cnx-1111-switching-documents-does-not-invalidate-active-connect…
Browse files Browse the repository at this point in the history
…or (#528)

* bug: close plugin when user switches model

* bug: refresh plugin when model changes

* style: remove log information
  • Loading branch information
bjoernsteinhagen authored Jan 28, 2025
1 parent 9e18134 commit 03f0b1f
Show file tree
Hide file tree
Showing 3 changed files with 134 additions and 41 deletions.
Original file line number Diff line number Diff line change
@@ -1,36 +1,54 @@
using Speckle.Connectors.DUI.Bindings;
using Speckle.Connectors.DUI.Bridge;
using Speckle.Connectors.DUI.Eventing;
using Speckle.Connectors.DUI.Models;
using Speckle.Connectors.DUI.Models.Card;
using Speckle.Sdk;

namespace Speckle.Connectors.CSiShared.Bindings;

public class CsiSharedBasicConnectorBinding(
IBrowserBridge parent,
ISpeckleApplication speckleApplication,
DocumentModelStore store
) : IBasicConnectorBinding
public class CsiSharedBasicConnectorBinding : IBasicConnectorBinding
{
private readonly ISpeckleApplication _speckleApplication;
private readonly DocumentModelStore _store;
private readonly IEventAggregator _eventAggregator;
public string Name => "baseBinding";
public IBrowserBridge Parent { get; } = parent;
public BasicConnectorBindingCommands Commands { get; } = new(parent);
public IBrowserBridge Parent { get; }
public BasicConnectorBindingCommands Commands { get; }

public string GetConnectorVersion() => speckleApplication.SpeckleVersion;
public CsiSharedBasicConnectorBinding(
IBrowserBridge parent,
ISpeckleApplication speckleApplication,
DocumentModelStore store,
IEventAggregator eventAggregator
)
{
Parent = parent;
_speckleApplication = speckleApplication;
_store = store;
Commands = new BasicConnectorBindingCommands(Parent);
_eventAggregator = eventAggregator;

public string GetSourceApplicationName() => speckleApplication.Slug;
_eventAggregator.GetEvent<DocumentStoreChangedEvent>().Subscribe(OnDocumentStoreChangedEvent);
}

public string GetSourceApplicationVersion() => speckleApplication.HostApplicationVersion;
private async Task OnDocumentStoreChangedEvent(object _) => await Commands.NotifyDocumentChanged();

public string GetConnectorVersion() => _speckleApplication.SpeckleVersion;

public string GetSourceApplicationName() => _speckleApplication.Slug;

public string GetSourceApplicationVersion() => _speckleApplication.HostApplicationVersion;

public DocumentInfo? GetDocumentInfo() => new("ETABS Model", "ETABS Model", "1");

public DocumentModelStore GetDocumentState() => store;
public DocumentModelStore GetDocumentState() => _store;

public void AddModel(ModelCard model) => store.AddModel(model);
public void AddModel(ModelCard model) => _store.AddModel(model);

public void UpdateModel(ModelCard model) => store.UpdateModel(model);
public void UpdateModel(ModelCard model) => _store.UpdateModel(model);

public void RemoveModel(ModelCard model) => store.RemoveModel(model);
public void RemoveModel(ModelCard model) => _store.RemoveModel(model);

public Task HighlightModel(string modelCardId) => Task.CompletedTask;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,40 +1,94 @@
using System.IO;
using System.Timers;
using Microsoft.Extensions.Logging;
using Speckle.Connectors.DUI.Eventing;
using Speckle.Connectors.DUI.Models;
using Speckle.Connectors.DUI.Utils;
using Speckle.Sdk;
using Speckle.Sdk.Helpers;
using Speckle.Sdk.Logging;
using Timer = System.Timers.Timer;

namespace Speckle.Connectors.CSiShared.HostApp;

public class CsiDocumentModelStore(
IJsonSerializer jsonSerializerSettings,
ISpeckleApplication speckleApplication,
ILogger<CsiDocumentModelStore> logger,
ICsiApplicationService csiApplicationService
) : DocumentModelStore(jsonSerializerSettings)
public class CsiDocumentModelStore : DocumentModelStore, IDisposable
{
private readonly ISpeckleApplication _speckleApplication;
private readonly ILogger<CsiDocumentModelStore> _logger;
private readonly ICsiApplicationService _csiApplicationService;
private readonly Timer _modelCheckTimer;
private readonly IEventAggregator _eventAggregator;
private string _lastModelFilename = string.Empty;
private bool _disposed;
private string HostAppUserDataPath { get; set; }
private string DocumentStateFile { get; set; }
private string ModelPathHash { get; set; }

public override Task OnDocumentStoreInitialized()
public CsiDocumentModelStore(
IJsonSerializer jsonSerializer,
ISpeckleApplication speckleApplication,
ILogger<CsiDocumentModelStore> logger,
ICsiApplicationService csiApplicationService,
IEventAggregator eventAggregator
)
: base(jsonSerializer)
{
_speckleApplication = speckleApplication;
_logger = logger;
_csiApplicationService = csiApplicationService;
_eventAggregator = eventAggregator;

// initialize timer to check for model changes
_modelCheckTimer = new Timer(1000);
_modelCheckTimer.Elapsed += CheckModelChanges;
_modelCheckTimer.Start();
}

private async void CheckModelChanges(object? source, ElapsedEventArgs e)
{
string currentFilename = _csiApplicationService.SapModel.GetModelFilename();

if (string.IsNullOrEmpty(currentFilename) || currentFilename == _lastModelFilename)
{
return;
}

_lastModelFilename = currentFilename;
SetPaths();
LoadState();

await _eventAggregator.GetEvent<DocumentStoreChangedEvent>().PublishAsync(new object());
}

public override Task OnDocumentStoreInitialized()
{
var currentFilename = _csiApplicationService.SapModel.GetModelFilename();
if (!string.IsNullOrEmpty(currentFilename))
{
_lastModelFilename = currentFilename;
SetPaths();
LoadState();
}
return Task.CompletedTask;
}

private void SetPaths()
{
ModelPathHash = Crypt.Md5(csiApplicationService.SapModel.GetModelFilepath(), length: 32);
HostAppUserDataPath = Path.Combine(
SpecklePathProvider.UserSpeckleFolderPath,
"ConnectorsFileData",
speckleApplication.Slug
);
DocumentStateFile = Path.Combine(HostAppUserDataPath, $"{ModelPathHash}.json");
try
{
ModelPathHash = Crypt.Md5(_csiApplicationService.SapModel.GetModelFilename(), length: 32);
HostAppUserDataPath = Path.Combine(
SpecklePathProvider.UserSpeckleFolderPath,
"ConnectorsFileData",
_speckleApplication.Slug
);
DocumentStateFile = Path.Combine(HostAppUserDataPath, $"{ModelPathHash}.json");
_logger.LogDebug($"Paths set - Hash: {ModelPathHash}, File: {DocumentStateFile}");
}
catch (Exception ex) when (!ex.IsFatal())
{
_logger.LogError(ex, "Error in setting paths for CsiDocumentModelStore");
}
}

protected override void HostAppSaveState(string modelCardState)
Expand All @@ -45,29 +99,53 @@ protected override void HostAppSaveState(string modelCardState)
{
Directory.CreateDirectory(HostAppUserDataPath);
}

File.WriteAllText(DocumentStateFile, modelCardState);
}
catch (Exception ex) when (!ex.IsFatal())
{
logger.LogError(ex.Message);
_logger.LogError(ex, "Failed to save state");
}
}

protected override void LoadState()
{
if (!Directory.Exists(HostAppUserDataPath))
try
{
if (!File.Exists(DocumentStateFile))
{
ClearAndSave();
return;
}

string serializedState = File.ReadAllText(DocumentStateFile);
LoadFromString(serializedState);
}
catch (Exception ex) when (!ex.IsFatal())
{
_logger.LogError(ex, "Failed to load state, initializing empty state");
ClearAndSave();
return;
}
}

if (!File.Exists(DocumentStateFile))
protected virtual void Dispose(bool disposing)
{
if (_disposed)
{
ClearAndSave();
return;
}

string serializedState = File.ReadAllText(DocumentStateFile);
LoadFromString(serializedState);
if (disposing)
{
_modelCheckTimer.Dispose();
}

_disposed = true;
}

public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -76,13 +76,10 @@ public void Initialize(ref cSapModel sapModel, ref cPluginCallback pluginCallbac
Host = new() { Child = webview, Dock = DockStyle.Fill };
Controls.Add(Host);
FormBorderStyle = FormBorderStyle.Sizable;
// this.TopLevel = true;
// TODO: Get IntrPtr for Csi window
FormClosing += Form1Closing;
}

private void Form1Closing(object? sender, FormClosingEventArgs e)
{
Host.Dispose();
_pluginCallback.Finish(0);
_container.Dispose();
}
private void Form1Closing(object? sender, FormClosingEventArgs e) => _pluginCallback.Finish(0);
}

0 comments on commit 03f0b1f

Please sign in to comment.