Example #1
0
        /// <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);
        }
Example #2
0
        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);