public virtual Task CreateSubscriptionCoreAsync(Uri subscriptionUri, Expression subscription, object state, CancellationToken token) { if (subscriptionUri == null) { throw new ArgumentNullException(nameof(subscriptionUri)); } if (subscription == null) { throw new ArgumentNullException(nameof(subscription)); } var rewritten = _rewriter(subscription); // NB: The functionality to insert the hook needs to be revisited in order to have an effect on subscriptions created via subscription // factories. However, its applicability will be limited when factories for things like "composite subscriptions" are used. While // only observable.Subscribe(observer) subscriptions can be "hooked" using a Finally operator, it's unclear how the same technique // could be applied to e.g. composite subscriptions. The better option is likely to add a mechanism that can detect the transition // of a subscription to a disposed state trigger from within the engine. However, that will lack information about the cause of // termination, e.g. due to an OnError or OnCompleted message (in fact, in a general notion of subscriptions there's no requirement // to have an observer given that the ISubscription algebra is one that operates on "traversable resources" in the most general // sense imaginable). // // One temporary workaround could be for the QC to intercept subscription factory definition operations and scan for a single // top-level occurrence of rx://observable/subscribe, and attach the hook the the observable portion. Other non-hookable expressions // could be rejected for the time being. The mechanism to put in this hook could simply rewrite rx://observable/subscribe to some // other subscription factory which expands into (o, v) => rx://observable/subscribe(o.CleanupHook(), v). // // See Reaqtor.Remoting.QueryCoordinator\QueryCoordinatorServiceProvider.cs for an implementation of the latter. var subscribeExpressionWithCompletedHook = rewritten.GetExpressionWithSubscriptionCleanupHook(throwWhenNotAttached: false); var subscribeExpressionSync = ExpressionRewriteHelpers.RewriteAsyncToSync(subscribeExpressionWithCompletedHook); return(_queryEngine.ServiceProvider.CreateSubscriptionAsync(subscriptionUri, subscribeExpressionSync, state, token)); }
public virtual Task CreateStreamCoreAsync(Uri streamUri, Expression stream, object state, CancellationToken token) { if (streamUri == null) { throw new ArgumentNullException(nameof(streamUri)); } if (stream == null) { throw new ArgumentNullException(nameof(stream)); } var syncStream = ExpressionRewriteHelpers.RewriteAsyncToSync(stream); return(_queryEngine.ServiceProvider.CreateStreamAsync(streamUri, syncStream, state, token)); }