//--- Methods ---
        protected override Yield Start(XDoc config, Result result)
        {
            yield return(Coroutine.Invoke(base.Start, config, new Result()));

            _varnish            = Plug.New(Config["uri.varnish"].AsUri);
            _deki               = Plug.New(Config["uri.deki"].AsUri);
            _apikey             = Config["apikey"].AsText;
            _delayPurgeTimespan = TimeSpan.FromSeconds(config["varnish-purge-delay"].AsInt ?? 10);
            var dispatcher = new UpdateRecordDispatcher(OnQueueExpire);

            _updateDelayQueue = new UpdateDelayQueue(_delayPurgeTimespan, dispatcher);

            // set up subscription for pubsub
            XDoc subscriptionSet = new XDoc("subscription-set")
                                   .Elem("uri.owner", Self.Uri)
                                   .Start("subscription")
                                   .Add(DreamCookie.NewSetCookie("service-key", InternalAccessKey, Self.Uri).AsSetCookieDocument)
                                   .Elem("channel", "event://*/deki/pages/create")
                                   .Elem("channel", "event://*/deki/pages/move")
                                   .Elem("channel", "event://*/deki/pages/update")
                                   .Elem("channel", "event://*/deki/pages/delete")
                                   .Elem("channel", "event://*/deki/pages/revert")
                                   .Elem("channel", "event://*/deki/pages/createalias")
                                   .Elem("channel", "event://*/deki/pages/tags/update")
                                   .Elem("channel", "event://*/deki/pages/dependentschanged/comments/create")
                                   .Elem("channel", "event://*/deki/pages/dependentschanged/comments/update")
                                   .Elem("channel", "event://*/deki/pages/dependentschanged/comments/delete")
                                   .Elem("channel", "event://*/deki/pages/dependentschanged/files/create")
                                   .Elem("channel", "event://*/deki/pages/dependentschanged/files/update")
                                   .Elem("channel", "event://*/deki/pages/dependentschanged/files/delete")
                                   .Elem("channel", "event://*/deki/pages/dependentschanged/files/move")
                                   .Elem("channel", "event://*/deki/pages/dependentschanged/files/restore")
                                   .Elem("channel", "event://*/deki/files/create")
                                   .Elem("channel", "event://*/deki/files/update")
                                   .Elem("channel", "event://*/deki/files/delete")
                                   .Elem("channel", "event://*/deki/files/move")
                                   .Elem("channel", "event://*/deki/files/restore")
                                   .Start("recipient")
                                   .Attr("authtoken", _apikey)
                                   .Elem("uri", Self.Uri.At("queue"))
                                   .End()
                                   .End();
            Result <DreamMessage> subscriptionResult;

            yield return(subscriptionResult = PubSub.At("subscribers").PostAsync(subscriptionSet));

            string accessKey = subscriptionResult.Value.ToDocument()["access-key"].AsText;
            XUri   location  = subscriptionResult.Value.Headers.Location;

            Cookies.Update(DreamCookie.NewSetCookie("access-key", accessKey, location), null);
            _subscriptionLocation = location.AsLocalUri().WithoutQuery();
            _log.DebugFormat("subscribed VarnishPurgeService for events at {0}", _subscriptionLocation);
            result.Return();
        }
Esempio n. 2
0
        /// <summary>
        /// Retrieve all cookies that apply to a Uri.
        /// </summary>
        /// <param name="uri">Uri to match.</param>
        /// <returns>List of cookies.</returns>
        public List <DreamCookie> Fetch(XUri uri)
        {
            if (uri == null)
            {
                throw new ArgumentNullException("uri");
            }
            List <DreamCookie> result = new List <DreamCookie>();

            Fetch(uri, 0, result);
            XUri localUri = uri.AsLocalUri();

            if (localUri != uri)
            {
                Fetch(localUri, 0, result);
            }
            return(result);
        }
        private IEnumerator <IYield> SubscribeInstanceEvents(Plug pubsubPlug, Result result)
        {
            _log.DebugFormat("subscribing to pubsub {0}", pubsubPlug.Uri.ToString());
            var subscriptionSet = new XDoc("subscription-set")
                                  .Elem("uri.owner", Self.Uri)
                                  .Start("subscription")
                                  .Add(DreamCookie.NewSetCookie("service-key", InternalAccessKey, Self.Uri).AsSetCookieDocument)
                                  .Elem("channel", "event://*/deki/site/started")
                                  .Start("recipient")
                                  .Attr("authtoken", _apikey)
                                  .Elem("uri", Self.Uri.At("queue"))
                                  .End()
                                  .End();
            DreamMessage subscription = null;

            yield return(pubsubPlug.At("subscribers").PostAsync(subscriptionSet).Set(x => subscription = x));

            // only care about created responses, but log other failures
            if (subscription.Status == DreamStatus.Created)
            {
                string accessKey = subscription.ToDocument()["access-key"].AsText;
                XUri   location  = subscription.Headers.Location;
                Cookies.Update(DreamCookie.NewSetCookie("access-key", accessKey, location), null);
                _subscriptionLocation = location.AsLocalUri().WithoutQuery();
                _log.DebugFormat("subscribed indexer for events at {0}", _subscriptionLocation);
            }
            else if (subscription.Status == DreamStatus.Conflict)
            {
                _log.DebugFormat("didn't subscribe, since we already had a subscription in place");
            }
            else
            {
                _log.WarnFormat("subscribe to {0} failed: {1}", pubsubPlug.Uri.ToString(), subscription.Status);
            }
            result.Return();
        }
Esempio n. 4
0
        //--- Methods ---
        protected override Yield Start(XDoc config, Result result)
        {
            yield return(Coroutine.Invoke(base.Start, config, new Result()));

            // set up cache reaper
            _ttl = TimeSpan.FromSeconds(Config["news-ttl"].AsDouble ?? 60 * 60);
            double?checkInterval = Config["check-interval"].AsDouble;

            if (checkInterval.HasValue)
            {
                _checkInterval = TimeSpan.FromSeconds(checkInterval.Value);
            }
            else
            {
                double checkInterval2 = _ttl.TotalSeconds / 10;
                if (_ttl.TotalSeconds < 30 || checkInterval2 < 30)
                {
                    checkInterval2 = 30;
                }
                _checkInterval = TimeSpan.FromSeconds(checkInterval2);
            }
            TaskTimer.New(_ttl, delegate(TaskTimer timer) {
                lock (_pageViews) {
                    View next;
                    do
                    {
                        if (_pageViews.Count == 0)
                        {
                            break;
                        }
                        next = _pageViews.Peek();
                        if (next != null)
                        {
                            if (next.Time.Add(_ttl) < DateTime.UtcNow)
                            {
                                _pageViews.Dequeue();
                            }
                            else
                            {
                                break;
                            }
                        }
                    } while(next != null);
                }
                timer.Change(_checkInterval, TaskEnv.None);
            }, null, TaskEnv.None);

            // get the apikey, which we will need as a subscription auth token for subscriptions not done on behalf of a user
            _apikey = config["apikey"].AsText;

            // build ignore list
            string ignore = config["ignore"].AsText;

            if (!string.IsNullOrEmpty(ignore))
            {
                foreach (string page in ignore.Split(new char[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries))
                {
                    _ignore[page] = null;
                }
            }
            // set up subscription for page views
            XDoc subscription = new XDoc("subscription-set")
                                .Elem("uri.owner", Self.Uri.AsServerUri().ToString())
                                .Start("subscription")
                                .Elem("channel", "event://*/deki/pages/view")
                                .Add(DreamCookie.NewSetCookie("service-key", InternalAccessKey, Self.Uri).AsSetCookieDocument)
                                .Start("recipient")
                                .Attr("authtoken", _apikey)
                                .Elem("uri", Self.Uri.AsServerUri().At("notify", "view").ToString())
                                .End()
                                .End();
            Result <DreamMessage> subscribe;

            yield return(subscribe = PubSub.At("subscribers").PostAsync(subscription));

            string accessKey = subscribe.Value.ToDocument()["access-key"].AsText;
            XUri   location  = subscribe.Value.Headers.Location;

            Cookies.Update(DreamCookie.NewSetCookie("access-key", accessKey, location), null);
            _subscriptionLocation = Plug.New(location.AsLocalUri().WithoutQuery());
            _log.DebugFormat("set up initial subscription location at {0}", _subscriptionLocation.Uri);
            result.Return();
        }
Esempio n. 5
0
        //--- Methods ---
        protected override Yield Start(XDoc config, Result result)
        {
            yield return(Coroutine.Invoke(base.Start, config, new Result()));

            // get the apikey, which we will need as a subscription auth token for subscriptions not done on behalf of a user
            _apikey = config["apikey"].AsText;

            // capture the wikiId of the wiki starting us
            string wikiId = config["wikiid"].AsText ?? "default";

            // set up plug deki, so we can validate users
            XUri dekiUri = config["uri.deki"].AsUri ?? new XUri("http://localhost:8081/deki");

            _deki = Plug.New(dekiUri).With("apikey", _apikey).WithHeader("X-Deki-Site", "id=" + wikiId);

            // get ajax polling interval
            _pollInterval = TimeSpan.FromSeconds(config["poll-interval"].AsDouble ?? 60);

            // set up subscription reaper
            TaskTimer.New(TimeSpan.FromSeconds(60), timer => {
                lock (_subscriptions) {
                    var staleSubs = new List <uint>();
                    foreach (KeyValuePair <uint, Subscription> pair in _subscriptions)
                    {
                        if (pair.Value.LastTouched.Add(_pollInterval).Add(TimeSpan.FromSeconds(10)) < DateTime.UtcNow)
                        {
                            staleSubs.Add(pair.Key);
                        }
                    }
                    foreach (uint pageId in staleSubs)
                    {
                        _log.DebugFormat("removing subscription for {0}", pageId);
                        _subscriptions.Remove(pageId);
                    }
                }
                timer.Change(TimeSpan.FromSeconds(60), TaskEnv.None);
            }, null, TaskEnv.None);


            // set up subscription for pubsub
            XDoc subscription = new XDoc("subscription-set")
                                .Elem("uri.owner", Self.Uri.AsServerUri().ToString())
                                .Start("subscription")
                                .Elem("channel", string.Format("event://{0}/deki/pages/update", wikiId))
                                .Elem("channel", string.Format("event://{0}/deki/pages/revert", wikiId))
                                .Elem("channel", string.Format("event://{0}/deki/pages/tags/update", wikiId))
                                .Elem("channel", string.Format("event://{0}/deki/pages/dependentschanged/comments/create", wikiId))
                                .Elem("channel", string.Format("event://{0}/deki/pages/dependentschanged/comments/update", wikiId))
                                .Elem("channel", string.Format("event://{0}/deki/pages/dependentschanged/comments/delete", wikiId))
                                .Elem("channel", string.Format("event://{0}/deki/pages/dependentschanged/files/create", wikiId))
                                .Elem("channel", string.Format("event://{0}/deki/pages/dependentschanged/files/update", wikiId))
                                .Elem("channel", string.Format("event://{0}/deki/pages/dependentschanged/files/delete", wikiId))
                                .Elem("channel", string.Format("event://{0}/deki/pages/dependentschanged/files/properties/*", wikiId))
                                .Elem("channel", string.Format("event://{0}/deki/pages/dependentschanged/files/restore", wikiId))
                                .Add(DreamCookie.NewSetCookie("service-key", InternalAccessKey, Self.Uri).AsSetCookieDocument)
                                .Start("recipient")
                                .Attr("authtoken", _apikey)
                                .Elem("uri", Self.Uri.AsServerUri().At("notify").ToString())
                                .End()
                                .End();
            Result <DreamMessage> subscribe;

            yield return(subscribe = PubSub.At("subscribers").PostAsync(subscription));

            string accessKey = subscribe.Value.ToDocument()["access-key"].AsText;
            XUri   location  = subscribe.Value.Headers.Location;

            Cookies.Update(DreamCookie.NewSetCookie("access-key", accessKey, location), null);
            _subscriptionLocation = Plug.New(location.AsLocalUri().WithoutQuery());
            _log.DebugFormat("set up initial subscription location at {0}", _subscriptionLocation.Uri);
            result.Return();
        }
        //--- Methods ---
        protected override Yield Start(XDoc config, IContainer container, Result result)
        {
            yield return(Coroutine.Invoke(base.Start, config, new Result()));

            // set up plug for phpscript that will handle the notifications
            _emailer = Plug.New(config["uri.emailer"].AsUri);

            // set up plug deki, so we can validate users
            _deki = Plug.New(config["uri.deki"].AsUri);

            // get the apikey, which we will need as a subscription auth token for subscriptions not done on behalf of a user
            _apikey = config["apikey"].AsText;
            _cache  = new PageChangeCache(_deki.With("apikey", _apikey), TimeSpan.FromSeconds(config["page-cache-ttl"].AsInt ?? 2));

            if (!container.IsRegistered <IPageSubscriptionInstance>())
            {
                var builder = new ContainerBuilder();
                builder.Register <PageSubscriptionInstance>().As <IPageSubscriptionInstance>().FactoryScoped();
                builder.Build(container);
            }

            // TODO (arnec): this should be hitting the API to retrieve resources

            // resource manager for email template
            var resourcePath = Config["resources-path"].AsText;

            if (!string.IsNullOrEmpty(resourcePath))
            {
                _resourceManager = new PlainTextResourceManager(Environment.ExpandEnvironmentVariables(resourcePath));
            }
            else
            {
                // creating a test resource manager
                _log.WarnFormat("'resource-path' was not defined in Config, using a test resource manager for email templating");
                var testSet = new TestResourceSet {
                    { "Notification.Page.email-subject", "Page Modified" },
                    { "Notification.Page.email-header", "The following pages have changed:" }
                };
                _resourceManager = new PlainTextResourceManager(testSet);
            }

            // set up subscription for pubsub
            var subscriptionSet = new XDoc("subscription-set")
                                  .Elem("uri.owner", Self.Uri.AsServerUri().ToString())
                                  .Start("subscription")
                                  .Elem("channel", "event://*/deki/users/*")
                                  .Add(DreamCookie.NewSetCookie("service-key", InternalAccessKey, Self.Uri).AsSetCookieDocument)
                                  .Start("recipient")
                                  .Attr("authtoken", _apikey)
                                  .Elem("uri", Self.Uri.AsServerUri().At("updateuser").ToString())
                                  .End()
                                  .End()
                                  .Start("subscription")
                                  .Elem("channel", "event://*/deki/pages/create")
                                  .Elem("channel", "event://*/deki/pages/update")
                                  .Elem("channel", "event://*/deki/pages/delete")
                                  .Elem("channel", "event://*/deki/pages/revert")
                                  .Elem("channel", "event://*/deki/pages/move")
                                  .Elem("channel", "event://*/deki/pages/tags/update")
                                  .Elem("channel", "event://*/deki/pages/dependentschanged/comments/create")
                                  .Elem("channel", "event://*/deki/pages/dependentschanged/comments/update")
                                  .Elem("channel", "event://*/deki/pages/dependentschanged/comments/delete")
                                  .Elem("channel", "event://*/deki/pages/dependentschanged/files/create")
                                  .Elem("channel", "event://*/deki/pages/dependentschanged/files/update")
                                  .Elem("channel", "event://*/deki/pages/dependentschanged/files/delete")
                                  .Elem("channel", "event://*/deki/pages/dependentschanged/files/properties/*")
                                  .Elem("channel", "event://*/deki/pages/dependentschanged/files/restore")
                                  .Add(DreamCookie.NewSetCookie("service-key", InternalAccessKey, Self.Uri).AsSetCookieDocument)
                                  .Start("recipient")
                                  .Attr("authtoken", _apikey)
                                  .Elem("uri", Self.Uri.AsServerUri().At("notify").ToString())
                                  .End()
                                  .End();
            Result <DreamMessage> subscribe;

            yield return(subscribe = PubSub.At("subscribers").PostAsync(subscriptionSet));

            string accessKey = subscribe.Value.ToDocument()["access-key"].AsText;
            XUri   location  = subscribe.Value.Headers.Location;

            Cookies.Update(DreamCookie.NewSetCookie("access-key", accessKey, location), null);
            _subscriptionLocation = Plug.New(location.AsLocalUri().WithoutQuery());
            _log.DebugFormat("set up initial subscription location at {0}", _subscriptionLocation.Uri);

            // set up notification accumulator queue
            TimeSpan accumulationMinutes = TimeSpan.FromSeconds(config["accumulation-time"].AsInt ?? 10 * 60);

            _log.DebugFormat("Initializing queue with {0:0.00} minute accumulation", accumulationMinutes.TotalMinutes);
            _notificationQueue = new NotificationDelayQueue(accumulationMinutes, SendEmail);
            result.Return();
        }