Exemplo n.º 1
0
        /// <summary>
        /// If the user is explicitly referencing this assembly, they probably want to use it.
        /// Attempt to use the engine and throw an exception if it doesn't work.
        /// </summary>
        public static void EnsureEngineFunctional()
        {
            int result = 0;

            try
            {
                using (var engine = new V8JsEngine())
                {
                    result = engine.Evaluate <int>("1 + 1");
                }
            }
            catch (Exception ex)
            {
                throw new ClearScriptV8InitialisationException(ex.Message);
            }

            if (result != 2)
            {
                throw new ReactException("Mathematics is broken. 1 + 1 = " + result);
            }
        }
Exemplo n.º 2
0
        Run(FileInfo mainScriptFile, string[] argv,
            bool inspect, bool pauseDebuggerOnStart,
            IImmutableSet <string> inspectLoadSet,
            Func <CancellationToken, Task <string> > f,
            Process parentProcess,
            bool verbose)
        {
            var rootDir = mainScriptFile.Directory;

            Debug.Assert(rootDir != null);

            var settings = new V8Settings
            {
                EnableDebugging =
                    inspect || pauseDebuggerOnStart ||
                    inspectLoadSet.Any(),
                AwaitDebuggerAndPauseOnStart =
                    pauseDebuggerOnStart || inspectLoadSet.Any(),
            };

            using (var engine = new V8JsEngine(settings))
            {
                var scheduler = new ConcurrentExclusiveSchedulerPair().ExclusiveScheduler;
                var console   = ConsoleService.Default;

                void Load(string module)
                {
                    var path   = Path.Combine(rootDir.FullName, module);
                    var source = File.ReadAllText(path);

                    if (inspectLoadSet.Contains(source))
                    {
                        source = "debugger;" + source;
                    }
                    engine.Execute(source, module);
                }

                using (var host = new Host(Load, console, scheduler))
                {
                    string FormatMessage(object sender, string message)
                    {
                        var senderName = sender is string s ? s : sender.GetType().Name;
                        var formatted  = $"{senderName}[{Thread.CurrentThread.ManagedThreadId}]: {message}";

                        return(formatted.FormatFoldedLines().TrimNewLineAtTail());
                    }

                    void OnUnobservedTaskException(object sender, UnobservedTaskExceptionEventArgs args) =>
                    console.Error(FormatMessage(sender, args.Exception.ToString()));

                    TaskScheduler.UnobservedTaskException += OnUnobservedTaskException;

                    var infoLog = !verbose ? null : new LogEventHandler((sender, message) =>
                                                                        host.Console.Info(FormatMessage(sender, message)));

                    var warnLog = !verbose ? null : new ErrorLogEventHandler((sender, e, message) =>
                                                                             host.Console.Warn(FormatMessage(sender, e == null ? message : string.IsNullOrEmpty(message) ? e.ToString() : message + Environment.NewLine + e)));

                    var errorLog = !verbose ? null : new ErrorLogEventHandler((sender, e, message) =>
                                                                              host.Console.Error(FormatMessage(sender, string.IsNullOrEmpty(message) ? e.ToString() : message + Environment.NewLine + e)));

                    foreach (var service in new ILogSource[] { host, host.Timer, host.Xhr })
                    {
                        service.InfoLog  = infoLog;
                        service.WarnLog  = warnLog;
                        service.ErrorLog = errorLog;
                    }

                    var tasks = new List <NamedTask>();

                    void AddTask(NamedTask task)
                    {
                        lock (tasks) tasks.Add(task);
                    }

                    void RemoveTask(NamedTask task)
                    {
                        lock (tasks) tasks.Remove(task);
                    }

                    host.TaskStarting  += (_, task) => AddTask(task);
                    host.TaskFinishing += (_, task) => RemoveTask(task);

                    if (verbose)
                    {
                        host.ServiceCreated += (_, service) =>
                        {
                            service.InfoLog  = infoLog;
                            service.WarnLog  = warnLog;
                            service.ErrorLog = errorLog;
                        };
                    }

                    engine.EmbedHostObject("host", host);
                    var     initScript = GetManifestResourceStream("init.js", typeof(Program)).ReadAsText();
                    dynamic init       = engine.Evaluate(initScript, "__init.js");
                    init(host, engine.Evaluate("this"), argv);

                    if (settings.AwaitDebuggerAndPauseOnStart)
                    {
                        console.Warn(FormatMessage(nameof(Program), "Will wait for debugger to attach."));
                    }

                    Load(mainScriptFile.Name);

                    void Schedule(string name, Action <AsyncTaskControl> action)
                    {
                        var task = AsyncTask.Create(name, thisTask =>
                        {
                            Exception error = null;
                            try
                            {
                                action(thisTask);
                            }
                            catch (Exception e)
                            {
                                error = e;
                            }
                            RemoveTask(thisTask);
                            switch (error)
                            {
                            case null:
                                thisTask.FlagSuccess();
                                break;

                            case OperationCanceledException e:
                                thisTask.FlagCanceled(e.CancellationToken);
                                break;

                            default:
                                errorLog?.Invoke(nameof(Program), error, null);
                                thisTask.FlagError(error);
                                break;
                            }
                        });

                        AddTask(task);
                        task.Start(scheduler);
                    }

                    var parentProcessTask = parentProcess.AsTask(dispose: true, p => p.ExitCode,
                                                                 _ => null,
                                                                 exit => exit);

                    while (true)
                    {
                        var readCommandTask = f(CancellationToken.None);
                        if (parentProcessTask != null)
                        {
                            if (parentProcessTask == await Task.WhenAny(readCommandTask, parentProcessTask))
                            {
                                break;
                            }
                        }
                        else
                        {
                            await readCommandTask;
                        }

                        var command = (await readCommandTask)?.Trim();

                        if (command == null)
                        {
                            break;
                        }

                        if (command.Length == 0)
                        {
                            continue;
                        }

                        const string ondata = "ondata";
                        Schedule(ondata, delegate
                        {
                            infoLog?.Invoke(nameof(Program), "STDIN: " + command);
                            engine.CallFunction(ondata, command);
                        });
                    }

                    const string onclose = "onclose";
                    Schedule(onclose, delegate
                    {
                        engine.Execute(@"if (typeof onclose === 'function') onclose();");
                    });

                    host.Timer.CancelAll();
                    host.Xhr.AbortAll();

                    infoLog?.Invoke(typeof(Program), "Shutting down...");

                    ImmutableArray <Task> tasksSnapshot;

                    lock (tasks)
                        tasksSnapshot = ImmutableArray.CreateRange(from t in tasks select t.Task);

                    if (await tasksSnapshot.WhenAll(TimeSpan.FromSeconds(30)))
                    {
                        Debug.Assert(tasks.Count == 0);
                    }
                    else
                    {
                        warnLog?.Invoke(typeof(Program), null, "Timed-out waiting for all tasks to end for a graceful shutdown!");
                    }

                    infoLog?.Invoke(typeof(Program), "Shutdown completed.");

                    TaskScheduler.UnobservedTaskException -= OnUnobservedTaskException;
                }
            }
        }