public async Task TestServiceBusWithLocalEventStore() { // run EventStore on Docker and then edit below for local address:port that maps to 1113 var serviceBus = ServiceBus.Configure() .WithEventStoreSharedConnectionScope("ConnectTo=tcp://admin:[email protected]:32777", config => config .WithEventStoreEndpoints <ITestMessage1>() .Named("Obvs.EventStore.Test") .AppendMessageProperties(message => null) .FilterReceivedMessages(properties => true) .UseSharedConnection() .SerializedAsJson() .AsClientAndServer()) .UsingConsoleLogging() .Create(); var fakeService = new AnonymousObserver <ITestMessage1>(msg => { var command = msg as TestCommand; if (command != null) { serviceBus.PublishAsync(new TestEvent { Id = command.Id }); return; } var request = msg as TestRequest; if (request != null) { serviceBus.ReplyAsync(request, new TestResponse { Id = request.Id }); } }); var sub = serviceBus.Commands.OfType <ITestMessage1>() .Merge(serviceBus.Requests.OfType <ITestMessage1>()) .ObserveOn(Scheduler.Default) .Subscribe(fakeService); var receivedEvent = await Observable.Create <TestEvent>(observer => { var disposable = serviceBus.Events .OfType <TestEvent>() .ObserveOn(Scheduler.Default) .Subscribe(observer); serviceBus.SendAsync(new TestCommand { Id = 123 }); return(disposable); }).Take(1); var receivedResponse = await serviceBus.GetResponse <TestResponse>(new TestRequest { Id = 456 }); sub.Dispose(); Assert.That(receivedEvent.Id, Is.EqualTo(123)); Assert.That(receivedResponse.Id, Is.EqualTo(456)); }
private IObservable <BuildInfo> GetBuilds(IScheduler scheduler, DateTime?sinceDate = null, bool?running = null) { return(Observable.Create <BuildInfo>((observer, cancellationToken) => ObserveBuildsAsync(sinceDate, running, observer, cancellationToken))); }
public void ByteBufferUntilTest() { var str = Encoding.Default.GetBytes("1234aa01020304bb4321"); var rst = string.Empty; var ts = new TestScheduler(); var start = Encoding.Default.GetBytes("aa"); var stop = Encoding.Default.GetBytes("bb"); var obs = Observable.Create <byte>(x => { foreach (var c in str) { x.OnNext(c); } return(Disposable.Empty); }) .Buffer(2, 2) .Select(p => p.ToArray()); //1 obs .BufferUntil(start, stop, 200) .Select(p => Encoding.Default.GetString(p)) .Subscribe(p => rst = p); ts.AdvanceTo(str.Length); rst.Should().Be("aa01020304bb"); //2 rst = ""; stop = Encoding.Default.GetBytes("ff"); obs .BufferUntil(start, stop, 200) .Select(p => Encoding.Default.GetString(p)) .Subscribe(p => rst = p); ts.AdvanceTo(str.Length); rst.Should().Be(""); //3 rst = ""; stop = Encoding.Default.GetBytes("bb"); obs .BufferUntil(start, stop, 200) .Select(p => Encoding.Default.GetString(p)) .Subscribe(p => rst = p); ts.AdvanceTo(str.Length); rst.Should().Be("aa01020304bb"); //4 rst = ""; obs .BufferUntil(start, 0, 200) .Select(p => Encoding.Default.GetString(p)) .Subscribe(p => rst = p); ts.AdvanceTo(str.Length); rst.Should().Be("aa"); //5 rst = ""; obs .BufferUntil(start, 6, 200) .Select(p => Encoding.Default.GetString(p)) .Subscribe(p => rst = p); ts.AdvanceTo(str.Length); rst.Should().Be("aa0102"); }
public IObservable <IChangeSet <TDestination, TLeftKey> > Run() { return(Observable.Create <IChangeSet <TDestination, TLeftKey> >( observer => { var locker = new object(); // create local backing stores var leftCache = _left.Synchronize(locker).AsObservableCache(false); var rightCache = _right.Synchronize(locker).ChangeKey(_rightKeySelector).AsObservableCache(false); // joined is the final cache var joinedCache = new LockFreeObservableCache <TDestination, TLeftKey>(); var leftLoader = leftCache.Connect().Subscribe( changes => { joinedCache.Edit( innerCache => { foreach (var change in changes.ToConcreteType()) { var left = change.Current; var right = rightCache.Lookup(change.Key); switch (change.Reason) { case ChangeReason.Add: case ChangeReason.Update: innerCache.AddOrUpdate(_resultSelector(change.Key, left, right), change.Key); break; case ChangeReason.Remove: if (!right.HasValue) { // remove from result because there is no left and no rights innerCache.Remove(change.Key); } else { // update with no left value innerCache.AddOrUpdate(_resultSelector(change.Key, Optional <TLeft> .None, right), change.Key); } break; case ChangeReason.Refresh: // propagate upstream innerCache.Refresh(change.Key); break; } } }); }); var rightLoader = rightCache.Connect().Subscribe( changes => { joinedCache.Edit( innerCache => { foreach (var change in changes.ToConcreteType()) { var right = change.Current; var left = leftCache.Lookup(change.Key); switch (change.Reason) { case ChangeReason.Add: case ChangeReason.Update: { innerCache.AddOrUpdate(_resultSelector(change.Key, left, right), change.Key); } break; case ChangeReason.Remove: { if (!left.HasValue) { // remove from result because there is no left and no rights innerCache.Remove(change.Key); } else { // update with no right value innerCache.AddOrUpdate(_resultSelector(change.Key, left, Optional <TRight> .None), change.Key); } } break; case ChangeReason.Refresh: // propagate upstream innerCache.Refresh(change.Key); break; } } }); }); return new CompositeDisposable(joinedCache.Connect().NotEmpty().SubscribeSafe(observer), leftCache, rightCache, leftLoader, joinedCache, rightLoader); })); }
static IObservable <Unit> Throws(string message) { Func <IObserver <Unit>, Action> f = _ => { throw new FileNotFoundException(message); }; return(Observable.Create(f)); }
public static IObservable <NotifyCollectionChangedEventArgs> WhenCollectionChanged(this INotifyCollectionChanged collection) => Observable.Create <NotifyCollectionChangedEventArgs>(ob => { var handler = new NotifyCollectionChangedEventHandler((sender, args) => ob.OnNext(args)); collection.CollectionChanged += handler; return(() => collection.CollectionChanged -= handler); });
/// <summary> /// Core logic of ObserveElementXXXXX methods. /// </summary> /// <typeparam name="TElement">Type of element.</typeparam> /// <typeparam name="TObserver">Type of observer.</typeparam> /// <param name="source">source collection</param> /// <param name="subscribeAction">element subscribe logic.</param> /// <returns></returns> private static IObservable <TResult> ObserveElementCore <TCollection, TElement, TResult>(TCollection source, Func <TElement, IObserver <TResult>, IDisposable> subscribeAction) where TCollection : INotifyCollectionChanged, IEnumerable <TElement> where TElement : class { return(Observable.Create <TResult>(observer => { //--- cache element property subscriptions var subscriptionCache = new Dictionary <object, IDisposable>(); //--- subscribe / unsubscribe property which all elements have Action <IEnumerable <TElement> > subscribe = elements => { foreach (var x in elements) { var subsctiption = subscribeAction(x, observer); subscriptionCache.Add(x, subsctiption); } }; Action unsubscribeAll = () => { foreach (var x in subscriptionCache.Values) { x.Dispose(); } subscriptionCache.Clear(); }; subscribe(source); //--- hook collection changed var disposable = source.CollectionChangedAsObservable().Subscribe(x => { if (x.Action == NotifyCollectionChangedAction.Remove || x.Action == NotifyCollectionChangedAction.Replace) { //--- unsubscribe var oldItems = x.OldItems.Cast <TElement>(); foreach (var y in oldItems) { subscriptionCache[y].Dispose(); subscriptionCache.Remove(y); } } if (x.Action == NotifyCollectionChangedAction.Add || x.Action == NotifyCollectionChangedAction.Replace) { var newItems = x.NewItems.Cast <TElement>(); subscribe(newItems); } if (x.Action == NotifyCollectionChangedAction.Reset) { unsubscribeAll(); subscribe(source); } }); //--- unsubscribe return Disposable.Create(() => { disposable.Dispose(); unsubscribeAll(); }); })); }
public IObservable <IChangeSet <TObject, TKey> > Run() { return(Observable.Create <IChangeSet <TObject, TKey> >(observer => { var locker = new object(); //this is the resulting cache which produces all notifications var resultCache = new ChangeAwareCache <TObject, TKey>(); //Transform to a merge container. //This populates a RefTracker when the original source is subscribed to var sourceLists = _source.Connect() .Synchronize(locker) .Transform(changeset => new MergeContainer(changeset)) .AsObservableList(); //merge the items back together var allChanges = sourceLists.Connect() .MergeMany(mc => mc.Source) .Synchronize(locker) .Subscribe(changes => { //Populate result list and chck for changes UpdateResultList(resultCache, sourceLists.Items.AsArray(), changes); var notifications = resultCache.CaptureChanges(); if (notifications.Count != 0) { observer.OnNext(notifications); } }); //when an list is removed, need to var removedItem = sourceLists.Connect() .OnItemRemoved(mc => { //Remove items if required ProcessChanges(resultCache, sourceLists.Items.AsArray(), mc.Cache.KeyValues); if (_type == CombineOperator.And || _type == CombineOperator.Except) { var itemsToCheck = sourceLists.Items.SelectMany(mc2 => mc2.Cache.KeyValues).ToArray(); ProcessChanges(resultCache, sourceLists.Items.AsArray(), itemsToCheck); } var notifications = resultCache.CaptureChanges(); if (notifications.Count != 0) { observer.OnNext(notifications); } }) .Subscribe(); //when an list is added or removed, need to var sourceChanged = sourceLists.Connect() .WhereReasonsAre(ListChangeReason.Add, ListChangeReason.AddRange) .ForEachItemChange(mc => { ProcessChanges(resultCache, sourceLists.Items.AsArray(), mc.Current.Cache.KeyValues); if (_type == CombineOperator.And || _type == CombineOperator.Except) { ProcessChanges(resultCache, sourceLists.Items.AsArray(), resultCache.KeyValues.ToArray()); } var notifications = resultCache.CaptureChanges(); if (notifications.Count != 0) { observer.OnNext(notifications); } }) .Subscribe(); return new CompositeDisposable(sourceLists, allChanges, removedItem, sourceChanged); })); }
public static IObservable <T> AsObservable <T>(this IServiceBus bus) where T : class { return(Observable.Create <T>( observer => new ServiceBusSubscription <T>(bus, observer, null))); }
public static IObservable <Unit> WhenReady(this CBPeripheralManager manager) => Observable.Create <Unit>(ob => { var handler = new EventHandler((sender, args) => { if (manager.State == CBPeripheralManagerState.PoweredOn) { ob.Respond(Unit.Default); } else { ob.OnError(new ArgumentException("Adapter state is invalid - " + manager.State)); } }); switch (manager.State) { case CBPeripheralManagerState.Unknown: manager.StateUpdated += handler; break; case CBPeripheralManagerState.PoweredOn: ob.Respond(Unit.Default); break; default: ob.OnError(new ArgumentException("Adapter state is invalid - " + manager.State)); break; } return(() => manager.StateUpdated -= handler); });
public override IObservable <CharacteristicGattResult> WriteWithoutResponse(byte[] value) => Observable.Create <CharacteristicGattResult>(ob => { this.AssertWrite(false); //var handler = new EventHandler((sender, args) => this.WriteWithoutResponse(ob, CBCharacteristicWriteType.WithoutResponse, value)); //this.Peripheral.IsReadyToSendWriteWithoutResponse += handler; var type = this.Peripheral.CanSendWriteWithoutResponse ? CBCharacteristicWriteType.WithoutResponse : CBCharacteristicWriteType.WithResponse; this.Write(ob, type, value); //return () => this.Peripheral.IsReadyToSendWriteWithoutResponse -= handler; return(Disposable.Empty); });
public IObservable <IChangeSet <T> > Run() { return(Observable.Create <IChangeSet <T> >(observer => { if (_expireAfter == null && _limitSizeTo < 1) { return _source.Scan(new ChangeAwareList <T>(), (state, latest) => { var items = latest.AsArray(); if (items.Length == 1) { state.Add(items); } else { state.AddRange(items); } return state; }) .Select(state => state.CaptureChanges()) .SubscribeSafe(observer); } long orderItemWasAdded = -1; var locker = new object(); var sourceList = new ChangeAwareList <ExpirableItem <T> >(); var sizeLimited = _source.Synchronize(locker) .Scan(sourceList, (state, latest) => { var items = latest.AsArray(); var expirable = items.Select(t => CreateExpirableItem(t, ref orderItemWasAdded)); if (items.Length == 1) { sourceList.Add(expirable); } else { sourceList.AddRange(expirable); } if (_limitSizeTo > 0 && state.Count > _limitSizeTo) { //remove oldest items [these will always be the first x in the list] var toRemove = state.Count - _limitSizeTo; state.RemoveRange(0, toRemove); } return state; }) .Select(state => state.CaptureChanges()) .Publish(); var timeLimited = (_expireAfter == null ? Observable.Never <IChangeSet <ExpirableItem <T> > >() : sizeLimited) .Filter(ei => ei.ExpireAt != DateTime.MaxValue) .GroupWithImmutableState(ei => ei.ExpireAt) .MergeMany(grouping => { var expireAt = grouping.Key.Subtract(_scheduler.Now.DateTime); return Observable.Timer(expireAt, _scheduler).Select(_ => grouping); }) .Synchronize(locker) .Select(grouping => { sourceList.RemoveMany(grouping.Items); return sourceList.CaptureChanges(); }); var publisher = sizeLimited .Merge(timeLimited) .Cast(ei => ei.Item) .NotEmpty() .SubscribeSafe(observer); return new CompositeDisposable(publisher, sizeLimited.Connect()); })); }
public override IObservable <AdapterStatus> WhenStatusChanged() => Observable.Create <AdapterStatus>(ob => { var handler = new EventHandler <StateChangedEventArgs>((sender, args) => ob.OnNext(this.Status)); BluetoothAdapter.StateChanged += handler; return(() => BluetoothAdapter.StateChanged -= handler); });
async Task <HubRequest[]> GetRequestsAsync() { var datamartIDs = _networkSetting.DataMartList .Where(dm => dm.AllowUnattendedOperation && (dm.NotifyOfNewQueries || dm.ProcessQueriesAndNotUpload || dm.ProcessQueriesAndUploadAutomatically)) .Select(dm => dm.DataMartId).ToArray(); if (datamartIDs.Length == 0) { return(Array.Empty <HubRequest>()); } var requestFilter = new RequestFilter { Statuses = new[] { Lpp.Dns.DTO.DataMartClient.Enums.DMCRoutingStatus.Submitted, Lpp.Dns.DTO.DataMartClient.Enums.DMCRoutingStatus.Resubmitted }, DataMartIds = datamartIDs, FromDate = DateTime.UtcNow.AddYears(-1), DateRange = DateRangeKind.Exact }; var ob = Observable.Create <DTO.DataMartClient.RequestList>(async observer => { int index = 0; int batchSize = 2; DTO.DataMartClient.RequestList rl = null; while (rl == null || (index < rl.TotalCount)) { _logger.Debug($"Observer loop: pageIndex={ index }."); rl = await DnsServiceManager.GetRequestList("RxQueryTests-DefaultDSM", _networkSetting, index, batchSize, requestFilter, null, null); _logger.Debug($"Observer loop: pageIndex={ index }, results returned={ rl.Segment.DefaultIfEmpty().Count() }, total results={ rl.TotalCount }"); if (rl.TotalCount == 0) { break; } observer.OnNext(rl); index += batchSize; } _logger.Debug("Observer loop firing OnComplete"); observer.OnCompleted(); }).DefaultIfEmpty().Aggregate((requestList1, requestList2) => { if (requestList1 == null && requestList2 == null) { return(new DTO.DataMartClient.RequestList { Segment = Array.Empty <DTO.DataMartClient.RequestListRow>(), SortedAscending = false, SortedByColumn = DTO.DataMartClient.RequestSortColumn.RequestTime }); } else if (requestList1 != null && requestList2 == null) { return(requestList1); } else if (requestList1 == null && requestList2 != null) { return(requestList2); } else { return(new DTO.DataMartClient.RequestList { Segment = requestList1.Segment.EmptyIfNull().Concat(requestList2.Segment.EmptyIfNull()).ToArray(), SortedAscending = requestList1.SortedAscending, SortedByColumn = requestList1.SortedByColumn, StartIndex = requestList1.StartIndex, TotalCount = requestList1.TotalCount }); } }) .SelectMany(requestList => { if (requestList == null) { return(Array.Empty <DTO.DataMartClient.RequestListRow>()); } return(requestList.Segment.DefaultIfEmpty().Where(s => s.AllowUnattendedProcessing)); }) .SelectMany(rlr => RequestCache.ForNetwork(_networkSetting).LoadRequest(rlr.ID, rlr.DataMartID)) .ToArray(); return(await ob); }
public IObservable <SaxEvent> Parse(TextReader textReader, IScheduler scheduler) { return(Observable.Create <SaxEvent>(x => scheduler.Schedule(() => { ParseInternal(textReader, x); }))); }
public static IObservable <T> AsObservable <T>(this IServiceBus bus, Predicate <T> condition) where T : class { return(Observable.Create <T>( observer => new ServiceBusSubscription <T>(bus, observer, condition))); }
/// <summary> /// Used for writing blobs /// </summary> /// <param name="ch">The characteristic to write on</param> /// <param name="stream">The stream to send</param> public static IObservable <BleWriteSegment> BlobWrite(this IGattCharacteristic ch, Stream stream) => Observable.Create <BleWriteSegment>(async(ob, ct) => { var trans = ch.Service.Peripheral.TryBeginTransaction() ?? new VoidGattReliableWriteTransaction(); using (trans) { var mtu = ch.Service.Peripheral.MtuSize; var buffer = new byte[mtu]; var read = stream.Read(buffer, 0, buffer.Length); var pos = read; var len = Convert.ToInt32(stream.Length); while (!ct.IsCancellationRequested && read > 0) { await trans .Write(ch, buffer) .ToTask(ct) .ConfigureAwait(false); //if (this.Value != buffer) //{ // trans.Abort(); // throw new GattReliableWriteTransactionException("There was a mismatch response"); //} var seg = new BleWriteSegment(buffer, pos, len); ob.OnNext(seg); read = stream.Read(buffer, 0, buffer.Length); pos += read; } await trans.Commit(); } ob.OnCompleted(); return(trans); });
public static IObservable <LocaleContainer> LoadLocalizationDataAsync(string directoryPath) { return(Observable.Create <LocaleContainer>( o => Observable.ToAsync <string, LocaleContainer>(LoadLocalizationData)(directoryPath).Subscribe(o) )); }
/// <summary> /// Publish target property when value is changed. If source is destructed, publish OnCompleted. /// </summary> public static IObservable <TProperty> ObserveEveryValueChanged <TSource, TProperty>(this TSource source, Func <TSource, TProperty> propertySelector, IEqualityComparer <TProperty> comparer = null) where TSource : class { if (source == null) { return(Observable.Empty <TProperty>()); } comparer = comparer ?? EqualityComparer <TProperty> .Default; var reference = new WeakReference(source); source = null; return(Observable.Create <TProperty>(observer => { var currentValue = default(TProperty); var prevValue = default(TProperty); var t = reference.Target; if (t != null) { try { currentValue = propertySelector((TSource)t); } catch (Exception ex) { observer.OnError(ex); } finally { t = null; } } else { observer.OnCompleted(); return Disposable.Empty; } observer.OnNext(currentValue); prevValue = currentValue; return Observable.FromEvent <EventHandler, EventArgs>( h => (sender, e) => h.Invoke(e), h => CompositionTarget.Rendering += h, h => CompositionTarget.Rendering -= h) .Subscribe(_ => { var target = reference.Target; if (target != null) { try { currentValue = propertySelector((TSource)target); } catch (Exception ex) { observer.OnError(ex); } finally { target = null; } } else { observer.OnCompleted(); } if (!comparer.Equals(currentValue, prevValue)) { observer.OnNext(currentValue); prevValue = currentValue; } }); })); }
public override IObservable <IDictionary <string, string> > WhenReceived() => Observable.Create <IDictionary <string, string> >(async ob => { var handler = new TypedEventHandler <PushNotificationChannel, PushNotificationReceivedEventArgs>((sender, args) => { //args.BadgeNotification != null; //args.NotificationType == PushNotificationType.Tile //args.NotificationType == PushNotificationType.Toast; //args.ToastNotification.Data var headers = args .RawNotification? .Headers? .ToDictionary( x => x.Key, x => x.Value ) ?? new Dictionary <string, string>(0); ob.OnNext(headers); }); this.channel.PushNotificationReceived += handler; return(() => this.channel.PushNotificationReceived -= handler); });
//readonly CapturePropertyCollection captureProperties = new CapturePropertyCollection(); // Functor public UCLAMiniscope() { lastLEDBrightness = LEDBrightness; lastExposure = Exposure; lastSensorGain = SensorGain; source = Observable.Create <IplImage>((observer, cancellationToken) => { return(Task.Factory.StartNew(() => { lock (captureLock) { using (var capture = Capture.CreateCameraCapture(Index)) { try { capture.SetProperty(CaptureProperty.Saturation, (double)FramesPerSecond); capture.SetProperty(CaptureProperty.Hue, LEDBrightness); capture.SetProperty(CaptureProperty.Gain, SensorGain); capture.SetProperty(CaptureProperty.Brightness, Exposure); while (!cancellationToken.IsCancellationRequested) { // Runtime settable properties if (LEDBrightness != lastLEDBrightness) { capture.SetProperty(CaptureProperty.Hue, LEDBrightness); lastLEDBrightness = LEDBrightness; } if (SensorGain != lastSensorGain) { capture.SetProperty(CaptureProperty.Gain, SensorGain); lastSensorGain = SensorGain; } if (Exposure != lastExposure) { capture.SetProperty(CaptureProperty.Brightness, Exposure); lastExposure = Exposure; } var image = capture.QueryFrame(); if (image == null) { observer.OnCompleted(); break; } else { observer.OnNext(image.Clone()); } } } finally { capture.Close(); //captureProperties.Capture = null; } } } }, cancellationToken, TaskCreationOptions.LongRunning, TaskScheduler.Default)); }) .PublishReconnectable() .RefCount(); }
/// <summary> /// Subscribes to bucket change notifications (a Minio-only extension) /// </summary> /// <param name="bucketName">Bucket to get notifications from</param> /// <param name="events">Events to listen for</param> /// <param name="prefix">Filter keys starting with this prefix</param> /// <param name="suffix">Filter keys ending with this suffix</param> /// <param name="cancellationToken">Optional cancellation token to cancel the operation</param> /// <returns>An observable of JSON-based notification events</returns> public IObservable <MinioNotificationRaw> ListenBucketNotificationsAsync(string bucketName, IList <EventType> events, string prefix = "", string suffix = "", CancellationToken cancellationToken = default(CancellationToken)) { return(Observable.Create <MinioNotificationRaw>( async(obs, ct) => { bool isRunning = true; using (var cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, ct)) { while (isRunning) { var queries = new List <string>(); queries.Add("prefix=" + Uri.EscapeDataString(prefix)); queries.Add("suffix=" + Uri.EscapeDataString(suffix)); foreach (var eventType in events) { queries.Add("events=" + Uri.EscapeDataString(eventType.value)); } string query = string.Join("&", queries); var request = await this.CreateRequest(Method.GET, bucketName, resourcePath: "?" + query) .ConfigureAwait(false); var startTime = DateTime.Now; // Logs full url when HTTPtracing is enabled (as in MinioClient.ExecuteTaskAsync) if (this.trace) { var fullUrl = this.restClient.BuildUri(request); Console.WriteLine($"Full URL of Request {fullUrl}"); } request.ResponseWriter = responseStream => { using (responseStream) { var sr = new StreamReader(responseStream); while (true) { string line = sr.ReadLine(); if (this.trace) { Console.WriteLine("== ListenBucketNotificationsAsync read line =="); Console.WriteLine(line); Console.WriteLine("=============================================="); } if (line == null) { break; } string trimmed = line.Trim(); if (trimmed.Length > 2) { obs.OnNext(new MinioNotificationRaw(trimmed)); } } } }; IRestResponse response = await this.restClient.ExecuteTaskAsync(request, cancellationToken).ConfigureAwait(false); this.HandleIfErrorResponse(response, this.NoErrorHandlers, startTime); cts.Token.ThrowIfCancellationRequested(); } } })); }
/// <summary> /// Consume the tasks in parallel but with a rate limit. The results /// are returned as an observable. /// </summary> /// <typeparam name="T"></typeparam> /// <param name="tasks"></param> /// <param name="rateLimit"></param> /// <returns></returns> public static IObservable <T> RateLimit <T>(IEnumerable <Func <Task <T> > > tasks, double rateLimit) { var s = System.Diagnostics.Stopwatch.StartNew(); var n = 0; var sem = new AsyncCountdownEvent(1); var errors = new ConcurrentBag <Exception>(); return(Observable.Create <T> (observer => { var ctx = new CancellationTokenSource(); Task.Run (async() => { foreach (var taskFn in tasks) { n++; ctx.Token.ThrowIfCancellationRequested(); var elapsedTotalSeconds = s.Elapsed.TotalSeconds; var delay = Delay(rateLimit, n, elapsedTotalSeconds); if (delay > 0) { await Task.Delay(TimeSpan.FromSeconds(delay), ctx.Token); } sem.AddCount(1); Task.Run (async() => { try { observer.OnNext(await taskFn()); } catch (Exception e) { errors.Add(e); } finally { sem.Signal(); } } , ctx.Token); } sem.Signal(); await sem.WaitAsync(ctx.Token); if (errors.Count > 0) { observer.OnError(new AggregateException(errors)); } else { observer.OnCompleted(); } } , ctx.Token); return Disposable.Create(() => ctx.Cancel()); })); }
public IObservable <JobInfo> Transfer() { return(Observable.Create <JobInfo>(observer => { Console.WriteLine("Crane Initiated" + Thread.CurrentThread.ManagedThreadId); observer.OnNext(new JobInfo() { State = CommandState.Initiated, ReturnCode = 0, BcrResult = String.Empty, CarrierLocation = "Source", ThreadId = Thread.CurrentThread.ManagedThreadId, }); Thread.Sleep(1000); Console.WriteLine("Crane Active" + Thread.CurrentThread.ManagedThreadId); observer.OnNext(new JobInfo() { State = CommandState.CraneActive, ReturnCode = 0, BcrResult = String.Empty, CarrierLocation = "Source", ThreadId = Thread.CurrentThread.ManagedThreadId, }); Thread.Sleep(1000); Console.WriteLine("Crane Transferring" + Thread.CurrentThread.ManagedThreadId); observer.OnNext(new JobInfo() { State = CommandState.Transferring, ReturnCode = 0, BcrResult = "CST001", CarrierLocation = "Crane", ThreadId = Thread.CurrentThread.ManagedThreadId, }); Thread.Sleep(1000); Console.WriteLine("Crane Idle" + Thread.CurrentThread.ManagedThreadId); observer.OnNext(new JobInfo() { State = CommandState.CraneIdle, ReturnCode = 0, BcrResult = "CST001", CarrierLocation = "Destination", ThreadId = Thread.CurrentThread.ManagedThreadId, }); Thread.Sleep(1000); Console.WriteLine("Crane Completed" + Thread.CurrentThread.ManagedThreadId); observer.OnNext(new JobInfo() { State = CommandState.Completed, ReturnCode = 92, BcrResult = "CST001", CarrierLocation = "Destination", ThreadId = Thread.CurrentThread.ManagedThreadId, }); Thread.Sleep(1000); observer.OnCompleted(); return Disposable.Empty; })); }
// Functor public FeatherScope() { #if !ALL_UVC_PROPERTIES lastSensorGain = SensorGain; #endif // Here we define our observable source. An observable is just a (possibly asynchronous) // sequence of events that gets propagated to an arbitrary number of downstream observers. // You can think about it as an iterator/generator/list/collection (pick your poison) // with the difference that instead of consumers having to pull out items from it, they // get pushed as notifications to each observer. // // One important point is that observable sequences only actually need to do something // when an observer subscribes to it. // // The Observable.Create method makes it easy to create one of these sequences, by simply // specifying a function that gets called for each observer. Inside this function, you can // send notifications to the observer by calling observer.OnNext(). Also, you need to specify // what happens if the observer cancels the subscription at any time (e.g. the workflow is // stopped). There are many possible overloads to Observable.Create, but in this case, we // are defining the sequence in terms of a Task that starts and stops tied to a particular // observer subscription. The cancellationToken variable allows us to be notified when the // observer cancelled the subscription. source = Observable.Create <IplImage>((observer, cancellationToken) => { // Here we simply start the task that will emit the notifications to the observer return(Task.Factory.StartNew(() => { // We wait until any previous connections are completely disposed. lock (captureLock) { // We create the camera connection using (var capture = Capture.CreateCameraCapture(Index)) { #if ALL_UVC_PROPERTIES // Apply the settings foreach (var setting in captureProperties) { capture.SetProperty(setting.Property, setting.Value); } captureProperties.Capture = capture; #else capture.SetProperty(CaptureProperty.Gain, SensorGain); #endif try { // Loop until the observer has cancelled the subscription while (!cancellationToken.IsCancellationRequested) { #if ALL_UVC_PROPERTIES // Read one image var image = captureProperties.Capture.QueryFrame(); #else // Runtime settable properties if (SensorGain != lastSensorGain) { capture.SetProperty(CaptureProperty.Gain, SensorGain); lastSensorGain = SensorGain; } var image = capture.QueryFrame(); #endif if (image == null) { // If the next image is null, the camera was somehow stopped, // so we signal the observer that the sequence has ended. // This mostly never happens, but just to be sure. observer.OnCompleted(); break; } // Otherwise, send a copy of the image to the observer. The reason we // send a copy is that acquisition of the next frame will overwrite the // original image; this is a problem if the observer cached the image // somewhere for future use. else { observer.OnNext(image.Clone()); } } } // Make sure we reset the capture property to null at the end finally { #if ALL_UVC_PROPERTIES captureProperties.Capture = null; #endif capture.Close(); // necessary? Not in Goncalo's example } } } }, // These next parameters specify the operation of the Task. We give it the token, so that // the task is cancelled in case the observer unsubscribes. We also indicate the Task is long // running so that the framework allocates a dedicated thread to it, rather than a worker thread // from the thread pool. The last parameter just assigns it the default scheduler. cancellationToken, TaskCreationOptions.LongRunning, TaskScheduler.Default)); }) // The next two methods make this source a shared (hot) source. This ensures there is only one observer // subscribed to the camera and all notifications are distributed among all other observers. // RefCount ensures that the connection is only made when there are actually observers. .PublishReconnectable() .RefCount(); }
public static IObservable <FileProgress> CopyProgress(this FileInfo from, FileInfo target, bool overwriteIfExists) => Observable.Create <FileProgress>(async ob => { var completed = false; var cts = new CancellationTokenSource(); if (overwriteIfExists) { target.DeleteIfExists(); } var buffer = new byte[65535]; var totalCopy = 0; var start = DateTime.UtcNow; using (var readStream = from.OpenRead()) { using (var writeStream = target.Create()) { var read = await readStream.ReadAsync(buffer, 0, buffer.Length, cts.Token); while (read > 0 && !cts.IsCancellationRequested) { await writeStream.WriteAsync(buffer, 0, read, cts.Token).ConfigureAwait(false); read = await readStream.ReadAsync(buffer, 0, buffer.Length, cts.Token).ConfigureAwait(false); totalCopy += read; ob.OnNext(new FileProgress(totalCopy, from.Length, start)); } } } completed = true; ob.OnCompleted(); return(() => { cts.Cancel(); if (!completed) { target.DeleteIfExists(); } }); });
public static ICollectedReactiveSet <T> Buffer <T>(this IReactiveSet <T> set, TimeSpan time) { if (set == null) { throw new ArgumentNullException(nameof(set)); } var obs = Observable.Create <ReactiveSetChange <T> >(observer => { var isFirst = true; return(set.AsObservable() .Where(x => { if (isFirst) { isFirst = false; observer.OnNext(x); return false; } else { return true; } }) .Buffer(time) .Subscribe( x => { var added = new HashSet <T>(); var removed = new HashSet <T>(); foreach (var change in x) { if (change.ChangeReason == ReactiveSetChangeReason.Add) { foreach (var item in change.Items) { if (removed.Contains(item)) { removed.Remove(item); } else { added.Add(item); } } } else { foreach (var item in change.Items) { if (added.Contains(item)) { added.Remove(item); } else { removed.Add(item); } } } } if (added.Any()) { observer.OnNext(new ReactiveSetChange <T>(ReactiveSetChangeReason.Add, added)); } if (removed.Any()) { observer.OnNext(new ReactiveSetChange <T>(ReactiveSetChangeReason.Remove, removed)); } }, observer.OnError, observer.OnCompleted )); }); return(obs.ToReactiveSet()); }
public IObservable <SaxEvent> Parse(string fullPath, IScheduler scheduler) { return(Observable.Create <SaxEvent>(x => scheduler.Schedule(() => { ParseInternal(fullPath, x); }))); }
public void Should_pause_and_resume() { //Arrange var scheduler = new TestScheduler(); var isRunningTrigger = new BehaviorSubject <bool>(true); Action pause = () => isRunningTrigger.OnNext(false); Action resume = () => isRunningTrigger.OnNext(true); var source = scheduler.CreateHotObservable( ReactiveTest.OnNext(0.1.Seconds(), 1), ReactiveTest.OnNext(2.0.Seconds(), 2), ReactiveTest.OnNext(4.0.Seconds(), 3), ReactiveTest.OnNext(6.0.Seconds(), 4), ReactiveTest.OnNext(8.0.Seconds(), 5)); scheduler.Schedule(TimeSpan.FromSeconds(0.5), () => { pause(); }); scheduler.Schedule(TimeSpan.FromSeconds(5.0), () => { resume(); }); //Act var sut = Observable.Create <IObservable <int> >(o => { var current = source.Replay(); var connection = new SerialDisposable(); connection.Disposable = current.Connect(); return(isRunningTrigger .DistinctUntilChanged() .Select(isRunning => { if (isRunning) { //Return the current replayed values. return current; } else { //Disconnect and replace current. current = source.Replay(); connection.Disposable = current.Connect(); //yield silence until the next time we resume. return Observable.Never <int>(); } }) .Subscribe(o)); }).Switch(); var observer = scheduler.CreateObserver <int>(); using (sut.Subscribe(observer)) { scheduler.Start(); } //Assert var expected = new[] { ReactiveTest.OnNext(0.1.Seconds(), 1), ReactiveTest.OnNext(5.0.Seconds(), 2), ReactiveTest.OnNext(5.0.Seconds(), 3), ReactiveTest.OnNext(6.0.Seconds(), 4), ReactiveTest.OnNext(8.0.Seconds(), 5) }; CollectionAssert.AreEqual(expected, observer.Messages); }
public static void Observable_Create() { // create an observable sequence from a specified subscribe method implementation // lets you specify a delegate any time a subscription is made //Blocking().Subscribe(s => Console.WriteLine($"Got {s}")); //Nonblocking().Subscribe(s => Console.WriteLine($"Got {s}")); // 2. Show Return<T> // 3. Returning an action instead of an IDisposable // var o = Observable.Create<string>(observer => // { // var timer = new Timer(1000); // timer.Elapsed += (sender, e) => observer.OnNext($"tick {e.SignalTime}"); // timer.Elapsed += TimerElapsed; // timer.Start(); // return Disposable.Empty; // }); // // var sub = o.Subscribe(Console.WriteLine); // Console.ReadLine(); // // sub.Dispose(); // // want to do timer.Dispose here // // Console.ReadLine(); // still getting the tocks // // have not released the 2nd event handler; // // have not disposed of the timer var o = Observable.Create <string>( observer => { var timer = new Timer(1000); timer.Elapsed += (sender, e) => observer.OnNext($"tick {e.SignalTime}"); timer.Elapsed += TimerElapsed; timer.Start(); // return a lambda that removes the timer // if we returned Disposable.Empty here "tock" would go on forever even when object o is set to null //return Disposable.Empty; return(() => { timer.Elapsed -= TimerElapsed; timer.Dispose(); }); }); var sub = o.Subscribe(WriteLine); ReadKey(); sub.Dispose(); WriteLine("Subscription disposed"); // not getting tocks here ReadKey(); o = null; WriteLine("Object o has been destroyed"); }