OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "base/bind.h" | 5 #include "base/bind.h" |
6 #include "base/memory/weak_ptr.h" | 6 #include "base/memory/weak_ptr.h" |
7 #include "mojo/application/application_runner_chromium.h" | 7 #include "mojo/application/application_runner_chromium.h" |
8 #include "mojo/public/c/system/main.h" | 8 #include "mojo/public/c/system/main.h" |
9 #include "mojo/public/cpp/application/application_delegate.h" | 9 #include "mojo/public/cpp/application/application_delegate.h" |
10 #include "mojo/public/cpp/application/application_impl.h" | 10 #include "mojo/public/cpp/application/application_impl.h" |
| 11 #include "net/server/http_server.h" |
| 12 #include "net/server/http_server_request_info.h" |
| 13 #include "net/socket/tcp_server_socket.h" |
11 #include "services/tracing/tracing.mojom.h" | 14 #include "services/tracing/tracing.mojom.h" |
12 #include "sky/tools/debugger/debugger.mojom.h" | 15 #include "sky/tools/debugger/debugger.mojom.h" |
13 #include <iostream> | 16 #include <iostream> |
14 | 17 |
15 namespace sky { | 18 namespace sky { |
16 namespace debugger { | 19 namespace debugger { |
17 namespace { | |
18 | 20 |
19 std::string GetCommand() { | 21 class Prompt : public mojo::ApplicationDelegate, public net::HttpServer::Delegat
e { |
20 std::cout << "(skydb) "; | |
21 std::cout.flush(); | |
22 | |
23 std::string command; | |
24 std::getline(std::cin, command); | |
25 // Any errors (including eof) just quit the debugger: | |
26 if (!std::cin.good()) | |
27 command = 'q'; | |
28 return command; | |
29 } | |
30 | |
31 } | |
32 | |
33 class Prompt : public mojo::ApplicationDelegate { | |
34 public: | 22 public: |
35 Prompt() | 23 Prompt() |
36 : is_tracing_(false), | 24 : is_tracing_(false), |
37 weak_ptr_factory_(this) { | 25 weak_ptr_factory_(this) { |
38 } | 26 } |
39 virtual ~Prompt() { | 27 virtual ~Prompt() { |
40 } | 28 } |
41 | 29 |
42 private: | 30 private: |
43 // Overridden from mojo::ApplicationDelegate: | 31 // Overridden from mojo::ApplicationDelegate: |
44 virtual void Initialize(mojo::ApplicationImpl* app) override { | 32 virtual void Initialize(mojo::ApplicationImpl* app) override { |
45 app->ConnectToService("mojo:tracing", &tracing_); | 33 app->ConnectToService("mojo:tracing", &tracing_); |
46 if (app->args().size() > 1) | 34 if (app->args().size() > 1) |
47 url_ = app->args()[1]; | 35 url_ = app->args()[1]; |
48 else { | 36 else { |
49 url_ = "https://raw.githubusercontent.com/domokit/mojo/master/sky/" | 37 url_ = "https://raw.githubusercontent.com/domokit/mojo/master/sky/" |
50 "examples/home.sky"; | 38 "examples/home.sky"; |
51 } | 39 } |
| 40 scoped_ptr<net::ServerSocket> server_socket( |
| 41 new net::TCPServerSocket(NULL, net::NetLog::Source())); |
| 42 // FIXME: This port needs to be configurable, as-is we can only run |
| 43 // one copy of mojo_shell with sky at a time! |
| 44 server_socket->ListenWithAddressAndPort("0.0.0.0", 7777, 1); |
| 45 web_server_.reset(new net::HttpServer(server_socket.Pass(), this)); |
52 } | 46 } |
53 | 47 |
54 virtual bool ConfigureIncomingConnection( | 48 virtual bool ConfigureIncomingConnection( |
55 mojo::ApplicationConnection* connection) override { | 49 mojo::ApplicationConnection* connection) override { |
56 connection->ConnectToService(&debugger_); | 50 connection->ConnectToService(&debugger_); |
57 std::cout << "Loading " << url_ << std::endl; | 51 std::cout << "Loading " << url_ << std::endl; |
58 Reload(); | 52 Reload(); |
59 #if !defined(OS_ANDROID) | |
60 // FIXME: To support device-centric development we need to re-write | |
61 // prompt.cc to just be a server and have all the command handling move | |
62 // to python (skydb). prompt.cc would just run until told to quit. | |
63 // If we don't comment this out then prompt.cc just quits when run headless | |
64 // as it immediately recieves EOF which it treats as quit. | |
65 ScheduleWaitForInput(); | |
66 #endif | |
67 return true; | 53 return true; |
68 } | 54 } |
69 | 55 |
70 bool ExecuteCommand(const std::string& command) { | 56 // net::HttpServer::Delegate |
71 if (command == "help" || command == "h") { | 57 void OnConnect(int connection_id) override { |
72 PrintHelp(); | |
73 return true; | |
74 } | |
75 if (command == "trace") { | |
76 ToggleTracing(); | |
77 return true; | |
78 } | |
79 if (command == "reload" || command == "r") { | |
80 Reload(); | |
81 return true; | |
82 } | |
83 if (command == "inspect") { | |
84 Inspect(); | |
85 return true; | |
86 } | |
87 if (command == "quit" || command == "q") { | |
88 Quit(); | |
89 return true; | |
90 } | |
91 if (command.size() == 1) { | |
92 std::cout << "Unknown command: " << command << std::endl; | |
93 return true; | |
94 } | |
95 return false; | |
96 } | 58 } |
97 | 59 |
98 void WaitForInput() { | 60 void OnClose(int connection_id) override { |
99 std::string command = GetCommand(); | |
100 | |
101 if (!ExecuteCommand(command)) { | |
102 if (command.size() > 0) { | |
103 url_ = command; | |
104 Reload(); | |
105 } | |
106 } | |
107 | |
108 ScheduleWaitForInput(); | |
109 } | 61 } |
110 | 62 |
111 void ScheduleWaitForInput() { | 63 void OnHttpRequest( |
112 base::MessageLoop::current()->PostTask(FROM_HERE, | 64 int connection_id, const net::HttpServerRequestInfo& info) override { |
113 base::Bind(&Prompt::WaitForInput, weak_ptr_factory_.GetWeakPtr())); | 65 |
| 66 // FIXME: We should use use a fancier lookup system more like what |
| 67 // services/http_server/http_server.cc does with AddHandler. |
| 68 if (info.path == "/trace") |
| 69 ToggleTracing(connection_id); |
| 70 else if (info.path == "/reload") |
| 71 Load(connection_id, url_); |
| 72 else if (info.path == "/inspect") |
| 73 Inspect(connection_id); |
| 74 else if (info.path == "/quit") |
| 75 Quit(connection_id); |
| 76 else if (info.path == "/load") |
| 77 Load(connection_id, info.data); |
| 78 else { |
| 79 Help(info.path, connection_id); |
| 80 } |
114 } | 81 } |
115 | 82 |
116 void PrintHelp() { | 83 void OnWebSocketRequest( |
117 std::cout | 84 int connection_id, const net::HttpServerRequestInfo& info) override { |
118 << "Sky Debugger" << std::endl | 85 web_server_->Send500(connection_id, "http only"); |
119 << "============" << std::endl | 86 } |
120 << "Type a URL to load in the debugger, enter to reload." << std::endl | 87 |
121 << "Commands: help -- Help" << std::endl | 88 void OnWebSocketMessage( |
122 << " trace -- Capture a trace" << std::endl | 89 int connection_id, const std::string& data) override { |
123 << " reload -- Reload the current page" << std::endl | 90 web_server_->Send500(connection_id, "http only"); |
124 << " inspect -- Inspect the current page" << std::endl | 91 } |
125 << " quit -- Quit" << std::endl; | 92 |
| 93 void Respond(int connection_id, std::string response) { |
| 94 web_server_->Send200(connection_id, response, "text/plain"); |
| 95 } |
| 96 |
| 97 void Help(std::string path, int connection_id) { |
| 98 std::string help = "Sky Debugger\n" |
| 99 "Supported URLs:\n" |
| 100 "/toggle_tracing -- Start/stop tracing\n" |
| 101 "/reload -- Reload the current page\n" |
| 102 "/inspect -- Start inspector server for current page\n" |
| 103 "/quit -- Quit\n" |
| 104 "/load -- Load a new URL, url in POST body.\n"; |
| 105 if (path != "/") |
| 106 help = "Unknown path: " + path + "\n\n" + help; |
| 107 Respond(connection_id, help); |
| 108 } |
| 109 |
| 110 void Load(int connection_id, std::string url) { |
| 111 url_ = url; |
| 112 Reload(); |
| 113 Respond(connection_id, "OK\n"); |
126 } | 114 } |
127 | 115 |
128 void Reload() { | 116 void Reload() { |
129 debugger_->NavigateToURL(url_); | 117 debugger_->NavigateToURL(url_); |
130 } | 118 } |
131 | 119 |
132 void Inspect() { | 120 void Inspect(int connection_id) { |
133 debugger_->InjectInspector(); | 121 debugger_->InjectInspector(); |
134 std::cout | 122 Respond(connection_id, |
135 << "Open the following URL in Chrome:" << std::endl | 123 "Open the following URL in Chrome:\n" |
136 << "chrome-devtools://devtools/bundled/devtools.html?ws=localhost:9898" | 124 "chrome-devtools://devtools/bundled/devtools.html?ws=localhost:9898\n"); |
137 << std::endl; | |
138 } | 125 } |
139 | 126 |
140 void Quit() { | 127 void Quit(int connection_id) { |
141 std::cout << "quitting" << std::endl; | 128 std::cout << "quitting" << std::endl; |
142 debugger_->Shutdown(); | 129 debugger_->Shutdown(); |
143 } | 130 } |
144 | 131 |
145 void ToggleTracing() { | 132 void ToggleTracing(int connection_id) { |
146 if (is_tracing_) { | 133 if (is_tracing_) { |
147 std::cout << "Stopping trace (writing to sky_viewer.trace)" << std::endl; | 134 std::cout << "Stopping trace (writing to sky_viewer.trace)" << std::endl; |
148 tracing_->StopAndFlush(); | 135 tracing_->StopAndFlush(); |
149 } else { | 136 } else { |
150 std::cout << "Starting trace (type 'trace' to stop tracing)" << std::endl; | 137 std::cout << "Starting trace (type 'trace' to stop tracing)" << std::endl; |
151 tracing_->Start(mojo::String("sky_viewer"), mojo::String("*")); | 138 tracing_->Start(mojo::String("sky_viewer"), mojo::String("*")); |
152 } | 139 } |
153 is_tracing_ = !is_tracing_; | 140 is_tracing_ = !is_tracing_; |
| 141 Respond(connection_id, "OK\n"); |
154 } | 142 } |
155 | 143 |
156 bool is_tracing_; | 144 bool is_tracing_; |
157 DebuggerPtr debugger_; | 145 DebuggerPtr debugger_; |
158 tracing::TraceCoordinatorPtr tracing_; | 146 tracing::TraceCoordinatorPtr tracing_; |
159 std::string url_; | 147 std::string url_; |
160 base::WeakPtrFactory<Prompt> weak_ptr_factory_; | 148 base::WeakPtrFactory<Prompt> weak_ptr_factory_; |
| 149 scoped_ptr<net::HttpServer> web_server_; |
161 | 150 |
162 DISALLOW_COPY_AND_ASSIGN(Prompt); | 151 DISALLOW_COPY_AND_ASSIGN(Prompt); |
163 }; | 152 }; |
164 | 153 |
165 } // namespace debugger | 154 } // namespace debugger |
166 } // namespace sky | 155 } // namespace sky |
167 | 156 |
168 MojoResult MojoMain(MojoHandle shell_handle) { | 157 MojoResult MojoMain(MojoHandle shell_handle) { |
169 mojo::ApplicationRunnerChromium runner(new sky::debugger::Prompt); | 158 mojo::ApplicationRunnerChromium runner(new sky::debugger::Prompt); |
| 159 runner.set_message_loop_type(base::MessageLoop::TYPE_IO); |
170 return runner.Run(shell_handle); | 160 return runner.Run(shell_handle); |
171 } | 161 } |
OLD | NEW |