//--- 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(); }
/// <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(); }
//--- 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(); }
//--- 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(); }