コード例 #1
0
        public Task <ExitUnityResult> ExitUnityAsync(bool force)
        {
            var lifetimeDef = myLifetime.CreateNested();

            if (myBackendUnityHost.BackendUnityModel.Value == null) // no connection
            {
                if (force)
                {
                    return(Task.FromResult(KillProcess()));
                }

                return(Task.FromResult(new ExitUnityResult(false, "No connection to Unity Editor.", null)));
            }

            var protocolTaskSource = new TaskCompletionSource <bool>();

            mySolution.Locks.Tasks.StartNew(lifetimeDef.Lifetime, Scheduling.MainGuard, () => myBackendUnityHost.BackendUnityModel.Value.ExitUnity.Start(lifetimeDef.Lifetime, Unit.Instance)
                                            .AsTask());
            var protocolTask = protocolTaskSource.Task;

            var waitTask = Task.WhenAny(protocolTask, Task.Delay(TimeSpan.FromSeconds(0.5), lifetimeDef.Lifetime)); // continue on timeout

            return(waitTask.ContinueWith(t =>
            {
                lifetimeDef.Terminate();
                if (protocolTask.Status != TaskStatus.RanToCompletion && force)
                {
                    return WaitModelUpdate();
                }

                return Task.FromResult(new ExitUnityResult(false, "Attempt to close Unity Editor failed.", null));
            }, TaskContinuationOptions.AttachedToParent).Unwrap());
        }
コード例 #2
0
        internal Lifetime Subscribe(Lifetime outerLifetime)
        {
            var taskWireSubscriptionDefinition = outerLifetime.CreateNested();
            var externalCancellation           = outerLifetime.CreateNested();

            myCall.Wire.Advise(taskWireSubscriptionDefinition.Lifetime, this); //this lifetimeDef listen only one value
            taskWireSubscriptionDefinition.Lifetime.TryOnTermination(() => ResultInternal.SetIfEmpty(RdTaskResult <TRes> .Cancelled()));

            Result.AdviseOnce(Lifetime.Eternal, taskResult =>
            {
                try
                {
                    var potentiallyBindable = taskResult.Result;
                    if (potentiallyBindable.IsBindable())
                    {
                        if (myIsEndpoint)
                        {
                            potentiallyBindable.IdentifyPolymorphic(myCall.Proto.Identities, myCall.RdId.Mix(RdId.ToString()));
                        }

                        potentiallyBindable.BindPolymorphic(externalCancellation.Lifetime, myCall, RdId.ToString());
                    }
                    else
                    {
                        externalCancellation.Terminate();
                    }

                    if (myIsEndpoint)
                    {
                        Trace(RdReactiveBase.ourLogSend, "send response", taskResult);
                        myWire.Send(RdId,
                                    writer =>
                        {
                            RdTaskResult <TRes> .Write(myCall.WriteResponseDelegate, myCall.SerializationContext, writer, taskResult);
                        });
                    }
                    else if (taskResult.Status == RdTaskStatus.Canceled) //we need to transfer cancellation to the other side
                    {
                        Trace(RdReactiveBase.ourLogSend, "send cancellation");
                        myWire.Send(RdId, writer => { writer.Write(Unit.Instance); }); //send cancellation to the other side
                    }
                }
                finally
                {
                    taskWireSubscriptionDefinition.Terminate(); //no need to listen result or cancellation from wire
                }
            });

            return(externalCancellation.Lifetime);
        }
コード例 #3
0
            public CallSite(Lifetime outerLifetime, RdCall <TReq, TRes> call, RdId rdId, IScheduler wireScheduler) : base(call, rdId, wireScheduler)
            {
                var taskWireSubscriptionDefinition = outerLifetime.CreateNested();

                myCall.Wire.Advise(taskWireSubscriptionDefinition.Lifetime, this); //this lifetimeDef listen only one value
                taskWireSubscriptionDefinition.Lifetime.TryOnTermination(() => ResultInternal.SetIfEmpty(RdTaskResult <TRes> .Cancelled()));

                Result.AdviseOnce(Lifetime.Eternal, taskResult =>
                {
                    taskWireSubscriptionDefinition.Terminate(); //no need to listen result or cancellation from wire

                    var potentiallyBindable = taskResult.Result;
                    if (potentiallyBindable.IsBindable())
                    {
                        potentiallyBindable.BindPolymorphic(outerLifetime, myCall, RdId.ToString());
                        if (!outerLifetime.TryOnTermination(SendCancellation))
                        {
                            SendCancellation();
                        }
                    }
                    else if (taskResult.Status == RdTaskStatus.Canceled) //we need to transfer cancellation to the other side
                    {
                        SendCancellation();
                    }
                });
            }
コード例 #4
0
            public Endpoint(Lifetime bindLifetime, RdCall <TReq, TRes> call, RdId rdId, IScheduler wireScheduler) : base(call, rdId, wireScheduler)
            {
                myDef = bindLifetime.CreateNested();

                myCall.Wire.Advise(Lifetime, this);
                Lifetime.TryOnTermination(() => ResultInternal.SetIfEmpty(RdTaskResult <TRes> .Cancelled()));

                Result.AdviseOnce(Lifetime.Eternal, taskResult =>
                {
                    var potentiallyBindable = taskResult.Result;
                    if (potentiallyBindable.IsBindable())
                    {
                        potentiallyBindable.IdentifyPolymorphic(myCall.Proto.Identities, myCall.RdId.Mix(RdId.ToString()));
                        potentiallyBindable.BindPolymorphic(Lifetime, myCall, RdId.ToString());
                    }
                    else
                    {
                        myDef.Terminate();
                    }

                    Trace(RdReactiveBase.ourLogSend, "send response", taskResult);
                    myWire.Send(RdId,
                                writer =>
                    {
                        RdTaskResult <TRes> .Write(myCall.WriteResponseDelegate, myCall.SerializationContext, writer, taskResult);
                    });
                });
            }
        private void ShowProgress(Lifetime lifetime, Task task)
        {
            var innerLifeDef = lifetime.CreateNested();

            myBackgroundProgressIndicatorManager.CreateIndicator(innerLifeDef.Lifetime, false, false, "Start Unity Editor");
            task.ContinueWith(x => innerLifeDef.Terminate(), myLifetime, TaskContinuationOptions.None, myShellLocks.Tasks.Scheduler);
        }
コード例 #6
0
        private void RememberExecution([NotNull] FileSystemPath path, bool withProgress)
        {
            var definition = Lifetime.CreateNested();

            if (withProgress)
            {
                var progress = new ProgressIndicator(definition.Lifetime);
                IProgressIndicator iProgress = progress;
                iProgress.Start(1);
                progress.Advance();
                var task = RiderBackgroundTaskBuilder
                           .FromProgressIndicator(progress)
                           .AsIndeterminate()
                           .WithHeader("Executing template")
                           .WithDescription($"{path.Name}")
                           .Build();
                Solution.Locks.ExecuteOrQueueEx(
                    definition.Lifetime,
                    "T4 execution progress launching",
                    () => BackgroundTaskHost.AddNewTask(definition.Lifetime, task)
                    );
            }

            RunningFiles[path] = definition;
        }
コード例 #7
0
        public Task <ExitUnityResult> ExitUnityAsync(bool force)
        {
            var lifetimeDef = myLifetime.CreateNested();

            if (myUnityEditorProtocol.UnityModel.Value == null) // no connection
            {
                if (force)
                {
                    return(Task.FromResult(KillProcess()));
                }

                return(Task.FromResult(new ExitUnityResult(false, "No connection to Unity Editor.", null)));
            }

            var protocolTask = myUnityEditorProtocol.UnityModel.Value.ExitUnity.Start(lifetimeDef.Lifetime, Unit.Instance).AsTask();
            var waitTask     = Task.WhenAny(protocolTask, Task.Delay(TimeSpan.FromSeconds(0.5), lifetimeDef.Lifetime)); // continue on timeout

            return(waitTask.ContinueWith(t =>
            {
                lifetimeDef.Terminate();
                if (protocolTask.Status != TaskStatus.RanToCompletion && force)
                {
                    return KillProcess();
                }
                return new ExitUnityResult(false, "Attempt to close Unity Editor failed.", null);
            }, TaskContinuationOptions.AttachedToParent));
        }
コード例 #8
0
        private async Task Refresh(IShellLocks locks, Lifetime lifetime)
        {
            var refreshTask = locks.Tasks.StartNew(lifetime, Scheduling.MainDispatcher, async() =>
            {
                var lifetimeDef = lifetime.CreateNested();
                myRiderSolutionSaver.Save(lifetime, mySolution, () =>
                {
                    myUnityRefresher.Refresh(RefreshType.Force);
                    lifetimeDef.Terminate();
                });
                while (lifetimeDef.Lifetime.IsAlive)
                {
                    await TaskEx.Delay(TimeSpan.FromMilliseconds(10), lifetimeDef.Lifetime);
                }
            });

            var lifetimeDefinition = lifetime.CreateNested();
            await refreshTask.ContinueWith(task =>
            {
                mySolution.Locks.QueueRecurring(lifetimeDefinition.Lifetime,
                                                "Periodic wait EditorState != UnityEditorState.Refresh",
                                                TimeSpan.FromSeconds(1), () =>
                {
                    if (myEditorProtocol.UnityModel.Value == null)
                    {
                        return;
                    }
                    var rdTask = myEditorProtocol.UnityModel.Value.GetUnityEditorState.Start(Unit.Instance);
                    rdTask?.Result.Advise(lifetime, result =>
                    {
                        // [TODO] Backend ConnectionTracker has IsConnectionEstablished method which has same logic
                        if (result.Result != UnityEditorState.Refresh && result.Result != UnityEditorState.Disconnected)
                        {
                            lifetimeDefinition.Terminate();
                            myLogger.Verbose("lifetimeDefinition.Terminate();");
                        }
                    });
                });
            }, locks.Tasks.UnguardedMainThreadScheduler);

            while (lifetimeDefinition.Lifetime.IsAlive)
            {
                await TaskEx.Delay(TimeSpan.FromMilliseconds(50), lifetimeDefinition.Lifetime);
            }
        }
コード例 #9
0
        private static void InitializeProtocol(Lifetime lifetime, string protocolInstancePath)
        {
            var currentDirectory = new DirectoryInfo(Directory.GetCurrentDirectory());
            var solutionNames    = new List <string>()
            {
                currentDirectory.Name
            };

            var solutionFiles = currentDirectory.GetFiles("*.sln", SearchOption.TopDirectoryOnly);

            foreach (var solutionFile in solutionFiles)
            {
                var solutionName = Path.GetFileNameWithoutExtension(solutionFile.FullName);
                if (!solutionName.Equals(currentDirectory.Name))
                {
                    solutionNames.Add(solutionName);
                }
            }

            var protocols = new List <ProtocolInstance>();

            // if any protocol connection losts, we will drop all protocol and recreate them
            var allProtocolsLifetimeDefinition = lifetime.CreateNested();

            foreach (var solutionName in solutionNames)
            {
                var port = CreateProtocolForSolution(allProtocolsLifetimeDefinition.Lifetime, solutionName, () =>
                {
                    allProtocolsLifetimeDefinition.Terminate();
                });

                if (port == -1)
                {
                    continue;
                }

                protocols.Add(new ProtocolInstance(solutionName, port));
            }

            allProtocolsLifetimeDefinition.Lifetime.OnTermination(() =>
            {
                if (Lifetime.IsAlive)
                {
                    ourLogger.Verbose("Recreating protocol, project lifetime is alive");
                    InitializeProtocol(lifetime, protocolInstancePath);
                }
                else
                {
                    ourLogger.Verbose("Protocol will be recreating on next domain load, project lifetime is not alive");
                }
            });


            var result = ProtocolInstance.ToJson(protocols);

            File.WriteAllText(protocolInstancePath, result);
        }
コード例 #10
0
        public static void AddOrReplaceLifetimed <K, V>(this IViewableMap <K, V> me, Lifetime lifetime, K k, Func <Lifetime, V> vfun)
        {
            var def = lifetime.CreateNested();

            me[k] = vfun(def.Lifetime);
            me.Change.Advise(def.Lifetime, _event =>
            {
                if (_event.Key.Equals(k))
                {
                    def.Terminate();
                }
            });
        }
        public Task PrepareForRun(IUnitTestRun run, ITaskRunnerHostController next)
        {
            var lifetimeDef = myLifetime.CreateNested();

            run.PutData(ourLifetimeDefinitionKey, lifetimeDef);

            lock (myStartUnitySync)
            {
                WrapStartUnityTask(() => PrepareForRunInternal(lifetimeDef.Lifetime, run));
                WrapStartUnityTask(() => next.PrepareForRun(run));

                return(myStartUnityTask);
            }
        }
コード例 #12
0
        private Task <ExitUnityResult> WaitModelUpdate()
        {
            var successExitResult = new ExitUnityResult(true, null, null);

            if (!myBackendUnityHost.BackendUnityModel.HasValue())
            {
                return(Task.FromResult(successExitResult));
            }

            var taskSource      = new TaskCompletionSource <ExitUnityResult>();
            var waitLifetimeDef = myLifetime.CreateNested();

            waitLifetimeDef.SynchronizeWith(taskSource);

            // Wait RdModel Update
            myBackendUnityHost.BackendUnityModel.ViewNull(waitLifetimeDef.Lifetime, _ => taskSource.SetResult(successExitResult));
            return(taskSource.Task);
        }
コード例 #13
0
        private void UpdatePackages(IEnumerable <PackageData> newPackages)
        {
            var existingPackages = myPackagesById.Keys.ToJetHashSet();

            foreach (var packageData in newPackages)
            {
                // If the package.json file has been updated, remove the entry and add the new one. This should capture
                // all changes to data + metadata. We don't care too much about duplicates, as this is invalid JSON and
                // Unity complains. Last write wins, but at least we won't crash
                if (myPackagesById.TryGetValue(packageData.Id, out var existingPackageData) &&
                    existingPackageData.PackageJsonTimestamp != packageData.PackageJsonTimestamp)
                {
                    RemovePackage(packageData.Id);
                }

                if (!myPackagesById.ContainsKey(packageData.Id))
                {
                    var lifetimeDefinition = myLifetime.CreateNested();
                    myPackagesById.Add(lifetimeDefinition.Lifetime, packageData.Id, packageData);

                    // Note that myPackagesLifetimes is only accessed inside this method, so is thread safe
                    myPackageLifetimes.Add(lifetimeDefinition.Lifetime, packageData.Id, lifetimeDefinition);

                    // Refresh if any editable package.json is modified, so we pick up changes to e.g. dependencies,
                    // display name, etc. We don't care if BuiltIn or Registry packages are modified because they're
                    // not user editable
                    if (packageData.Source == PackageSource.Local && packageData.PackageFolder != null)
                    {
                        myFileSystemTracker.AdviseFileChanges(lifetimeDefinition.Lifetime,
                                                              packageData.PackageFolder.Combine("package.json"),
                                                              _ => ScheduleRefresh());
                    }
                }

                existingPackages.Remove(packageData.Id);
            }

            // Remove any left overs
            foreach (var id in existingPackages)
            {
                RemovePackage(id);
            }
        }
コード例 #14
0
        public override void Start(Lifetime startLifetime)
        {
            if (myRiderBackgroundTaskHost != null)
            {
                // avoid problems with background task host after terminating lifetime on daemon thread
                var lifetimeDef = myLifetime.CreateNested();
                startLifetime.OnTermination(() =>
                {
                    myLocks.Tasks.StartNew(myLifetime, Scheduling.MainDispatcher, () => lifetimeDef.Terminate());
                });

                var count          = myCache.FilesToProcess.Count;
                var processedCount = 0;
                var progress       = new Property <double>(startLifetime, "DeferredCacheProgressBarProgress", 0);

                myCache.AfterRemoveFromProcess.Advise(startLifetime, _ =>
                {
                    processedCount++;
                    if (count != 0)
                    {
                        progress.Value = Math.Min(0.99, ((double)processedCount) / count);
                    }
                });

                var description = new Property <string>(startLifetime, "DeferredCacheProgressBarDescription", "Processing assets");
                var task        = RiderBackgroundTaskBuilder.Create()
                                  .WithTitle("Calculating asset index")
                                  .WithDescription(description)
                                  .WithProgress(progress)
                                  .Build();

                CurrentFile.AdviseNotNull(startLifetime, v => { description.Value = $"Processing {v.DisplayName}"; });

                myLocks.Tasks.StartNew(startLifetime, Scheduling.MainDispatcher,
                                       () => { myRiderBackgroundTaskHost.AddNewTask(lifetimeDef.Lifetime, task); });
            }
        }
コード例 #15
0
        private static int CreateProtocolForSolution(Lifetime lifetime, string solutionName, Action onDisconnected)
        {
            try
            {
                var dispatcher = MainThreadDispatcher.Instance;
                var currentWireAndProtocolLifetimeDef = lifetime.CreateNested();
                var currentWireAndProtocolLifetime    = currentWireAndProtocolLifetimeDef.Lifetime;


                var riderProtocolController = new RiderProtocolController(dispatcher, currentWireAndProtocolLifetime);

#if !NET35
                var serializers = new Serializers(lifetime, null, null);
#else
                var serializers = new Serializers();
#endif
                var identities = new Identities(IdKind.Server);

                MainThreadDispatcher.AssertThread();
                var protocol = new Protocol("UnityEditorPlugin" + solutionName, serializers, identities, MainThreadDispatcher.Instance, riderProtocolController.Wire, currentWireAndProtocolLifetime);
                riderProtocolController.Wire.Connected.WhenTrue(currentWireAndProtocolLifetime, connectionLifetime =>
                {
                    ourLogger.Log(LoggingLevel.VERBOSE, "Create UnityModel and advise for new sessions...");
                    var model = new BackendUnityModel(connectionLifetime, protocol);
                    AdviseUnityActions(model, connectionLifetime);
                    AdviseEditorState(model);
                    OnModelInitialization(new UnityModelAndLifetime(model, connectionLifetime));
                    AdviseRefresh(model);
                    var paths = GetLogPaths();

                    model.UnityApplicationData.SetValue(new UnityApplicationData(
                                                            EditorApplication.applicationPath,
                                                            EditorApplication.applicationContentsPath,
                                                            UnityUtils.UnityApplicationVersion,
                                                            paths[0], paths[1],
                                                            Process.GetCurrentProcess().Id));

                    model.UnityApplicationSettings.ScriptCompilationDuringPlay.Set(UnityUtils.SafeScriptCompilationDuringPlay);

                    model.UnityProjectSettings.ScriptingRuntime.SetValue(UnityUtils.ScriptingRuntime);

                    AdviseShowPreferences(model, connectionLifetime, ourLogger);
                    AdviseGenerateUISchema(model);
                    AdviseExitUnity(model);
                    GetBuildLocation(model);
                    AdviseRunMethod(model);
                    GetInitTime(model);

                    ourLogger.Verbose("UnityModel initialized.");
                    var pair = new ModelWithLifetime(model, connectionLifetime);
                    connectionLifetime.OnTermination(() => { UnityModels.Remove(pair); });
                    UnityModels.Add(pair);

                    connectionLifetime.OnTermination(() =>
                    {
                        ourLogger.Verbose($"Connection lifetime is not alive for {solutionName}, destroying protocol");
                        onDisconnected();
                    });
                });

                return(riderProtocolController.Wire.Port);
            }
            catch (Exception ex)
            {
                ourLogger.Error("Init Rider Plugin " + ex);
                return(-1);
            }
        }
コード例 #16
0
ファイル: RdCall.cs プロジェクト: LongJohnCoder/rd
        public override void OnWireReceived(UnsafeReader reader)
        {
            var taskId = RdId.Read(reader);
            var value  = ReadRequestDelegate(SerializationContext, reader);

            if (LogReceived.IsTraceEnabled())
            {
                LogReceived.Trace("endpoint `{0}`::({1}), taskId={2}, request = {3}", Location, RdId, taskId, value.PrintToString());
            }


            var taskLifetimeDef = myBindLifetime.CreateNested();

            //subscribe for lifetime cancellation
            new WiredLifetime(taskLifetimeDef, taskId, this, Wire);

            RdTask <TRes> rdTask;

            using (UsingDebugInfo()) //now supports only sync handlers
            {
                try
                {
                    rdTask = Handler(taskLifetimeDef.Lifetime, value);
                }
                catch (Exception e)
                {
                    rdTask = RdTask <TRes> .Faulted(e);
                }
            }



            rdTask.Result.Advise(taskLifetimeDef.Lifetime, result =>
            {
                if (LogSend.IsTraceEnabled())
                {
                    LogSend.Trace("endpoint `{0}`::({1}), taskId={2}, response = {3}", Location, RdId, taskId, result.PrintToString());
                }

                RdTaskResult <TRes> validatedResult;
                try
                {
                    if (result.Status == RdTaskStatus.Success)
                    {
                        AssertNullability(result.Result);
                    }
                    validatedResult = result;
                }
                catch (Exception e)
                {
                    LogSend.Error(e);
                    validatedResult = RdTaskResult <TRes> .Faulted(e);
                }

                Wire.Send(taskId, writer =>
                {
                    RdTaskResult <TRes> .Write(WriteResponseDelegate, SerializationContext, writer, validatedResult);
                });

                taskLifetimeDef.Terminate(); //need to terminate to unsubscribe lifetime listener - not for bindable entries
            });
        }