/// <summary> /// Parse a <see cref="DebugServerException"/> from the server response. /// </summary> /// <param name="content"> /// JSON response returned by the debug server. /// </param> /// <returns>The exception instance.</returns> public static DebugServerException Parse(string content) { if (!string.IsNullOrEmpty(content)) { try { var jsonObject = JObject.Parse(content); var fileName = jsonObject.Value <string>("filename"); var description = jsonObject.Value <string>("description"); if (description != null) { return(new DebugServerException( jsonObject.Value <string>("description"), ShortenFileName(fileName), jsonObject.Value <int>("lineNumber"), jsonObject.Value <int>("column"))); } } catch (JsonException ex) { RnLog.Error(ReactConstants.RNW, ex, $"Failure deserializing debug server exception message."); } } return(null); }
private async Task <ReactContext> InitializeReactContextAsync( Func <IJavaScriptExecutor> jsExecutorFactory, JavaScriptBundleLoader jsBundleLoader, CancellationToken token) { var currentReactContext = _currentReactContext; if (currentReactContext != null) { await TearDownReactContextAsync(currentReactContext, token); _currentReactContext = null; } try { var reactContext = await CreateReactContextCoreAsync(jsExecutorFactory, jsBundleLoader, token); await SetupReactContextAsync(reactContext); return(reactContext); } catch (OperationCanceledException) when(token.IsCancellationRequested) { RnLog.Info(ReactConstants.RNW, $"ReactInstanceManager: Creating React context has been canceled"); throw; } catch (Exception ex) { RnLog.Error(ReactConstants.RNW, ex, $"ReactInstanceManager: Exception when creating React context: {ex.Message}"); _devSupportManager.HandleException(ex); } return(null); }
/// <summary> /// Runs the script at the given path. /// </summary> /// <param name="sourcePath">The source path.</param> /// <param name="sourceUrl">The source URL.</param> public void RunScript(string sourcePath, string sourceUrl) { if (sourcePath == null) { throw new ArgumentNullException(nameof(sourcePath)); } if (sourceUrl == null) { throw new ArgumentNullException(nameof(sourceUrl)); } var startupCode = default(string); if (IsUnbundle(sourcePath)) { _unbundle = new FileBasedJavaScriptUnbundle(sourcePath); InstallNativeRequire(); startupCode = _unbundle.GetStartupCode(); } else if (IsIndexedUnbundle(sourcePath)) { _unbundle = new IndexedJavaScriptUnbundle(sourcePath); InstallNativeRequire(); startupCode = _unbundle.GetStartupCode(); } else { startupCode = LoadScript(sourcePath); try { if (this._modifyBundle != null) { //Modify bundle function returns modified bundle. var updatedBundle = this._modifyBundle(startupCode); startupCode = updatedBundle; } } catch (Exception ex) { RnLog.Error("Native", ex, @"Exception during bundle modification."); #if DEBUG throw; #endif } } EvaluateScript(startupCode, sourceUrl); }
private JavaScriptValue NativeLoggingHook( JavaScriptValue callee, bool isConstructCall, JavaScriptValue[] arguments, ushort argumentCount, IntPtr callbackData) { try { var message = arguments[1].ToString(); var logLevel = (LogLevel)(int)arguments[2].ToDouble(); RnLog.Info("JS", $"{logLevel} {message}"); } catch { RnLog.Error("JS", $"Unable to process JavaScript console statement"); } return(JavaScriptValue.Undefined); }
public void close(ushort code, string reason, int id) { if (!_webSocketConnections.TryGetValue(id, out var webSocket)) { RnLog.Warn(ReactConstants.RNW, $"Cannot close WebSocket. Unknown WebSocket id {id}."); return; } try { var writer = _dataWriters[id]; _dataWriters.Remove(id); _webSocketConnections.Remove(id); writer.Dispose(); webSocket.Close(code, reason); } catch (Exception ex) { RnLog.Error(ReactConstants.RNW, ex, $"Could not close WebSocket connection for id '{id}'."); } }
public /* TODO: internal? */ void InvokeFunction(string module, string method, JArray arguments, string tracingName) { QueueConfiguration.JavaScriptQueue.Dispatch(() => { QueueConfiguration.JavaScriptQueue.AssertOnThread(); if (IsDisposed) { return; } using (Tracer.Trace(Tracer.TRACE_TAG_REACT_BRIDGE, tracingName).Start()) { if (_bridge == null) { RnLog.Error(ReactConstants.RNW, $"Invoking JS callback before bridge has been initialized. tracingName:{tracingName}."); throw new InvalidOperationException($"Bridge has not been initialized. tracingName:{tracingName}."); } _bridge.CallFunction(module, method, arguments); } }); }
private static void JsExecutorOnNewLogLine(ChakraBridge.LogLevel logLevel, string logline) { // ChakraBridge.LogLevel value is lost when it gets marshaled to .Net native optimized code, // we need to do a proper marshaling to get actual value // Also, JavaScript already has a log level in the message, hence just RnLog.Info string tag = "JS"; FormattableString message = $"{logline}"; switch (logLevel) { case ChakraBridge.LogLevel.Error: RnLog.Error(tag, message); break; case ChakraBridge.LogLevel.Warning: RnLog.Warn(tag, message); break; case ChakraBridge.LogLevel.Info: case ChakraBridge.LogLevel.Trace: RnLog.Info(tag, message); break; } }
/// <summary> /// Runs the JavaScript at the given path. /// </summary> /// <param name="sourcePath">The source path.</param> /// <param name="sourceUrl">The source URL.</param> public void RunScript(string sourcePath, string sourceUrl) { if (sourcePath == null) { throw new ArgumentNullException(nameof(sourcePath)); } if (sourceUrl == null) { throw new ArgumentNullException(nameof(sourceUrl)); } try { var binPath = Path.Combine(ApplicationData.Current.LocalFolder.Path, BytecodeFileName); if (_useSerialization) { var srcFileInfo = new FileInfo(sourcePath); var binFileInfo = new FileInfo(binPath); bool ranSuccessfully = false; // The idea is to run the JS bundle and generate bytecode for it on a background thread. // This eliminates the need to delay the first start when the app doesn't have bytecode. // Next time the app starts, it checks if bytecode is still good and runs it directly. if (binFileInfo.Exists && binFileInfo.LastWriteTime > srcFileInfo.LastWriteTime) { try { Native.ThrowIfError((JavaScriptErrorCode)_executor.RunSerializedScript(sourcePath, binPath, sourceUrl)); ranSuccessfully = true; } catch (JavaScriptUsageException exc) { if (exc.ErrorCode == JavaScriptErrorCode.BadSerializedScript) { // Bytecode format is dependent on Chakra engine version, so an OS upgrade may require a recompilation RnLog.Warn(ReactConstants.RNW, $"Serialized bytecode script is corrupted or wrong format, will generate new one"); } else { // Some more severe error. We still have a chance (recompiling), so we keep continuing. RnLog.Error(ReactConstants.RNW, exc, $"Failed to run serialized bytecode script, will generate new one"); } File.Delete(binPath); } } else { RnLog.Info(ReactConstants.RNW, $"Serialized bytecode script doesn't exist or is obsolete, will generate one"); } if (!ranSuccessfully) { Task.Run(() => { try { // In Chakra JS engine, only one runtime can be active on a particular thread at a time, // and a runtime can only be active on one thread at a time. However it's possible to // create two runtimes and let them run on different threads. var rt = new ChakraBridge.NativeJavaScriptExecutor(); Native.ThrowIfError((JavaScriptErrorCode)rt.InitializeHost()); Native.ThrowIfError((JavaScriptErrorCode)rt.SerializeScript(sourcePath, binPath)); Native.ThrowIfError((JavaScriptErrorCode)rt.DisposeHost()); } catch (Exception ex) { RnLog.Error(ReactConstants.RNW, ex, $"Failed to generate serialized bytecode script."); // It's fine if the bytecode couldn't be generated: RN can still use the JS bundle. } }); Native.ThrowIfError((JavaScriptErrorCode)_executor.RunScript(sourcePath, sourceUrl)); } } else { Native.ThrowIfError((JavaScriptErrorCode)_executor.RunScript(sourcePath, sourceUrl)); } } catch (JavaScriptScriptException ex) { var jsonError = JavaScriptValueToJTokenConverter.Convert(ex.Error); var message = jsonError.Value <string>("message"); var stackTrace = jsonError.Value <string>("stack"); throw new Modules.Core.JavaScriptException(message ?? ex.Message, stackTrace, ex); } }