private DekiScriptLiteral InvokeHelper(DekiScriptRuntime runtime, DekiScriptList args) { // convert passed in arguments object[] arguments = new object[Parameters.Length]; int i = 0; try { for (; i < Parameters.Length; ++i) { var value = args[i].NativeValue; // check if we need to convert the value if ((value != null) && (Parameters[i].NativeType != typeof(object))) { // check for the special case where we cast from XML to STR if ((value is XDoc) && (Parameters[i].NativeType == typeof(string))) { XDoc xml = (XDoc)value; if (xml.HasName("html")) { value = xml["body[not(@target)]"].Contents; } else { value = xml.ToString(); } } else { // rely on the default type conversion rules value = SysUtil.ChangeType(value, Parameters[i].NativeType); } } arguments[i] = value; } } catch { throw new ArgumentException(string.Format("could not convert parameter '{0}' (index {1}) from {2} to {3}", Parameters[i].Name, i, args[i].ScriptTypeName, DekiScriptLiteral.AsScriptTypeName(Parameters[i].ScriptType))); } // invoke method var result = _invoke(runtime, arguments); // check if result is a URI if (result is XUri) { // normalize URI if possible DreamContext context = DreamContext.CurrentOrNull; if (context != null) { result = context.AsPublicUri((XUri)result); } } var literal = DekiScriptLiteral.FromNativeValue(result); try { return(literal.Convert(ReturnType)); } catch (DekiScriptInvalidCastException) { throw new DekiScriptInvalidReturnCastException(Location.None, literal.ScriptType, ReturnType); } }
internal static string AsPublicUiUri(Title title, bool forceUseIndexPhp) { DreamContext context = DreamContext.Current; string baseUri = context.GetParam("baseuri", null); if (baseUri != null) { return(baseUri + title.AsUiUriPath(true).Substring(Title.INDEX_PHP_TITLE.Length)); } else { DekiContext deki = DekiContext.Current; XUri global = context.AsPublicUri(deki.UiUri.Uri.WithoutPathQueryFragment().WithoutCredentials()); return(global.SchemeHostPort + "/" + title.AsUiUriPath(forceUseIndexPhp)); } }
public virtual Yield GetServiceInfo(DreamContext context, DreamMessage request, Result<DreamMessage> response) { XDoc blueprint = Blueprint; string title = blueprint["name"].AsText ?? "Service Blueprint"; XDoc result = new XDoc("html").Attr("xmlns", "http://www.w3.org/1999/xhtml") .Start("head") .Elem("title", title) .Start("meta").Attr("http-equiv", "content-type").Attr("content", "text/html;charset=utf-8").End() .Start("meta").Attr("http-equiv", "Content-Style-Type").Attr("content", "text/css").End() .End(); if(blueprint.IsEmpty) { result.Elem("body", "Missing service blueprint"); } else { result.Start("body") .Elem("h1", title) .Start("p") .Value(blueprint["copyright"].Contents) .Value(" ") .Start("a").Attr("href", blueprint["info"].Contents).Value("(more)").End() .Value(" ") .Start("a").Attr("href", Self.Uri.At("@blueprint").Path).Value("(blueprint)").End() .End(); // show configuration information XDoc config = blueprint["configuration"]; if(!config.IsEmpty) { result.Elem("h2", "Configuration"); result.Start("ul"); foreach(XDoc entry in config["entry"]) { result.Start("li"); if(entry["valuetype"].Contents != string.Empty) { result.Value(string.Format("{0} = {1} : {2}", entry["name"].Contents, entry["valuetype"].Contents, entry["description"].Contents)); } else { result.Value(string.Format("{0} : {1}", entry["name"].Contents, entry["description"].Contents)); } result.End(); } result.End(); } // sort features by signature then verb blueprint["features"].Sort(delegate(XDoc first, XDoc second) { string[] firstPattern = first["pattern"].Contents.Split(new[] { ':' }, 2); string[] secondPattern = second["pattern"].Contents.Split(new[] { ':' }, 2); int cmp = firstPattern[1].CompareInvariantIgnoreCase(secondPattern[1]); if(cmp != 0) { return cmp; } return firstPattern[0].CompareInvariant(secondPattern[0]); }); // display features XDoc features = blueprint["features/feature"]; if(!features.IsEmpty) { result.Elem("h2", "Features"); List<string> modifiers = new List<string>(); foreach(XDoc feature in features) { modifiers.Clear(); // add modifiers string modifier = feature["access"].AsText; if(modifier != null) { modifiers.Add(modifier); } modifier = feature["obsolete"].AsText; if(modifier != null) { modifiers.Add("OBSOLETE => " + modifier); } if(modifiers.Count > 0) { modifier = " (" + string.Join(", ", modifiers.ToArray()) + ")"; } else { modifier = string.Empty; } // check if feature has GET verb and no path parameters string pattern = feature["pattern"].Contents; if(pattern.StartsWithInvariantIgnoreCase(Verb.GET + ":") && (pattern.IndexOfAny(new[] { '{', '*', '?' }) == -1)) { string[] parts = pattern.Split(new[] { ':' }, 2); result.Start("h3") .Start("a").Attr("href", context.AsPublicUri(Self.Uri.AtPath(parts[1]))) .Value(feature["pattern"].Contents) .End() .Value(modifier) .End(); } else { result.Elem("h3", feature["pattern"].Contents + modifier); } result.Start("p") .Value(feature["description"].Contents) .Value(" ") .Start("a").Attr("href", feature["info"].Contents).Value("(more)").End(); XDoc paramlist = feature["param"]; if(!paramlist.IsEmpty) { result.Start("ul"); foreach(XDoc param in paramlist) { result.Start("li"); if(param["valuetype"].Contents != string.Empty) { result.Value(string.Format("{0} = {1} : {2}", param["name"].Contents, param["valuetype"].Contents, param["description"].Contents)); } else { result.Value(string.Format("{0} : {1}", param["name"].Contents, param["description"].Contents)); } result.End(); } result.End(); } result.End(); } } } response.Return(DreamMessage.Ok(MimeType.HTML, result.ToString())); yield break; }
internal Yield GetServices(DreamContext context, DreamMessage request, Result<DreamMessage> response) { XDoc result = new XDoc("services"); result.WithXslTransform(context.AsPublicUri(context.Env.Self).At("resources", "services.xslt").Path); lock(_services) { result.Attr("count", _services.Count); foreach(KeyValuePair<string, ServiceEntry> entry in _services) { result.Start("service"); result.Elem("path", entry.Key); result.Elem("uri", entry.Value.Uri); if(entry.Value.Owner != null) { result.Elem("uri.owner", entry.Value.Owner); } if(entry.Value.SID != null) { result.Elem("sid", entry.Value.SID); } result.Elem("type", entry.Value.Service.GetType().FullName); result.End(); } } response.Return(DreamMessage.Ok(result)); yield break; }
private Yield GetStatus(DreamContext context, DreamMessage request, Result<DreamMessage> response) { DateTime now = DateTime.UtcNow; XDoc result = new XDoc("status"); result.WithXslTransform(context.AsPublicUri(context.Env.Self).At("resources", "status.xslt").Path); XUri self = Self.Uri.With("apikey", context.GetParam("apikey", null)); // host information double age = Math.Max((now - _created).TotalSeconds, 1); result.Start("host").Attr("created", _created).Attr("age", age).Attr("requests", _requestCounter).Attr("rate", _requestCounter / age); result.Elem("uri.local", _localMachineUri.ToString()); result.Elem("uri.public", _publicUri); // host/aliases result.Start("aliases").Attr("count", _aliases.Count).Attr("href", self.At("status", "aliases")).End(); // connections result.Start("connections").Attr("count", _connectionCounter).Attr("limit", _connectionLimit).End(); // activities lock(_activities) { result.Start("activities").Attr("count", _activities.Count).Attr("href", self.At("status", "activities")); foreach(Tuplet<DateTime, string> description in _activities.Values) { result.Start("description").Attr("created", description.Item1).Attr("age", (now - description.Item1).TotalSeconds).Value(description.Item2).End(); } result.End(); } // infos lock(_infos) { result.Start("infos").Attr("count", _infos.Count); foreach(KeyValuePair<string, Tuplet<int, string>> entry in _infos) { result.Start("info").Attr("source", entry.Key).Attr("hits", entry.Value.Item1).Attr("rate", entry.Value.Item1 / age).Value(entry.Value.Item2).End(); } result.End(); } // host/services information result.Start("services").Attr("count", _services.Count).Attr("href", self.At("services")).End(); // host/features result.Start("features").Attr("href", self.At("status", "features")).End(); // host/cache long size = 0; int count = 0; lock(_responseCache) { foreach(Dictionary<object, DreamMessage> cache in _responseCache.Values) { count += cache.Count; foreach(DreamMessage message in cache.Values) { size += message.ToBytes().LongLength; } } } result.Start("cache").Attr("count", count).Attr("size", size).Attr("hits", _responseCacheHits).Attr("misses", _responseCacheMisses).End(); // end host information result.End(); // system information result.Start("system"); // system/memory information result.Elem("memory.used", GC.GetTotalMemory(false)); // system/thread information int workerThreads; int completionThreads; int dispatcherThreads; Async.GetAvailableThreads(out workerThreads, out completionThreads, out dispatcherThreads); int maxWorkerThreads; int maxCompletionThreads; int maxDispatcherThreads; Async.GetMaxThreads(out maxWorkerThreads, out maxCompletionThreads, out maxDispatcherThreads); result.Elem("workerthreads.max", maxWorkerThreads); result.Elem("workerthreads.used", maxWorkerThreads - workerThreads); result.Elem("completionthreads.max", maxCompletionThreads); result.Elem("completionthreads.used", maxCompletionThreads - completionThreads); result.Elem("dispatcherthreads.max", maxDispatcherThreads); result.Elem("dispatcherthreads.used", maxDispatcherThreads - dispatcherThreads); // timer information var taskTimerStats = TaskTimerFactory.GetStatistics(); result.Start("timers.queued").Attr("href", self.At("status", "timers")).Value(taskTimerStats.QueuedTimers).End(); result.Start("timers.pending").Attr("href", self.At("status", "timers")).Value(taskTimerStats.PendingTimers).End(); result.Elem("timers.counter", taskTimerStats.Counter); result.Elem("timers.last", taskTimerStats.Last); // rendez-vous events result.Start("async").Attr("count", RendezVousEvent.PendingCounter + AResult.PendingCounter); lock(RendezVousEvent.Pending) { foreach(var entry in RendezVousEvent.Pending.Values) { result.Start("details"); if(entry.Key != null) { var dc = entry.Key.GetState<DreamContext>(); if(dc != null) { result.Elem("verb", dc.Verb); result.Elem("uri", dc.Uri); } } if(entry.Value != null) { result.Start("stacktrace"); XException.AddStackTrace(result, entry.Value.ToString()); result.End(); } result.End(); } } result.End(); // xml name table stats LockFreeXmlNameTable table = SysUtil.NameTable as LockFreeXmlNameTable; if(table != null) { int capacity; int entries; long bytes; int[] distribution; double expected; table.GetStats(out capacity, out entries, out bytes, out distribution, out expected); result.Start("xmlnametable").Attr("href", self.At("status", "xmlnametable")); result.Elem("capacity", capacity.ToString("#,##0")); result.Elem("bytes", bytes.ToString("#,##0")); result.Elem("entries", entries.ToString("#,##0")); result.Elem("expected-comparisons", expected); result.Elem("distribution", "[" + string.Join("; ", Array.ConvertAll(distribution, i => i.ToString("#,##0"))) + "]"); result.End(); } // replicate app settings result.Start("app-settings"); foreach(var key in System.Configuration.ConfigurationManager.AppSettings.AllKeys) { result.Start("entry").Attr("key", key).Attr("value", System.Configuration.ConfigurationManager.AppSettings[key]).End(); } result.End(); // end of </system> result.End(); response.Return(DreamMessage.Ok(result)); yield break; }
private void LoadScript() { _manifestPath = null; _resourcesPath = null; _manifestUri = null; _resourcesUri = null; _manifest = null; // read manifest _manifestPath = Config["manifest"].AsText; if (string.IsNullOrEmpty(_manifestPath)) { throw new ArgumentNullException("manifest"); } _manifestUri = XUri.TryParse(_manifestPath); if (_manifestUri != null) { _manifestPath = null; _manifest = Plug.New(_manifestUri).Get().ToDocument(); _resourcesUri = Config["resources"].AsUri ?? _manifestUri.WithoutLastSegment(); } else { _manifest = XDocFactory.LoadFrom(_manifestPath, MimeType.XML); _resourcesPath = Config["resources"].AsText ?? Path.GetDirectoryName(_manifestPath); } if (!_manifest.HasName("extension")) { throw new ArgumentException("invalid extension manifest"); } // initilize runtime _runtime = new DekiScriptRuntime(); // read manifest settings _title = _manifest["title"].AsText; _label = _manifest["label"].AsText; _copyright = _manifest["copyright"].AsText; _description = _manifest["description"].AsText; _help = _manifest["uri.help"].AsText; _logo = _manifest["uri.logo"].AsText; _namespace = _manifest["namespace"].AsText; // initialize evaluation environment _commonEnv = _runtime.CreateEnv(); // read functions _functions = new Dictionary <XUri, DekiScriptInvocationTargetDescriptor>(); foreach (var function in _manifest["function"]) { var descriptor = ConvertFunction(function); if (descriptor != null) { var uri = Self.At(descriptor.SystemName); DekiScriptInvocationTargetDescriptor old; if (_functions.TryGetValue(uri, out old)) { _log.WarnFormat("duplicate function name {0} in script {1}", descriptor.Name, _manifestUri); } _functions[uri] = descriptor; } } _runtime.RegisterExtensionFunctions(_functions); // add extension functions to env foreach (var function in _functions) { _commonEnv.Vars.AddNativeValueAt(function.Value.Name.ToLowerInvariant(), function.Key); } // add configuration settings DreamContext context = DreamContext.Current; DekiScriptMap scriptConfig = new DekiScriptMap(); foreach (KeyValuePair <string, string> entry in Config.ToKeyValuePairs()) { XUri local; if (XUri.TryParse(entry.Value, out local)) { local = context.AsPublicUri(local); scriptConfig.AddAt(entry.Key.Split('/'), DekiScriptExpression.Constant(local.ToString())); } else { scriptConfig.AddAt(entry.Key.Split('/'), DekiScriptExpression.Constant(entry.Value)); } } _commonEnv.Vars.Add("config", scriptConfig); }