@@ -186,6 +186,8 @@ class AgentImpl {
186
186
const std::string& path);
187
187
static void WriteCbIO (uv_async_t * async);
188
188
189
+ void InstallInspectorOnProcess ();
190
+
189
191
void WorkerRunIO ();
190
192
void OnInspectorConnectionIO (inspector_socket_t * socket);
191
193
void OnRemoteDataIO (inspector_socket_t * stream, ssize_t read,
@@ -276,6 +278,9 @@ class ChannelImpl final : public blink::protocol::FrontendChannel {
276
278
AgentImpl* const agent_;
277
279
};
278
280
281
+ // Used in V8NodeInspector::currentTimeMS() below.
282
+ #define NANOS_PER_MSEC 1000000
283
+
279
284
class V8NodeInspector : public blink ::V8InspectorClient {
280
285
public:
281
286
V8NodeInspector (AgentImpl* agent, node::Environment* env,
@@ -308,6 +313,10 @@ class V8NodeInspector : public blink::V8InspectorClient {
308
313
running_nested_loop_ = false ;
309
314
}
310
315
316
+ double currentTimeMS () override {
317
+ return uv_hrtime () * 1.0 / NANOS_PER_MSEC;
318
+ }
319
+
311
320
void quitMessageLoopOnPause () override {
312
321
terminated_ = true ;
313
322
}
@@ -361,11 +370,78 @@ AgentImpl::~AgentImpl() {
361
370
data_written_ = nullptr ;
362
371
}
363
372
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
+
364
438
bool AgentImpl::Start (v8::Platform* platform, int port, bool wait) {
365
439
auto env = parent_env_;
366
440
inspector_ = new V8NodeInspector (this , env, platform);
367
441
platform_ = platform;
368
442
443
+ InstallInspectorOnProcess ();
444
+
369
445
int err = uv_loop_init (&child_loop_);
370
446
CHECK_EQ (err, 0 );
371
447
@@ -403,6 +479,22 @@ void AgentImpl::WaitForDisconnect() {
403
479
inspector_->runMessageLoopOnPause (0 );
404
480
}
405
481
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
+
406
498
// static
407
499
void AgentImpl::ThreadCbIO (void * agent) {
408
500
static_cast <AgentImpl*>(agent)->WorkerRunIO ();
0 commit comments