/// <summary> /// Creates a <see cref="IObserver{WorkDoneProgressReport}" /> that will send all of its progress information to the same source. /// The other side can cancel this, so the <see cref="CancellationToken" /> should be respected. /// </summary> public ProgressObserver <WorkDoneProgressReport> Create(WorkDoneProgressBegin begin, Func <Exception, WorkDoneProgressEnd> onError = null, Func <WorkDoneProgressEnd> onComplete = null, CancellationToken?cancellationToken = null) { if (!_supported) { return(ProgressObserver <WorkDoneProgressReport> .Noop); } onError ??= error => new WorkDoneProgressEnd() { Message = error.ToString() }; onComplete ??= () => new WorkDoneProgressEnd(); var observer = ProgressObserver.CreateWorkDoneProgress(_router, _serializer, begin, onError, onComplete, cancellationToken ?? CancellationToken.None); _activeObservers.TryAdd(observer.ProgressToken, observer); observer.CancellationToken.Register(() => { if (_activeObservers.TryRemove(observer.ProgressToken, out _)) { observer.OnCompleted(); } }); return(observer); }
public async Task Should_Support_Creating_Work_Done_From_Sever_To_Client() { var token = new ProgressToken(Guid.NewGuid().ToString()); var workDoneObservable = Client.WorkDoneManager.Monitor(token); var observable = workDoneObservable.Replay(); using var _ = observable.Connect(); using var workDoneObserver = await Server.WorkDoneManager.Create( token, new WorkDoneProgressBegin { Cancellable = true, Message = "Begin", Percentage = 0, Title = "Work is pending" }, onComplete : () => new WorkDoneProgressEnd { Message = "End" } ); workDoneObserver.OnNext( new WorkDoneProgressReport { Percentage = 10, Message = "Report 1" } ); workDoneObserver.OnNext( new WorkDoneProgressReport { Percentage = 20, Message = "Report 2" } ); workDoneObserver.OnNext( new WorkDoneProgressReport { Percentage = 30, Message = "Report 3" } ); workDoneObserver.OnNext( new WorkDoneProgressReport { Percentage = 40, Message = "Report 4" } ); workDoneObserver.OnCompleted(); var results = await observable.Select( z => z switch { WorkDoneProgressBegin begin => begin.Message, WorkDoneProgressReport begin => begin.Message, WorkDoneProgressEnd begin => begin.Message, _ => throw new NotSupportedException() }
public async Task Should_Support_Creating_Work_Done_From_Sever_To_Client() { var(client, server) = await Initialize(ConfigureClient, ConfigureServer); var token = new ProgressToken(Guid.NewGuid().ToString()); var data = new List <WorkDoneProgress>(); using var workDoneObservable = client.WorkDoneManager.Monitor(token); workDoneObservable.Subscribe(x => data.Add(x)); using var workDoneObserver = await server.WorkDoneManager.Create(token, new WorkDoneProgressBegin () { Cancellable = true, Message = "Begin", Percentage = 0, Title = "Work is pending" }, onComplete : () => new WorkDoneProgressEnd() { Message = "End" }); workDoneObserver.OnNext(new WorkDoneProgressReport() { Percentage = 10, Message = "Report 1" }); workDoneObserver.OnNext(new WorkDoneProgressReport() { Percentage = 20, Message = "Report 2" }); workDoneObserver.OnNext(new WorkDoneProgressReport() { Percentage = 30, Message = "Report 3" }); workDoneObserver.OnNext(new WorkDoneProgressReport() { Percentage = 40, Message = "Report 4" }); workDoneObserver.OnCompleted(); await SettleNext(); var results = data.Select(z => z switch { WorkDoneProgressBegin begin => begin.Message, WorkDoneProgressReport begin => begin.Message, WorkDoneProgressEnd begin => begin.Message, });
public async Task <Metadata> CreateMetadataForProject(WorkspaceProject project) { string projectName = project.Name; var begin = new WorkDoneProgressBegin { Title = "Avalonia", Message = "Loading metadata for " + projectName, Percentage = 0 }; using IWorkDoneObserver manager = await _languageServer.WorkDoneManager.Create(begin); var outputDllPath = project.OutputFile; if (outputDllPath == null) { manager.OnNext(new WorkDoneProgressReport { Message = "Failed to load metadata for " + projectName + ", building project may solve the problem", Percentage = 100 }); } var metadata = await CreateMetadataForAssembly(outputDllPath); manager.Dispose(); if (metadata != null) { manager.OnNext(new WorkDoneProgressReport { Message = "Loaded metadata for " + projectName, Percentage = 100, }); } else { manager.OnNext(new WorkDoneProgressReport { Message = "Failed to load metadata for " + projectName, Percentage = 100 }); } return(metadata); }
public static ProgressObserver <WorkDoneProgressReport> CreateWorkDoneProgress( ProgressToken token, IResponseRouter router, ISerializer serializer, WorkDoneProgressBegin begin, Func <Exception, WorkDoneProgressEnd> onError, Func <WorkDoneProgressEnd> onComplete, CancellationToken cancellationToken) { var disposable = new CompositeDisposable(); var worker = CreateWorker <WorkDoneProgress>(token, router, serializer, onError, onComplete, disposable); worker.OnNext(begin); return(new ProgressObserver <WorkDoneProgressReport>(token, worker, CancellationTokenSource.CreateLinkedTokenSource(cancellationToken))); }
public static ProgressObserver <WorkDoneProgressReport> CreateWorkDoneProgress( IResponseRouter router, ISerializer serializer, WorkDoneProgressBegin begin, Func <Exception, WorkDoneProgressEnd> onError, Func <WorkDoneProgressEnd> onComplete, CancellationToken cancellationToken) { var token = new ProgressToken(Guid.NewGuid().ToString()); var earlyEvents = new AsyncSubject <List <WorkDoneProgress> >(); var observer = new Subject <WorkDoneProgress>(); var disposable = new CompositeDisposable { observer, earlyEvents }; var worker = CreateWorker <WorkDoneProgress>(token, router, serializer, onError, onComplete, disposable); disposable.Add( observer .Scan(new List <WorkDoneProgress>() { begin }, (acc, v) => { acc.Add(v); return(acc); }) .Subscribe(earlyEvents.OnNext) ); disposable.Add( Observable.FromAsync(ct => router.CreateProgress(token, ct)) .Subscribe(_ => { }, e => { }, () => { earlyEvents.OnCompleted(); }) ); disposable.Add( earlyEvents .SelectMany(z => z) .Concat(observer) .Subscribe(worker) ); return(new ProgressObserver <WorkDoneProgressReport>(token, observer, CancellationTokenSource.CreateLinkedTokenSource(cancellationToken))); }
public WorkDoneObserver( ProgressToken progressToken, IResponseRouter router, ISerializer serializer, WorkDoneProgressBegin begin, Func <Exception, WorkDoneProgressEnd> onError, Func <WorkDoneProgressEnd> onComplete, CancellationToken cancellationToken) { _progressToken = progressToken; _router = router; _serializer = serializer; _onError = onError; _onComplete = onComplete; _disposable = new CompositeDisposable { Disposable.Create(OnCompleted) }; cancellationToken.Register(Dispose); OnNext(begin); }
/// <summary> /// Creates a <see cref="IObserver{WorkDoneProgressReport}" /> that will send all of its progress information to the same source. /// The other side can cancel this, so the <see cref="CancellationToken" /> should be respected. /// </summary> public async Task <IWorkDoneObserver> Create(ProgressToken progressToken, WorkDoneProgressBegin begin, Func <Exception, WorkDoneProgressEnd> onError = null, Func <WorkDoneProgressEnd> onComplete = null, CancellationToken cancellationToken = default) { if (!_supported) { return(NoopWorkDoneObserver.Instance); } if (_activeObservers.TryGetValue(progressToken, out var item)) { return(item); } await _router.SendRequest(new WorkDoneProgressCreateParams() { Token = progressToken }, cancellationToken); onError ??= error => new WorkDoneProgressEnd() { Message = error.ToString() }; onComplete ??= () => new WorkDoneProgressEnd(); var cts = new CancellationTokenSource(); var observer = new WorkDoneObserver( progressToken, _router, _serializer, begin, onError, onComplete, cts.Token ); _activeObservers.TryAdd(observer.WorkDoneToken, observer); _activeObserverTokens.TryAdd(observer.WorkDoneToken, cts); return(observer); }
/// <summary> /// Creates a <see cref="IWorkDoneObserver" /> that will send all of its progress information to the same source. /// </summary> public IWorkDoneObserver For( IWorkDoneProgressParams request, WorkDoneProgressBegin begin, Func <Exception, WorkDoneProgressEnd> onError = null, Func <WorkDoneProgressEnd> onComplete = null ) { if (!IsSupported || request.WorkDoneToken == null) { return(NoopWorkDoneObserver.Instance); } if (_activeObservers.TryGetValue(request.WorkDoneToken, out var item)) { return(item); } onError ??= error => new WorkDoneProgressEnd { Message = error.ToString() }; onComplete ??= () => new WorkDoneProgressEnd(); var cts = new CancellationTokenSource(); var observer = new WorkDoneObserver( request.WorkDoneToken, _router, _serializer, begin, onError, onComplete, cts.Token ); _activeObservers.TryAdd(observer.WorkDoneToken, observer); _activeObserverTokens.TryAdd(observer.WorkDoneToken, cts); return(observer); }
/// <summary> /// Creates a <see cref="IObserver{WorkDoneProgressReport}" /> that will send all of its progress information to the same source. /// The other side can cancel this, so the <see cref="CancellationToken" /> should be respected. /// </summary> public Task <IWorkDoneObserver> Create( WorkDoneProgressBegin begin, Func <Exception, WorkDoneProgressEnd> onError = null, Func <WorkDoneProgressEnd> onComplete = null, CancellationToken cancellationToken = default ) => Create(new ProgressToken(Guid.NewGuid().ToString()), begin, onError, onComplete, cancellationToken);