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);
        }
예제 #2
0
        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);
                        }
                    });
                }
            });
        }
예제 #4
0
        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);
 }