コード例 #1
0
        //--- Methods ---
        protected override Yield Start(XDoc config, 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));

            // resource manager for email template
            string 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");
                TestResourceSet testSet = new TestResourceSet();
                testSet.Add("Notification.Page.email-subject", "Page Modified");
                testSet.Add("Notification.Page.email-header", "The following pages have changed:");
                _resourceManager = new PlainTextResourceManager(testSet);
            }

            // get persisted subscription storage
            List<Tuplet<string, List<XDoc>>> allWikiSubs = new List<Tuplet<string, List<XDoc>>>();
            Result<DreamMessage> storageCatalog;
            yield return storageCatalog = Storage.At("subscriptions").GetAsync();
            foreach(XDoc wikiSubs in storageCatalog.Value.ToDocument()["folder/name"]) {
                string wikihost = wikiSubs.AsText;
                Tuplet<string, List<XDoc>> wikiDoc = new Tuplet<string, List<XDoc>>(wikihost, new List<XDoc>());
                allWikiSubs.Add(wikiDoc);
                Result<DreamMessage> wikiUsers;
                yield return wikiUsers = Storage.At("subscriptions", wikihost).GetAsync();
                foreach(XDoc userDocname in wikiUsers.Value.ToDocument()["file/name"]) {
                    string userFile = userDocname.AsText;
                    if(!userFile.EndsWith(".xml")) {
                        _log.WarnFormat("Found stray file '{0}' in wiki '{1}' store, ignoring", userFile, wikihost);
                        continue;
                    }
                    Result<DreamMessage> userDoc;
                    yield return userDoc = Storage.At("subscriptions", wikihost, userFile).GetAsync();
                    try {
                        wikiDoc.Item2.Add(userDoc.Value.ToDocument());
                    } catch(InvalidDataException e) {
                        _log.Error(string.Format("Unable to retrieve subscription store for user {0}/{1}", wikihost, userFile), e);
                    }
                }
            }
            _subscriptions = new SubscriptionManager(Self.Uri.AsServerUri().At("notify"), allWikiSubs);
            _subscriptions.RecordsChanged += PersistSubscriptions;
            _subscriptions.SubscriptionsChanged += PushSubscriptionSetUpstream;

            // set up subscription for pubsub
            _baseSubscriptionSet = 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();
            XDoc subSet = _baseSubscriptionSet.Clone();
            foreach(XDoc sub in _subscriptions.Subscriptions) {
                subSet.Add(sub);
            }
            Result<DreamMessage> subscribe;
            yield return subscribe = PubSub.At("subscribers").PostAsync(subSet);
            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();
        }
コード例 #2
0
        //--- 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();
        }
コード例 #3
0
        protected override Yield Start(XDoc config, IContainer container, Result result)
        {
            yield return(Coroutine.Invoke(base.Start, config, new Result()));

            // ensure imagemagick is setup correctly.
            if (string.IsNullOrEmpty(ImageMagickConvertPath))
            {
                throw new NotImplementedException("Please set 'imagemagick-convert-path' in config to path of ImageMagick's 'convert'");
            }
            if (!File.Exists(ImageMagickIdentifyPath))
            {
                throw new FileNotFoundException("Cannot find ImagicMagick 'identify' binary: ", ImageMagickIdentifyPath);
            }
            if (string.IsNullOrEmpty(ImageMagickIdentifyPath))
            {
                throw new NotImplementedException("Please set 'imagemagick-identify-path' in config to path of ImageMagick's 'identify'");
            }
            if (!File.Exists(ImageMagickConvertPath))
            {
                throw new FileNotFoundException("Cannot find ImagicMagick 'convert' binary: ", ImageMagickConvertPath);
            }

            // check for 'apikey'
            _apikey = Config["api-key"].AsText ?? Config["apikey"].AsText;
            if (string.IsNullOrEmpty(_apikey))
            {
                throw new ArgumentNullException("apikey", "The global apikey is not defined. Please ensure that you have a global <apikey> defined in the MindTouch Core service settings xml file.");
            }
            InitializeContainer(container);

            // intialize instance manager
            _instanceManager = InstanceManager.New(this, this.TimerFactory);

            // setup resource manager
            lock (SyncRoot) {
                if (ResourceManager == null)
                {
                    ResourceManager = new PlainTextResourceManager(ResourcesPath);
                    ScreenFont      = new DekiFont(Plug.New("resource://mindtouch.deki/MindTouch.Deki.Resources.Arial.mtdf").Get().AsBytes());
                }
            }

            // initialize scripting engine
            XDoc scripting = Config["scripting"];

            DekiScriptLibrary.InsertTextLimit = scripting["max-web-response-length"].AsLong ?? DekiScriptLibrary.InsertTextLimit;
            DekiScriptLibrary.MinCacheTtl     = scripting["min-web-cache-ttl"].AsDouble ?? DekiScriptLibrary.MinCacheTtl;

            // set up deki pub sub (by default we override uri.publish with our own service, unless @must-use=true is specified)
            if (!(Config["uri.publish/@must-use"].AsBool ?? false))
            {
                Result <Plug> pubsubResult;
                XDoc          pubsubConfig = new XDoc("config")
                                             .Elem("uri.deki", Self.Uri.With("apikey", MasterApiKey))
                                             .Start("downstream")
                                             .Elem("uri", PubSub.At("publish").Uri.WithoutLastSegment().At("subscribers"))
                                             .End()
                                             .Start("components")
                                             .Start("component")
                                             .Attr("type", typeof(IPubSubDispatcher).AssemblyQualifiedName)
                                             .Attr("implementation", typeof(DekiDispatcher).AssemblyQualifiedName)
                                             .End()
                                             .End()
                                             .Elem("authtoken", MasterApiKey);
                foreach (var cookie in Cookies.Fetch(PubSub.Uri))
                {
                    pubsubConfig.Add(cookie.AsSetCookieDocument);
                }
                var messageQueuePath = config["publish/queue-path"].AsText;
                if (!string.IsNullOrEmpty(messageQueuePath))
                {
                    pubsubConfig.Elem("queue-path", messageQueuePath);
                }
                yield return(pubsubResult = CreateService(
                                 "pubsub",
                                 "sid://mindtouch.com/dream/2008/10/pubsub",
                                 pubsubConfig,
                                 new Result <Plug>()));

                PubSub = pubsubResult.Value;
            }

            // set up package updater service (unless it was passed in)
            XUri packageUpdater;

            if (config["packageupdater/@uri"].IsEmpty)
            {
                var packageConfig = config["packageupdater"];
                packageConfig = packageConfig.IsEmpty ? new XDoc("config") : packageConfig.Clone();
                if (packageConfig["package-path"].IsEmpty)
                {
                    packageConfig.Elem("package-path", Path.Combine(Path.Combine(config["deki-path"].AsText, "packages"), "default"));
                }
                yield return(CreateService(
                                 "packageupdater",
                                 "sid://mindtouch.com/2010/04/packageupdater",
                                 new XDoc("config")
                                 .Elem("apikey", MasterApiKey)
                                 .AddNodes(packageConfig),
                                 new Result <Plug>()
                                 ));

                packageUpdater = Self.Uri.At("packageupdater");
            }
            else
            {
                packageUpdater = config["packageupdater/@uri"].AsUri;
            }
            _packageUpdater = Plug.New(packageUpdater);

            // set up emailer service (unless it was passed in)
            XUri mailerUri;

            if (config["uri.mailer"].IsEmpty)
            {
                yield return(CreateService(
                                 "mailer",
                                 "sid://mindtouch.com/2009/01/dream/email",
                                 new XDoc("config")
                                 .Elem("apikey", MasterApiKey)
                                 .AddAll(Config["smtp/*"]),
                                 new Result <Plug>()
                                 ));

                mailerUri = Self.Uri.At("mailer");
            }
            else
            {
                mailerUri = config["uri.mailer"].AsUri;
            }
            _mailer = Plug.New(mailerUri);

            // set up the email subscription service (unless it was passed in)
            XUri pageSubscription;

            if (config["uri.page-subscription"].IsEmpty)
            {
                XDoc pagesubserviceConfig = new XDoc("config")
                                            .Elem("uri.deki", Self.Uri)
                                            .Elem("uri.emailer", mailerUri.At("message"))
                                            .Elem("resources-path", ResourcesPath)
                                            .Elem("apikey", MasterApiKey)
                                            .Start("components")
                                            .Start("component")
                                            .Attr("scope", "factory")
                                            .Attr("type", typeof(IPageSubscriptionDataSessionFactory).AssemblyQualifiedName)
                                            .Attr("implementation", "MindTouch.Deki.Data.MySql.UserSubscription.MySqlPageSubscriptionSessionFactory, mindtouch.deki.data.mysql")
                                            .End()
                                            .End()
                                            .AddAll(Config["page-subscription/*"]);
                foreach (var cookie in Cookies.Fetch(mailerUri))
                {
                    pagesubserviceConfig.Add(cookie.AsSetCookieDocument);
                }
                yield return(CreateService(
                                 "pagesubservice",
                                 "sid://mindtouch.com/deki/2008/11/changesubscription",
                                 pagesubserviceConfig,
                                 new Result <Plug>()
                                 ));

                pageSubscription = Self.Uri.At("pagesubservice");
                config.Elem("uri.page-subscription", pageSubscription);
            }
            else
            {
                pageSubscription = config["uri.page-subscription"].AsUri;
            }
            _pageSubscription = Plug.New(pageSubscription);

            // set up package importer, if not provided
            if (Config["uri.package"].IsEmpty)
            {
                yield return(CreateService(
                                 "package",
                                 "sid://mindtouch.com/2009/07/package",
                                 new XDoc("config").Elem("uri.deki", Self.Uri),
                                 new Result <Plug>()));

                Config.Elem("uri.package", Self.Uri.At("package"));
            }

            // set up lucene
            _luceneIndex = Plug.New(Config["indexer/@src"].AsUri);
            if (_luceneIndex == null)
            {
                // create the indexer service
                XDoc luceneIndexConfig = new XDoc("config")
                                         .AddNodes(Config["indexer"])
                                         .Start("apikey").Attr("hidden", true).Value(MasterApiKey).End();
                if (luceneIndexConfig["path.store"].IsEmpty)
                {
                    luceneIndexConfig.Elem("path.store", Path.Combine(Path.Combine(config["deki-path"].AsText, "luceneindex"), "$1"));
                }
                yield return(CreateService("luceneindex", SID_FOR_LUCENE_INDEX, luceneIndexConfig, new Result <Plug>()).Set(v => _luceneIndex = v));

                _isLocalLuceneService = true;
            }
            else
            {
                // push our host's pubsub service to lucene, to keep it up to date on our changes
                var pubsub = new XDoc("pubsub").Attr("href", PubSub);
                foreach (var cookie in PubSub.CookieJar.Fetch(PubSub.Uri))
                {
                    pubsub.Add(cookie.AsSetCookieDocument);
                }
                yield return(_luceneIndex.At("subscriptions").PostAsync(pubsub));
            }

            // configure indexing whitelist
            _indexNamespaceWhitelist = new[] { NS.MAIN, NS.PROJECT, NS.USER, NS.TEMPLATE, NS.HELP, NS.MAIN_TALK, NS.PROJECT_TALK, NS.USER_TALK, NS.TEMPLATE_TALK, NS.HELP_TALK, NS.SPECIAL, NS.SPECIAL_TALK };
            if (!string.IsNullOrEmpty(Config["indexer/namespace-whitelist"].AsText))
            {
                List <NS> customWhitelist = new List <NS>();
                foreach (string item in Config["indexer/namespace-whitelist"].AsText.Split(','))
                {
                    NS ns;
                    if (SysUtil.TryParseEnum(item, out ns))
                    {
                        customWhitelist.Add(ns);
                    }
                }
                _indexNamespaceWhitelist = customWhitelist.ToArray();
            }

            if (!Config["wikis/globalconfig/cache/varnish"].IsEmpty)
            {
                // create the varnish service

                // TODO (petee): getting the varnish config from wikis/globalconfig/cache is a hack
                // The frontend needs to get the max-age to send out the cache headers but we currently have no way
                // of getting the DekiWikiService config so we'll hack it so it comes back in GET:site/settings.
                XDoc varnishConfig = new XDoc("config")
                                     .Elem("uri.deki", Self.Uri.With("apikey", MasterApiKey))
                                     .Elem("uri.varnish", Config["wikis/globalconfig/cache/varnish"].AsUri)
                                     .Elem("varnish-purge-delay", Config["wikis/globalconfig/cache/varnish-purge-delay"].AsInt ?? 10)
                                     .Elem("varnish-max-age", Config["wikis/globalconfig/cache/varnish-max-age"].AsInt ?? 300)
                                     .Start("apikey").Attr("hidden", true).Value(MasterApiKey).End();
                yield return(CreateService("varnish", SID_FOR_VARNISH_SERVICE, varnishConfig, new Result <Plug>()));
            }
            _isInitialized = true;
            result.Return();
        }
コード例 #4
0
        //--- 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();
        }