Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
96 changes: 90 additions & 6 deletions src/DynamoCore/Core/CustomNodeManager.cs
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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
Expand All @@ -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<CustomNodeInfo> ("C:\\Temp\\CustomNodeInforCache.temp");
}

#region Fields and properties

private LibraryServices libraryServices;
private JsonCache<CustomNodeInfo> customNodeInfoCache;

private readonly OrderedSet<Guid> loadOrder = new OrderedSet<Guid>();

Expand Down Expand Up @@ -684,6 +690,18 @@ internal bool TryGetInfoFromPath(string path, bool isTestMode, out CustomNodeInf
Exception ex;
try
{
var fileinfo = new FileInfo(path);

This comment was marked as resolved.

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))
Expand All @@ -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)
Expand Down Expand Up @@ -1419,4 +1440,67 @@ public void Dispose()
this.loadedCustomNodes.ToList().ForEach(x => Uninitialize(x.Value.FunctionId));
}
}

//Location temporary
public class JsonCache<T> : IDisposable
{
private readonly string cacheFilePath;
private readonly Dictionary<string, T> 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();
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need to unsubscribe this?

}

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)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm curious if the Remove function needs to be called at any time to clean up the cache dictionary. I think it may be needed when updating a custom node definition, i.e., a custom node with the same name as one that's already in the dictionary, but with a new time stamp that indicates that it has been edited.

{
if (cache.Remove(key))
dirty = true;
}

private void Load()
{
if (File.Exists(cacheFilePath))
{
var json = File.ReadAllText(cacheFilePath);
var loaded = JsonSerializer.Deserialize<Dictionary<string, T>>(json);
if (loaded != null)
foreach (var kv in loaded)
cache[kv.Key] = kv.Value;
}
}

private void FlushIfDirty()
{
if (dirty)
Flush();
}

public void Flush()
Copy link
Copy Markdown

@aparajit-pratap aparajit-pratap Jun 5, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nitpick, but perhaps this will be clearer if you just call this method Serialize?

{
var json = JsonSerializer.Serialize(cache, new JsonSerializerOptions { WriteIndented = true });
File.WriteAllText(cacheFilePath, json);
dirty = false;
}

public void Dispose()
{
flushTimer?.Dispose();
Flush();
}
}

}
Loading