protected Yield PrologueDekiContext(DreamContext context, DreamMessage request, Result <DreamMessage> response) { // check if we need to skip this feature if (context.Feature.PathSegments.Length > 1 && context.Feature.PathSegments[context.Feature.ServiceUri.Segments.Length].StartsWith("@")) { response.Return(request); yield break; } if (context.Feature.Signature.StartsWithInvariantIgnoreCase("host") && !context.Feature.Signature.EqualsInvariantIgnoreCase("host/stop")) { // all host features except host/stop drop out before dekicontext so that there is no instance data response.Return(request); yield break; } var startInstanceIfNotRunning = true; if (context.Feature.Signature.StartsWithInvariantIgnoreCase("host/")) { startInstanceIfNotRunning = false; } // check if service has initialized if (!_isInitialized) { throw new DreamInternalErrorException("service not initialized"); } //Build the dekicontext out of current request details and info from this wiki instance's details DekiInstance instance = _instanceManager.GetWikiInstance(request, startInstanceIfNotRunning); if (instance == null && !startInstanceIfNotRunning) { _log.Debug("no instance found, and on a code path that functions without one"); response.Return(request); yield break; } // TODO (arnec): need to be able to get DreamContext.Current.StartTime injected into a feature signature var hostheader = request.Headers.Host ?? string.Empty; var dekiContext = new DekiContext(this, instance, hostheader, context.StartTime, ResourceManager); // Note (arnec): By attaching DekiContext to the current DreamContext we guarantee that it is disposed at the end of the request DreamContext.Current.SetState(dekiContext); // check if instance has already been initialized if (instance != null) { if (instance.Status == DekiInstanceStatus.CREATED) { bool created; try { lock (instance) { created = (instance.Status == DekiInstanceStatus.CREATED); if (created) { // initialize instance instance.Startup(dekiContext); } } // BUGBUGBUG (steveb): we startup the services AFTER the lock, because of race conditions, but this needs to be fixed if (created) { instance.StartServices(); } } catch (Exception e) { created = false; instance.StatusDescription = "Initialization exception: " + e.GetCoroutineStackTrace(); instance.Log.Error("Error initializing instance", e); } if (created) { // Note (arnec) this has to happen down here, since yield cannot exist inside a try/catch // send instance settings to mailer yield return(Coroutine.Invoke(ConfigureMailer, ConfigBL.GetInstanceSettingsAsDoc(false), new Result()).CatchAndLog(_log)); // check whether we have an index XDoc lucenestate = null; yield return(LuceneIndex.At("initstate").With("wikiid", instance.Id).Get(new Result <XDoc>()).Set(x => lucenestate = x)); // Note (arnec): defaulting to true, to avoid accidental re-index on false positive if (!(lucenestate["@exists"].AsBool ?? true)) { _log.DebugFormat("instance '{0}' doesn't have an index yet, forcing a rebuild", instance.Id); yield return(Self.At("site", "search", "rebuild").With("apikey", MasterApiKey).Post(new Result <DreamMessage>())); } } } if (instance.Status != DekiInstanceStatus.ABANDONED) { try { // force a state check to verify that license is good var state = dekiContext.LicenseManager.LicenseState; _log.DebugFormat("instance '{0}' license state: {1}", instance.Id, state); } catch (MindTouchRemoteLicenseFailedException) { _instanceManager.ShutdownCurrentInstance(); } } instance.CheckInstanceIsReady(); if (instance.Status == DekiInstanceStatus.ABANDONED) { //If instance was abandoned (failed to initialize), error out. throw new DreamInternalErrorException(string.Format("wiki '{0}' has failed to initialize or did not start up properly: {1}", instance.Id, instance.StatusDescription)); } if (instance.Status == DekiInstanceStatus.STOPPING) { throw new DreamInternalErrorException(string.Format("wiki '{0}' is currently shutting down", instance.Id)); } if (instance.Status == DekiInstanceStatus.STOPPED) { throw new DreamInternalErrorException(string.Format("wiki '{0}' has just shut down and may be restarted with a new request", instance.Id)); } // intialize culture/language + user if (context.Culture.IsNeutralCulture || context.Culture.Equals(System.Globalization.CultureInfo.InvariantCulture)) { try { context.Culture = new System.Globalization.CultureInfo(instance.SiteLanguage); } catch { // in case the site language is invalid, default to US English context.Culture = new System.Globalization.CultureInfo("en-US"); } } if (!context.Feature.Signature.EqualsInvariantIgnoreCase("users/authenticate")) { bool allowAnon = context.Uri.GetParam("authenticate", "false").EqualsInvariantIgnoreCase("false"); bool altPassword; SetContextAndAuthenticate(request, 0, false, allowAnon, false, out altPassword); } // TODO (steveb): we should update the culture based on the user's preferences } // continue processing response.Return(request); yield break; }