Skip to content

Commit

Permalink
DYN-6311 checksum generation (DynamoDS#14542)
Browse files Browse the repository at this point in the history
* Add the Checksum property

* Naming and Test file

* Checksum function of a graph and storage in the preferences for later comparisons

* Checksum generation - Rrefactoring

* Assignation of the checksum properties refactored

---------

Co-authored-by: Jesus Alfredo Alviño <[email protected]>
Co-authored-by: Aaron (Qilong) <[email protected]>
  • Loading branch information
3 people authored Nov 13, 2023
1 parent 40e4357 commit f0cd05c
Show file tree
Hide file tree
Showing 8 changed files with 198 additions and 7 deletions.
17 changes: 17 additions & 0 deletions src/DynamoCore/Configuration/GraphChecksumItem.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
using System;
using System.Collections.ObjectModel;
using Dynamo.Core;
using Dynamo.Properties;

namespace Dynamo.Configuration
{
/// <summary>
/// Represents the stringified version of the nodes connections from a graph
/// </summary>
public class GraphChecksumItem
{
public string GraphId { get; set; }

public string Checksum { get; set; }
}
}
6 changes: 6 additions & 0 deletions src/DynamoCore/Configuration/IPreferences.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using Dynamo.Configuration;
using Dynamo.Graph.Connectors;

namespace Dynamo.Interfaces
Expand Down Expand Up @@ -146,6 +147,11 @@ public interface IPreferences
/// <param name="name">Background preview name</param>
/// <param name="value">Active state to set</param>
void SetIsBackgroundPreviewActive(string name, bool value);

/// <summary>
/// Return a list of GraphChecksumItems
/// </summary>
List<GraphChecksumItem> GraphChecksumItemsList { get; set; }
}

/// <summary>
Expand Down
6 changes: 6 additions & 0 deletions src/DynamoCore/Configuration/PreferenceSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -458,6 +458,11 @@ public bool DisableTrustWarnings
/// </summary>
private List<string> trustedLocations { get; set; } = new List<string>();

/// <summary>
/// Return a list of GraphChecksumItems
/// </summary>
public List<GraphChecksumItem> GraphChecksumItemsList { get; set; }

// This function is used to deserialize the trusted locations manually
// so that the TrustedLocation propertie's setter does not need to be public.
private List<string> DeserializeTrustedLocations(XmlNode preferenceSettingsElement)
Expand Down Expand Up @@ -915,6 +920,7 @@ public PreferenceSettings()
EnableDynamoPlayerRenamedWatchAsOutput = false;
DynamoPlayerFolderGroups = new List<DynamoPlayerFolderGroup>();
backupLocation = string.Empty;
GraphChecksumItemsList = new List<GraphChecksumItem>();
}

/// <summary>
Expand Down
2 changes: 1 addition & 1 deletion src/DynamoCore/Graph/Workspaces/WorkspaceModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2013,7 +2013,7 @@ internal bool IsValidForFDX
{
get
{
return !HasErrors && !HasNoneGeometryRelatedWarnings;
return Nodes.Count() > 1 && !HasErrors && !HasNoneGeometryRelatedWarnings;
}
}

Expand Down
43 changes: 40 additions & 3 deletions src/DynamoCoreWpf/ViewModels/Core/DynamoViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2090,15 +2090,52 @@ internal bool CanSaveAs(object parameters)
return (parameters != null);
}

/// <summary>
/// Indicates if the graph has been changed substantially bearing in mind the connections of its nodes and store the checksum value of the graph in the preferences to later comparison
/// </summary>
/// <returns></returns>
private bool HasSubstantialCheckSum()
{
bool substantialChecksum = false;
string graphId = Model.CurrentWorkspace.Guid.ToString();

GraphChecksumItem checksumItem = PreferenceSettings.GraphChecksumItemsList.Where(i => i.GraphId == graphId).FirstOrDefault();
if (checksumItem != null)
{
if (checksumItem.Checksum != currentWorkspaceViewModel.Checksum)
{
PreferenceSettings.GraphChecksumItemsList.Remove(checksumItem);
PreferenceSettings.GraphChecksumItemsList.Add(new GraphChecksumItem() { GraphId = graphId, Checksum = currentWorkspaceViewModel.Checksum });
substantialChecksum = true;
}
}
else
{
PreferenceSettings.GraphChecksumItemsList.Add(new GraphChecksumItem() { GraphId = graphId, Checksum = currentWorkspaceViewModel.Checksum });
substantialChecksum = true;
}
return substantialChecksum;
}

private void InternalSaveAs(string path, SaveContext saveContext, bool isBackup = false)
{
try
{
Model.Logger.Log(String.Format(Properties.Resources.SavingInProgress, path));
CurrentSpaceViewModel.Save(path, isBackup, Model.EngineController, saveContext);
if (!isBackup) AddToRecentFiles(path);
if (currentWorkspaceViewModel?.IsHomeSpace ?? true)
Model.Logger.Log("The Workspace is valid for FDX : " + (HomeSpace.HasRunWithoutCrash && Model.CurrentWorkspace.IsValidForFDX).ToString());

if (!isBackup)
{
AddToRecentFiles(path);

if ((currentWorkspaceViewModel?.IsHomeSpace ?? true) && HomeSpace.HasRunWithoutCrash && Model.CurrentWorkspace.IsValidForFDX && currentWorkspaceViewModel.Checksum != string.Empty)
{
Model.Logger.Log("The Workspace is valid for FDX");
Model.Logger.Log("The Workspace id is : " + currentWorkspaceViewModel.Model.Guid.ToString());
Model.Logger.Log("The Workspace checksum is : " + currentWorkspaceViewModel.Checksum);
Model.Logger.Log("The Workspace has Substantial checksum, so is ready to send to FDX : " + HasSubstantialCheckSum().ToString());
}
}
}
catch (Exception ex)
{
Expand Down
113 changes: 110 additions & 3 deletions src/DynamoCoreWpf/ViewModels/Core/WorkspaceViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -357,6 +357,106 @@ public bool IsHomeSpace
get { return Model == DynamoViewModel.HomeSpace; }
}

/// <summary>
/// Returns the Json representation of the current graph
/// </summary>
[JsonIgnore]
internal JObject JsonRepresentation { get; set; }

/// <summary>
/// Returns the stringified representation of the connected nodes
/// </summary>
[JsonIgnore]
public string Checksum
{
get
{
List<string> nodeInfoConnections = new List<string>();
JObject jsonWorkspace = JsonRepresentation;
var nodes = jsonWorkspace["Nodes"];

List<string> nodeIds = new List<string>();
foreach (JObject node in nodes)
{
var nodeProperties = node.Children<JProperty>();
JProperty id = nodeProperties.FirstOrDefault(x => x.Name == "Id");
nodeIds.Add(id.Value.ToString());
}

nodeIds.Sort();

foreach (string nodeId in nodeIds)
{
List<string> outputIds = new List<string>();
var node = jsonWorkspace["Nodes"].Where(t => t.Value<string>("Id") == nodeId).Select(t => t).FirstOrDefault();
var outputsProperty = node.Children<JProperty>().FirstOrDefault(x => x.Name == "Outputs");
var outputs = (JArray)outputsProperty.Value;
int outputIndex = 1;

foreach (JObject output in outputs)
{
var outputProperties = output.Children<JProperty>();
JProperty outputId = outputProperties.FirstOrDefault(x => x.Name == "Id");
outputIds.Add(outputId.Value.ToString());

var connectorsProperty = jsonWorkspace["Connectors"].Where(t => t.Value<string>("Start") == outputId.Value.ToString());

foreach (var connector in connectorsProperty)
{
var connectorProperties = connector.Children<JProperty>();
JProperty endProperty = connectorProperties.FirstOrDefault(x => x.Name == "End");
string inputId = (String)endProperty.Value;

var outputConnectedNode = GetNodeByInputId(inputId, jsonWorkspace);
nodeInfoConnections.Add(nodeId + "|[" + outputIndex.ToString() + "|" + outputConnectedNode.Item1 + "|" + outputConnectedNode.Item2.ToString() + "]");
}
outputIndex++;
}
}
return nodeInfoConnections.Count > 0 ? string.Join(",", nodeInfoConnections) : string.Empty;
}
}

Tuple<string,int> GetNodeByInputId(string inputId, JObject jsonWorkspace)
{
var nodes = jsonWorkspace["Nodes"];

string nodeId = string.Empty;
int connectedInputIndex = 1;
bool foundNode = false;

foreach (var node in nodes)
{
if (!foundNode)
{
nodeId = string.Empty;
connectedInputIndex = 1;

var nodeProperties = node.Children<JProperty>();
JProperty nodeProperty = nodeProperties.FirstOrDefault(x => x.Name == "Id");
nodeId = (String)nodeProperty.Value;

JProperty nodeInputs = nodeProperties.FirstOrDefault(x => x.Name == "Inputs");
var inputs = (JArray)nodeInputs.Value;

foreach (JObject input in inputs)
{
var inputProperties = input.Children<JProperty>();
JProperty connectedNodeInputId = inputProperties.FirstOrDefault(x => x.Name == "Id");

if ((String)connectedNodeInputId.Value == inputId)
{
foundNode = true;
break;
}
connectedInputIndex++;
}
}
}

return new Tuple<string, int>(nodeId, connectedInputIndex);
}

[JsonIgnore]
public bool HasUnsavedChanges
{
Expand Down Expand Up @@ -652,19 +752,26 @@ internal void Save(string filePath, bool isBackup = false, EngineController engi
}
}
}

saveContent = GuidUtility.UpdateWorkspaceGUIDs(jo.ToString());
saveContent = GuidUtility.UpdateWorkspaceGUIDs(jo.ToString());
}
else
{
saveContent = jo.ToString();
}
}

File.WriteAllText(filePath, saveContent);

// Handle Workspace or CustomNodeWorkspace related non-serialization internal logic
// Only for actual save, update file path and recent file list
// The assignation of the JsonRepresentation and Guid is only for the checksum flow, it will grab info only from .dyn files
if (!isBackup)
{
if (Path.GetExtension(filePath).Equals(".dyn"))
{
JsonRepresentation = JObject.Parse(saveContent);
DynamoViewModel.Workspaces[0].Model.Guid = new Guid(JsonRepresentation.Properties().First(p => p.Name == "Uuid").Value.ToString());
}

Model.FileName = filePath;
Model.OnSaved();
}
Expand Down
12 changes: 12 additions & 0 deletions test/DynamoCoreTests/Configuration/PreferenceSettingsTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -358,6 +358,18 @@ PreferencesComparison comparePrefenceSettings(PreferenceSettings defaultSettings
propertiesWithDifferentValue.Add(destinationPi.Name);
}
}
else if (destinationPi.PropertyType == typeof(List<GraphChecksumItem>))
{
if (((List<GraphChecksumItem>)sourcePi.GetValue(newGeneralSettings, null)).Count ==
((List<GraphChecksumItem>)destinationPi.GetValue(defaultSettings, null)).Count)
{
propertiesWithSameValue.Add(destinationPi.Name);
}
else
{
propertiesWithDifferentValue.Add(destinationPi.Name);
}
}
else
{
if (newValue?.ToString() == oldValue?.ToString())
Expand Down
6 changes: 6 additions & 0 deletions test/settings/DynamoSettings-NewSettings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,12 @@
<string>C:\ProgramData\Dynamo\Dynamo Core\2.16\packages</string>
</CustomPackageFolders>
<DisableTrustWarnings>true</DisableTrustWarnings>
<GraphChecksumItemsList>
<GraphChecksumItem>
<GraphId>a6f6ab04-752c-4b17-8360-2e563bea7c23</GraphId>
<Checksum>588c8174ea314ee3945243a19457796f|[1|f9ec27ad6b584c0babf7055a787df6ad|1]</Checksum>
</GraphChecksumItem>
</GraphChecksumItemsList>
<TrustedLocations>
<string>C:\</string>
<string>E:\</string>
Expand Down

0 comments on commit f0cd05c

Please sign in to comment.