Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

wrap launch darkly in CLI to avoid bringing in new deps #12801

Merged
merged 31 commits into from
Apr 22, 2022
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
201792b
expose user id method to dynamocore
mjkkirschner Apr 7, 2022
9eb65ab
fix bug where user id was not captured
mjkkirschner Apr 8, 2022
ac36eb0
switch to using xml to read config directly to fix build
mjkkirschner Apr 12, 2022
376ef6d
make internal
mjkkirschner Apr 12, 2022
c82e987
review suggestion
mjkkirschner Apr 12, 2022
aef6e1e
reset to 4.5.3 :(
mjkkirschner Apr 13, 2022
8899ef7
move feature flags to a CLI
mjkkirschner Apr 13, 2022
beffd90
try to fix build on GitHub action runner
mjkkirschner Apr 14, 2022
0889459
simplify
mjkkirschner Apr 14, 2022
9cee007
add watchdog
mjkkirschner Apr 14, 2022
78afd4c
Merge branch 'ldcli' of https://github.com/mjkkirschner/Dynamo into l…
mjkkirschner Apr 14, 2022
c0628bb
remove todo
mjkkirschner Apr 14, 2022
c2dc6dc
fix bug
mjkkirschner Apr 14, 2022
b66d21c
get rid of reflection
mjkkirschner Apr 14, 2022
e550089
better null checking when analytics is not disabled, but in testmode
mjkkirschner Apr 15, 2022
0916d94
fix bug where cli crashed immediately
mjkkirschner Apr 15, 2022
e80688a
check has exited before trying to read data
mjkkirschner Apr 15, 2022
fd2055c
add event based check, run CLI on threadpool thread
mjkkirschner Apr 19, 2022
578af7d
typo
mjkkirschner Apr 19, 2022
e2facb7
revert changes to core tests csproj
mjkkirschner Apr 19, 2022
562a1e9
typo
mjkkirschner Apr 19, 2022
9e428ea
don't start cli in test mode
mjkkirschner Apr 19, 2022
5f05748
reverse logic
mjkkirschner Apr 19, 2022
09bfab5
refactor shared constructor
mjkkirschner Apr 20, 2022
95be7b5
skip config loading if in test mode
mjkkirschner Apr 20, 2022
963c6a9
add tests
mjkkirschner Apr 20, 2022
02c06d4
only show one messagebox
mjkkirschner Apr 20, 2022
a63e24a
missed commit
mjkkirschner Apr 20, 2022
ef4b5d4
bool flag fix
mjkkirschner Apr 20, 2022
67aa344
review comments
mjkkirschner Apr 21, 2022
44b23ae
review comments
mjkkirschner Apr 21, 2022
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
15 changes: 13 additions & 2 deletions src/Dynamo.All.sln
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.32106.194
# Visual Studio Version 17
VisualStudioVersion = 17.1.32228.430
mjkkirschner marked this conversation as resolved.
Show resolved Hide resolved
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DynamoCore", "DynamoCore\DynamoCore.csproj", "{7858FA8C-475F-4B8E-B468-1F8200778CF8}"
ProjectSection(ProjectDependencies) = postProject
Expand Down Expand Up @@ -241,6 +241,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AssemblyRenamerCLI", "Tools
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AssemblyInfoGenerator", "AssemblySharedInfoGenerator\AssemblyInfoGenerator.csproj", "{133FC760-5699-46D9-BEA6-E816B5F01016}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DynamoFeatureFlags", "Tools\DynamoFeatureFlags\DynamoFeatureFlags.csproj", "{94CF053D-BB66-4FC7-883B-48F072701BA9}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -905,6 +907,14 @@ Global
{133FC760-5699-46D9-BEA6-E816B5F01016}.Release|Any CPU.Build.0 = Release|Any CPU
{133FC760-5699-46D9-BEA6-E816B5F01016}.Release|x64.ActiveCfg = Release|Any CPU
{133FC760-5699-46D9-BEA6-E816B5F01016}.Release|x64.Build.0 = Release|Any CPU
{94CF053D-BB66-4FC7-883B-48F072701BA9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{94CF053D-BB66-4FC7-883B-48F072701BA9}.Debug|Any CPU.Build.0 = Debug|Any CPU
{94CF053D-BB66-4FC7-883B-48F072701BA9}.Debug|x64.ActiveCfg = Debug|Any CPU
{94CF053D-BB66-4FC7-883B-48F072701BA9}.Debug|x64.Build.0 = Debug|Any CPU
{94CF053D-BB66-4FC7-883B-48F072701BA9}.Release|Any CPU.ActiveCfg = Release|Any CPU
{94CF053D-BB66-4FC7-883B-48F072701BA9}.Release|Any CPU.Build.0 = Release|Any CPU
{94CF053D-BB66-4FC7-883B-48F072701BA9}.Release|x64.ActiveCfg = Release|Any CPU
{94CF053D-BB66-4FC7-883B-48F072701BA9}.Release|x64.Build.0 = Release|Any CPU
Copy link
Contributor

Choose a reason for hiding this comment

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

do we want to build this tool by default ....with the rest of the solution ?

Copy link
Member Author

Choose a reason for hiding this comment

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

We do so for the other CLI tools, why wouldn't we?

Copy link
Contributor

Choose a reason for hiding this comment

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

I guess if the tool does not directly depend on any other Dynamo projects it may have a slower dev cycle than the rest.
But I guess it is a small project (few cs files) so it does not really slow down the build process that much

EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down Expand Up @@ -990,6 +1000,7 @@ Global
{E6DF2FBD-7D4D-4465-94DC-D576D737E985} = {0E492D35-2310-4849-9694-A2A53C09F21B}
{12FB4DA4-7E9C-4C2E-91CD-1D0B523A9535} = {88D45B00-E564-41DB-B57C-9509646CAA49}
{F382C3F8-C55C-4350-800A-3D13A94F8E13} = {D114C59C-CF66-4CC2-980F-9301FB4EA4E1}
{94CF053D-BB66-4FC7-883B-48F072701BA9} = {D114C59C-CF66-4CC2-980F-9301FB4EA4E1}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {89CB19C6-BF0A-4E6A-BFDA-79D143EAB59D}
Expand Down
13 changes: 11 additions & 2 deletions src/DynamoCore/Logging/AnalyticsService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ class AnalyticsService
{
// Use the Analytics.Core interface so that we do not have to load the ADP assembly at this time.
private static IAnalyticsUI adpAnalyticsUI;

private static IAnalyticsClient dynamoAnalyticsClient;
mjkkirschner marked this conversation as resolved.
Show resolved Hide resolved
/// <summary>
/// Starts the client when DynamoModel is created. This method initializes
/// the Analytics service and application life cycle start is tracked.
Expand Down Expand Up @@ -41,8 +41,9 @@ internal static void Start(DynamoModel model, bool isHeadless, bool isTestMode)
// This will also load the Analytics.Net.ADP assembly
// We must initialize the ADPAnalyticsUI instance before the Analytics.Start call.
adpAnalyticsUI = new ADPAnalyticsUI();
dynamoAnalyticsClient = new DynamoAnalyticsClient(model);

Analytics.Start(new DynamoAnalyticsClient(model));
Analytics.Start(dynamoAnalyticsClient);
model.WorkspaceAdded += OnWorkspaceAdded;
}

Expand Down Expand Up @@ -107,5 +108,13 @@ internal static void ShowADPConsetDialog(IntPtr? host)
adpAnalyticsUI.ShowOptInDialog(System.Threading.Thread.CurrentThread.CurrentUICulture.Name, false, host);
}
}
internal static string GetUserIDForSession()
{
if (dynamoAnalyticsClient is DynamoAnalyticsClient dac)
{
return dac.Session.UserId;
}
return null;
}
}
}
22 changes: 19 additions & 3 deletions src/DynamoCore/Models/DynamoModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ public partial class DynamoModel : IDynamoModel, IDisposable, IEngineControllerM
private Timer backupFilesTimer;
private Dictionary<Guid, string> backupFilesDict = new Dictionary<Guid, string>();
internal readonly Stopwatch stopwatch = Stopwatch.StartNew();

#endregion

#region static properties
Expand Down Expand Up @@ -376,6 +376,8 @@ public IEnumerable<WorkspaceModel> Workspaces
public AuthenticationManager AuthenticationManager { get; set; }

internal static string DefaultPythonEngine { get; private set; }

internal static DynamoUtilities.DynamoFeatureFlagsManager FeatureFlags { get; private set; }
#endregion

#region initialization and disposal
Expand Down Expand Up @@ -647,6 +649,14 @@ protected DynamoModel(IStartConfiguration config)
if (!areAnalyticsDisabledFromConfig && !Dynamo.Logging.Analytics.DisableAnalytics)
{
AnalyticsService.Start(this, IsHeadless, IsTestMode);
//only start feature flags if analytics is not disabled.
try
{
//TODO consider CLI lifetime, should this be reset for each flag check, or okay to leave running for Dynamo lifetime?
FeatureFlags = new DynamoUtilities.DynamoFeatureFlagsManager(AnalyticsService.GetUserIDForSession());
FeatureFlags.MessageLogged += LogMessageWrapper;
}
catch (Exception e) { Logger.LogError($"could not start feature flags manager {e}"); };
}

if (!IsTestMode && PreferenceSettings.IsFirstRun)
Expand Down Expand Up @@ -1199,7 +1209,8 @@ public void Dispose()
CustomNodeManager.MessageLogged -= LogMessage;
CustomNodeManager.Dispose();
MigrationManager.MessageLogged -= LogMessage;

FeatureFlags.MessageLogged -= LogMessageWrapper;
FeatureFlags.Dispose();
mjkkirschner marked this conversation as resolved.
Show resolved Hide resolved
}

private void InitializeCustomNodeManager()
Expand Down Expand Up @@ -2744,6 +2755,11 @@ private void LogMessage(ILogMessage obj)
{
Logger.Log(obj);
}
private void LogMessageWrapper(string m)
mjkkirschner marked this conversation as resolved.
Show resolved Hide resolved
{
LogMessage(Dynamo.Logging.LogMessage.Info(m));

}

#if DEBUG_LIBRARY
private void DumpLibrarySnapshot(IEnumerable<Engine.FunctionGroup> functionGroups)
Expand All @@ -2770,7 +2786,7 @@ select string.IsNullOrEmpty(function.Namespace)
}
#endif

private void AddNodeTypeToSearch(TypeLoadData typeLoadData)
private void AddNodeTypeToSearch(TypeLoadData typeLoadData)
mjkkirschner marked this conversation as resolved.
Show resolved Hide resolved
{
if (!typeLoadData.IsDSCompatible || typeLoadData.IsDeprecated || typeLoadData.IsHidden
|| typeLoadData.IsMetaNode)
Expand Down
12 changes: 12 additions & 0 deletions src/DynamoCoreWpf/Views/Core/DynamoView.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1008,6 +1008,18 @@ private void DynamoView_Loaded(object sender, EventArgs e)
this.Deactivated += (s, args) => { HidePopupWhenWindowDeactivated(null); };
}
loaded = true;

//feature flag test.
if (DynamoModel.FeatureFlags.CheckFeatureFlag<bool>("EasterEggIcon1", false))
{
dynamoViewModel.Model.Logger.Log("EasterEggIcon1 is true");
MessageBoxService.Show(this,"EasterEggIcon1 was true", "eastereggicon1", MessageBoxButton.OK, MessageBoxImage.Asterisk);
}
else
{
dynamoViewModel.Model.Logger.Log("EasterEggIcon1 is false");
}

}

/// <summary>
Expand Down
102 changes: 102 additions & 0 deletions src/DynamoUtilities/DynamoFeatureFlagsManager.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
using Dynamo.Utilities;
using System;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Reflection;


namespace DynamoUtilities
{


/// <summary>
/// A wrapper around the DynamoFeatureFlags CLI tool.
/// Which is itself a wrapper around LaunchDarkly.
/// Not thread safe.
/// </summary>
internal class DynamoFeatureFlagsManager : CLIWrapper
{
private const string checkFeatureFlagCommandToken = @"<<<<<CheckFeatureFlag>>>>>";
private string relativePath = Path.Combine("DynamoFeatureFlags", "DynamoFeatureFlags.exe");
internal event Action<string> MessageLogged;
public override void Dispose()
mjkkirschner marked this conversation as resolved.
Show resolved Hide resolved
{
KillProcess();
}
/// <summary>
/// Constructor
/// Start the CLI tool and keep it around...
/// TODO we need to better handle if Dynamo crashes/is terminated - this process needs to be cleaned up.
/// </summary>
internal DynamoFeatureFlagsManager(string userkey)
{
ProcessStartInfo startInfo = new ProcessStartInfo
{
CreateNoWindow = true,
RedirectStandardOutput = true,
RedirectStandardInput = true,

UseShellExecute = false,
Arguments = $"-u {userkey}",
FileName = GetToolPath(relativePath)
};

process.StartInfo = startInfo;
try
{
process.Start();
started = true;
}
catch (Win32Exception)
{
// Do nothing
}
}

internal T CheckFeatureFlag<T>(string featureFlagKey, T defaultval)
{
if(!(defaultval is bool || defaultval is string)){
MessageLogged?.Invoke("unsupported flag type");
return defaultval;
}
if (!started)
{
MessageLogged?.Invoke(GetCantStartErrorMessage());
return defaultval;
}
try
{
process.StandardInput.WriteLine(checkFeatureFlagCommandToken);
process.StandardInput.WriteLine(featureFlagKey);
process.StandardInput.WriteLine(defaultval);
process.StandardInput.WriteLine(typeof(T).FullName);
process.StandardInput.WriteLine(endOfDataToken);
}
catch (Exception e) when (e is IOException || e is ObjectDisposedException)
{
KillProcess();
MessageLogged?.Invoke(GetCantCommunicateErrorMessage());
return defaultval;
}
//TODO if we start moving more complex types than bool/string we should use
//JSON (either newtonsoft or system.runtime.serializer which we already reference in this csproj).
var dataFromCLI = GetData();
//convert from string to string or bool.
var output = Convert.ChangeType(dataFromCLI, typeof(T));

return (T)output;
}


protected override string GetCantStartErrorMessage()
{
return $"$can't start { GetToolPath(relativePath)}";
}

protected override string GetCantCommunicateErrorMessage()
{
return $"$can't communicate with { GetToolPath(relativePath)}";
}
}
}
Loading