Пример #1
0
        private Yield GetCache(uint pageId, string wikiId, DateTime time, CultureInfo culture, Result <PageChangeCacheData> result)
        {
            // Note (arnec): going back 10 seconds before event, because timestamps in a request are not currently synced
            string keytime = time.ToString("yyyyMMddHHmm");
            string since   = time.Subtract(TimeSpan.FromSeconds(10)).ToString("yyyyMMddHHmmss");
            PageChangeCacheData cacheData;
            string key = string.Format("{0}:{1}:{2}:{3}", pageId, wikiId, keytime, culture);

            _log.DebugFormat("getting data for key: {0}", key);
            lock (_cache) {
                if (_cache.TryGetValue(key, out cacheData))
                {
                    result.Return(cacheData);
                    yield break;
                }
            }

            // fetch the page data
            Result <DreamMessage> pageResponse;

            yield return(pageResponse = _deki
                                        .At("pages", pageId.ToString())
                                        .WithHeader("X-Deki-Site", "id=" + wikiId)
                                        .With("redirects", "0").GetAsync());

            if (!pageResponse.Value.IsSuccessful)
            {
                _log.WarnFormat("Unable to fetch page '{0}' info: {1}", pageId, pageResponse.Value.Status);
                result.Return((PageChangeCacheData)null);
                yield break;
            }
            XDoc   page          = pageResponse.Value.ToDocument();
            string title         = page["title"].AsText;
            XUri   pageUri       = page["uri.ui"].AsUri;
            string pageUriString = CleanUriForEmail(pageUri);
            string unsubUri      = CleanUriForEmail(pageUri
                                                    .WithoutPathQueryFragment()
                                                    .At("index.php")
                                                    .With("title", "Special:PageAlerts")
                                                    .With("id", pageId.ToString()));

            // fetch the revision history
            Result <DreamMessage> feedResponse;

            yield return(feedResponse = _deki
                                        .At("pages", pageId.ToString(), "feed")
                                        .WithHeader("X-Deki-Site", "id=" + wikiId)
                                        .With("redirects", "0")
                                        .With("format", "raw")
                                        .With("since", since)
                                        .GetAsync());

            if (!feedResponse.Value.IsSuccessful)
            {
                _log.WarnFormat("Unable to fetch page '{0}' changes: {1}", pageId, feedResponse.Value.Status);
                result.Return((PageChangeCacheData)null);
                yield break;
            }

            // build the docs
            XDoc feed = feedResponse.Value.ToDocument()["change"];

            if (feed.ListLength == 0)
            {
                _log.WarnFormat("Change feed is empty for page: {0}", pageId);
                result.Return((PageChangeCacheData)null);
                yield break;
            }
            string who    = feed["rc_user_name"].AsText;
            string whoUri = CleanUriForEmail(pageUri.WithoutPathQueryFragment().At(XUri.EncodeSegment("User:"******"rc_comment"].AsText;
                string revisionUri  = CleanUriForEmail(pageUri.With("revision", change["rc_revision"].AsText));
                who    = change["rc_user_name"].AsText;
                whoUri = CleanUriForEmail(pageUri.WithoutPathQueryFragment().At(XUri.EncodeSegment("User:"******"rc_timestamp"].AsText);
                cacheData.Items.Add(item);
            }
            lock (_cache) {
                // even though we override the entry if one was created in the meantime
                // we do the existence check so that we don't set up two expiration timers;
                if (!_cache.ContainsKey(key))
                {
                    _cacheItemCallback(key, () => {
                        lock (_cache) {
                            _cache.Remove(key);
                        }
                    });
                }
                _cache[key] = cacheData;
            }
            result.Return(cacheData);
            yield break;
        }
Пример #2
0
        //--- Methods ---
        public Yield GetPageData(uint pageId, string wikiId, DateTime time, CultureInfo culture, string timezone, Result <PageChangeData> result)
        {
            // Note (arnec): going back 10 seconds before event, because timestamps in a request are not currently synced
            Result <PageChangeCacheData> cacheResult;

            yield return(cacheResult = Coroutine.Invoke(GetCache, pageId, wikiId, time, culture, new Result <PageChangeCacheData>()));

            PageChangeCacheData cacheData = cacheResult.Value;

            if (cacheData == null)
            {
                result.Return((PageChangeData)null);
                yield break;
            }
            StringBuilder plainBody = new StringBuilder();

            plainBody.AppendFormat("{0}\r\n[ {1} ]\r\n\r\n", cacheData.Title, cacheData.PageUri);
            XDoc htmlBody = new XDoc("html")
                            .Start("p")
                            .Start("b")
                            .Start("a").Attr("href", cacheData.PageUri).Value(cacheData.Title).End()
                            .End()
                            .Value(" ( Last edited by ")
                            .Start("a").Attr("href", cacheData.WhoUri).Value(cacheData.Who).End()
                            .Value(" )")
                            .Elem("br")
                            .Start("small")
                            .Start("a").Attr("href", cacheData.PageUri).Value(cacheData.PageUri).End()
                            .End()
                            .Elem("br")
                            .Start("small")
                            .Start("a").Attr("href", cacheData.UnsubUri).Value("Unsubscribe").End()
                            .End()
                            .End()
                            .Start("p")
                            .Start("ol");
            string   tz       = "GMT";
            TimeSpan tzOffset = TimeSpan.Zero;

            if (!string.IsNullOrEmpty(timezone))
            {
                tz = timezone;
                string[] parts = timezone.Split(':');
                int      hours;
                int      minutes;
                int.TryParse(parts[0], out hours);
                int.TryParse(parts[1], out minutes);
                tzOffset = new TimeSpan(hours, minutes, 0);
            }
            foreach (PageChangeCacheData.Item item in cacheData.Items)
            {
                string t = item.Time.Add(tzOffset).ToString(string.Format("ddd, dd MMM yyyy HH':'mm':'ss '{0}'", tz), culture);
                plainBody.AppendFormat(" - {0} by {1} ({2})\r\n", item.ChangeDetail, item.Who, t);
                plainBody.AppendFormat("   [ {0} ]\r\n", item.RevisionUri);

                htmlBody.Start("li")
                .Value(item.ChangeDetail)
                .Value(" ( ")
                .Start("a").Attr("href", item.RevisionUri).Value(t).End()
                .Value(" by ")
                .Start("a").Attr("href", item.WhoUri).Value(item.Who).End()
                .Value(" )")
                .End();
                plainBody.Append("\r\n");
            }
            htmlBody
            .End()
            .End()
            .Elem("br");
            result.Return(new PageChangeData(plainBody.ToString(), htmlBody));
            yield break;
        }
        private Yield GetCache(uint pageId, string wikiId, DateTime time, CultureInfo culture, Result<PageChangeCacheData> result) {

            // Note (arnec): going back 10 seconds before event, because timestamps in a request are not currently synced
            string keytime = time.ToString("yyyyMMddHHmm");
            string since = time.Subtract(TimeSpan.FromSeconds(10)).ToString("yyyyMMddHHmmss");
            PageChangeCacheData cacheData;
            string key = string.Format("{0}:{1}:{2}:{3}", pageId, wikiId, keytime, culture);
            _log.DebugFormat("getting data for key: {0}", key);
            lock(_cache) {
                if(_cache.TryGetValue(key, out cacheData)) {
                    result.Return(cacheData);
                    yield break;
                }
            }

            // fetch the page data
            Result<DreamMessage> pageResponse;
            yield return pageResponse = _deki
                .At("pages", pageId.ToString())
                .WithHeader("X-Deki-Site", "id=" + wikiId)
                .With("redirects", "0").GetAsync();
            if(!pageResponse.Value.IsSuccessful) {
                _log.WarnFormat("Unable to fetch page '{0}' info: {1}", pageId, pageResponse.Value.Status);
                result.Return((PageChangeCacheData)null);
                yield break;
            }
            XDoc page = pageResponse.Value.ToDocument();
            string title = page["title"].AsText;
            XUri pageUri = page["uri.ui"].AsUri;
            string pageUriString = CleanUriForEmail(pageUri);
            string unsubUri = CleanUriForEmail(pageUri
                .WithoutPathQueryFragment()
                .At("index.php")
                .With("title", "Special:PageAlerts")
                .With("id", pageId.ToString()));

            // fetch the revision history
            Result<DreamMessage> feedResponse;
            yield return feedResponse = _deki
                .At("pages", pageId.ToString(), "feed")
                .WithHeader("X-Deki-Site", "id=" + wikiId)
                .With("redirects", "0")
                .With("format", "raw")
                .With("since", since)
                .GetAsync();
            if(!feedResponse.Value.IsSuccessful) {
                _log.WarnFormat("Unable to fetch page '{0}' changes: {1}", pageId, feedResponse.Value.Status);
                result.Return((PageChangeCacheData)null);
                yield break;
            }

            // build the docs
            XDoc feed = feedResponse.Value.ToDocument()["change"];
            if(feed.ListLength == 0) {
                _log.WarnFormat("Change feed is empty for page: {0}", pageId);
                result.Return((PageChangeCacheData)null);
                yield break;
            }
            string who = feed["rc_user_name"].AsText;
            string whoUri = CleanUriForEmail(pageUri.WithoutPathQueryFragment().At(XUri.EncodeSegment("User:"******"rc_comment"].AsText;
                string revisionUri = CleanUriForEmail(pageUri.With("revision", change["rc_revision"].AsText));
                who = change["rc_user_name"].AsText;
                whoUri = CleanUriForEmail(pageUri.WithoutPathQueryFragment().At(XUri.EncodeSegment("User:"******"rc_timestamp"].AsText);
                cacheData.Items.Add(item);
            }
            lock(_cache) {

                // even though we override the entry if one was created in the meantime
                // we do the existence check so that we don't set up two expiration timers;
                if(!_cache.ContainsKey(key)) {
                    _cacheItemCallback(key, () => {
                        lock(_cache) {
                            _cache.Remove(key);
                        }
                    });
                }
                _cache[key] = cacheData;
            }
            result.Return(cacheData);
            yield break;
        }