From 8694ebd5772c8b7a704067f9c186789236cf070b Mon Sep 17 00:00:00 2001 From: Craig Long Date: Wed, 4 Jun 2025 13:49:56 -0400 Subject: [PATCH] First pass --- src/DynamoCore/Core/CustomNodeManager.cs | 96 ++++++++++++++++++++++-- 1 file changed, 90 insertions(+), 6 deletions(-) diff --git a/src/DynamoCore/Core/CustomNodeManager.cs b/src/DynamoCore/Core/CustomNodeManager.cs index 8dabe1ec45b..626bddc35c2 100644 --- a/src/DynamoCore/Core/CustomNodeManager.cs +++ b/src/DynamoCore/Core/CustomNodeManager.cs @@ -1,9 +1,3 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.IO; -using System.Linq; -using System.Xml; using Dynamo.Engine; using Dynamo.Engine.NodeToCode; using Dynamo.Exceptions; @@ -25,6 +19,14 @@ using Dynamo.Selection; using Dynamo.Utilities; using ProtoCore.AST.AssociativeAST; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Text.Json; +using System.Threading; +using System.Xml; using Symbol = Dynamo.Graph.Nodes.CustomNodes.Symbol; namespace Dynamo.Core @@ -47,11 +49,15 @@ public CustomNodeManager(NodeFactory nodeFactory, MigrationManager migrationMana this.nodeFactory = nodeFactory; this.migrationManager = migrationManager; this.libraryServices = libraryServices; + + //Todo decide were we want to store this + customNodeInfoCache = new JsonCache ("C:\\Temp\\CustomNodeInforCache.temp"); } #region Fields and properties private LibraryServices libraryServices; + private JsonCache customNodeInfoCache; private readonly OrderedSet loadOrder = new OrderedSet(); @@ -684,6 +690,18 @@ internal bool TryGetInfoFromPath(string path, bool isTestMode, out CustomNodeInf Exception ex; try { + var fileinfo = new FileInfo(path); + var lastWriteTime = fileinfo.LastWriteTimeUtc; + var length = fileinfo.Length; + + //create a fast check for checking if the file has been loaded before. Could also do a file hash but we don't care too much about false negatives + var key = path + lastWriteTime.ToString() + length.ToString(); + + if (customNodeInfoCache.TryGet(key, out info)) + { + return true; + } + if (DynamoUtilities.PathHelper.isValidJson(path, out jsonDoc, out ex)) { if (!WorkspaceInfo.FromJsonDocument(jsonDoc, path, isTestMode, false, AsLogger(), out header)) @@ -710,6 +728,9 @@ internal bool TryGetInfoFromPath(string path, bool isTestMode, out CustomNodeInf header.Description, path, header.IsVisibleInDynamoLibrary); + + customNodeInfoCache.Set(key, info); + return true; } catch (Exception e) @@ -1419,4 +1440,67 @@ public void Dispose() this.loadedCustomNodes.ToList().ForEach(x => Uninitialize(x.Value.FunctionId)); } } + + //Location temporary + public class JsonCache : IDisposable + { + private readonly string cacheFilePath; + private readonly Dictionary cache = new(); + private bool dirty = false; + private readonly Timer flushTimer; + + public JsonCache(string filePath) + { + cacheFilePath = filePath; + Load(); + // Not sure if this covers all cases. Can also add flush to Dispose + AppDomain.CurrentDomain.ProcessExit += (s, e) => FlushIfDirty(); + } + + public void Set(string key, T value) + { + cache[key] = value; + dirty = true; + } + + public bool TryGet(string key, out T value) => cache.TryGetValue(key, out value); + + public void Remove(string key) + { + if (cache.Remove(key)) + dirty = true; + } + + private void Load() + { + if (File.Exists(cacheFilePath)) + { + var json = File.ReadAllText(cacheFilePath); + var loaded = JsonSerializer.Deserialize>(json); + if (loaded != null) + foreach (var kv in loaded) + cache[kv.Key] = kv.Value; + } + } + + private void FlushIfDirty() + { + if (dirty) + Flush(); + } + + public void Flush() + { + var json = JsonSerializer.Serialize(cache, new JsonSerializerOptions { WriteIndented = true }); + File.WriteAllText(cacheFilePath, json); + dirty = false; + } + + public void Dispose() + { + flushTimer?.Dispose(); + Flush(); + } + } + }