@@ -186,6 +186,8 @@ class AgentImpl {
186186 const std::string& path);
187187 static void WriteCbIO (uv_async_t * async);
188188
189+ void InstallInspectorOnProcess ();
190+
189191 void WorkerRunIO ();
190192 void OnInspectorConnectionIO (inspector_socket_t * socket);
191193 void OnRemoteDataIO (inspector_socket_t * stream, ssize_t read,
@@ -276,6 +278,9 @@ class ChannelImpl final : public blink::protocol::FrontendChannel {
276278 AgentImpl* const agent_;
277279};
278280
281+ // Used in V8NodeInspector::currentTimeMS() below.
282+ #define NANOS_PER_MSEC 1000000
283+
279284class V8NodeInspector : public blink ::V8InspectorClient {
280285 public:
281286 V8NodeInspector (AgentImpl* agent, node::Environment* env,
@@ -308,6 +313,10 @@ class V8NodeInspector : public blink::V8InspectorClient {
308313 running_nested_loop_ = false ;
309314 }
310315
316+ double currentTimeMS () override {
317+ return uv_hrtime () * 1.0 / NANOS_PER_MSEC;
318+ }
319+
311320 void quitMessageLoopOnPause () override {
312321 terminated_ = true ;
313322 }
@@ -361,11 +370,78 @@ AgentImpl::~AgentImpl() {
361370 data_written_ = nullptr ;
362371}
363372
373+ void InspectorConsoleCall (const v8::FunctionCallbackInfo<v8::Value>& info) {
374+ v8::Isolate* isolate = info.GetIsolate ();
375+ v8::Local<v8::Context> context = isolate->GetCurrentContext ();
376+
377+ CHECK (info.Data ()->IsArray ());
378+ v8::Local<v8::Array> args = info.Data ().As <v8::Array>();
379+ CHECK_EQ (args->Length (), 3 );
380+
381+ v8::Local<v8::Value> inspector_method =
382+ args->Get (context, 0 ).ToLocalChecked ();
383+ CHECK (inspector_method->IsFunction ());
384+ v8::Local<v8::Value> node_method =
385+ args->Get (context, 1 ).ToLocalChecked ();
386+ CHECK (node_method->IsFunction ());
387+ v8::Local<v8::Value> config_value =
388+ args->Get (context, 2 ).ToLocalChecked ();
389+ CHECK (config_value->IsObject ());
390+ v8::Local<v8::Object> config_object = config_value.As <v8::Object>();
391+
392+ std::vector<v8::Local<v8::Value>> call_args (info.Length ());
393+ for (int i = 0 ; i < info.Length (); ++i) {
394+ call_args[i] = info[i];
395+ }
396+
397+ v8::Local<v8::String> in_call_key = OneByteString (isolate, " in_call" );
398+ bool in_call = config_object->Has (context, in_call_key).FromMaybe (false );
399+ if (!in_call) {
400+ CHECK (config_object->Set (context,
401+ in_call_key,
402+ v8::True (isolate)).FromJust ());
403+ CHECK (!inspector_method.As <v8::Function>()->Call (
404+ context,
405+ info.Holder (),
406+ call_args.size (),
407+ call_args.data ()).IsEmpty ());
408+ }
409+
410+ v8::TryCatch try_catch (info.GetIsolate ());
411+ node_method.As <v8::Function>()->Call (context,
412+ info.Holder (),
413+ call_args.size (),
414+ call_args.data ());
415+ CHECK (config_object->Delete (context, in_call_key).FromJust ());
416+ if (try_catch.HasCaught ())
417+ try_catch.ReThrow ();
418+ }
419+
420+ void InspectorWrapConsoleCall (const v8::FunctionCallbackInfo<v8::Value>& args) {
421+ Environment* env = Environment::GetCurrent (args);
422+
423+ if (args.Length () != 3 || !args[0 ]->IsFunction () ||
424+ !args[1 ]->IsFunction () || !args[2 ]->IsObject ()) {
425+ return env->ThrowError (" inspector.wrapConsoleCall takes exactly 3 "
426+ " arguments: two functions and an object." );
427+ }
428+
429+ v8::Local<v8::Array> array = v8::Array::New (env->isolate (), args.Length ());
430+ CHECK (array->Set (env->context (), 0 , args[0 ]).FromJust ());
431+ CHECK (array->Set (env->context (), 1 , args[1 ]).FromJust ());
432+ CHECK (array->Set (env->context (), 2 , args[2 ]).FromJust ());
433+ args.GetReturnValue ().Set (v8::Function::New (env->context (),
434+ InspectorConsoleCall,
435+ array).ToLocalChecked ());
436+ }
437+
364438bool AgentImpl::Start (v8::Platform* platform, int port, bool wait) {
365439 auto env = parent_env_;
366440 inspector_ = new V8NodeInspector (this , env, platform);
367441 platform_ = platform;
368442
443+ InstallInspectorOnProcess ();
444+
369445 int err = uv_loop_init (&child_loop_);
370446 CHECK_EQ (err, 0 );
371447
@@ -403,6 +479,22 @@ void AgentImpl::WaitForDisconnect() {
403479 inspector_->runMessageLoopOnPause (0 );
404480}
405481
482+ #define READONLY_PROPERTY (obj, str, var ) \
483+ do { \
484+ obj->DefineOwnProperty (env->context (), \
485+ OneByteString (env->isolate (), str), \
486+ var, \
487+ v8::ReadOnly).FromJust (); \
488+ } while (0 )
489+
490+ void AgentImpl::InstallInspectorOnProcess() {
491+ auto env = parent_env_;
492+ v8::Local<v8::Object> process = env->process_object ();
493+ v8::Local<v8::Object> inspector = v8::Object::New (env->isolate ());
494+ READONLY_PROPERTY (process, " inspector" , inspector);
495+ env->SetMethod (inspector, " wrapConsoleCall" , InspectorWrapConsoleCall);
496+ }
497+
406498// static
407499void AgentImpl::ThreadCbIO (void * agent) {
408500 static_cast <AgentImpl*>(agent)->WorkerRunIO ();
0 commit comments