Beispiel #1
0
        internal Yield CreateSubscriptionSet(DreamContext context, DreamMessage request, Result <DreamMessage> response)
        {
            XDoc subscriptionSet = request.ToDocument();
            Tuplet <PubSubSubscriptionSet, bool> set = _dispatcher.RegisterSet(subscriptionSet);
            XUri         locationUri = Self.At("subscribers", set.Item1.Location).Uri.AsPublicUri();
            DreamMessage msg         = null;

            if (set.Item2)
            {
                // existing subs cause a Conflict with ContentLocation of the sub
                msg = DreamMessage.Conflict("The specified owner already has a registered subscription set");
                msg.Headers.ContentLocation = locationUri;
            }
            else
            {
                // new subs cause a Created with Location of the sub, plus XDoc containing the location
                XDoc responseDoc = new XDoc("subscription-set")
                                   .Elem("uri.location", locationUri)
                                   .Elem("access-key", set.Item1.AccessKey);
                msg = DreamMessage.Created(locationUri, responseDoc);
                msg.Headers.Location = locationUri.With("access-key", set.Item1.AccessKey);
            }
            response.Return(msg);
            yield break;
        }
Beispiel #2
0
        //--- Methods ---
        protected override Yield Start(XDoc config, IContainer container, Result result)
        {
            yield return Coroutine.Invoke(base.Start, config, container, new Result());
            _log.DebugFormat("starting {0}", Self.Uri);

            // make sure we have an IPubSubDispatcher registered
            ContainerBuilder builder = null;
            if(!container.IsRegistered<IPubSubDispatcher>()) {
                builder = new ContainerBuilder();
                builder.Register<Dispatcher>().As<IPubSubDispatcher>().ServiceScoped();
            }
            if(!container.IsRegistered<IPubSubDispatchQueueRepository>()) {
                var localQueuePath = config["queue-path"].AsText;
                builder = builder ?? new ContainerBuilder();
                var retryTime = (config["failed-dispatch-retry"].AsInt ?? 60).Seconds();
                if(string.IsNullOrEmpty(localQueuePath)) {
                    _log.Debug("no queue persistent path provided, using memory queues");
                    builder.Register(new MemoryPubSubDispatchQueueRepository(TimerFactory, retryTime))
                        .As<IPubSubDispatchQueueRepository>();
                } else {
                    builder.Register(new PersistentPubSubDispatchQueueRepository(localQueuePath, TimerFactory, retryTime))
                        .As<IPubSubDispatchQueueRepository>();
                }
            }
            if(builder != null) {
                builder.Build(container);
            }

            // initialize dispatcher
            _dispatcher = container.Resolve<IPubSubDispatcher>(
                TypedParameter.From(new DispatcherConfig {
                    ServiceUri = Self,
                    ServiceAccessCookie = DreamCookie.NewSetCookie("service-key", InternalAccessKey, Self.Uri),
                    ServiceCookies = Cookies,
                    ServiceConfig = config
                })
            );

            // check for upstream chaining
            if(!config["upstream"].IsEmpty) {
                _dispatcher.CombinedSet.AsDocument();

                // we've been provided 1 or more upstream pubsub services that we need to subscribe to
                foreach(XDoc upstream in config["upstream/uri"]) {
                    int retry = 0;
                    while(true) {
                        retry++;
                        _log.DebugFormat("setting up upstream chain to {0} (attempt {1})", upstream, retry);
                        XUri upstreamUri = upstream.AsUri;

                        // subscribe with an empty set, since there are no child subs at Start, but we need a place to subscribe updates on
                        XDoc emptySub = new XDoc("subscription-set").Elem("uri.owner", Self.Uri);
                        Result<DreamMessage> upstreamResult;
                        yield return upstreamResult = Plug.New(upstreamUri).Post(emptySub, new Result<DreamMessage>(TimeSpan.MaxValue));
                        if(upstreamResult.Value.IsSuccessful) {
                            XUri location = new XUri(upstreamResult.Value.Headers.Location).WithoutQuery();
                            string accessKey = upstreamResult.Value.ToDocument()["access-key"].AsText;

                            // subscribe the resulting location to our pubsub:///* changes
                            XDoc subscribeToChanges = new XDoc("subscription-set")
                                .Elem("uri.owner", upstreamUri.WithScheme("upstream"))
                                .Start("subscription")
                                .Attr("id", "1")
                                .Elem("channel", "pubsub://*/*")
                                .Add(DreamCookie.NewSetCookie("access-key", accessKey, location).AsSetCookieDocument)
                                .Start("recipient").Elem("uri", upstreamResult.Value.Headers.Location).End()
                                .End();
                            _dispatcher.RegisterSet(StringUtil.CreateAlphaNumericKey(8), subscribeToChanges, StringUtil.CreateAlphaNumericKey(8));
                            break;
                        }
                        _log.WarnFormat("unable to subscribe to upstream pubsub (attempt {0}): {1}", retry, upstreamResult.Value.Status);
                        if(retry >= 3) {
                            _log.WarnFormat("giving up on upstream chaining to {0}", upstream);
                            break;
                        }
                        yield return Async.Sleep(TimeSpan.FromMilliseconds(500));
                        continue;
                    }
                }
            }
            if(!config["downstream"].IsEmpty) {

                // we've been provided 1 or more downstream pubsub services that we need to get to subscribe to us
                foreach(XDoc downstream in config["downstream/uri"]) {
                    int retry = 0;
                    while(true) {
                        retry++;
                        _log.DebugFormat("setting up downstream chain to {0} (attempt {1})", downstream, retry);
                        Result<DreamMessage> downstreamResult;
                        yield return downstreamResult = Plug.New(downstream.AsUri).Get(new Result<DreamMessage>(TimeSpan.MaxValue));
                        if(downstreamResult.Value.IsSuccessful) {
                            XDoc downstreamSet = downstreamResult.Value.ToDocument();
                            Tuplet<PubSubSubscriptionSet, bool> set = _dispatcher.RegisterSet(StringUtil.CreateAlphaNumericKey(8), downstreamSet, StringUtil.CreateAlphaNumericKey(8));
                            XUri locationUri = Self.At("subscribers", set.Item1.Location).Uri;
                            XUri featureUri = Self.At("subscribers").Uri;
                            _log.DebugFormat("downstream chain to {0} registered {1}", downstream, set.Item1.Location);
                            XDoc subscribeToChanges = new XDoc("subscription-set")
                                .Elem("uri.owner", Self.Uri)
                                .Start("subscription")
                                .Attr("id", "1")
                                .Elem("channel", "pubsub://*/*")
                                .Add(DreamCookie.NewSetCookie("access-key", set.Item1.AccessKey, featureUri).AsSetCookieDocument)
                                .Start("recipient").Elem("uri", locationUri).End()
                                .End();
                            yield return downstreamResult = Plug.New(downstream.AsUri).Post(subscribeToChanges, new Result<DreamMessage>(TimeSpan.MaxValue));
                            if(downstreamResult.Value.IsSuccessful) {
                                break;
                            }
                            _log.WarnFormat("unable to subscribe to downstream pubsub (attempt {0}): {1}", retry, downstreamResult.Value.Status);
                        } else {
                            _log.WarnFormat("unable to retrieve downstream set (attempt {0}): {1}", retry, downstreamResult.Value.Status);
                        }
                        if(retry >= 3) {
                            _log.WarnFormat("giving up on downstream chaining to {0}", downstream);
                            break;
                        }
                        yield return Async.Sleep(TimeSpan.FromMilliseconds(500));
                    }
                }
            }
            result.Return();
        }
Beispiel #3
0
        //--- Methods ---
        protected override Yield Start(XDoc config, IContainer container, Result result)
        {
            yield return(Coroutine.Invoke(base.Start, config, container, new Result()));

            _log.DebugFormat("starting {0}", Self.Uri);

            // make sure we have an IPubSubDispatcher registered
            if (!container.IsRegistered <IPubSubDispatcher>())
            {
                var builder = new ContainerBuilder();
                builder.Register <Dispatcher>().As <IPubSubDispatcher>().ServiceScoped();
                builder.Build(container);
            }

            // initialize dispatcher
            _dispatcher = container.Resolve <IPubSubDispatcher>(TypedParameter.From(new DispatcherConfig {
                ServiceUri          = Self,
                ServiceAccessCookie = DreamCookie.NewSetCookie("service-key", InternalAccessKey, Self.Uri),
                ServiceCookies      = Cookies,
                ServiceConfig       = config
            }));

            // check for upstream chaining
            if (!config["upstream"].IsEmpty)
            {
                XDoc combinedset = _dispatcher.CombinedSet.AsDocument();

                // we've been provided 1 or more upstream pubsub services that we need to subscribe to
                foreach (XDoc upstream in config["upstream/uri"])
                {
                    int retry = 0;
                    while (true)
                    {
                        retry++;
                        _log.DebugFormat("setting up upstream chain to {0} (attempt {1})", upstream, retry);
                        XUri upstreamUri = upstream.AsUri;

                        // subscribe with an empty set, since there are no child subs at Start, but we need a place to subscribe updates on
                        XDoc emptySub = new XDoc("subscription-set").Elem("uri.owner", Self.Uri);
                        Result <DreamMessage> upstreamResult;
                        yield return(upstreamResult = Plug.New(upstreamUri).Post(emptySub, new Result <DreamMessage>(TimeSpan.MaxValue)));

                        if (upstreamResult.Value.IsSuccessful)
                        {
                            XUri   location  = new XUri(upstreamResult.Value.Headers.Location).WithoutQuery();
                            string accessKey = upstreamResult.Value.ToDocument()["access-key"].AsText;

                            // subscribe the resulting location to our pubsub:///* changes
                            XDoc subscribeToChanges = new XDoc("subscription-set")
                                                      .Elem("uri.owner", upstreamUri.WithScheme("upstream"))
                                                      .Start("subscription")
                                                      .Attr("id", "1")
                                                      .Elem("channel", "pubsub://*/*")
                                                      .Add(DreamCookie.NewSetCookie("access-key", accessKey, location).AsSetCookieDocument)
                                                      .Start("recipient").Elem("uri", upstreamResult.Value.Headers.Location).End()
                                                      .End();
                            _dispatcher.RegisterSet(subscribeToChanges);
                            break;
                        }
                        _log.WarnFormat("unable to subscribe to upstream pubsub (attempt {0}): {1}", retry, upstreamResult.Value.Status);
                        if (retry >= 3)
                        {
                            _log.WarnFormat("giving up on upstream chaining to {0}", upstream);
                            break;
                        }
                        yield return(Async.Sleep(TimeSpan.FromMilliseconds(500)));

                        continue;
                    }
                }
            }
            if (!config["downstream"].IsEmpty)
            {
                // we've been provided 1 or more downstream pubsub services that we need to get to subscribe to us
                foreach (XDoc downstream in config["downstream/uri"])
                {
                    int retry = 0;
                    while (true)
                    {
                        retry++;
                        _log.DebugFormat("setting up downstream chain to {0} (attempt {1})", downstream, retry);
                        Result <DreamMessage> downstreamResult;
                        yield return(downstreamResult = Plug.New(downstream.AsUri).Get(new Result <DreamMessage>(TimeSpan.MaxValue)));

                        if (downstreamResult.Value.IsSuccessful)
                        {
                            XDoc downstreamSet = downstreamResult.Value.ToDocument();
                            Tuplet <PubSubSubscriptionSet, bool> set = _dispatcher.RegisterSet(downstreamSet);
                            XUri locationUri = Self.At("subscribers", set.Item1.Location).Uri;
                            XUri featureUri  = Self.At("subscribers").Uri;
                            _log.DebugFormat("downstream chain to {0} registered {1}", downstream, set.Item1.Location);
                            XDoc subscribeToChanges = new XDoc("subscription-set")
                                                      .Elem("uri.owner", Self.Uri)
                                                      .Start("subscription")
                                                      .Attr("id", "1")
                                                      .Elem("channel", "pubsub://*/*")
                                                      .Add(DreamCookie.NewSetCookie("access-key", set.Item1.AccessKey, featureUri).AsSetCookieDocument)
                                                      .Start("recipient").Elem("uri", locationUri).End()
                                                      .End();
                            yield return(downstreamResult = Plug.New(downstream.AsUri).Post(subscribeToChanges, new Result <DreamMessage>(TimeSpan.MaxValue)));

                            if (downstreamResult.Value.IsSuccessful)
                            {
                                break;
                            }
                            _log.WarnFormat("unable to subscribe to downstream pubsub (attempt {0}): {1}", retry, downstreamResult.Value.Status);
                        }
                        else
                        {
                            _log.WarnFormat("unable to retrieve downstream set (attempt {0}): {1}", retry, downstreamResult.Value.Status);
                        }
                        if (retry >= 3)
                        {
                            _log.WarnFormat("giving up on downstream chaining to {0}", downstream);
                            break;
                        }
                        yield return(Async.Sleep(TimeSpan.FromMilliseconds(500)));
                    }
                }
            }
            result.Return();
        }