private void PollEditorState(BackendUnityModel backendUnityModel, FrontendBackendHost frontendBackendHost, Lifetime modelLifetime, IThreading threading, ILogger logger) { if (!backendUnityModel.IsBound) { myEditorState = UnityEditorState.Disconnected; UpdateFrontendEditorState(frontendBackendHost, logger); return; } var task = backendUnityModel.GetUnityEditorState.Start(Unit.Instance); task?.Result.AdviseOnce(modelLifetime, result => { logger.Trace($"Got poll result from Unity editor: {result.Result}"); myEditorState = result.Result; UpdateFrontendEditorState(frontendBackendHost, logger); }); Task.Delay(TimeSpan.FromSeconds(2), modelLifetime).ContinueWith(_ => { if (task != null && !task.AsTask().IsCompleted) { logger.Trace( "There were no response from Unity in two seconds. Setting state to Disconnected."); myEditorState = UnityEditorState.Disconnected; UpdateFrontendEditorState(frontendBackendHost, logger); } }, threading.Tasks.GuardedMainThreadScheduler); }
public PassthroughHost(Lifetime lifetime, ISolution solution, IThreading threading, IEditorManager editorManager, UnitySolutionTracker unitySolutionTracker, BackendUnityHost backendUnityHost, FrontendBackendHost frontendBackendHost) { mySolution = solution; myThreading = threading; myEditorManager = editorManager; myBackendUnityHost = backendUnityHost; myFrontendBackendHost = frontendBackendHost; if (!frontendBackendHost.IsAvailable) { return; } unitySolutionTracker.IsUnityProject.View(lifetime, (unityProjectLifetime, args) => { var model = frontendBackendHost.Model; if (args && model != null) { AdviseFrontendToUnityModel(unityProjectLifetime, model); // Advise the backend/Unity model as high priority so we can add our subscriptions first using (Signal.PriorityAdviseCookie.Create()) { backendUnityHost.BackendUnityModel.ViewNotNull(unityProjectLifetime, AdviseUnityToFrontendModel); } } }); }
public PassthroughHost(Lifetime lifetime, ISolution solution, IThreading threading, IEditorManager editorManager, UnitySolutionTracker unitySolutionTracker, BackendUnityHost backendUnityHost, FrontendBackendHost frontendBackendHost) { mySolution = solution; myThreading = threading; myEditorManager = editorManager; myBackendUnityHost = backendUnityHost; myFrontendBackendHost = frontendBackendHost; if (!frontendBackendHost.IsAvailable) { return; } unitySolutionTracker.IsUnityProject.View(lifetime, (unityProjectLifetime, args) => { var model = frontendBackendHost.Model; if (args && model != null) { AdviseFrontendToUnityModel(unityProjectLifetime, model); // Advise the backend/Unity model as high priority so we get called back before other subscribers. // This allows us to populate the protocol on reconnection before other subscribes start to advise using (Signal.PriorityAdviseCookie.Create()) { backendUnityHost.BackendUnityModel.ViewNotNull(unityProjectLifetime, AdviseUnityToFrontendModel); } backendUnityHost.BackendUnityModel.Advise(lifetime, backendUnityModel => { // https://github.com/JetBrains/resharper-unity/pull/2023 if (backendUnityModel == null) { frontendBackendHost.Model?.PlayControlsInitialized.SetValue(false); } }); } }); }
public BackendUnityProtocol(Lifetime lifetime, ILogger logger, BackendUnityHost backendUnityHost, FrontendBackendHost frontendBackendHost, IScheduler dispatcher, IShellLocks locks, ISolution solution, IApplicationWideContextBoundSettingStore settingsStore, UnitySolutionTracker unitySolutionTracker, UnityVersion unityVersion, NotificationsModel notificationsModel, IHostProductInfo hostProductInfo, IFileSystemTracker fileSystemTracker) { myPluginInstallations = new JetHashSet <FileSystemPath>(); myLifetime = lifetime; myLogger = logger; myBackendUnityHost = backendUnityHost; myDispatcher = dispatcher; myLocks = locks; mySolution = solution; myUnityVersion = unityVersion; myNotificationsModel = notificationsModel; myHostProductInfo = hostProductInfo; myFrontendBackendHost = frontendBackendHost; myBoundSettingsStore = settingsStore.BoundSettingsStore; mySessionLifetimes = new SequentialLifetimes(lifetime); if (solution.GetData(ProjectModelExtensions.ProtocolSolutionKey) == null) { return; } unitySolutionTracker.IsUnityProject.View(lifetime, (lf, args) => { if (!args) { return; } var solFolder = mySolution.SolutionDirectory; // todo: consider non-Unity Solution with Unity-generated projects var protocolInstancePath = solFolder.Combine("Library/ProtocolInstance.json"); fileSystemTracker.AdviseFileChanges(lf, protocolInstancePath, OnProtocolInstanceJsonChange); // connect on start of Rider CreateProtocol(protocolInstancePath); }); }
private void StartPollingUnityEditorState(BackendUnityModel backendUnityModel, Lifetime modelLifetime, FrontendBackendHost frontendBackendHost, IThreading threading, IIsApplicationActiveState isApplicationActiveState, ILogger logger) { modelLifetime.StartAsync(threading.Tasks.GuardedMainThreadScheduler, async() => { // TODO: This would be much easier with a property // Would have to reset the property when the connection drops while (modelLifetime.IsAlive) { if (isApplicationActiveState.IsApplicationActive.Value || frontendBackendHost.Model?.RiderFrontendTests.HasTrueValue() == true) { PollEditorState(backendUnityModel, frontendBackendHost, modelLifetime, threading, logger); } await Task.Delay(1000, modelLifetime); } }); }
// TODO: Remove FrontendBackendHost. It's too easy to get circular dependencies public BackendUnityHost(Lifetime lifetime, ILogger logger, FrontendBackendHost frontendBackendHost, IThreading threading, IIsApplicationActiveState isApplicationActiveState, PackageManager packageManager, JetBrains.Application.ActivityTrackingNew.UsageStatistics usageStatistics) { myUsageStatistics = usageStatistics; myEditorState = UnityEditorState.Disconnected; BackendUnityModel.ViewNotNull(lifetime, (modelLifetime, backendUnityModel) => { InitialiseModel(backendUnityModel); AdviseModel(backendUnityModel, modelLifetime, packageManager); StartPollingUnityEditorState(backendUnityModel, modelLifetime, frontendBackendHost, threading, isApplicationActiveState, logger); }); BackendUnityModel.ViewNull(lifetime, _ => { myEditorState = UnityEditorState.Disconnected; if (frontendBackendHost.IsAvailable) { UpdateFrontendEditorState(frontendBackendHost, logger); } }); // Are we testing? if (frontendBackendHost.IsAvailable) { // Tell the frontend if the backend/Unity connection is available // (not actually passthrough) var frontendBackendModel = frontendBackendHost.Model.NotNull("frontendBackendHost.Model != null"); BackendUnityModel.FlowIntoRdSafe(lifetime, backendUnityModel => backendUnityModel != null, frontendBackendModel.UnityEditorConnected); } }
private void UpdateFrontendEditorState(FrontendBackendHost frontendBackendHost, ILogger logger) { logger.Trace($"Sending connection state to frontend: {myEditorState}"); frontendBackendHost.Do(m => m.UnityEditorState.Value = myEditorState); }