public static void ParseResponseBody(ManticoreEngine engine, ObjectInstance response, String format, Stream byteStream) { if ("json".Equals(format, StringComparison.OrdinalIgnoreCase)) { String json = new StreamReader(byteStream, Encoding.UTF8).ReadToEnd(); if (json != null && json.Length > 0) { JsValue jsObject = engine.jsEngine.Json.Parse(JsValue.Null, new JsValue[] { json }); response.FastAddProperty("body", jsObject, false, true, false); } } else if (!"binary".Equals(format, StringComparison.OrdinalIgnoreCase)) { String bodyString = new StreamReader(byteStream, Encoding.UTF8).ReadToEnd(); response.FastAddProperty("body", new JsValue(bodyString), false, true, false); } else { byte[] bytes = ReadAllBytes(byteStream); if (bytes != null && bytes.Length > 0) { response.FastAddProperty("body", new JsValue(Convert.ToBase64String(bytes)), false, true, false); } } }
public void Register(ManticoreEngine engine) { engine.ManticoreJsObject.FastAddProperty("_log", engine.AsJsFunction((thisObject, args) => { JsValue extra = JsValue.Null; if (args.Length > 2) { extra = args[2]; } Log(args[0].AsString(), args[1].AsString(), extra); return(JsValue.Undefined); }), true, false, false); engine.ManticoreJsObject.FastAddProperty("_setTimeout", engine.AsJsFunction((thisObject, args) => { SetTimeout(engine, args[0].As <FunctionInstance>(), (int)args[1].AsNumber()); return(JsValue.Undefined); }), true, false, false); engine.ManticoreJsObject.FastAddProperty("_fetch", engine.AsJsFunction((thisObject, args) => { Task.Factory.StartNew(() => { Fetch(engine, args[0], args[1]); }); return(JsValue.Undefined); }), true, false, false); }
internal ManticoreJsError(ManticoreEngine manticoreEngine, Exception ex, int?code = null) : base(manticoreEngine.jsEngine, ex.Message) { FastAddProperty("message", ex.Message, true, false, true); FastAddProperty("code", code.HasValue ? new JsValue(code.Value) : JsValue.Null, true, false, true); FastAddProperty("stack", ex.StackTrace, true, false, true); FastAddProperty("toString", manticoreEngine.AsJsFunction(((thisObj, args) => ex.ToString())), true, false, false); }
private async void sendRequest(ManticoreEngine engine, int timeout, HttpClient client, HttpRequestMessage request, JsValue callback) { var responseInfo = engine.CreateJsObject(); HttpResponseMessage response = null; CancellationTokenSource cts = new CancellationTokenSource(timeout); try { response = await client.SendRequestAsync(request, HttpCompletionOption.ResponseContentRead).AsTask(cts.Token); } catch (Exception x) { var ei = new JsErrorBuilder(engine, x).Build(); responseInfo.FastAddProperty("error", ei, false, true, false); } if (response != null && response.Headers.Count > 0) { var headerCollection = engine.CreateJsObject(); foreach (var kv in response.Headers) { try { headerCollection.FastAddProperty(kv.Key, new JsValue(kv.Value), false, true, false); } catch (ArgumentException) { // Swallow duplicate headers for now. } } responseInfo.FastAddProperty("headers", headerCollection, false, true, false); } byte[] binaryResult = null; if (response != null) { responseInfo.FastAddProperty("status", new JsValue((int)response.StatusCode), false, true, false); // TODO find a way to sneak this wait into the gap between returning and asking for the results // json/body/text signatures probably need to change to take a callback. binaryResult = (await response.Content.ReadAsBufferAsync()).ToArray(); } engine.Js(() => { responseInfo.FastAddProperty("json", engine.AsJsFunction((thisObject, args) => { return(engine.jsEngine.Json.Parse(JsValue.Null, new JsValue[] { Encoding.UTF8.GetString(binaryResult, 0, binaryResult.Length) })); }), false, false, false); responseInfo.FastAddProperty("body", engine.AsJsFunction((thisObject, args) => { return(engine.jsEngine.Json.Parse(JsValue.Null, new JsValue[] { Convert.ToBase64String(binaryResult) })); }), false, false, false); responseInfo.FastAddProperty("text", engine.AsJsFunction((thisObject, args) => { return(new JsValue(Encoding.UTF8.GetString(binaryResult, 0, binaryResult.Length))); }), false, false, false); callback.As <FunctionInstance>().Call(engine.ManticoreJsObject, new JsValue[] { JsValue.Null, responseInfo }); }); }
public void Register(ManticoreEngine engine) { this.engine = engine; engine.ManticoreJsObject._log = new Action <String, String>((level, message) => log(level, message)); engine.ManticoreJsObject._setTimeout = new Action <dynamic, int>((fn, msec) => { setTimeout(fn, msec); }); engine.ManticoreJsObject._fetch = new Action <dynamic, dynamic>((opts, cb) => this.fetch(opts, cb)); }
public static void CreateManticoreEngine(String script, String name) { if (Engine != null && Engine.IsStarted) { throw new InvalidOperationException("You must shut down the existing engine before creating a new one."); } var e = new ManticoreEngine(); e.Converter = new DefaultConverter <JsBackedObject>(e, (native) => native.impl, (jsErr) => new ManticoreException(jsErr)); // Typically, you would add your own native method implementations to // the ManticoreJsObject here, before you load your script e.LoadScript(script, name); Engine = e; }
private async void SetTimeout(ManticoreEngine engine, FunctionInstance callback, int timeout) { await Task.Delay(TimeSpan.FromMilliseconds(timeout)); engine.Js(() => { try { callback.Call(JsValue.Null, new JsValue[] { }); } catch (Exception x) { Debug.WriteLine(x); } }); }
private void SetTimeout(ManticoreEngine engine, FunctionInstance callback, int timeout) { System.Timers.Timer timer = new System.Timers.Timer(); // TODO not sure there may be a better way to emulate NextTick timer.Interval = Math.Max(1, timeout); timer.AutoReset = false; timer.Elapsed += (obj, args) => { engine.Js(() => { try { callback.Call(JsValue.Null, new JsValue[] { }); } catch (Exception x) { // TODO perhaps throw this error INTO JS? Log("error", x.ToString(), JsValue.Null); } }); }; timer.Start(); }
public static void ParseResponseBody(ManticoreEngine engine, dynamic responseInfo, String format, byte[] response) { if ("json".Equals(format, StringComparison.OrdinalIgnoreCase)) { String json = Encoding.UTF8.GetString(response); if (json.Length > 0) { responseInfo.body = engine.v8.Script.JSON.parse(json); } } else if (!"binary".Equals(format, StringComparison.OrdinalIgnoreCase)) { String bodyString = Encoding.UTF8.GetString(response); responseInfo.body = bodyString; } else { if (response.Length > 0) { responseInfo.body = Convert.ToBase64String(response); } } }
public JsErrorBuilder(ManticoreEngine manticoreEngine, Exception ex) { _engine = manticoreEngine; _exception = ex; }
public void Fetch(ManticoreEngine engine, JsValue optionsValue, JsValue callback) { var options = optionsValue.As <ObjectInstance>(); JsValue rawBody = options.Get("nativeBody").As <FunctionInstance>().Call(options, ManticoreEngine.EmptyArgs); var hasBody = rawBody.IsString() && rawBody.AsString().Length > 0; var request = (HttpWebRequest)WebRequest.Create(options.Get("url").AsString()); request.Method = "GET"; if (options.HasProperty("method")) { request.Method = options.Get("method").AsString(); } if (options.HasProperty("headers")) { var headers = options.Get("headers").AsObject(); var raw = headers.Get("raw").As <FunctionInstance>().Call(headers, ManticoreEngine.EmptyArgs); if (raw.IsObject()) { foreach (var p in raw.AsObject().GetOwnProperties()) { if (p.Key.Equals("Content-Type", StringComparison.OrdinalIgnoreCase)) { if (hasBody) { request.ContentType = p.Value.Value.Value.AsString(); } } else if (p.Key.Equals("If-Modified-Since", StringComparison.OrdinalIgnoreCase)) { request.IfModifiedSince = DateTime.Parse(p.Value.Value.Value.AsString()); } else { request.Headers.Add(p.Key, p.Value.Value.Value.AsString()); } } } } if (hasBody) { var body = rawBody.AsString(); byte[] bodyBytes; if (options.HasProperty("isBase64") && options.Get("isBase64").AsBoolean()) { bodyBytes = Convert.FromBase64String(body); } else { bodyBytes = Encoding.UTF8.GetBytes(body); } request.ContentLength = bodyBytes.Length; var errorInstance = JsValue.Null; try { var rqStream = request.GetRequestStream(); rqStream.Write(bodyBytes, 0, bodyBytes.Length); rqStream.Close(); } catch (Exception x) { // TODO fire this log into JS? manticore.onError()? Log("error", x.ToString(), JsValue.Null); var errorBuilder = new JsErrorBuilder(engine, x); if (x is WebException) { errorBuilder.SetErrorCode((int)ErrorCodes.NetworkOffline); } errorInstance = errorBuilder.Build(); } if (errorInstance != JsValue.Null) { engine.Js(() => { callback.As <FunctionInstance>().Call(engine.ManticoreJsObject, new[] { errorInstance, JsValue.Null }); }); return; } } sendRequest(engine, request, callback); }
public void Fetch(ManticoreEngine engine, JsValue optionsValue, JsValue callback) { var options = optionsValue.As <ObjectInstance>(); var httpBaseFilter = new HttpBaseProtocolFilter { AllowUI = false }; var client = new HttpClient(httpBaseFilter); HttpMethod requestMethod = HttpMethod.Get; if (options.HasProperty("method")) { var method = options.Get("method").AsString(); if (method != null) { switch (method.ToLower()) { case "delete": requestMethod = HttpMethod.Delete; break; case "head": requestMethod = HttpMethod.Head; break; case "options": requestMethod = HttpMethod.Options; break; case "patch": requestMethod = HttpMethod.Patch; break; case "post": requestMethod = HttpMethod.Post; break; case "put": requestMethod = HttpMethod.Put; break; } } } var urlString = options.Get("url").AsString(); var rawBody = options.Get("nativeBody").As <ScriptFunctionInstance>().Call(options, ManticoreEngine.EmptyArgs); var hasBody = rawBody.IsString() && rawBody.AsString().Length > 0; var request = new HttpRequestMessage(requestMethod, new Uri(urlString)); if (options.HasProperty("headers")) { var headers = options.Get("headers").AsObject(); var raw = headers.Get("raw").As <FunctionInstance>().Call(headers, ManticoreEngine.EmptyArgs); if (raw.IsObject()) { foreach (var p in raw.AsObject().GetOwnProperties()) { if (p.Key.Equals("Content-Type", StringComparison.OrdinalIgnoreCase)) { if (hasBody) { request.Content.Headers.Add(p.Key, p.Value.Value.Value.AsString()); } } else { request.Headers.Add(p.Key, p.Value.Value.Value.AsString()); } } } } if (hasBody) { if (options.HasProperty("isBase64") && options.Get("isBase64").AsBoolean()) { request.Content = new HttpBufferContent(Convert.FromBase64String(rawBody.AsString()).AsBuffer()); } else { request.Content = new HttpBufferContent(Encoding.UTF8.GetBytes(rawBody.AsString()).AsBuffer()); } } int timeout = 60000; if (options.HasProperty("timeout") && options.Get("timeout").IsNumber()) { timeout = (int)options.Get("timeout").AsNumber(); } sendRequest(engine, timeout, client, request, callback); }
private void sendRequest(ManticoreEngine engine, HttpWebRequest request, JsValue callback) { request.BeginGetResponse((asyncResult) => { HttpWebResponse response = null; var errorInstance = JsValue.Null; try { response = (HttpWebResponse)request.EndGetResponse(asyncResult); } catch (WebException e) { if (e.Status == WebExceptionStatus.ProtocolError) //Response was received from server but indicated protocol level error { response = (HttpWebResponse)e.Response; } else { errorInstance = new JsErrorBuilder(engine, e).SetErrorCode((int)ErrorCodes.NetworkOffline).Build(); } } if (response == null) { engine.Js(() => { callback.As <FunctionInstance>().Call(engine.ManticoreJsObject, new[] { errorInstance, JsValue.Null }); }); return; } var responseInfo = engine.CreateJsObject(); if (response.Headers.Count > 0) { var headerCollection = engine.CreateJsObject(); foreach (var kv in response.Headers.AllKeys) { headerCollection.FastAddProperty(kv, new JsValue(response.Headers[kv]), false, true, false); } responseInfo.FastAddProperty("headers", headerCollection, false, true, false); } responseInfo.FastAddProperty("status", new JsValue((int)response.StatusCode), false, true, false); // TODO find a way to sneak this wait into the gap between returning and asking for the results // json/body/text signatures probably need to change to take a callback. var memStream = new MemoryStream(); response.GetResponseStream().CopyTo(memStream); var binaryResult = memStream.ToArray(); responseInfo.FastAddProperty("json", engine.AsJsFunction((thisObject, args) => { return(engine.jsEngine.Json.Parse(JsValue.Null, new JsValue[] { Encoding.UTF8.GetString(binaryResult) })); }), false, false, false); responseInfo.FastAddProperty("body", engine.AsJsFunction((thisObject, args) => { return(engine.jsEngine.Json.Parse(JsValue.Null, new JsValue[] { Convert.ToBase64String(binaryResult) })); }), false, false, false); responseInfo.FastAddProperty("text", engine.AsJsFunction((thisObject, args) => { return(new JsValue(Encoding.UTF8.GetString(binaryResult))); }), false, false, false); engine.Js(() => { callback.As <FunctionInstance>().Call(engine.ManticoreJsObject, new[] { errorInstance, responseInfo }); }); }, null); }
/// <summary> /// One of the important goals of Manticore is to isolate the fact that you have chosen to use it /// for services you advertise to others (e.g. the SDK scenario). SO, you can't have your objects /// inherit from our base class. This converter constructor is your punishment. You need to provide /// us two simple lambdas - one that retrives the JS value from your objects and one that makes /// your exception class. This means that in most simple cases you won't have to derive from /// DefaultConverter, just create one. /// </summary> public DefaultConverter(ManticoreEngine engine, Func <JsBaseClass, dynamic> jsExtractor, Func <dynamic, Exception> jsException) { this.engine = engine; this.jsExtractor = jsExtractor; this.jsException = jsException; }
/// <summary> /// One of the important goals of Manticore is to isolate the fact that you have chosen to use it /// for services you advertise to others (e.g. the SDK scenario). SO, you can't have your objects /// inherit from our base class. This converter constructor is your punishment. You need to provide /// us two simple lambdas - one that retrives the JS value from your objects and one that makes /// your exception class. This means that in most simple cases you won't have to derive from /// DefaultConverter, just create one. /// </summary> public DefaultConverter(ManticoreEngine engine, Func <JsBaseClass, JsValue> jsExtractor, Func <ObjectInstance, Exception> jsException) { this.engine = engine; this.jsExtractor = jsExtractor; this.jsException = jsException; }