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()); }
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); }
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(); } }); }
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); }
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; }
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)); }
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); } }
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); }
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); } }
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); }
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); } }
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); }); } }
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); } }
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 }); }