Revert "Remove our own debugger implementation"
authorCheng Zhao <zcbenz@gmail.com>
Thu, 27 Aug 2015 04:25:28 +0000 (12:25 +0800)
committerCheng Zhao <zcbenz@gmail.com>
Thu, 27 Aug 2015 04:25:28 +0000 (12:25 +0800)
This reverts commit 1d148fe2fb0d7013d7d6633539de952e71d756f1.

atom/browser/atom_browser_main_parts.cc
atom/browser/atom_browser_main_parts.h
atom/browser/node_debugger.cc [new file with mode: 0644]
atom/browser/node_debugger.h [new file with mode: 0644]
atom/common/node_bindings.cc
filenames.gypi

index 15ffd05..c472b87 100644 (file)
@@ -9,6 +9,7 @@
 #include "atom/browser/atom_browser_context.h"
 #include "atom/browser/browser.h"
 #include "atom/browser/javascript_environment.h"
+#include "atom/browser/node_debugger.h"
 #include "atom/common/api/atom_bindings.h"
 #include "atom/common/node_bindings.h"
 #include "base/command_line.h"
@@ -69,9 +70,16 @@ void AtomBrowserMainParts::PostEarlyInitialization() {
 
   node_bindings_->Initialize();
 
+  // Support the "--debug" switch.
+  node_debugger_.reset(new NodeDebugger(js_env_->isolate()));
+
   // Create the global environment.
   global_env = node_bindings_->CreateEnvironment(js_env_->context());
 
+  // Make sure node can get correct environment when debugging.
+  if (node_debugger_->IsRunning())
+    global_env->AssignToContext(v8::Debug::GetDebugContext());
+
   // Add atom-shell extended APIs.
   atom_bindings_->BindTo(js_env_->isolate(), global_env->process_object());
 
index 2b308e8..97663a7 100644 (file)
@@ -19,6 +19,7 @@ class AtomBindings;
 class Browser;
 class JavascriptEnvironment;
 class NodeBindings;
+class NodeDebugger;
 
 class AtomBrowserMainParts : public brightray::BrowserMainParts {
  public:
@@ -57,6 +58,7 @@ class AtomBrowserMainParts : public brightray::BrowserMainParts {
   scoped_ptr<JavascriptEnvironment> js_env_;
   scoped_ptr<NodeBindings> node_bindings_;
   scoped_ptr<AtomBindings> atom_bindings_;
+  scoped_ptr<NodeDebugger> node_debugger_;
 
   base::Timer gc_timer_;
 
diff --git a/atom/browser/node_debugger.cc b/atom/browser/node_debugger.cc
new file mode 100644 (file)
index 0000000..4e23027
--- /dev/null
@@ -0,0 +1,202 @@
+// Copyright (c) 2014 GitHub, Inc.
+// Use of this source code is governed by the MIT license that can be
+// found in the LICENSE file.
+
+#include "atom/browser/node_debugger.h"
+
+#include <string>
+
+#include "base/bind.h"
+#include "base/command_line.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/stringprintf.h"
+#include "base/strings/utf_string_conversions.h"
+#include "content/public/browser/browser_thread.h"
+#include "net/socket/tcp_listen_socket.h"
+
+#include "atom/common/node_includes.h"
+
+namespace atom {
+
+namespace {
+
+// NodeDebugger is stored in Isolate's data, slots 0, 1, 3 have already been
+// taken by gin, blink and node, using 2 is a safe option for now.
+const int kIsolateSlot = 2;
+
+const char* kContentLength = "Content-Length";
+
+}  // namespace
+
+NodeDebugger::NodeDebugger(v8::Isolate* isolate)
+    : isolate_(isolate),
+      thread_("NodeDebugger"),
+      content_length_(-1),
+      weak_factory_(this) {
+  bool use_debug_agent = false;
+  int port = 5858;
+  bool wait_for_connection = false;
+
+  std::string port_str;
+  base::CommandLine* cmd = base::CommandLine::ForCurrentProcess();
+  if (cmd->HasSwitch("debug")) {
+    use_debug_agent = true;
+    port_str = cmd->GetSwitchValueASCII("debug");
+  }
+  if (cmd->HasSwitch("debug-brk")) {
+    use_debug_agent = true;
+    wait_for_connection = true;
+    port_str = cmd->GetSwitchValueASCII("debug-brk");
+  }
+
+  if (use_debug_agent) {
+    if (!port_str.empty())
+      base::StringToInt(port_str, &port);
+
+    isolate_->SetData(kIsolateSlot, this);
+    v8::Debug::SetMessageHandler(DebugMessageHandler);
+
+    if (wait_for_connection)
+      v8::Debug::DebugBreak(isolate_);
+
+    // Start a new IO thread.
+    base::Thread::Options options;
+    options.message_loop_type = base::MessageLoop::TYPE_IO;
+    if (!thread_.StartWithOptions(options)) {
+      LOG(ERROR) << "Unable to start debugger thread";
+      return;
+    }
+
+    // Start the server in new IO thread.
+    thread_.message_loop()->PostTask(
+        FROM_HERE,
+        base::Bind(&NodeDebugger::StartServer, weak_factory_.GetWeakPtr(),
+                   port));
+  }
+}
+
+NodeDebugger::~NodeDebugger() {
+  thread_.Stop();
+}
+
+bool NodeDebugger::IsRunning() const {
+  return thread_.IsRunning();
+}
+
+void NodeDebugger::StartServer(int port) {
+  server_ = net::TCPListenSocket::CreateAndListen("127.0.0.1", port, this);
+  if (!server_) {
+    LOG(ERROR) << "Cannot start debugger server";
+    return;
+  }
+}
+
+void NodeDebugger::CloseSession() {
+  accepted_socket_.reset();
+}
+
+void NodeDebugger::OnMessage(const std::string& message) {
+  if (message.find("\"type\":\"request\",\"command\":\"disconnect\"}") !=
+          std::string::npos)
+    CloseSession();
+
+  base::string16 message16 = base::UTF8ToUTF16(message);
+  v8::Debug::SendCommand(
+      isolate_,
+      reinterpret_cast<const uint16_t*>(message16.data()), message16.size());
+
+  content::BrowserThread::PostTask(
+      content::BrowserThread::UI, FROM_HERE,
+      base::Bind(&v8::Debug::ProcessDebugMessages));
+}
+
+void NodeDebugger::SendMessage(const std::string& message) {
+  if (accepted_socket_) {
+    std::string header = base::StringPrintf(
+        "%s: %d\r\n\r\n", kContentLength, static_cast<int>(message.size()));
+    accepted_socket_->Send(header);
+    accepted_socket_->Send(message);
+  }
+}
+
+void NodeDebugger::SendConnectMessage() {
+  accepted_socket_->Send(base::StringPrintf(
+      "Type: connect\r\n"
+      "V8-Version: %s\r\n"
+      "Protocol-Version: 1\r\n"
+      "Embedding-Host: %s\r\n"
+      "%s: 0\r\n",
+      v8::V8::GetVersion(), ATOM_PRODUCT_NAME, kContentLength), true);
+}
+
+// static
+void NodeDebugger::DebugMessageHandler(const v8::Debug::Message& message) {
+  NodeDebugger* self = static_cast<NodeDebugger*>(
+      message.GetIsolate()->GetData(kIsolateSlot));
+
+  if (self) {
+    std::string message8(*v8::String::Utf8Value(message.GetJSON()));
+    self->thread_.message_loop()->PostTask(
+        FROM_HERE,
+        base::Bind(&NodeDebugger::SendMessage, self->weak_factory_.GetWeakPtr(),
+                   message8));
+  }
+}
+
+void NodeDebugger::DidAccept(net::StreamListenSocket* server,
+                             scoped_ptr<net::StreamListenSocket> socket) {
+  // Only accept one session.
+  if (accepted_socket_) {
+    socket->Send(std::string("Remote debugging session already active"), true);
+    return;
+  }
+
+  accepted_socket_ = socket.Pass();
+  SendConnectMessage();
+}
+
+void NodeDebugger::DidRead(net::StreamListenSocket* socket,
+                           const char* data,
+                           int len) {
+  buffer_.append(data, len);
+
+  do {
+    if (buffer_.size() == 0)
+      return;
+
+    // Read the "Content-Length" header.
+    if (content_length_ < 0) {
+      size_t pos = buffer_.find("\r\n\r\n");
+      if (pos == std::string::npos)
+        return;
+
+      // We can be sure that the header is "Content-Length: xxx\r\n".
+      std::string content_length = buffer_.substr(16, pos - 16);
+      if (!base::StringToInt(content_length, &content_length_)) {
+        DidClose(accepted_socket_.get());
+        return;
+      }
+
+      // Strip header from buffer.
+      buffer_ = buffer_.substr(pos + 4);
+    }
+
+    // Read the message.
+    if (buffer_.size() >= static_cast<size_t>(content_length_)) {
+      std::string message = buffer_.substr(0, content_length_);
+      buffer_ = buffer_.substr(content_length_);
+
+      OnMessage(message);
+
+      // Get ready for next message.
+      content_length_ = -1;
+    }
+  } while (true);
+}
+
+void NodeDebugger::DidClose(net::StreamListenSocket* socket) {
+  // If we lost the connection, then simulate a disconnect msg:
+  OnMessage("{\"seq\":1,\"type\":\"request\",\"command\":\"disconnect\"}");
+}
+
+}  // namespace atom
diff --git a/atom/browser/node_debugger.h b/atom/browser/node_debugger.h
new file mode 100644 (file)
index 0000000..6ee5b1e
--- /dev/null
@@ -0,0 +1,59 @@
+// Copyright (c) 2014 GitHub, Inc.
+// Use of this source code is governed by the MIT license that can be
+// found in the LICENSE file.
+
+#ifndef ATOM_BROWSER_NODE_DEBUGGER_H_
+#define ATOM_BROWSER_NODE_DEBUGGER_H_
+
+#include <string>
+
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/weak_ptr.h"
+#include "base/threading/thread.h"
+#include "net/socket/stream_listen_socket.h"
+#include "v8/include/v8-debug.h"
+
+namespace atom {
+
+// Add support for node's "--debug" switch.
+class NodeDebugger : public net::StreamListenSocket::Delegate {
+ public:
+  explicit NodeDebugger(v8::Isolate* isolate);
+  virtual ~NodeDebugger();
+
+  bool IsRunning() const;
+
+ private:
+  void StartServer(int port);
+  void CloseSession();
+  void OnMessage(const std::string& message);
+  void SendMessage(const std::string& message);
+  void SendConnectMessage();
+
+  static void DebugMessageHandler(const v8::Debug::Message& message);
+
+  // net::StreamListenSocket::Delegate:
+  void DidAccept(net::StreamListenSocket* server,
+                 scoped_ptr<net::StreamListenSocket> socket) override;
+  void DidRead(net::StreamListenSocket* socket,
+               const char* data,
+               int len) override;
+  void DidClose(net::StreamListenSocket* socket) override;
+
+  v8::Isolate* isolate_;
+
+  base::Thread thread_;
+  scoped_ptr<net::StreamListenSocket> server_;
+  scoped_ptr<net::StreamListenSocket> accepted_socket_;
+
+  std::string buffer_;
+  int content_length_;
+
+  base::WeakPtrFactory<NodeDebugger> weak_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(NodeDebugger);
+};
+
+}  // namespace atom
+
+#endif  // ATOM_BROWSER_NODE_DEBUGGER_H_
index 304b6a7..827033b 100644 (file)
@@ -180,14 +180,9 @@ node::Environment* NodeBindings::CreateEnvironment(
 
 void NodeBindings::LoadEnvironment(node::Environment* env) {
   node::node_isolate = env->isolate();
-  if (node::use_debug_agent)
-    node::StartDebug(env, node::debug_wait_connect);
 
   node::LoadEnvironment(env);
 
-  if (node::use_debug_agent)
-    node::EnableDebug(env);
-
   mate::EmitEvent(env->isolate(), env->process_object(), "loaded");
 }
 
index 260c9a4..b401592 100644 (file)
       'atom/browser/net/url_request_buffer_job.h',
       'atom/browser/net/url_request_fetch_job.cc',
       'atom/browser/net/url_request_fetch_job.h',
+      'atom/browser/node_debugger.cc',
+      'atom/browser/node_debugger.h',
       'atom/browser/ui/accelerator_util.cc',
       'atom/browser/ui/accelerator_util.h',
       'atom/browser/ui/accelerator_util_mac.mm',