//--- Constructors --- protected AttachmentBL() { _dekiContext = DekiContext.Current; _session = DbUtils.CurrentSession; _resources = _dekiContext.Resources; _resourceBL = ResourceBL.Instance; }
protected virtual void ShutdownInstance(string wikiid, DekiInstance instance) { lock (instance) { _log.DebugFormat("shutting down instance '{0}'", wikiid); var context = DreamContext.Current; var currentDekiContext = context.GetState <DekiContext>(); DekiContext tempDekiContext = null; try { if (currentDekiContext == null || currentDekiContext.Instance.Id != wikiid) { _log.DebugFormat("creating temp deki context for shutdown of instance '{0}'", wikiid); // Note (arnec): the host header is only used for logging in the Epilogue which will never be invoked // by this temporary dekicontext var hostheader = wikiid + "-notused"; tempDekiContext = new DekiContext(_dekiService, instance, hostheader, context.StartTime, DekiWikiService.ResourceManager); context.SetState(tempDekiContext); } instance.EndShutdown(); } finally { if (tempDekiContext != null) { tempDekiContext.Dispose(); } context.SetState(currentDekiContext); } } }
public TagBL() { _dekiContext = DekiContext.Current; _session = DbUtils.CurrentSession; _user = _dekiContext.User; _eventSink = _dekiContext.Instance.EventSink; _culture = DreamContext.Current.Culture; }
private static XDoc BuildHtmlSiteMap(PageBE current, XDoc doc, Dictionary <ulong, PageBE> allowedPagesById, Dictionary <ulong, PageBE> filteredPagesById, int depth, bool reverse) { doc.Start("li"); string uri = Utils.AsPublicUiUri(current.Title); List <string> classValues = new List <string>(); if (filteredPagesById.ContainsKey(current.ID)) { classValues.Add("statusRestricted"); } if (current.ID == DekiContext.Current.Instance.HomePageId) { classValues.Add("statusHome"); } doc.Start("a").Attr("rel", "internal").Attr("href", uri).Attr("title", current.Title.AsPrefixedUserFriendlyPath()).Attr("pageid", current.ID); if (classValues.Count > 0) { doc.Attr("class", string.Join(" ", classValues.ToArray())); } doc.Value(current.Title.AsUserFriendlyName()).End(); if (depth > 0 && !ArrayUtil.IsNullOrEmpty(current.ChildPages)) { PageBE[] visibleChildren = Array.FindAll(current.ChildPages, delegate(PageBE child) { return(allowedPagesById.ContainsKey(child.ID)); }); DreamContext context = DreamContext.CurrentOrNull; if (context != null) { DekiContext deki = DekiContext.CurrentOrNull; CultureInfo culture = HttpUtil.GetCultureInfoFromHeader(current.Language ?? ((deki != null) ? deki.Instance.SiteLanguage : string.Empty), context.Culture); string[] paths = new string[visibleChildren.Length]; for (int i = 0; i < visibleChildren.Length; ++i) { paths[i] = XUri.Decode(visibleChildren[i].Title.AsPrefixedDbPath()).Replace("//", "\uFFEF").Replace("/", "\t"); } Array.Sort(paths, visibleChildren, new CompareInfoComparer(culture.CompareInfo)); } if (visibleChildren.Length > 0) { doc.Start("ul"); if (reverse) { Array.Reverse(visibleChildren); } foreach (PageBE p in visibleChildren) { doc = BuildHtmlSiteMap(p, doc, allowedPagesById, filteredPagesById, depth - 1, reverse); } doc.End(); } } doc.End(); return(doc); }
private static ServiceBE StopService(uint serviceId, ServiceBE service, ServiceStopType stopType) { if (IsLocalAuthService(serviceId)) { return(service); } DekiContext context = DekiContext.Current; bool saveBe = false; if (service != null && service.ServiceLocal) { // local services should have their uri cleared out _log.DebugFormat("stopping service '{0}'", service.SID); service.Uri = null; saveBe = true; } if (service != null && stopType == ServiceStopType.Disable) { // wipe out last error on disable service.ServiceLastStatus = null; saveBe = true; } var serviceInfo = context.Instance.RunningServices[serviceId]; if (serviceInfo == null) { if (saveBe) { service = UpdateService(service) ?? service; } // service is not registered as running, we're done here return(service); } try { context.Instance.DeregisterService(serviceId); } catch (Exception e) { // log the error, but ignore it otherwise if (service == null) { context.Instance.Log.WarnExceptionMethodCall(e, "StopService", string.Format("Unable to stop {0} service id '{1}'", serviceInfo.IsLocal ? "local" : "remote", serviceId)); } else { context.Instance.Log.WarnExceptionMethodCall(e, "StopService", string.Format("Unable to stop {0} service id '{1}' with SID '{2}'", serviceInfo.IsLocal ? "local" : "remote", serviceId, service.SID)); } } if (service != null && (stopType == ServiceStopType.Disable || saveBe)) { service.ServiceEnabled = (stopType != ServiceStopType.Disable); service = UpdateService(service) ?? service; } return(service); }
private static bool ValidateImpersonationToken(DekiContext context, Token token) { if (token.Timestamp < DateTime.UtcNow.Subtract(1.Minutes())) { return(false); } var userToken = string.IsNullOrEmpty(token.Username) ? token.UserId.ToString() : token.Username; var valid = false; if (!string.IsNullOrEmpty(context.Instance.ApiKey)) { valid = token.Hash.Equals(StringUtil.ComputeHashString(userToken + ":" + token.Timestamp.ToEpoch() + ":" + context.Instance.ApiKey, Encoding.UTF8)); } if (!valid) { valid = token.Hash.Equals(StringUtil.ComputeHashString(userToken + ":" + token.Timestamp.ToEpoch() + ":" + context.Deki.MasterApiKey, Encoding.UTF8)); } return(valid); }
public static void InitializeCustomDekiScriptHeaders(PageBE page) { var current = DreamContext.Current; DekiScriptMap env = current.GetState <DekiScriptMap>("pageimplicitenv-" + page.ID); // check if we already have an initialized environment if (env == null) { DekiContext deki = DekiContext.Current; DekiInstance instance = deki.Instance; env = new DekiScriptMap(); // add site fields DekiScriptMap siteFields = new DekiScriptMap(); siteFields.Add("name", DekiScriptExpression.Constant(instance.SiteName)); siteFields.Add("host", DekiScriptExpression.Constant(deki.UiUri.Uri.Host)); siteFields.Add("language", DekiScriptExpression.Constant(instance.SiteLanguage)); siteFields.Add("uri", DekiScriptExpression.Constant(deki.UiUri.Uri.ToString())); siteFields.Add("id", DekiScriptExpression.Constant(instance.Id)); env.Add("site", siteFields); // add page fields DekiScriptMap pageFields = new DekiScriptMap(); pageFields.Add("title", DekiScriptExpression.Constant(page.Title.AsUserFriendlyName())); pageFields.Add("path", DekiScriptExpression.Constant(page.Title.AsPrefixedDbPath())); pageFields.Add("namespace", DekiScriptExpression.Constant(Title.NSToString(page.Title.Namespace))); pageFields.Add("id", DekiScriptExpression.Constant(page.ID.ToString())); pageFields.Add("uri", DekiScriptExpression.Constant(Utils.AsPublicUiUri(page.Title))); pageFields.Add("date", DekiScriptExpression.Constant(page.TimeStamp.ToString("R"))); pageFields.Add("language", DekiScriptExpression.Constant(string.IsNullOrEmpty(page.Language) ? null : page.Language)); env.Add("page", pageFields); // add user fields DekiScriptMap userFields = new DekiScriptMap(); if (deki.User != null) { UserBE user = deki.User; userFields.Add("id", DekiScriptExpression.Constant(user.ID.ToString())); userFields.Add("name", DekiScriptExpression.Constant(user.Name)); userFields.Add("uri", DekiScriptExpression.Constant(Utils.AsPublicUiUri(Title.FromDbPath(NS.USER, user.Name, null)))); userFields.Add("emailhash", DekiScriptExpression.Constant(StringUtil.ComputeHashString((user.Email ?? string.Empty).Trim().ToLowerInvariant(), Encoding.UTF8))); userFields.Add("anonymous", DekiScriptExpression.Constant(UserBL.IsAnonymous(user).ToString().ToLowerInvariant())); userFields.Add("language", DekiScriptExpression.Constant(string.IsNullOrEmpty(user.Language) ? null : user.Language)); } else { userFields.Add("id", DekiScriptExpression.Constant("0")); userFields.Add("name", DekiScriptExpression.Constant(string.Empty)); userFields.Add("uri", DekiScriptExpression.Constant(string.Empty)); userFields.Add("emailhash", DekiScriptExpression.Constant(string.Empty)); userFields.Add("anonymous", DekiScriptExpression.Constant("true")); userFields.Add("language", DekiScriptNil.Value); } env.Add("user", userFields); // store env for later current.SetState("pageimplicitenv-" + page.ID, env); } // set implicit environment DreamContext.Current.SetState(env); }
private DreamMessage PreProcessRequest(string verb, XUri uri, XUri normalizedUri, DreamMessage message) { DreamContext current = DreamContext.Current; DekiContext deki = DekiContext.Current; DekiInstance instance = deki.Instance; // set preferred culture message.Headers.AcceptLanguage = string.Format("{0}, *;q=0.5", current.Culture.Name); // add the 'deki' header message.Headers[DekiExtService.DEKI_HEADER] = instance.Token; // convert implicit environment into a message headers DekiScriptMap implicitEnv = DreamContext.Current.GetState <DekiScriptMap>(); if (implicitEnv != null) { foreach (KeyValuePair <string, DekiScriptLiteral> outer in implicitEnv.Value) { DekiScriptMap map = outer.Value as DekiScriptMap; if ((map != null) && !map.IsEmpty) { StringBuilder header = new StringBuilder(); foreach (KeyValuePair <string, DekiScriptLiteral> inner in map.Value) { string value = inner.Value.AsString(); if (value != null) { if (header.Length > 0) { header.Append(", "); } header.AppendFormat("{0}.{1}={2}", outer.Key, inner.Key, value.QuoteString()); } } // add header string headerValue = header.ToString(); message.Headers.Add(DekiExtService.IMPLICIT_ENVIRONMENT_HEADER, headerValue); } } } // add digital signature DSACryptoServiceProvider dsa = instance.PrivateDigitalSignature; if (dsa != null) { MemoryStream data = new MemoryStream(); // get message bytes byte[] bytes = message.AsBytes(); data.Write(bytes, 0, bytes.Length); // retrieve headers to sign string[] headers = message.Headers.GetValues(DekiExtService.IMPLICIT_ENVIRONMENT_HEADER); if (!ArrayUtil.IsNullOrEmpty(headers)) { Array.Sort(headers, StringComparer.Ordinal); bytes = Encoding.UTF8.GetBytes(string.Join(",", headers)); data.Write(bytes, 0, bytes.Length); } // add request date string date = DateTime.UtcNow.ToString(XDoc.RFC_DATETIME_FORMAT); bytes = Encoding.UTF8.GetBytes(date); data.Write(bytes, 0, bytes.Length); // sign data byte[] signature = dsa.SignData(data.GetBuffer()); message.Headers.Add(DekiExtService.IMPLICIT_SIGNATURE_HEADER, string.Format("dsig=\"{0}\", date=\"{1}\"", Convert.ToBase64String(signature), date)); } return(message); }
protected virtual void ShutdownInstance(string wikiid, DekiInstance instance) { if(instance.Status == DekiInstanceStatus.RUNNING) { DekiContext dekiContext = new DekiContext(_dekiService, instance, DreamContext.Current.Request); DreamContext.Current.SetState<DekiContext>(dekiContext); lock(instance) { instance.Shutdown(); } } }
//--- Class Methods --- public static ServiceBE StartService(ServiceBE service, bool forceRefresh, bool disableOnFailure) { // create subordinate request id for service start var dreamContext = DreamContext.Current; var requestId = dreamContext.GetState <string>(DreamHeaders.DREAM_REQUEST_ID); dreamContext.SetState(DreamHeaders.DREAM_REQUEST_ID, requestId + "-service_" + service.Id); try { var stopwatch = Stopwatch.StartNew(); service.ServiceLastStatus = string.Empty; StopService(service.Id, service, ServiceStopType.Restart); DekiContext context = DekiContext.Current; bool dirtyServiceEntity = false; XUri location; ServiceRepository.IServiceInfo serviceInfo = null; try { // check if service is local if (service.ServiceLocal) { if (string.IsNullOrEmpty(service.SID)) { throw new Exception("missing SID"); } // start service if (IsLocalAuthService(service)) { // this service is the built-in authentication provider; no need to start it location = context.Deki.Self; } else { // convert local service configuration into an xdoc XDoc config = new XDoc("config"); foreach (KeyValuePair <string, string> configEntry in ArrayUtil.AllKeyValues(service.Config)) { config.InsertValueAt(configEntry.Key, configEntry.Value); } // if no apikey was provided, create a random one so that CreateService doesn't inject the parent one if (config["apikey"].IsEmpty) { config.Elem("apikey", StringUtil.CreateAlphaNumericKey(16)); } // add information for service to callback into deki if (config["uri.deki"].IsEmpty) { config.Elem("uri.deki", context.Deki.Self); config.Elem("wikiid.deki", context.Instance.Id); // Providing master apikey to service for setups that don't use per instance keys config.Elem("apikey.deki", context.Instance.ApiKey.IfNullOrEmpty(context.Deki.MasterApiKey)); } // the service location must use the service ID and the instance ID string servicePath = string.Format("services/{0}/{1}", context.Instance.Id, service.Id); _log.DebugFormat("starting service '{0}' at path {1} w/ namespace {2}", service.SID, servicePath, service.Preferences["namespace"]); serviceInfo = context.Instance.CreateLocalService(service, servicePath, config); location = serviceInfo.ServiceUri; } // check if the service uri has changed since last invocation (happens when service is started for the first time or server GUID has changed) if (!service.Uri.EqualsInvariantIgnoreCase(location.ToString())) { dirtyServiceEntity = true; service.Uri = location.ToString(); } } else { _log.DebugFormat("registering remote service '{0}'", service.SID); if (string.IsNullOrEmpty(service.Uri)) { throw new Exception("missing URI"); } location = new XUri(service.Uri); serviceInfo = context.Instance.RegisterRemoteService(service, location); } // check if service is an Extension service if (service.Type == ServiceType.EXT) { if (service.ServiceLocal) { _log.DebugFormat("registering service '{0}' as extension", service.SID); } ExtensionBL.StartExtensionService(context, service, serviceInfo, forceRefresh); } //Successfully starting a service enables it. if (!service.ServiceEnabled) { dirtyServiceEntity = true; service.ServiceEnabled = true; } } catch (Exception e) { dirtyServiceEntity = true; DreamMessage dm = null; if (e is DreamResponseException) { dm = ((DreamResponseException)e).Response; string message = dm.HasDocument ? dm.ToDocument()[".//message"].AsText.IfNullOrEmpty(e.Message) : dm.ToText(); service.ServiceLastStatus = string.Format("unable to initialize service ({0})", message); } else { service.ServiceLastStatus = e.GetCoroutineStackTrace(); } if (serviceInfo != null) { try { context.Instance.DeregisterService(service.Id); } catch { } } // A service that fails to start becomes disabled if it's started explicitly (not during deki startup) if (disableOnFailure) { service.ServiceEnabled = false; } _log.ErrorExceptionMethodCall(e, "StartService", string.Format("Unable to start local service id '{0}' with SID '{1}' Error: '{2}'", service.Id, service.SID, service.ServiceLastStatus)); if (dm != null) { throw new ExternalServiceResponseException(dm); } else { throw; } } finally { // don't update remote services that haven't changed if (dirtyServiceEntity) { service = UpdateService(service); } } stopwatch.Stop(); _log.InfoFormat("Service '{0}' ({1}) started in {2}ms", service.Description, service.SID, stopwatch.ElapsedMilliseconds); return(service); } finally { // restore the request id dreamContext.SetState(DreamHeaders.DREAM_REQUEST_ID, requestId); } }
//--- Class Methods --- public static void StartExtensionService(DekiContext context, ServiceBE service, ServiceRepository.IServiceInfo serviceInfo, bool forceRefresh) { // retrieve document describing the extension functions XUri uri = new XUri(service.Uri); XDoc manifest = null; DekiWikiService deki = context.Deki; var extension = serviceInfo.Extension; if(!service.ServiceLocal) { lock(deki.RemoteExtensionLibraries) { deki.RemoteExtensionLibraries.TryGetValue(uri, out manifest); } } if(manifest == null || forceRefresh) { manifest = Plug.New(uri).Get().ToDocument(); // normalize the extension XML manifest = manifest.TransformAsXml(_extensionConverterXslt); // check if document describes a valid extension: either the extension has no functions, or the functions have end-points if(manifest.HasName("extension") && ((manifest["function"].ListLength == 0) || (manifest["function/uri"].ListLength > 0))) { // add source uri for service manifest.Attr("uri", uri); // register service in extension list lock(deki.RemoteExtensionLibraries) { deki.RemoteExtensionLibraries[uri] = manifest; } } else { throw new ExtensionRemoveServiceInvalidOperationException(uri); } } extension.Manifest = manifest; // add function prefix if one is defined serviceInfo.Extension.SetPreference("namespace.custom", service.Preferences["namespace"]); string serviceNamespace = service.Preferences["namespace"] ?? manifest["namespace"].AsText; if(serviceNamespace != null) { serviceNamespace = serviceNamespace.Trim(); if(string.IsNullOrEmpty(serviceInfo.Namespace)) { // Note (arnec): Namespace from preferences is assigned at service creation. If we do not have one at this // point, it came from the extension manifest and needs to be registered as our default. Otherwise the // preference override persists as the namespace. context.Instance.RunningServices.RegisterNamespace(serviceInfo, serviceNamespace); } if(serviceNamespace.Length != 0) { if(!DekiScriptParser.IsIdentifier(serviceNamespace)) { throw new ExtensionNamespaceInvalidArgumentException(service.Preferences["namespace"] ?? manifest["namespace"].AsText); } } else { serviceNamespace = null; } } serviceNamespace = (serviceNamespace == null) ? string.Empty : (serviceNamespace + "."); // add custom library title extension.SetPreference("title.custom", service.Preferences["title"]); extension.SetPreference("label.custom", service.Preferences["label"]); extension.SetPreference("description.custom", service.Preferences["description"]); extension.SetPreference("uri.logo.custom", service.Preferences["uri.logo"]); extension.SetPreference("functions", service.Preferences["functions"]); extension.SetPreference("protected", service.Preferences["protected"]); // add each extension function bool.TryParse(service.Preferences["protected"], out extension.IsProtected); var functions = new List<ServiceRepository.ExtensionFunctionInfo>(); foreach(XDoc function in manifest["function"]) { XUri functionUri = function["uri"].AsUri; if(functionUri != null) { functions.Add(new ServiceRepository.ExtensionFunctionInfo(serviceNamespace + function["name"].Contents, functionUri)); } } extension.Functions = functions.ToArray(); }
private static bool ValidateImpersonationToken(DekiContext context, Token token) { if(token.Timestamp < DateTime.UtcNow.Subtract(1.Minutes())) { return false; } var userToken = string.IsNullOrEmpty(token.Username) ? token.UserId.ToString() : token.Username; var valid = false; if(!string.IsNullOrEmpty(context.Instance.ApiKey)) { valid = token.Hash.Equals(StringUtil.ComputeHashString(userToken + ":" + token.Timestamp.ToEpoch() + ":" + context.Instance.ApiKey, Encoding.UTF8)); } if(!valid) { valid = token.Hash.Equals(StringUtil.ComputeHashString(userToken + ":" + token.Timestamp.ToEpoch() + ":" + context.Deki.MasterApiKey, Encoding.UTF8)); } return valid; }
//--- Class Methods --- internal static void Log(TimeSpan elapsed, PageBE basePage, DekiContext context, IDekiDataSession session) { _log.WarnFormat("slow page render for: {0}\n{1}", basePage.Title.AsPrefixedDbPath().IfNullOrEmpty("_homepage_"), CreateProfilerDoc(elapsed, basePage, context, session).ToPrettyString()); }
public static DekiScriptEnv CreateEnvironment(PageBE page) { DekiScriptEnv commonEnv = DekiContext.Current.Instance.CreateEnvironment(); // need to strip the config value back out for Deki commonEnv.Vars["config"] = new DekiScriptMap(); // initialize environment DekiScriptEnv env = commonEnv; DekiContext deki = DekiContext.Current; DekiInstance instance = deki.Instance; // add site variables env.Vars.AddNativeValueAt("site.name", instance.SiteName); env.Vars.AddNativeValueAt("site.hostname", deki.UiUri.Uri.HostPort); env.Vars.AddNativeValueAt("site.api", deki.ApiUri.SchemeHostPortPath); env.Vars.AddNativeValueAt("site.language", instance.SiteLanguage); env.Vars.AddNativeValueAt("site.uri", deki.UiUri.Uri.ToString()); env.Vars.AddNativeValueAt("site.pagecount", deki.Deki.PropertyAt("$sitepagecount")); env.Vars.AddNativeValueAt("site.usercount", deki.Deki.PropertyAt("$siteusercount")); env.Vars.AddNativeValueAt("site.homepage", deki.Deki.PropertyAt("$page", DekiContext.Current.Instance.HomePageId, true)); env.Vars.AddNativeValueAt("site.feed", deki.ApiUri.At("site", "feed").ToString()); env.Vars.AddNativeValueAt("site.tags", deki.Deki.PropertyAt("$sitetags")); env.Vars.AddNativeValueAt("site.users", deki.Deki.PropertyAt("$siteusers")); env.Vars.AddNativeValueAt("site.id", DekiScriptExpression.Constant(instance.Id)); env.Vars.AddNativeValueAt("site.timezone", DekiScriptExpression.Constant(instance.SiteTimezone)); // add page variables env.Vars.Add("page", deki.Deki.PropertyAt("$page", page.ID, true)); // add user variables env.Vars.Add("user", deki.Deki.PropertyAt("$user", (deki.User != null) ? deki.User.ID : 0)); // add instance functions & properties bool hasUnsafeContentPermission = DekiXmlParser.PageAuthorCanExecute(); foreach (var service in instance.RunningServices.ExtensionServices) { if (service != null) { var extension = service.Extension; if (extension != null) { if (hasUnsafeContentPermission || !extension.IsProtected) { var functions = extension.Functions; if (functions != null) { foreach (var function in functions) { env.Vars.AddNativeValueAt(function.Name.ToLowerInvariant(), function.Uri); } } else { _log.WarnFormat("CreateEnvironment - null functions (id: {0})", service.ServiceId); } } } else { _log.WarnFormat("CreateEnvironment - null extension (id: {0})", service.ServiceId); } } else { _log.Warn("CreateEnvironment - null service"); } } return(env); }
internal static XDoc CreateProfilerDoc(TimeSpan elapsed, PageBE basePage, DekiContext context, IDekiDataSession session) { var profiler = new XDoc("profiler") .Attr("elapsed", elapsed.TotalSeconds.ToString("###,0.00##")) .Attr("id", context.Instance.Id) .Attr("path", basePage.Title.AsPrefixedDbPath()); var history = DekiXmlParser.GetParseState().ProfilerHistory; // show profiling for rendered pages profiler.Start("rendered-content"); foreach(var pageHistory in history) { profiler.Start("page") .Attr("wikiid", pageHistory.PageId) .Attr("path", pageHistory.PagePath) .Attr("elapsed", pageHistory.Elapsed.TotalSeconds.ToString("###,0.00##")) .Attr("mode", pageHistory.Mode.ToString().ToLowerInvariant()); foreach(var functionHistory in from function in pageHistory.Functions group function by function.Location into functionByLocation select new { Function = functionByLocation.First(), Count = functionByLocation.Count(), TotalSeconds = functionByLocation.Sum(f => f.Elapsed.TotalSeconds) } ) { profiler.Start("function") .Attr("name", functionHistory.Function.FunctionName) .Attr("elapsed", functionHistory.TotalSeconds.ToString("###,0.00##")) .Attr("count", functionHistory.Count) .Attr("location", functionHistory.Function.Location) .End(); } profiler.End(); } profiler.End(); // show summary for function profiling profiler.Start("functions-summary"); foreach(var functionHistory in from pageHistory in history from function in pageHistory.Functions group function by function.FunctionName into functionByName let totalSeconds = functionByName.Sum(f => f.Elapsed.TotalSeconds) orderby totalSeconds descending select new { Function = functionByName.First(), Count = functionByName.Count(), TotalSeconds = totalSeconds, MaxSeconds = functionByName.Max(f => f.Elapsed.TotalSeconds) } ) { profiler.Start("function") .Attr("name", functionHistory.Function.FunctionName) .Attr("elapsed", functionHistory.TotalSeconds.ToString("###,0.00##")) .Attr("average", (functionHistory.TotalSeconds / functionHistory.Count).ToString("###,0.00##")) .Attr("max", functionHistory.MaxSeconds.ToString("###,0.00##")) .Attr("count", functionHistory.Count) .End(); } profiler.End(); // show summary for page profiling profiler.Start("pages-summary"); foreach(var pageHistory in from page in history group page by page.PageId.ToString() + page.Mode into pageByIdAndMode let totalSeconds = pageByIdAndMode.Sum(p => p.Elapsed.TotalSeconds) orderby totalSeconds descending select new { Page = pageByIdAndMode.First(), Count = pageByIdAndMode.Count(), TotalSeconds = totalSeconds, MaxSeconds = pageByIdAndMode.Max(p => p.Elapsed.TotalSeconds) } ) { profiler.Start("page") .Attr("id", pageHistory.Page.PageId) .Attr("path", pageHistory.Page.PagePath) .Attr("elapsed", pageHistory.TotalSeconds.ToString("###,0.00##")) .Attr("average", (pageHistory.TotalSeconds / pageHistory.Count).ToString("###,0.00##")) .Attr("max", pageHistory.MaxSeconds.ToString("###,0.00##")) .Attr("count", pageHistory.Count) .Attr("mode", pageHistory.Page.Mode.ToString().ToLowerInvariant()) .End(); } profiler.End(); // show summary for query operations var dbprofiler = GetSessionProfiler(session); if(dbprofiler != null) { var dbhistory = dbprofiler.History; profiler.Start("db-summary") .Attr("elapsed", dbhistory.Sum(p => p.Elapsed.TotalSeconds).ToString("###,0.00##")) .Attr("count", dbhistory.Count); foreach(var dbsummary in from dbentry in dbhistory group dbentry by dbentry.Function into dbentryByName let totalSeconds = dbentryByName.Sum(f => f.Elapsed.TotalSeconds) orderby totalSeconds descending select new { Query = dbentryByName.First(), Count = dbentryByName.Count(), TotalSeconds = totalSeconds, MaxSeconds = dbentryByName.Max(f => f.Elapsed.TotalSeconds) } ) { profiler.Start("query") .Attr("name", dbsummary.Query.Function) .Attr("elapsed", dbsummary.TotalSeconds.ToString("###,0.00##")) .Attr("average", (dbsummary.TotalSeconds / dbsummary.Count).ToString("###,0.00##")) .Attr("max", dbsummary.MaxSeconds.ToString("###,0.00##")) .Attr("count", dbsummary.Count) .End(); } profiler.End(); } // add data stats Dictionary<string, string> stats; var sessionStats = session as IDekiDataStats; if(sessionStats != null) { profiler.Start("data-stats"); stats = sessionStats.GetStats(); if(stats != null) { foreach(var pair in stats) { profiler.Start("entry").Attr("name", pair.Key).Attr("value", pair.Value).End(); } } profiler.End(); } // add misc. statistics stats = DekiContext.Current.Stats; if(stats.Count > 0) { profiler.Start("misc-stats"); foreach(var pair in stats) { profiler.Start("entry").Attr("name", pair.Key).Attr("value", pair.Value).End(); } profiler.End(); } return profiler; }
internal static XDoc CreateProfilerDoc(TimeSpan elapsed, PageBE basePage, DekiContext context, IDekiDataSession session) { var profiler = new XDoc("profiler") .Attr("elapsed", elapsed.TotalSeconds.ToString("###,0.00##")) .Attr("id", context.Instance.Id) .Attr("path", basePage.Title.AsPrefixedDbPath()); var history = DekiXmlParser.GetParseState().ProfilerHistory; // show profiling for rendered pages profiler.Start("rendered-content"); foreach (var pageHistory in history) { profiler.Start("page") .Attr("wikiid", pageHistory.PageId) .Attr("path", pageHistory.PagePath) .Attr("elapsed", pageHistory.Elapsed.TotalSeconds.ToString("###,0.00##")) .Attr("mode", pageHistory.Mode.ToString().ToLowerInvariant()); foreach (var functionHistory in from function in pageHistory.Functions group function by function.Location into functionByLocation select new { Function = functionByLocation.First(), Count = functionByLocation.Count(), TotalSeconds = functionByLocation.Sum(f => f.Elapsed.TotalSeconds) } ) { profiler.Start("function") .Attr("name", functionHistory.Function.FunctionName) .Attr("elapsed", functionHistory.TotalSeconds.ToString("###,0.00##")) .Attr("count", functionHistory.Count) .Attr("location", functionHistory.Function.Location) .End(); } profiler.End(); } profiler.End(); // show summary for function profiling profiler.Start("functions-summary"); foreach (var functionHistory in from pageHistory in history from function in pageHistory.Functions group function by function.FunctionName into functionByName let totalSeconds = functionByName.Sum(f => f.Elapsed.TotalSeconds) orderby totalSeconds descending select new { Function = functionByName.First(), Count = functionByName.Count(), TotalSeconds = totalSeconds, MaxSeconds = functionByName.Max(f => f.Elapsed.TotalSeconds) } ) { profiler.Start("function") .Attr("name", functionHistory.Function.FunctionName) .Attr("elapsed", functionHistory.TotalSeconds.ToString("###,0.00##")) .Attr("average", (functionHistory.TotalSeconds / functionHistory.Count).ToString("###,0.00##")) .Attr("max", functionHistory.MaxSeconds.ToString("###,0.00##")) .Attr("count", functionHistory.Count) .End(); } profiler.End(); // show summary for page profiling profiler.Start("pages-summary"); foreach (var pageHistory in from page in history group page by page.PageId.ToString() + page.Mode into pageByIdAndMode let totalSeconds = pageByIdAndMode.Sum(p => p.Elapsed.TotalSeconds) orderby totalSeconds descending select new { Page = pageByIdAndMode.First(), Count = pageByIdAndMode.Count(), TotalSeconds = totalSeconds, MaxSeconds = pageByIdAndMode.Max(p => p.Elapsed.TotalSeconds) } ) { profiler.Start("page") .Attr("id", pageHistory.Page.PageId) .Attr("path", pageHistory.Page.PagePath) .Attr("elapsed", pageHistory.TotalSeconds.ToString("###,0.00##")) .Attr("average", (pageHistory.TotalSeconds / pageHistory.Count).ToString("###,0.00##")) .Attr("max", pageHistory.MaxSeconds.ToString("###,0.00##")) .Attr("count", pageHistory.Count) .Attr("mode", pageHistory.Page.Mode.ToString().ToLowerInvariant()) .End(); } profiler.End(); // show summary for query operations var dbprofiler = GetSessionProfiler(session); if (dbprofiler != null) { var dbhistory = dbprofiler.History; profiler.Start("db-summary") .Attr("elapsed", dbhistory.Sum(p => p.Elapsed.TotalSeconds).ToString("###,0.00##")) .Attr("count", dbhistory.Count); foreach (var dbsummary in from dbentry in dbhistory group dbentry by dbentry.Function into dbentryByName let totalSeconds = dbentryByName.Sum(f => f.Elapsed.TotalSeconds) orderby totalSeconds descending select new { Query = dbentryByName.First(), Count = dbentryByName.Count(), TotalSeconds = totalSeconds, MaxSeconds = dbentryByName.Max(f => f.Elapsed.TotalSeconds) } ) { profiler.Start("query") .Attr("name", dbsummary.Query.Function) .Attr("elapsed", dbsummary.TotalSeconds.ToString("###,0.00##")) .Attr("average", (dbsummary.TotalSeconds / dbsummary.Count).ToString("###,0.00##")) .Attr("max", dbsummary.MaxSeconds.ToString("###,0.00##")) .Attr("count", dbsummary.Count) .End(); } profiler.End(); } // add data stats Dictionary <string, string> stats; var sessionStats = session as IDekiDataStats; if (sessionStats != null) { profiler.Start("data-stats"); stats = sessionStats.GetStats(); if (stats != null) { foreach (var pair in stats) { profiler.Start("entry").Attr("name", pair.Key).Attr("value", pair.Value).End(); } } profiler.End(); } // add misc. statistics stats = DekiContext.Current.Stats; if (stats.Count > 0) { profiler.Start("misc-stats"); foreach (var pair in stats) { profiler.Start("entry").Attr("name", pair.Key).Attr("value", pair.Value).End(); } profiler.End(); } return(profiler); }
//--- Class Methods --- public static void StartExtensionService(DekiContext context, ServiceBE service, ServiceRepository.IServiceInfo serviceInfo, bool forceRefresh) { // retrieve document describing the extension functions XUri uri = new XUri(service.Uri); XDoc manifest = null; DekiWikiService deki = context.Deki; var extension = serviceInfo.Extension; if (!service.ServiceLocal) { lock (deki.RemoteExtensionLibraries) { deki.RemoteExtensionLibraries.TryGetValue(uri, out manifest); } } if (manifest == null || forceRefresh) { manifest = Plug.New(uri).Get().ToDocument(); // normalize the extension XML manifest = manifest.TransformAsXml(_extensionConverterXslt); // check if document describes a valid extension: either the extension has no functions, or the functions have end-points if (manifest.HasName("extension") && ((manifest["function"].ListLength == 0) || (manifest["function/uri"].ListLength > 0))) { // add source uri for service manifest.Attr("uri", uri); // register service in extension list lock (deki.RemoteExtensionLibraries) { deki.RemoteExtensionLibraries[uri] = manifest; } } else { throw new ExtensionRemoveServiceInvalidOperationException(uri); } } extension.Manifest = manifest; // add function prefix if one is defined serviceInfo.Extension.SetPreference("namespace.custom", service.Preferences["namespace"]); string serviceNamespace = service.Preferences["namespace"] ?? manifest["namespace"].AsText; if (serviceNamespace != null) { serviceNamespace = serviceNamespace.Trim(); if (string.IsNullOrEmpty(serviceInfo.Namespace)) { // Note (arnec): Namespace from preferences is assigned at service creation. If we do not have one at this // point, it came from the extension manifest and needs to be registered as our default. Otherwise the // preference override persists as the namespace. context.Instance.RunningServices.RegisterNamespace(serviceInfo, serviceNamespace); } if (serviceNamespace.Length != 0) { if (!DekiScriptParser.IsIdentifier(serviceNamespace)) { throw new ExtensionNamespaceInvalidArgumentException(service.Preferences["namespace"] ?? manifest["namespace"].AsText); } } else { serviceNamespace = null; } } serviceNamespace = (serviceNamespace == null) ? string.Empty : (serviceNamespace + "."); // add custom library title extension.SetPreference("title.custom", service.Preferences["title"]); extension.SetPreference("label.custom", service.Preferences["label"]); extension.SetPreference("description.custom", service.Preferences["description"]); extension.SetPreference("uri.logo.custom", service.Preferences["uri.logo"]); extension.SetPreference("functions", service.Preferences["functions"]); extension.SetPreference("protected", service.Preferences["protected"]); // add each extension function bool.TryParse(service.Preferences["protected"], out extension.IsProtected); var functions = new List <ServiceRepository.ExtensionFunctionInfo>(); foreach (XDoc function in manifest["function"]) { XUri functionUri = function["uri"].AsUri; if (functionUri != null) { functions.Add(new ServiceRepository.ExtensionFunctionInfo(serviceNamespace + function["name"].Contents, functionUri)); } } extension.Functions = functions.ToArray(); }
protected virtual void ShutdownInstance(string wikiid, DekiInstance instance) { lock(instance) { _log.DebugFormat("shutting down instance '{0}'", wikiid); var context = DreamContext.Current; var currentDekiContext = context.GetState<DekiContext>(); DekiContext tempDekiContext = null; try { if(currentDekiContext == null || currentDekiContext.Instance.Id != wikiid) { _log.DebugFormat("creating temp deki context for shutdown of instance '{0}'", wikiid); // Note (arnec): the host header is only used for logging in the Epilogue which will never be invoked // by this temporary dekicontext var hostheader = wikiid + "-notused"; tempDekiContext = new DekiContext(_dekiService, instance, hostheader, context.StartTime, DekiWikiService.ResourceManager); context.SetState(tempDekiContext); } instance.EndShutdown(); } finally { if(tempDekiContext != null) { tempDekiContext.Dispose(); } context.SetState(currentDekiContext); } } }
public static XDoc GetUserXml(UserBE user, string relation, bool showPrivateInfo) { XDoc userXml = new XDoc(string.IsNullOrEmpty(relation) ? "user" : "user." + relation); userXml.Attr("id", user.ID); userXml.Attr("href", DekiContext.Current.ApiUri.At("users", user.ID.ToString())); userXml.Elem("nick", user.Name); userXml.Elem("username", user.Name); userXml.Elem("fullname", user.RealName ?? String.Empty); // check if we can add the email address if (showPrivateInfo) { userXml.Elem("email", user.Email); } else { userXml.Start("email").Attr("hidden", true).End(); } // seat assignment and site ownership var license = DekiContext.Current.LicenseManager; if (license.IsSeatLicensingEnabled()) { userXml.Start("license.seat").Value(user.LicenseSeat); if (user.LicenseSeat && (license.GetSiteOwnerUserId() ?? 0) == user.ID) { userXml.Attr("owner", true); } userXml.End(); } // add gravatar if (!IsAnonymous(user) && !string.IsNullOrEmpty(user.Email)) { DekiContext context = DekiContext.CurrentOrNull; XUri gravatar = new XUri("http://www.gravatar.com/avatar"); string hash = string.Empty; if (context != null) { DekiInstance deki = context.Instance; string secure = context.Instance.GravatarSalt ?? string.Empty; if (!secure.EqualsInvariantIgnoreCase("hidden")) { hash = StringUtil.ComputeHashString(secure + (user.Email ?? string.Empty).Trim().ToLowerInvariant(), System.Text.Encoding.UTF8); } // add size, if any string size = deki.GravatarSize; if (size != null) { gravatar = gravatar.With("s", size); } // add rating, if any string rating = deki.GravatarRating; if (rating != null) { gravatar = gravatar.With("r", rating); } // add default icon, if any string def = deki.GravatarDefault; if (def != null) { gravatar = gravatar.With("d", def); } } if (!string.IsNullOrEmpty(hash)) { userXml.Elem("hash.email", hash); userXml.Elem("uri.gravatar", gravatar.At(hash + ".png")); userXml.Elem("uri.avatar", gravatar.At(hash + ".png")); } else { userXml.Elem("hash.email", string.Empty); userXml.Elem("uri.gravatar", gravatar.At("no-email.png")); userXml.Elem("uri.avatar", gravatar.At(hash + ".png")); } } return(userXml); }