v8toolkit  0.0.1
Utility library for embedding V8 Javascript engine in a c++ program
debugger.h
Go to the documentation of this file.
1 #pragma once
2 
3 #define V8TOOLKIT_DEBUGGING_ACTIVE
4 
5 #include <websocketpp/config/asio_no_tls.hpp>
6 #include <websocketpp/server.hpp>
7 
8 #include <string>
9 #include <sstream>
10 #include <fmt/ostream.h>
11 
12 #include <v8-debug.h>
13 #include <v8-inspector.h>
14 #include <v8-debug.h>
15 
16 
17 #include <nlohmann/json.hpp>
18 
19 #include "javascript.h"
20 
21 namespace v8toolkit {
22 
23 class DebugContext;
24 
25 /**
26 Inspector types:
27 
28 v8_inspector::V8Inspector::Channel
29  - Interface: sendResponse, sendNotification, flushProtocol
30  - basically takes a string and sends it out
31 
32 
33 
34 v8_inspector::V8InspectorClient
35  - has a "channel"
36  - has an V8Inspector
37  - creates a V8InspectorSesssion when an inspector is "connected" to a channel
38 
39 V8InspectorSession:
40  - Does the "main work"
41  - Received messages are sent to session::dispatchProtocolMessage
42 
43 
44 
45  v8_inspector::V8Inspector
46  - associated and 'connected' to a v8::Context
47 
48 
49 */
50 #if 0
51 //class ResponseMessage;
52 //
53 //class DebugMessage {
54 //
55 //public:
56 // DebugMessage(v8toolkit::DebugContext & debug_context) :
57 // debug_context(debug_context)
58 // {}
59 //
60 // DebugMessage(DebugMessage const &) = default;
61 //
62 // // the message id associated with this message (either the incoming ID of a
63 // // RequestMessage or the ID of the request a ResponseMessage is for
64 // v8toolkit::DebugContext & debug_context;
65 //
66 // virtual nlohmann::json to_json() const = 0;
67 //};
68 //
69 ///**
70 // *sent from the application to the debugger as informational data, not in direct response to a
71 // * request
72 // */
73 //class InformationalMessage : public DebugMessage {
74 //
75 //public:
76 // InformationalMessage(v8toolkit::DebugContext & debug_context) :
77 // DebugMessage(debug_context)
78 // {}
79 //
80 //};
81 //
82 //void to_json(nlohmann::json& j, const InformationalMessage & informational_message);
83 //
84 //
85 //
86 //class RequestResponseMessage : public DebugMessage {
87 //
88 //public:
89 // RequestResponseMessage(v8toolkit::DebugContext & debug_context, int message_id) :
90 // DebugMessage(debug_context),
91 // message_id(message_id)
92 // {}
93 //
94 // int const message_id;
95 //};
96 //
97 //
98 //class RequestMessage : public RequestResponseMessage {
99 //private:
100 // std::string method_name;
101 //public:
102 // RequestMessage(v8toolkit::DebugContext & context, nlohmann::json const & json);
103 //
104 // /**
105 // * Every RequestMessage must generate a ResponseMessage
106 // * @return the corresponding ResponseMessage to this RequestMessage
107 // */
108 // virtual std::unique_ptr<ResponseMessage> generate_response_message() const = 0;
109 //
110 // /**
111 // * A RequestMessage generates 0 or more InformationalMessage objects
112 // * @return Any InformationalMessage objects which need to be sent back to the debugger
113 // */
114 // virtual std::vector<std::unique_ptr<InformationalMessage> > generate_additional_messages() const {return {};}
115 //
116 //
117 // nlohmann::json to_json() const override;
118 //};
119 //
120 ///**
121 // * Any message involved in a query/response from the debugger
122 // */
123 //class ResponseMessage : public RequestResponseMessage {
124 // friend class RequestMessage;
125 //
126 //protected:
127 // ResponseMessage(RequestMessage const & request_message);
128 //
129 //public:
130 //
131 //};
132 //void to_json(nlohmann::json& j, const ResponseMessage & response_message);
133 //
134 //
135 ///**
136 // * Stores mapping between
137 // */
138 //class MessageManager {
139 //public:
140 // // map type between
141 // using MessageMap = std::map<std::string, std::function<std::unique_ptr<RequestMessage>(std::string const &)>>;
142 //private:
143 //
144 // MessageMap message_map;
145 //
146 // v8toolkit::DebugContext & debug_context;
147 //
148 //public:
149 // MessageManager(v8toolkit::DebugContext & context);
150 //
151 // template<class RequestMessageT, std::enable_if_t<std::is_base_of<RequestMessage, RequestMessageT>::value, int> = 0>
152 // void add_request_message_handler() {
153 // this->message_map[RequestMessageT::message_name] = [this](std::string const & message_payload){
154 // nlohmann::json const & json = nlohmann::json::parse(message_payload);
155 // return std::make_unique<RequestMessageT>(this->debug_context, json);
156 // };
157 // };
158 //
159 // std::vector<std::unique_ptr<ResponseMessage>> generate_response_message(RequestMessage const & request_message);
160 //
161 // void process_request_message(std::string const &message_payload);
162 //};
163 #endif
164 
165 // implements sending data to debugger
166 class WebsocketChannel : public v8_inspector::V8Inspector::Channel {
167 public:
168  WebsocketChannel(v8toolkit::DebugContext & debug_context, short port);
169 
170  virtual ~WebsocketChannel();
171 
172 private:
173  void sendResponse(int callId,
174  std::unique_ptr<v8_inspector::StringBuffer> message) override {
175  Send(message->string());
176  }
177 
178 
179  void sendNotification(std::unique_ptr<v8_inspector::StringBuffer> message) override {
180 
181  Send(message->string());
182  }
183 
184 
185  void flushProtocolNotifications() override {}
186 
187 
188  void Send(const v8_inspector::StringView &string);
189 
190  v8::Isolate *isolate;
191  v8toolkit::DebugContext & debug_context;
192 
193  using DebugServerType = websocketpp::server<websocketpp::config::asio>;
194  DebugServerType debug_server;
195 
196  unsigned short port = 0;
197 
198  using WebSocketConnections = std::set<websocketpp::connection_hdl, std::owner_less<websocketpp::connection_hdl>>;
199  WebSocketConnections connections;
200 
201 // void send_message(std::wstring const &message);
202 
203 
204  bool websocket_validation_handler(websocketpp::connection_hdl hdl);
205 
206  // registered callbacks with websocketpp
207  void on_open(websocketpp::connection_hdl hdl);
208 
209  void on_close(websocketpp::connection_hdl hdl);
210 
211  void on_message(websocketpp::connection_hdl hdl, DebugServerType::message_ptr msg);
212 
213  void on_http(websocketpp::connection_hdl hdl);
214 
215  std::chrono::time_point<std::chrono::high_resolution_clock> message_received_time = std::chrono::high_resolution_clock::now();
216  std::chrono::time_point<std::chrono::high_resolution_clock> message_sent_time = std::chrono::high_resolution_clock::now();
217 
218 public:
219  void wait_for_connection(std::chrono::duration<float> sleep_between_polls = std::chrono::duration<float>(0.1f));
220  void poll();
221 
222  /**
223  * runs a single request if available, otherwise returns immediately
224  */
225  void poll_one();
226 
227  /**
228  * polls until connection has been idle for specified amount of time
229  * @param idle_time amount of time between messages to wait until returning
230  */
231  void poll_until_idle(float idle_time = 1.0f);
232 
233  /**
234  * blocks until a request is handled
235  */
236  void run_one();
237 
238  void send_message(void * data, size_t length);
239 
240 
241  /**
242  * How long ago was most recent message received
243  * @return number of seconds
244  */
246 
247  /**
248  * How long ago was most recent message sent
249  * @return number of sceonds
250  */
252 
253  /**
254  * how long ago was a message either sent or received
255  * @return number of seconds
256  */
257  float seconds_since_message();
258 
259 // MessageManager message_manager;
260 };
261 
262 
263 enum {
264  // The debugger reserves the first slot in the Context embedder data.
268 };
269 
270 
271 class DebugContext : public v8_inspector::V8InspectorClient, public v8toolkit::Context {
272 private:
273  short port;
274  std::string frame_id = "12345.1"; // arbitrary value
275  std::unique_ptr<WebsocketChannel> channel;
276  std::unique_ptr<v8_inspector::V8Inspector> inspector;
277  std::unique_ptr<v8_inspector::V8InspectorSession> session;
278 
279  std::vector<std::string> message_types_handled_by_v8_inspector = {};
280 
281 
282 public:
283  DebugContext(std::shared_ptr<v8toolkit::Isolate> isolate_helper, v8::Local<v8::Context> context, short port);
284 
285 
286  virtual void runMessageLoopOnPause(int contextGroupId) override {
287  this->paused = true;
288  while (this->paused) {
289  this->channel->run_one();
290  }
291  std::cerr << fmt::format("exiting runMessageLoopOnPause") << std::endl;
292  }
293 
294  virtual void quitMessageLoopOnPause() override {
295  std::cerr << fmt::format("quitMessageLoopOnPause, setting paused=false") << std::endl;
296  this->paused = false;
297  }
298 
299  std::string const & get_frame_id() const {return this->frame_id;}
300  std::string get_base_url() const {return this->get_uuid_string();}
301 
302 public:
304  return *this;
305  }
306 
307  static const int kContextGroupId = 1;
308  bool paused = false;
309 
310  WebsocketChannel & get_channel() {return *this->channel;}
311  v8_inspector::V8InspectorSession & get_session() {return *this->session;}
312  void reset_session();
313 
314 
315 
316 };
317 ///// END NEW DEBUG CODE
318 
319 } // end v8toolkit namespace
float seconds_since_message_received()
Definition: debugger.cpp:294
virtual void runMessageLoopOnPause(int contextGroupId) override
Definition: debugger.h:286
::std::string string
Definition: gtest-port.h:1097
v8::Local< v8::Context > ensureDefaultContextInGroup(int group_id) override
Definition: debugger.h:303
void poll_until_idle(float idle_time=1.0f)
Definition: debugger.cpp:238
void wait_for_connection(std::chrono::duration< float > sleep_between_polls=std::chrono::duration< float >(0.1f))
Definition: debugger.cpp:247
void send_message(void *data, size_t length)
Definition: debugger.cpp:215
v8_inspector::V8InspectorSession & get_session()
Definition: debugger.h:311
WebsocketChannel(v8toolkit::DebugContext &debug_context, short port)
Definition: debugger.cpp:83
virtual void quitMessageLoopOnPause() override
Definition: debugger.h:294
std::string get_base_url() const
Definition: debugger.h:300
std::string const & get_frame_id() const
Definition: debugger.h:299
WebsocketChannel & get_channel()
Definition: debugger.h:310