internal static XDoc CreateWarningFromException(DekiScriptList callstack, Location location, Exception exception) { // unwrap nested async exception exception = UnwrapAsyncException(null, exception); // determine exception XDoc result; if (exception is DreamAbortException) { DreamAbortException e = (DreamAbortException)exception; if (e.Response.ContentType.IsXml) { result = CreateWarningElement(callstack, string.Format("{1}, a web exception was thrown (status: {0})", (int)e.Response.Status, location), new XMessage(e.Response).ToPrettyString()); } else { result = CreateWarningElement(callstack, string.Format("{1}, a web exception was thrown (status: {0})", (int)e.Response.Status, location), e.Response.AsText()); } } else if (exception is DekiScriptException) { result = CreateWarningElement(callstack, exception.Message, exception.GetCoroutineStackTrace()); } else { result = CreateWarningElement(callstack, string.Format("{0}: {1}", exception.Message, location), exception.GetCoroutineStackTrace()); } return(result); }
private static DekiScriptLiteral FromXmlRpcToDekiScript(XDoc xdoc) { if (xdoc.HasName("html")) { return(new DekiScriptList().Add(new DekiScriptXml(xdoc))); } if (xdoc.HasName("methodResponse")) { if (!xdoc["fault"].IsEmpty) { string errorMessage = xdoc["fault/value/struct/member[name='faultString']/value/string"].AsText; throw new DekiScriptXmlRpcException(errorMessage ?? xdoc.ToPrettyString()); } if (!xdoc["params"].IsEmpty) { DekiScriptList result = new DekiScriptList(); foreach (XDoc param in xdoc["params/param/value"]) { result.Add(ToDekiScriptRecurse(param)); } return(result); } else { // NOTE: unexpected result, treat it as a nil result DekiScriptList result = new DekiScriptList(); result.Add(DekiScriptNil.Value); return(result); } } throw new DekiScriptUnsupportedTypeException(Location.None, string.Format("<{0}>", xdoc.Name)); }
public static XDoc CreateWarningElement(DekiScriptList callstack, String description, string message) { if (callstack != null) { StringBuilder stacktrace = new StringBuilder(); foreach (var entry in from item in callstack.Value let entry = item.AsString() where entry != null select entry) { stacktrace.AppendFormat(" at {0}\n", entry); } if (stacktrace.Length > 0) { if (message == null) { message = "Callstack:\n" + stacktrace; } else { message = "Callstack:\n" + stacktrace + "\n" + message; } } } XDoc result = new XDoc("div"); result.Start("span").Attr("class", "warning").Value(description).End(); if (message != null) { string id = StringUtil.CreateAlphaNumericKey(8); result.Value(" "); result.Start("span").Attr("style", "cursor: pointer;").Attr("onclick", string.Format("$('#{0}').toggle()", id)).Value("(click for details)").End(); result.Start("pre").Attr("id", id).Attr("style", "display: none;").Value(message).End(); } return(result); }
public static DekiScriptMap ValidateToMap(DekiScriptParameter[] parameters, DekiScriptList args) { DekiScriptMap result = new DekiScriptMap(); // check passed in arguments int i = 0; var count = Math.Min(args.Value.Count, parameters.Length); for(; i < count; ++i) { var value = args[i]; if(value.IsNil) { if((parameters[i].ScriptType != DekiScriptType.ANY) && !parameters[i].Optional) { throw new ArgumentException(string.Format("missing value for parameter '{0}' (index {1})", parameters[i].Name, i)); } // set default value for this parameter result.Add(parameters[i].Name, parameters[i].Default); } else { result.Add(parameters[i].Name, parameters[i].Convert(value)); } } // check that missing arguments are optional for(; i < parameters.Length; ++i) { if((parameters[i].ScriptType != DekiScriptType.ANY) && !parameters[i].Optional) { throw new ArgumentException(string.Format("missing value for parameter '{0}' (index {1})", parameters[i].Name, i)); } result.Add(parameters[i].Name, parameters[i].Default); } return result; }
public DekiScriptExpression Visit(DekiScriptListConstructor expr, DekiScriptExpressionEvaluationState state) { // TODO (steveb): need to figure out how to optimize lists with generators if (expr.Generator != null) { return(expr); } // optimize each item in the list DekiScriptExpression[] list = new DekiScriptExpression[expr.Items.Length]; bool isLiteral = true; for (int i = 0; i < expr.Items.Length; i++) { DekiScriptExpression item = expr.Items[i].VisitWith(this, state); list[i] = item; isLiteral = isLiteral && (item is DekiScriptLiteral); } if (!isLiteral) { return(DekiScriptExpression.List(expr.Location, list)); } // convert expression to a list DekiScriptList result = new DekiScriptList(); foreach (DekiScriptLiteral literal in list) { result.Add(literal); } return(result); }
//--- Methods --- public override DekiScriptLiteral InvokeList(DekiScriptRuntime runtime, DekiScriptList args) { // prepare uri for invocation Plug plug = Plug.New(_endpoint); plug = runtime.PreparePlug(plug); // make web-request DreamMessage response = plug.Post(args.ToXml(), new Tasking.Result<DreamMessage>()).Wait(); if(!response.IsSuccessful) { if(response.HasDocument) { var error = response.ToDocument(); var message = error["message"]; if(error.HasName("exception") && !message.IsEmpty) { throw new DekiScriptRemoteException(Location.None, message.Contents); } } throw new DreamResponseException(response); } // convert response to literal DekiScriptLiteral list; try { list = DekiScriptLiteral.FromXml(response.ToDocument()); } catch(ArgumentException) { throw new DekiScriptUnsupportedTypeException(Location.None, string.Format("<{0}>", response.ToDocument().Name)); } if(list.ScriptType != DekiScriptType.LIST) { throw new DekiScriptBadTypeException(Location.None, list.ScriptType, new[] { DekiScriptType.LIST }); } return ((DekiScriptList)list)[0]; }
//--- Class Methods --- public static DekiScriptMap MakeErrorObject(Exception e, DekiScriptEnv env) { DekiScriptMap exception = new DekiScriptMap(); // add call stack if one is available DekiScriptList callstack = null; if(env != null) { DekiScriptLiteral callstackVar; if(env.Vars.TryGetValue(DekiScriptEnv.CALLSTACK, out callstackVar)) { callstack = callstackVar as DekiScriptList; } } while(e is DekiScriptInvokeException) { var ex = (DekiScriptInvokeException)e; if(callstack == null) { callstack = new DekiScriptList(); } callstack.AddNativeValue(ex.FunctionName); e = ex.InnerException; } if(callstack != null) { exception.Add("callstack", callstack); } // add exception text exception.Add("message", DekiScriptExpression.Constant(e.Message)); exception.Add("stacktrace", DekiScriptExpression.Constant(e.GetCoroutineStackTrace())); if(e.InnerException != null) { exception.Add("inner", MakeErrorObject(e.InnerException, null)); } if(e is DekiScriptException) { exception.Add("source", DekiScriptExpression.Constant(((DekiScriptException)e).Location.Origin)); } return exception; }
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 void InsertExceptionMessageBeforeNode(DekiScriptEnv env, XmlNode parent, XmlNode reference, Location location, Exception exception) { if (Fallthrough) { throw exception; } if (exception is DekiScriptDocumentTooLargeException) { DekiScriptDocumentTooLargeException e = (DekiScriptDocumentTooLargeException)exception; // check if an error message was already embedded if (e.Handled) { throw exception; } e.Handled = true; } // check if environment has a __callstack variable DekiScriptList callstack = null; DekiScriptLiteral callstackVar; if (env.Vars.TryGetValue(DekiScriptEnv.CALLSTACK, out callstackVar)) { callstack = callstackVar as DekiScriptList; } XDoc warning = DekiScriptRuntime.CreateWarningFromException(callstack, location, exception); parent.InsertBefore(parent.OwnerDocument.ImportNode(warning.AsXmlNode, true), reference); if (exception is DekiScriptDocumentTooLargeException) { throw exception; } }
public static DekiScriptList ValidateToList(DekiScriptParameter[] parameters, DekiScriptMap args) { DekiScriptList result = new DekiScriptList(); // check passed in arguments for (int i = 0; i < parameters.Length; ++i) { var value = args[parameters[i].Name]; if (value.IsNil) { if ((parameters[i].ScriptType != DekiScriptType.ANY) && !parameters[i].Optional) { throw new ArgumentException(string.Format("missing value for parameter '{0}' (index {1})", parameters[i].Name, i)); } // set default value for this parameter result.Add(parameters[i].Default); } else { result.Add(parameters[i].Convert(value)); } } return(result); }
public void Call_func_with_arg_list() { string path = LoadExtension(); DekiScriptList args = new DekiScriptList() .Add(DekiScriptExpression.Constant("1")) .Add(DekiScriptExpression.Constant("2")); DreamMessage result = Plug.New(_host.LocalMachineUri).At(path, "Addition").Post(args.ToXml()); Assert.IsTrue(result.IsSuccessful); XDoc resultDoc = result.ToDocument(); Assert.AreEqual("value", resultDoc.Name); Assert.AreEqual(3, resultDoc.Elements.First.AsInt); }
public object Fetch( [DekiExtParam("document id")] string id ) { // fetch response from cache CacheEntry result; lock (_cacheLookup) { _cacheLookup.TryGetValue(id, out result); } // check if we have a cached entry XDoc document = null; if (result != null) { _log.DebugFormat("cache hit for '{0}'", result.Id); result.ResetMemoryExpiration(); if (result.Cache != null) { _log.DebugFormat("cache data in memory '{0}'", result.Id); document = XDocFactory.From(result.Cache, MimeType.XML); } else { // we have the result on disk, so let's fetch it DreamMessage msg = Storage.At(CACHE_DATA, result.Guid + ".bin").GetAsync().Wait(); if (msg.IsSuccessful) { _log.DebugFormat("cache data pulled from disk"); result.Cache = Encoding.UTF8.GetString(msg.AsBytes()); document = XDocFactory.From(result.Cache, MimeType.XML); } else { _log.DebugFormat("unable to fetch cache data from disk: {0}", msg.Status); } } } // check if we have a document to convert if (document != null) { try { DekiScriptList list = (DekiScriptList)DekiScriptLiteral.FromXml(document); return(list[0]); } catch { // the cached entry is corrupted, remove it Clear(id); } } return(null); }
private static DekiScriptLiteral ToDekiScriptRecurse(XDoc doc) { XDoc xdoc = doc.Elements; switch (xdoc.Name) { case "nil": return(DekiScriptNil.Value); case "boolean": if (xdoc.Contents.GetType().Equals(typeof(String))) { return(DekiScriptExpression.Constant((xdoc.Contents.Contains("1") || xdoc.Contents.Contains("true")) ? true : false)); } return(DekiScriptExpression.Constant(xdoc.AsBool ?? false)); case "double": return(DekiScriptExpression.Constant(xdoc.AsDouble ?? 0.0)); case "int": case "i4": return(DekiScriptExpression.Constant(xdoc.AsDouble ?? 0.0)); case "string": return(DekiScriptExpression.Constant(xdoc.AsText ?? string.Empty)); case "struct": { DekiScriptMap result = new DekiScriptMap(); foreach (XDoc value in xdoc["member"]) { result.Add(value["name"].Contents, ToDekiScriptRecurse(value["value"])); } return(result); } case "array": { DekiScriptList result = new DekiScriptList(); foreach (XDoc value in xdoc["data/value"]) { result.Add(ToDekiScriptRecurse(value)); } return(result); } default: throw new ArgumentException("this type does not exist in the XML-RPC standard"); } }
//--- Methods --- public override DekiScriptLiteral InvokeList(DekiScriptRuntime runtime, DekiScriptList args) { // prepare uri for invocation Plug plug = Plug.New(_endpoint); plug = runtime.PreparePlug(plug); DreamMessage response = plug.Post(DekiScriptToXmlRpc(_methodname, args)); // convert response to literal DekiScriptLiteral list = FromXmlRpcToDekiScript(response.ToDocument()); if (list.ScriptType != DekiScriptType.LIST) { throw new DekiScriptBadReturnTypeException(Location.None, list.ScriptType, new[] { DekiScriptType.LIST }); } return(((DekiScriptList)list)[0]); }
//--- Class Methods --- public static DekiScriptMap MakeErrorObject(Exception e, DekiScriptEnv env) { DekiScriptMap exception = new DekiScriptMap(); // add call stack if one is available DekiScriptList callstack = null; if (env != null) { DekiScriptLiteral callstackVar; if (env.Vars.TryGetValue(DekiScriptEnv.CALLSTACK, out callstackVar)) { callstack = callstackVar as DekiScriptList; } } while (e is DekiScriptInvokeException) { var ex = (DekiScriptInvokeException)e; if (callstack == null) { callstack = new DekiScriptList(); } callstack.AddNativeValue(ex.FunctionName); e = ex.InnerException; } if (callstack != null) { exception.Add("callstack", callstack); } // add exception text exception.Add("message", DekiScriptExpression.Constant(e.Message)); exception.Add("stacktrace", DekiScriptExpression.Constant(e.GetCoroutineStackTrace())); if (e.InnerException != null) { exception.Add("inner", MakeErrorObject(e.InnerException, null)); } if (e is DekiScriptException) { exception.Add("source", DekiScriptExpression.Constant(((DekiScriptException)e).Location.Origin)); } return(exception); }
public DekiScriptLiteral Visit(DekiScriptListConstructor expr, DekiScriptEnv env) { DekiScriptList result = new DekiScriptList(); if (expr.Generator == null) { foreach (DekiScriptExpression item in expr.Items) { result.Add(item.VisitWith(this, env)); } } else { DekiScriptGeneratorEvaluation.Instance.Generate(expr.Generator, delegate(DekiScriptEnv subEnv) { foreach (DekiScriptExpression item in expr.Items) { result.Add(item.VisitWith(this, subEnv)); } }, env.NewLocalScope()); } return(result); }
public static DekiScriptMap ValidateToMap(DekiScriptParameter[] parameters, DekiScriptList args) { DekiScriptMap result = new DekiScriptMap(); // check passed in arguments int i = 0; var count = Math.Min(args.Value.Count, parameters.Length); for (; i < count; ++i) { var value = args[i]; if (value.IsNil) { if ((parameters[i].ScriptType != DekiScriptType.ANY) && !parameters[i].Optional) { throw new ArgumentException(string.Format("missing value for parameter '{0}' (index {1})", parameters[i].Name, i)); } // set default value for this parameter result.Add(parameters[i].Name, parameters[i].Default); } else { result.Add(parameters[i].Name, parameters[i].Convert(value)); } } // check that missing arguments are optional for (; i < parameters.Length; ++i) { if ((parameters[i].ScriptType != DekiScriptType.ANY) && !parameters[i].Optional) { throw new ArgumentException(string.Format("missing value for parameter '{0}' (index {1})", parameters[i].Name, i)); } result.Add(parameters[i].Name, parameters[i].Default); } return(result); }
//--- Methods --- public override DekiScriptLiteral InvokeList(DekiScriptRuntime runtime, DekiScriptList args) { // prepare uri for invocation Plug plug = Plug.New(_endpoint); plug = runtime.PreparePlug(plug); // make web-request DreamMessage response = plug.Post(args.ToXml(), new Tasking.Result <DreamMessage>()).Wait(); if (!response.IsSuccessful) { if (response.HasDocument) { var error = response.ToDocument(); var message = error["message"]; if (error.HasName("exception") && !message.IsEmpty) { throw new DekiScriptRemoteException(Location.None, message.Contents); } } throw new DreamResponseException(response); } // convert response to literal DekiScriptLiteral list; try { list = DekiScriptLiteral.FromXml(response.ToDocument()); } catch (ArgumentException) { throw new DekiScriptUnsupportedTypeException(Location.None, string.Format("<{0}>", response.ToDocument().Name)); } if (list.ScriptType != DekiScriptType.LIST) { throw new DekiScriptBadTypeException(Location.None, list.ScriptType, new[] { DekiScriptType.LIST }); } return(((DekiScriptList)list)[0]); }
public DekiScriptOutputBuffer.Range Visit(DekiScriptListConstructor expr, DekiScriptExpressionEvaluationState state) { DekiScriptList result = new DekiScriptList(); if (expr.Generator == null) { foreach (DekiScriptExpression item in expr.Items) { result.Add(state.Pop(item.VisitWith(this, state))); } } else { DekiScriptGeneratorEvaluation.Generate(expr.Generator, delegate(DekiScriptEnv subEnv) { foreach (DekiScriptExpression item in expr.Items) { var eval = state.Pop(item.VisitWith(this, state.With(subEnv))); result.Add(eval); } }, state); } return(state.Push(result)); }
//--- Abstract Methods --- public abstract DekiScriptLiteral InvokeList(DekiScriptRuntime runtime, DekiScriptList args);
public void Create_entries_in_cache() { DekiScriptLiteral result; // create web-cahce extension service var webcache = DreamTestHelper.CreateService( _hostInfo, new XDoc("config") .Elem("class", typeof(WebCacheService).FullName) .Elem("path", "webcache") ); // extract entry points for web-cache functions var manifest = webcache.AtLocalHost.Get().AsDocument(); var fetch = Plug.New(manifest["function[name/text()='fetch']/uri"].AsUri); var store = Plug.New(manifest["function[name/text()='store']/uri"].AsUri); var clear = Plug.New(manifest["function[name/text()='clear']/uri"].AsUri); // create MAX_ITERATIONS entries in web-cache var sw = Stopwatch.StartNew(); for (int i = 1; i <= MAX_ITERATIONS; ++i) { var key = "key" + i; var list = new DekiScriptList() .Add(DekiScriptExpression.Constant(key)) .Add(DekiScriptExpression.Constant(CONTENT)); var response = store.Post(list.ToXml()); var doc = response.ToDocument(); result = DekiScriptLiteral.FromXml(doc); _log.DebugFormat("webcache.store('{0}') -> {1}", key, result); } sw.Stop(); _log.DebugFormat("webcache.store() all took {0:#,##0} seconds", sw.Elapsed.TotalSeconds); // shutdown web-cache service webcache.WithPrivateKey().AtLocalHost.Delete(); // re-create web-cache extension service webcache = DreamTestHelper.CreateService( _hostInfo, new XDoc("config") .Elem("class", typeof(WebCacheService).FullName) .Elem("path", "webcache") ); // re-extract entry points for web-cache functions manifest = webcache.AtLocalHost.Get().AsDocument(); fetch = Plug.New(manifest["function[name/text()='fetch']/uri"].AsUri); store = Plug.New(manifest["function[name/text()='store']/uri"].AsUri); clear = Plug.New(manifest["function[name/text()='clear']/uri"].AsUri); // loop over all entries in web-cache and fetch them sw = Stopwatch.StartNew(); for (int i = 1; i <= MAX_ITERATIONS; ++i) { int count = 0; var key = "key" + i; do { result = DekiScriptLiteral.FromXml(fetch.Post(new DekiScriptList().Add(DekiScriptExpression.Constant(key)).ToXml()).ToDocument()); var text = ((DekiScriptList)result)[0].AsString(); if (text == CONTENT) { break; } Thread.Sleep(50); } while(++count < 100); if (count >= 100) { Assert.Fail("too many attempts to load " + key); return; } } sw.Stop(); _log.DebugFormat("webcache.fetch() all took {0:#,##0} seconds", sw.Elapsed.TotalSeconds); // loop over all entries in web-cache and clear them out sw = Stopwatch.StartNew(); for (int i = 1; i <= MAX_ITERATIONS; ++i) { var key = "key" + i; var list = new DekiScriptList() .Add(DekiScriptExpression.Constant(key)); var response = clear.Post(list.ToXml()); var doc = response.ToDocument(); result = DekiScriptLiteral.FromXml(doc); _log.DebugFormat("webcache.clear('{0}') -> {1}", key, result); } sw.Stop(); _log.DebugFormat("webcache.clear() all took {0:#,##0} seconds", sw.Elapsed.TotalSeconds); // loop over all entries in web-cache and fetch them sw = Stopwatch.StartNew(); for (int i = 1; i <= MAX_ITERATIONS; ++i) { var key = "key" + i; result = DekiScriptLiteral.FromXml(fetch.Post(new DekiScriptList().Add(DekiScriptExpression.Constant(key)).ToXml()).ToDocument()); var text = ((DekiScriptList)result)[0].AsString(); Assert.AreEqual(null, text, "entry " + key + " was not deleted"); } sw.Stop(); _log.DebugFormat("webcache.fetch() all took {0:#,##0} seconds", sw.Elapsed.TotalSeconds); // shutdown web-cache service again webcache.WithPrivateKey().AtLocalHost.Delete(); }
//--- Methods --- public override DekiScriptLiteral InvokeList(DekiScriptRuntime runtime, DekiScriptList args) { throw new DekiScriptBadTypeException(Location.None, args.ScriptType, new[] { DekiScriptType.MAP }); }
//--- Methods --- public override DekiScriptLiteral InvokeList(DekiScriptRuntime runtime, DekiScriptList args) { return InvokeHelper(runtime, DekiScriptParameter.ValidateToMap(Parameters, args)); }
public DekiScriptLiteral Visit(DekiScriptList expr, DekiScriptEnv env) { return(expr); }
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); } }
public static XDoc CreateWarningElement(DekiScriptList callstack, String description, string message) { if(callstack != null) { StringBuilder stacktrace = new StringBuilder(); foreach(var entry in from item in callstack.Value let entry = item.AsString() where entry != null select entry) { stacktrace.AppendFormat(" at {0}\n", entry); } if(stacktrace.Length > 0) { if(message == null) { message = "Callstack:\n" + stacktrace; } else { message = "Callstack:\n" + stacktrace + "\n" + message; } } } XDoc result = new XDoc("div"); result.Start("span").Attr("class", "warning").Value(description).End(); if(message != null) { string id = StringUtil.CreateAlphaNumericKey(8); result.Value(" "); result.Start("span").Attr("style", "cursor: pointer;").Attr("onclick", string.Format("$('#{0}').toggle()", id)).Value("(click for details)").End(); result.Start("pre").Attr("id", id).Attr("style", "display: none;").Value(message).End(); } return result; }
public DekiScriptOutputBuffer.Range Visit(DekiScriptCall expr, DekiScriptExpressionEvaluationState state) { state.ThrowIfTimedout(); // evaluate prefix DekiScriptLiteral prefix = state.Pop(expr.Prefix.VisitWith(this, state)); if (prefix.ScriptType != DekiScriptType.URI) { if (prefix.ScriptType == DekiScriptType.NIL) { throw new DekiScriptUndefinedNameException(expr.Location, expr.Prefix.ToString()); } else { throw new DekiScriptBadTypeException(expr.Location, prefix.ScriptType, new[] { DekiScriptType.URI }); } } // evaluate arguments DekiScriptLiteral arguments = state.Pop(expr.Arguments.VisitWith(this, state)); if ((arguments.ScriptType != DekiScriptType.MAP) && (arguments.ScriptType != DekiScriptType.LIST)) { throw new DekiScriptBadTypeException(expr.Location, arguments.ScriptType, new[] { DekiScriptType.MAP, DekiScriptType.LIST }); } // check if the URI was curried DekiScriptUri uri = (DekiScriptUri)prefix; if (!uri.Arguments.IsNil) { switch (uri.Arguments.ScriptType) { case DekiScriptType.LIST: // append argument to list DekiScriptList list = new DekiScriptList((DekiScriptList)uri.Arguments); list.Add(arguments); arguments = list; break; case DekiScriptType.MAP: if (arguments.ScriptType == DekiScriptType.MAP) { // concatenate both maps DekiScriptMap map = new DekiScriptMap(); map.AddRange((DekiScriptMap)uri.Arguments); map.AddRange((DekiScriptMap)arguments); arguments = map; } else if ((arguments.ScriptType != DekiScriptType.LIST) || ((DekiScriptList)arguments).Value.Count > 0) { // we can't append a list to a map throw new DekiScriptBadTypeException(expr.Location, arguments.ScriptType, new[] { DekiScriptType.MAP }); } break; default: throw new DekiScriptBadTypeException(expr.Location, arguments.ScriptType, new[] { DekiScriptType.MAP, DekiScriptType.LIST }); } } // check if this is an invocation or curry operation if (expr.IsCurryOperation) { return(state.Push(new DekiScriptUri(uri.Value, arguments))); } // invoke function try { return(state.Push(state.Runtime.Invoke(expr.Location, uri.Value, arguments, state.Env))); } catch (DekiScriptFatalException) { throw; } catch (Exception e) { var descriptor = state.Runtime.ResolveRegisteredFunctionUri(uri.Value); throw new DekiScriptInvokeException(expr.Location, uri.Value, (descriptor != null) ? descriptor.Name : uri.Value.ToString(), e); } }
//--- Methods --- private DekiScriptEnv ProcessEnvironment() { var current = DreamContext.Current; DekiScriptEnv env = current.GetState<DekiScriptEnv>("pageenv-" + _basePage.ID); // check if we already have an initialized environment if(env == null) { // create environment env = ExtensionBL.CreateEnvironment(_basePage); // add request arguments DekiScriptMap request = new DekiScriptMap(); DekiScriptMap queryArgs = new DekiScriptMap(); DreamContext context = DreamContext.CurrentOrNull; if(context != null) { if(context.Uri.Params != null) { foreach(KeyValuePair<string, string> query in context.Uri.Params) { // check that query parameter doesn't have 'dream.' prefix if(!query.Key.StartsWithInvariantIgnoreCase("dream.")) { DekiScriptLiteral value; // check if a query parameter with the same name was alreayd found if(queryArgs.TryGetValue(query.Key, out value)) { DekiScriptList list = value as DekiScriptList; // check if the current value is already a list if(list == null) { list = new DekiScriptList(); list.Add(value); // replace current value queryArgs.Add(query.Key, list); } // append new value to list list.Add(DekiScriptExpression.Constant(query.Value)); } else { // add query parameter queryArgs.Add(query.Key, DekiScriptExpression.Constant(query.Value)); } } } } // show User-Agent, Referer and Host information in __request request.Add("referer", DekiScriptExpression.Constant(context.Request.Headers.Referer)); request.Add("useragent", DekiScriptExpression.Constant(context.Request.Headers.UserAgent)); request.Add("host", DekiScriptExpression.Constant(context.Request.Headers.Host)); // determine the client IP address var clientIPs = current.Request.Headers.DreamClientIP; if(clientIPs.Length > 0) { request.Add("client", DekiScriptExpression.Constant(clientIPs[clientIPs.Length - 1])); } else { request.Add("client", DekiScriptNil.Value); } // parse form fields from a request for requests with a mimetype of application/x-www-form-urlencoded DekiScriptMap postParams; if(context.Request.ContentType.Match(MimeType.FORM_URLENCODED)) { KeyValuePair<string, string>[] formFields = XUri.ParseParamsAsPairs(context.Request.ToText()); if(!ArrayUtil.IsNullOrEmpty(formFields)) { postParams = new DekiScriptMap(); foreach(KeyValuePair<string, string> kvp in formFields) { postParams.Add(kvp.Key, DekiScriptExpression.Constant(kvp.Value)); } request.Add("fields", postParams); } } } request.Add("args", queryArgs); env.Vars.Add("__request", request); // store computed environment for subsequent calls current.SetState("pageenv-" + _basePage.ID, env); } env = env.NewScope(); // global processing variables env.Vars.Add("__include", DekiScriptExpression.Constant(_isInclude)); env.Vars.Add("__mode", DekiScriptExpression.Constant(_mode.ToString().ToLowerInvariant())); env.Vars.Add(DekiScriptEnv.SAFEMODE, DekiScriptExpression.Constant(ExtensionRuntime.IsSafeMode(_page))); env.Vars.Add("__page", DekiContext.Current.Deki.PropertyAt("$page", _page.ID, true)); // set processing settings DekiScriptMap settings = new DekiScriptMap(); settings.Add("nofollow", DekiScriptExpression.Constant(DekiContext.Current.Instance.WebLinkNoFollow)); env.Vars.Add(DekiScriptEnv.SETTINGS, settings); // add callstack (specific for each page invocation) DekiScriptList callstack = new DekiScriptList(); ParserState parseState = GetParseState(); if(parseState != null) { foreach(PageBE includingPage in parseState.ProcessingStack) { callstack.Add(DekiScriptExpression.Constant(includingPage.Title.AsPrefixedDbPath())); } env.Vars.Add(DekiScriptEnv.CALLSTACK, callstack); } // add arguments environment vars env.Vars.Add("args", _args ?? DekiScriptNil.Value); env.Vars.Add("$", _args ?? DekiScriptNil.Value); return env.NewScope(); }
internal DekiScriptLiteral Evaluate(DekiScriptAccess expr, DekiScriptExpressionEvaluationState state, bool evaluateProperties) { DekiScriptLiteral prefix = state.Pop(expr.Prefix.VisitWith(this, state)); DekiScriptLiteral index = state.Pop(expr.Index.VisitWith(this, state)); switch (prefix.ScriptType) { case DekiScriptType.MAP: { DekiScriptLiteral result = ((DekiScriptMap)prefix)[index]; if (evaluateProperties) { result = state.Runtime.EvaluateProperty(expr.Location, result, state.Env); } return(result); } case DekiScriptType.LIST: { DekiScriptLiteral value = DekiScriptExpression.Constant(index.AsNumber()); DekiScriptLiteral result = ((DekiScriptList)prefix)[value]; if (evaluateProperties) { result = state.Runtime.EvaluateProperty(expr.Location, result, state.Env); } return(result); } case DekiScriptType.URI: { DekiScriptUri uri = (DekiScriptUri)prefix; // coerce the index type to STR index = DekiScriptExpression.Constant(index.AsString()); if (index.ScriptType != DekiScriptType.STR) { throw new DekiScriptBadTypeException(expr.Location, index.ScriptType, new[] { DekiScriptType.STR }); } // curry the argument DekiScriptList args; if (!uri.Arguments.IsNil) { // the uri already has curried parameters, make sure they are in LIST format; otherwise fail if (uri.Arguments.ScriptType != DekiScriptType.LIST) { throw new DekiScriptBadTypeException(expr.Location, uri.Arguments.ScriptType, new[] { DekiScriptType.NIL, DekiScriptType.LIST }); } args = new DekiScriptList((DekiScriptList)uri.Arguments); } else { args = new DekiScriptList(); } args.Add(index); return(new DekiScriptUri(uri.Value, args)); } case DekiScriptType.STR: { DekiScriptString text = (DekiScriptString)prefix; // coerce the index type to NUM double?value = index.AsNumber(); if (value == null) { throw new DekiScriptBadTypeException(expr.Location, index.ScriptType, new[] { DekiScriptType.NUM }); } // retrieve character at given index position int position = (int)value; if ((position < 0) || (position >= text.Value.Length)) { // index is out of bounds, return nil return(DekiScriptNil.Value); } return(DekiScriptExpression.Constant(text.Value[position].ToString())); } case DekiScriptType.XML: { string path = index.AsString(); if (path == null) { throw new DekiScriptBadTypeException(expr.Location, index.ScriptType, new[] { DekiScriptType.STR }); } XDoc doc = ((DekiScriptXml)prefix).Value[path]; if (doc.HasName("html")) { doc = DekiScriptLibrary.CleanseHtmlDocument(doc); } return(new DekiScriptXml(doc)); } case DekiScriptType.NIL: return(DekiScriptNil.Value); } throw new DekiScriptBadTypeException(expr.Location, prefix.ScriptType, new[] { DekiScriptType.MAP, DekiScriptType.LIST, DekiScriptType.XML, DekiScriptType.STR, DekiScriptType.URI }); }
public DekiScriptOutputBuffer.Range Visit(DekiScriptBinary expr, DekiScriptExpressionEvaluationState state) { DekiScriptExpression Left = expr.Left; DekiScriptExpression Right = expr.Right; switch (expr.OpCode) { case DekiScriptBinary.Op.LeftValue: return(Left.VisitWith(this, state)); case DekiScriptBinary.Op.IdentityEqual: { DekiScriptLiteral left = state.Pop(Left.VisitWith(this, state)); DekiScriptLiteral right = state.Pop(Right.VisitWith(this, state)); return(state.Push(DekiScriptBinary.IdentityEqual(left, right))); } case DekiScriptBinary.Op.IdentityNotEqual: { DekiScriptLiteral left = state.Pop(Left.VisitWith(this, state)); DekiScriptLiteral right = state.Pop(Right.VisitWith(this, state)); return(state.Push(DekiScriptBinary.IdentityNotEqual(left, right))); } case DekiScriptBinary.Op.IsType: { DekiScriptLiteral left = state.Pop(Left.VisitWith(this, state)); string type = ((DekiScriptString)Right).Value; return(state.Push(DekiScriptExpression.Constant(type.EqualsInvariantIgnoreCase("any") || left.ScriptTypeName.EqualsInvariantIgnoreCase(type)))); } case DekiScriptBinary.Op.Equal: { DekiScriptLiteral left = state.Pop(Left.VisitWith(this, state)); DekiScriptLiteral right = state.Pop(Right.VisitWith(this, state)); return(state.Push(DekiScriptBinary.Equal(left, right))); } case DekiScriptBinary.Op.NotEqual: { DekiScriptLiteral left = state.Pop(Left.VisitWith(this, state)); DekiScriptLiteral right = state.Pop(Right.VisitWith(this, state)); return(state.Push(DekiScriptBinary.NotEqual(left, right))); } case DekiScriptBinary.Op.GreaterOrEqual: { DekiScriptLiteral left = state.Pop(Left.VisitWith(this, state)); DekiScriptLiteral right = state.Pop(Right.VisitWith(this, state)); if (DekiScriptLiteral.CoerceValuesToSameType(ref left, ref right)) { switch (left.ScriptType) { case DekiScriptType.BOOL: case DekiScriptType.NUM: return(state.Push(DekiScriptExpression.Constant(left.AsNumber() >= right.AsNumber()))); case DekiScriptType.STR: return(state.Push(DekiScriptExpression.Constant(left.AsString().CompareInvariant(right.AsString()) >= 0))); default: return(DekiScriptOutputBuffer.Range.Empty); } } else { return(DekiScriptOutputBuffer.Range.Empty); } } case DekiScriptBinary.Op.GreaterThan: { DekiScriptLiteral left = state.Pop(Left.VisitWith(this, state)); DekiScriptLiteral right = state.Pop(Right.VisitWith(this, state)); if (DekiScriptLiteral.CoerceValuesToSameType(ref left, ref right)) { switch (left.ScriptType) { case DekiScriptType.BOOL: case DekiScriptType.NUM: return(state.Push(DekiScriptExpression.Constant(left.AsNumber() > right.AsNumber()))); case DekiScriptType.STR: return(state.Push(DekiScriptExpression.Constant(left.AsString().CompareInvariant(right.AsString()) > 0))); default: return(DekiScriptOutputBuffer.Range.Empty); } } else { return(DekiScriptOutputBuffer.Range.Empty); } } case DekiScriptBinary.Op.LessOrEqual: { DekiScriptLiteral left = state.Pop(Left.VisitWith(this, state)); DekiScriptLiteral right = state.Pop(Right.VisitWith(this, state)); if (DekiScriptLiteral.CoerceValuesToSameType(ref left, ref right)) { switch (left.ScriptType) { case DekiScriptType.BOOL: case DekiScriptType.NUM: return(state.Push(DekiScriptExpression.Constant(left.AsNumber() <= right.AsNumber()))); case DekiScriptType.STR: return(state.Push(DekiScriptExpression.Constant(left.AsString().CompareInvariant(right.AsString()) <= 0))); default: return(DekiScriptOutputBuffer.Range.Empty); } } else { return(DekiScriptOutputBuffer.Range.Empty); } } case DekiScriptBinary.Op.LessThan: { DekiScriptLiteral left = state.Pop(Left.VisitWith(this, state)); DekiScriptLiteral right = state.Pop(Right.VisitWith(this, state)); if (DekiScriptLiteral.CoerceValuesToSameType(ref left, ref right)) { switch (left.ScriptType) { case DekiScriptType.BOOL: case DekiScriptType.NUM: return(state.Push(DekiScriptExpression.Constant(left.AsNumber() < right.AsNumber()))); case DekiScriptType.STR: return(state.Push(DekiScriptExpression.Constant(left.AsString().CompareInvariant(right.AsString()) < 0))); default: return(DekiScriptOutputBuffer.Range.Empty); } } else { return(DekiScriptOutputBuffer.Range.Empty); } } case DekiScriptBinary.Op.LogicalAnd: { DekiScriptLiteral result = state.Pop(Left.VisitWith(this, state)); if (!result.IsNilFalseZero) { return(Right.VisitWith(this, state)); } return(state.Push(result)); } case DekiScriptBinary.Op.LogicalOr: { DekiScriptLiteral result = state.Pop(Left.VisitWith(this, state)); if (result.IsNilFalseZero) { return(Right.VisitWith(this, state)); } return(state.Push(result)); } case DekiScriptBinary.Op.Addition: return(state.Push(DekiScriptExpression.Constant(state.Pop(Left.VisitWith(this, state)).AsNumber() + state.Pop(Right.VisitWith(this, state)).AsNumber()))); case DekiScriptBinary.Op.Division: return(state.Push(DekiScriptExpression.Constant(state.Pop(Left.VisitWith(this, state)).AsNumber() / state.Pop(Right.VisitWith(this, state)).AsNumber()))); case DekiScriptBinary.Op.Modulo: { DekiScriptLiteral left = state.Pop(Left.VisitWith(this, state)); DekiScriptLiteral right = state.Pop(Right.VisitWith(this, state)); if ((left is DekiScriptString) && ((right is DekiScriptMap) || (right is DekiScriptList))) { // NOTE (steveb): string.format shorthand notation: "abc = $abc" % { abc: 123 } -OR- "0 = $0" % [ 123 ] return(state.Push(DekiScriptLiteral.FromNativeValue(DekiScriptLibrary.StringFormat(((DekiScriptString)left).Value, right.NativeValue)))); } else { return(state.Push(DekiScriptExpression.Constant(left.AsNumber() % right.AsNumber()))); } } case DekiScriptBinary.Op.Multiplication: return(state.Push(DekiScriptExpression.Constant(state.Pop(Left.VisitWith(this, state)).AsNumber() * state.Pop(Right.VisitWith(this, state)).AsNumber()))); case DekiScriptBinary.Op.Subtraction: return(state.Push(DekiScriptExpression.Constant(state.Pop(Left.VisitWith(this, state)).AsNumber() - state.Pop(Right.VisitWith(this, state)).AsNumber()))); case DekiScriptBinary.Op.NullCoalesce: { DekiScriptLiteral result = state.Pop(Left.VisitWith(this, state)); if (result.IsNil) { return(Right.VisitWith(this, state)); } return(state.Push(result)); } case DekiScriptBinary.Op.Concat: { DekiScriptLiteral left = state.Pop(Left.VisitWith(this, state)); DekiScriptLiteral right = state.Pop(Right.VisitWith(this, state)); if (left is DekiScriptNil) { return(state.Push(right)); } else if (right is DekiScriptNil) { return(state.Push(left)); } else if ((left is DekiScriptMap) && (right is DekiScriptMap)) { // left and right expressions are maps, merge them DekiScriptMap result = new DekiScriptMap(); result.AddRange((DekiScriptMap)left); result.AddRange((DekiScriptMap)right); return(state.Push(result)); } else if ((left is DekiScriptList) && (right is DekiScriptList)) { // left and right expressions are lists, concatenate them DekiScriptList result = new DekiScriptList(); result.AddRange((DekiScriptList)left); result.AddRange((DekiScriptList)right); return(state.Push(result)); } else { // treat left and right expressions as strings string leftText = left.AsString(); string rightText = right.AsString(); if ((leftText != null) && (rightText != null)) { return(state.Push(DekiScriptExpression.Constant(leftText + rightText))); } else if (leftText != null) { return(state.Push(DekiScriptExpression.Constant(leftText))); } else if (rightText != null) { return(state.Push(DekiScriptExpression.Constant(rightText))); } else { return(DekiScriptOutputBuffer.Range.Empty); } } } case DekiScriptBinary.Op.UriAppend: { // TODO (steveb): we should throw an exception when the LHS is not a valid string or uri XUri left = XUri.TryParse(state.Pop(Left.VisitWith(this, state)).AsString()); string result = null; if (left != null) { DekiScriptLiteral right = state.Pop(Right.VisitWith(this, state)); if (right is DekiScriptString) { result = DekiScriptLibrary.UriBuild(left, right.AsString(), null); } else if (right is DekiScriptMap) { result = DekiScriptLibrary.UriBuild(left, null, (Hashtable)right.NativeValue); } else { result = left.ToString(); } } return(state.Push(DekiScriptLiteral.FromNativeValue(result))); } case DekiScriptBinary.Op.InCollection: { DekiScriptLiteral left = state.Pop(Left.VisitWith(this, state)); DekiScriptLiteral right = state.Pop(Right.VisitWith(this, state)); if (right is DekiScriptList) { foreach (DekiScriptLiteral item in ((DekiScriptList)right).Value) { if (!DekiScriptBinary.Equal(left, item).IsNilFalseZero) { return(state.Push(DekiScriptBool.True)); } } return(state.Push(DekiScriptBool.False)); } else if (right is DekiScriptMap) { foreach (DekiScriptLiteral item in ((DekiScriptMap)right).Value.Values) { if (!DekiScriptBinary.Equal(left, item).IsNilFalseZero) { return(state.Push(DekiScriptBool.True)); } } return(state.Push(DekiScriptBool.False)); } else { return(state.Push(DekiScriptBool.False)); } } } throw new InvalidOperationException("invalid op code:" + expr.OpCode); }
public DekiScriptOutputBuffer.Range Visit(DekiScriptList expr, DekiScriptExpressionEvaluationState state) { return(state.Push(expr)); }
public static DekiScriptLiteral FromXml(XDoc doc) { // check if response is an HTML document if(doc.HasName("html")) { // TODO (steveb): this handling seems to be to specific to belong here. return new DekiScriptList().Add(new DekiScriptXml(doc)); } // check if response is a DekiScript XML document if(!doc.HasName("value") || (doc["@type"].AsText == null)) { throw new ArgumentException("doc"); } switch(doc["@type"].AsText) { case "nil": return DekiScriptNil.Value; case "bool": return Constant(doc.AsBool ?? false); case "num": return Constant(doc.AsDouble ?? 0.0); case "str": return Constant(doc.AsText ?? string.Empty); case "uri": { return Constant(doc.AsUri); } case "map": { DekiScriptMap result = new DekiScriptMap(); foreach(XDoc value in doc["value"]) { result.Add(value["@key"].AsText, FromXml(value)); } return result; } case "list": { DekiScriptList result = new DekiScriptList(); foreach(XDoc value in doc["value"]) { result.Add(FromXml(value)); } return result; } case "xml": if((doc.AsXmlNode.ChildNodes.Count == 1) && (doc.AsXmlNode.ChildNodes[0].NodeType == XmlNodeType.Element)) { return new DekiScriptXml(doc[doc.AsXmlNode.ChildNodes[0]]); } return DekiScriptNil.Value; default: throw new ArgumentException("doc"); } }
private static DekiScriptLiteral ToDekiScriptRecurse(XDoc doc) { XDoc xdoc = doc.Elements; switch(xdoc.Name) { case "nil": return DekiScriptNil.Value; case "boolean": if(xdoc.Contents.GetType().Equals(typeof(String))) { return DekiScriptExpression.Constant((xdoc.Contents.Contains("1") || xdoc.Contents.Contains("true")) ? true : false); } return DekiScriptExpression.Constant(xdoc.AsBool ?? false); case "double": return DekiScriptExpression.Constant(xdoc.AsDouble ?? 0.0); case "int": case "i4": return DekiScriptExpression.Constant(xdoc.AsDouble ?? 0.0); case "string": return DekiScriptExpression.Constant(xdoc.AsText ?? string.Empty); case "struct": { DekiScriptMap result = new DekiScriptMap(); foreach(XDoc value in xdoc["member"]) { result.Add(value["name"].Contents, ToDekiScriptRecurse(value["value"])); } return result; } case "array": { DekiScriptList result = new DekiScriptList(); foreach(XDoc value in xdoc["data/value"]) { result.Add(ToDekiScriptRecurse(value)); } return result; } default: throw new ArgumentException("this type does not exist in the XML-RPC standard"); } }
internal static XDoc CreateWarningFromException(DekiScriptList callstack, Location location, Exception exception) { // unwrap nested async exception exception = UnwrapAsyncException(null, exception); // determine exception XDoc result; if(exception is DreamAbortException) { DreamAbortException e = (DreamAbortException)exception; if(e.Response.ContentType.IsXml) { result = CreateWarningElement(callstack, string.Format("{1}, a web exception was thrown (status: {0})", (int)e.Response.Status, location), new XMessage(e.Response).ToPrettyString()); } else { result = CreateWarningElement(callstack, string.Format("{1}, a web exception was thrown (status: {0})", (int)e.Response.Status, location), e.Response.AsText()); } } else if(exception is DekiScriptException) { result = CreateWarningElement(callstack, exception.Message, exception.GetCoroutineStackTrace()); } else { result = CreateWarningElement(callstack, string.Format("{0}: {1}", exception.Message, location), exception.GetCoroutineStackTrace()); } return result; }
//--- Methods --- public override DekiScriptLiteral InvokeList(DekiScriptRuntime runtime, DekiScriptList args) { // prepare uri for invocation Plug plug = Plug.New(_endpoint); plug = runtime.PreparePlug(plug); DreamMessage response = plug.Post(DekiScriptToXmlRpc(_methodname, args)); // convert response to literal DekiScriptLiteral list = FromXmlRpcToDekiScript(response.ToDocument()); if(list.ScriptType != DekiScriptType.LIST) { throw new DekiScriptBadReturnTypeException(Location.None, list.ScriptType, new[] { DekiScriptType.LIST }); } return ((DekiScriptList)list)[0]; }
private static DekiScriptLiteral FromXmlRpcToDekiScript(XDoc xdoc) { if(xdoc.HasName("html")) { return new DekiScriptList().Add(new DekiScriptXml(xdoc)); } if(xdoc.HasName("methodResponse")) { if(!xdoc["fault"].IsEmpty) { string errorMessage = xdoc["fault/value/struct/member[name='faultString']/value/string"].AsText; throw new DekiScriptXmlRpcException(errorMessage ?? xdoc.ToPrettyString()); } if(!xdoc["params"].IsEmpty) { DekiScriptList result = new DekiScriptList(); foreach(XDoc param in xdoc["params/param/value"]) { result.Add(ToDekiScriptRecurse(param)); } return result; } else { // NOTE: unexpected result, treat it as a nil result DekiScriptList result = new DekiScriptList(); result.Add(DekiScriptNil.Value); return result; } } throw new DekiScriptUnsupportedTypeException(Location.None, string.Format("<{0}>", xdoc.Name)); }
public DekiScriptExpression Visit(DekiScriptList expr, DekiScriptExpressionEvaluationState state) { return(expr); }
public void Create_entries_in_cache() { DekiScriptLiteral result; // create web-cahce extension service var webcache = DreamTestHelper.CreateService( _hostInfo, new XDoc("config") .Elem("class", typeof(WebCacheService).FullName) .Elem("path", "webcache") ); // extract entry points for web-cache functions var manifest = webcache.AtLocalHost.Get().AsDocument(); var fetch = Plug.New(manifest["function[name/text()='fetch']/uri"].AsUri); var store = Plug.New(manifest["function[name/text()='store']/uri"].AsUri); var clear = Plug.New(manifest["function[name/text()='clear']/uri"].AsUri); // create MAX_ITERATIONS entries in web-cache var sw = Stopwatch.StartNew(); for(int i = 1; i <= MAX_ITERATIONS; ++i) { var key = "key" + i; var list = new DekiScriptList() .Add(DekiScriptExpression.Constant(key)) .Add(DekiScriptExpression.Constant(CONTENT)); var response = store.Post(list.ToXml()); var doc = response.ToDocument(); result = DekiScriptLiteral.FromXml(doc); _log.DebugFormat("webcache.store('{0}') -> {1}", key, result); } sw.Stop(); _log.DebugFormat("webcache.store() all took {0:#,##0} seconds", sw.Elapsed.TotalSeconds); // shutdown web-cache service webcache.WithPrivateKey().AtLocalHost.Delete(); // re-create web-cache extension service webcache = DreamTestHelper.CreateService( _hostInfo, new XDoc("config") .Elem("class", typeof(WebCacheService).FullName) .Elem("path", "webcache") ); // re-extract entry points for web-cache functions manifest = webcache.AtLocalHost.Get().AsDocument(); fetch = Plug.New(manifest["function[name/text()='fetch']/uri"].AsUri); store = Plug.New(manifest["function[name/text()='store']/uri"].AsUri); clear = Plug.New(manifest["function[name/text()='clear']/uri"].AsUri); // loop over all entries in web-cache and fetch them sw = Stopwatch.StartNew(); for(int i = 1; i <= MAX_ITERATIONS; ++i) { int count = 0; var key = "key" + i; do { result = DekiScriptLiteral.FromXml(fetch.Post(new DekiScriptList().Add(DekiScriptExpression.Constant(key)).ToXml()).ToDocument()); var text = ((DekiScriptList)result)[0].AsString(); if(text == CONTENT) { break; } Thread.Sleep(50); } while(++count < 100); if(count >= 100) { Assert.Fail("too many attempts to load " + key); return; } } sw.Stop(); _log.DebugFormat("webcache.fetch() all took {0:#,##0} seconds", sw.Elapsed.TotalSeconds); // loop over all entries in web-cache and clear them out sw = Stopwatch.StartNew(); for(int i = 1; i <= MAX_ITERATIONS; ++i) { var key = "key" + i; var list = new DekiScriptList() .Add(DekiScriptExpression.Constant(key)); var response = clear.Post(list.ToXml()); var doc = response.ToDocument(); result = DekiScriptLiteral.FromXml(doc); _log.DebugFormat("webcache.clear('{0}') -> {1}", key, result); } sw.Stop(); _log.DebugFormat("webcache.clear() all took {0:#,##0} seconds", sw.Elapsed.TotalSeconds); // loop over all entries in web-cache and fetch them sw = Stopwatch.StartNew(); for(int i = 1; i <= MAX_ITERATIONS; ++i) { var key = "key" + i; result = DekiScriptLiteral.FromXml(fetch.Post(new DekiScriptList().Add(DekiScriptExpression.Constant(key)).ToXml()).ToDocument()); var text = ((DekiScriptList)result)[0].AsString(); Assert.AreEqual(null, text, "entry " + key + " was not deleted"); } sw.Stop(); _log.DebugFormat("webcache.fetch() all took {0:#,##0} seconds", sw.Elapsed.TotalSeconds); // shutdown web-cache service again webcache.WithPrivateKey().AtLocalHost.Delete(); }
public Yield PostExtensionFunction(DreamContext context, DreamMessage request, Result<DreamMessage> response) { string name = context.GetParam("function"); // check if we need to reload the manifest if(_debug) { LoadScript(); } // find function DekiScriptInvocationTargetDescriptor descriptor; if(!_functions.TryGetValue(Self.At(name), out descriptor)) { response.Return(DreamMessage.NotFound(string.Format("function {0} not found", name))); yield break; } // set optional culture from request context.Culture = HttpUtil.GetCultureInfoFromHeader(request.Headers.AcceptLanguage, context.Culture); // read input arguments for invocation DekiScriptLiteral args = DekiScriptLiteral.FromXml(request.ToDocument()); // create custom environment var implicitEnv = DekiExtService.GetImplicitEnvironment(request, _publicDigitalSignature); implicitEnv.AddNativeValueAt("self", Self.Uri.AsPublicUri().ToString()); DreamContext.Current.SetState("env.implicit", implicitEnv); // invoke target DekiScriptLiteral eval; try { eval = descriptor.Target.Invoke(ScriptRuntime, args); } catch(Exception e) { response.Return(DreamMessage.InternalError(e)); yield break; } // check if response is embeddable XML if(eval is DekiScriptXml) { XDoc doc = ((DekiScriptXml)eval).Value; if(doc.HasName("html")) { // replace all self: references foreach(XDoc item in doc[".//*[starts-with(@src, 'self:')]/@src | .//*[starts-with(@href, 'self:')]/@href"]) { try { item.ReplaceValue(Self.AtPath(item.Contents.Substring(5))); } catch { } } } } // process response DekiScriptList result = new DekiScriptList().Add(eval); response.Return(DreamMessage.Ok(result.ToXml())); }
public object Store( [DekiExtParam("document id")] string id, [DekiExtParam("document to cache", true)] object document, [DekiExtParam("caching duration in seconds (range: 300+; default: 300)", true)] double?ttl ) { if (document == null) { return(Clear(id)); } // fetch entry from cache CacheEntry result; bool isNew = true; lock (_cacheLookup) { _cacheLookup.TryGetValue(id, out result); } // check if we have a cached entry if (result != null) { _log.DebugFormat("cache hit for '{0}'", result.Id); isNew = false; result.ResetMemoryExpiration(); } else { _log.DebugFormat("new cache item for '{0}'", id); result = new CacheEntry(id, ttl); } // update cache with document DekiScriptLiteral literal = DekiScriptLiteral.FromNativeValue(document); XDoc xml = new DekiScriptList().Add(literal).ToXml(); result.Cache = xml.ToString(); // start timer to clean-up cached result if (result.Cache != null) { XDoc infoDoc = new XDoc("cache-entry") .Elem("guid", result.Guid) .Elem("id", result.Id) .Elem("expires", result.Expires); lock (result) { Storage.At(CACHE_DATA, result.Guid + ".bin").PutAsync(new DreamMessage(DreamStatus.Ok, null, MimeType.BINARY, Encoding.UTF8.GetBytes(result.Cache))).Wait(); Storage.At(CACHE_INFO, result.Guid + ".xml").PutAsync(infoDoc).Wait(); } if (isNew) { lock (_cacheLookup) { _cacheLookup[id] = result; } // this timer removes the cache entry from disk SetupCacheTimer(result); } } return(document); }
public DekiScriptLiteral Visit(DekiScriptCall expr, DekiScriptEnv env) { // evaluate prefix DekiScriptLiteral prefix = expr.Prefix.VisitWith(this, env); if (prefix.ScriptType != DekiScriptType.URI) { if (prefix.ScriptType == DekiScriptType.NIL) { throw new DekiScriptUndefinedNameException(expr.Line, expr.Column, expr.Prefix.ToString()); } else { throw new DekiScriptBadTypeException(expr.Line, expr.Column, prefix.ScriptType, new DekiScriptType[] { DekiScriptType.URI }); } } // evaluate arguments DekiScriptLiteral arguments = expr.Arguments.VisitWith(this, env); if ((arguments.ScriptType != DekiScriptType.MAP) && (arguments.ScriptType != DekiScriptType.LIST)) { throw new DekiScriptBadTypeException(expr.Line, expr.Column, arguments.ScriptType, new DekiScriptType[] { DekiScriptType.MAP, DekiScriptType.LIST }); } // check if the URI was curried DekiScriptUri uri = (DekiScriptUri)prefix; if (!uri.Arguments.IsNil) { switch (uri.Arguments.ScriptType) { case DekiScriptType.LIST: // append argument to list DekiScriptList list = new DekiScriptList((DekiScriptList)uri.Arguments); list.Add(arguments); arguments = list; break; case DekiScriptType.MAP: if (arguments.ScriptType == DekiScriptType.MAP) { // concatenate both maps DekiScriptMap map = new DekiScriptMap(); map.AddRange((DekiScriptMap)uri.Arguments); map.AddRange((DekiScriptMap)arguments); arguments = map; } else if ((arguments.ScriptType != DekiScriptType.LIST) || ((DekiScriptList)arguments).Value.Count > 0) { // we can't append a list to a map throw new DekiScriptBadTypeException(expr.Line, expr.Column, arguments.ScriptType, new DekiScriptType[] { DekiScriptType.MAP }); } break; default: throw new DekiScriptBadTypeException(expr.Line, expr.Column, arguments.ScriptType, new DekiScriptType[] { DekiScriptType.MAP, DekiScriptType.LIST }); } } // check if this is an invocation or curry operation if (expr.IsCurryOperation) { return(new DekiScriptUri(uri.Value, arguments)); } else { // invoke function return(Coroutine.Invoke(DekiScriptRuntime.Invoke, uri.Value, arguments, env, new Result <DekiScriptLiteral>()).Wait()); } }
public Yield PostExtensionFunction(DreamContext context, DreamMessage request, Result <DreamMessage> response) { string name = context.GetParam("function"); // check if we need to reload the manifest if (_debug) { LoadScript(); } // find function DekiScriptInvocationTargetDescriptor descriptor; if (!_functions.TryGetValue(Self.At(name), out descriptor)) { response.Return(DreamMessage.NotFound(string.Format("function {0} not found", name))); yield break; } // set optional culture from request context.Culture = HttpUtil.GetCultureInfoFromHeader(request.Headers.AcceptLanguage, context.Culture); // read input arguments for invocation DekiScriptLiteral args = DekiScriptLiteral.FromXml(request.ToDocument()); // create custom environment var implicitEnv = DekiExtService.GetImplicitEnvironment(request, _publicDigitalSignature); implicitEnv.AddNativeValueAt("self", Self.Uri.AsPublicUri().ToString()); DreamContext.Current.SetState("env.implicit", implicitEnv); // invoke target DekiScriptLiteral eval; try { eval = descriptor.Target.Invoke(ScriptRuntime, args); } catch (Exception e) { response.Return(DreamMessage.InternalError(e)); yield break; } // check if response is embeddable XML if (eval is DekiScriptXml) { XDoc doc = ((DekiScriptXml)eval).Value; if (doc.HasName("html")) { // replace all self: references foreach (XDoc item in doc[".//*[starts-with(@src, 'self:')]/@src | .//*[starts-with(@href, 'self:')]/@href"]) { try { item.ReplaceValue(Self.AtPath(item.Contents.Substring(5))); } catch { } } } } // process response DekiScriptList result = new DekiScriptList().Add(eval); response.Return(DreamMessage.Ok(result.ToXml())); }
//--- Methods --- public override DekiScriptLiteral InvokeList(DekiScriptRuntime runtime, DekiScriptList args) { return(InvokeHelper(runtime, DekiScriptParameter.ValidateToList(Parameters, args))); }
public static DekiScriptList ValidateToList(DekiScriptParameter[] parameters, DekiScriptMap args) { DekiScriptList result = new DekiScriptList(); // check passed in arguments for(int i = 0; i < parameters.Length; ++i) { var value = args[parameters[i].Name]; if(value.IsNil) { if((parameters[i].ScriptType != DekiScriptType.ANY) && !parameters[i].Optional) { throw new ArgumentException(string.Format("missing value for parameter '{0}' (index {1})", parameters[i].Name, i)); } // set default value for this parameter result.Add(parameters[i].Default); } else { result.Add(parameters[i].Convert(value)); } } return result; }
public object Store( [DekiExtParam("document id")] string id, [DekiExtParam("document to cache", true)] object document, [DekiExtParam("caching duration in seconds (range: 300+; default: 300)", true)] double? ttl ) { if(document == null) { return Clear(id); } // fetch entry from cache CacheEntry result; bool isNew = true; lock(_cacheLookup) { _cacheLookup.TryGetValue(id, out result); } // check if we have a cached entry if(result != null) { _log.DebugFormat("cache hit for '{0}'", result.Id); isNew = false; result.ResetMemoryExpiration(); } else { _log.DebugFormat("new cache item for '{0}'", id); result = new CacheEntry(id, ttl); } // update cache with document DekiScriptLiteral literal = DekiScriptLiteral.FromNativeValue(document); XDoc xml = new DekiScriptList().Add(literal).ToXml(); result.Cache = xml.ToString(); // start timer to clean-up cached result if(result.Cache != null) { XDoc infoDoc = new XDoc("cache-entry") .Elem("guid", result.Guid) .Elem("id", result.Id) .Elem("expires", result.Expires); lock(result) { Storage.At(CACHE_DATA, result.Guid + ".bin").PutAsync(new DreamMessage(DreamStatus.Ok, null, MimeType.BINARY, Encoding.UTF8.GetBytes(result.Cache))).Wait(); Storage.At(CACHE_INFO, result.Guid + ".xml").PutAsync(infoDoc).Wait(); } if(isNew) { lock(_cacheLookup) { _cacheLookup[id] = result; } // this timer removes the cache entry from disk SetupCacheTimer(result); } } return document; }
public DekiScriptExpression Visit(DekiScriptList expr, DekiScriptOptimizerState state) { return(expr); }