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); }
public override DekiScriptLiteral InvokeMap(DekiScriptRuntime runtime, DekiScriptMap 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 override DekiScriptLiteral InvokeMap(DekiScriptRuntime runtime, DekiScriptMap args) { // prepare uri for invocation Plug plug = Plug.New(_endpoint); plug = runtime.PreparePlug(plug); // invoke function DreamMessage response = plug.Get(); // 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 DekiScriptBadReturnTypeException(Location.None, list.ScriptType, new[] { DekiScriptType.LIST }); } return(((DekiScriptList)list)[0]); }
public Yield PostExtensionFunction(DreamContext context, DreamMessage request, Result <DreamMessage> response) { var name = context.GetParam("function"); XUri uri = Self.At(name); // check if deki server is permitted to invoke this function if (this is IDreamServiceLicense) { string deki; if (context.ServiceLicense.TryGetValue("deki", out deki) && !deki.EqualsInvariant(request.Headers[DEKI_HEADER] ?? string.Empty)) { throw new DreamAbortException(DreamMessage.Forbidden("deki server is not licensed for this service")); } } // check if any functions were found DekiScriptInvocationTargetDescriptor descriptor; if (!_functions.TryGetValue(uri, out descriptor)) { response.Return(DreamMessage.NotFound(string.Format("function {0} not found", context.GetParam("function")))); yield break; } // check if invoker has access to function if ((descriptor.Access != DreamAccess.Public) && (descriptor.Access > DetermineAccess(context, request))) { response.Return(DreamMessage.Forbidden("insufficient access privileges")); yield break; } // check if request has a requested culture context.Culture = HttpUtil.GetCultureInfoFromHeader(request.Headers.AcceptLanguage, context.Culture); // check for implicit arguments context.SetState(GetImplicitEnvironment(request, _publicDigitalSignature)); // create custom environment DekiScriptEnv env = CreateEnvironment(); // create custom target for custom environment var target = descriptor.Target as DekiScriptExpressionInvocationTarget; if (target != null) { // TODO (steveb): re-initializing the invocation target works for the first call, but not if the function calls another function in the same extension! target = new DekiScriptExpressionInvocationTarget(target.Access, target.Parameters, target.Expression, env); } // invoke target DekiScriptLiteral eval; if (target != null) { eval = target.Invoke(ScriptRuntime, DekiScriptLiteral.FromXml(request.ToDocument())); } else { eval = descriptor.Target.Invoke(ScriptRuntime, DekiScriptLiteral.FromXml(request.ToDocument())); } // invoke function response.Return(DreamMessage.Ok(new DekiScriptList().Add(eval).ToXml())); yield break; }
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 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(); }