Skip to content

Commit 2ab4b8d

Browse files
Merge pull request #27 from lightpanda-io/inspector
v8 Inspector support
2 parents 0c61a85 + 7d46232 commit 2ab4b8d

File tree

4 files changed

+613
-0
lines changed

4 files changed

+613
-0
lines changed

src/binding.cpp

Lines changed: 235 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,12 @@
22

33
#include <cassert>
44
#include "include/libplatform/libplatform.h"
5+
#include "include/v8-inspector.h"
56
#include "include/v8.h"
67
#include "src/api/api.h"
78

9+
#include "inspector.h"
10+
811
template <class T, class... Args>
912
class Wrapper {
1013
public:
@@ -1501,4 +1504,236 @@ void v8__base__SetDcheckFunction(void (*func)(const char*, int, const char*)) {
15011504
v8::base::SetDcheckFunction(func);
15021505
}
15031506

1507+
// Inspector
1508+
// ---------
1509+
1510+
// v8 inspector is not really documented and not easy.
1511+
// Sources:
1512+
// - https://v8.dev/docs/inspector
1513+
// - C++ doc https://v8.github.io/api/head/namespacev8__inspector.html
1514+
// - Rusty (Deno) bindings https://github.com/denoland/rusty_v8/blob/main/src/binding.cc
1515+
// - https://github.com/ahmadov/v8_inspector_example
1516+
// - https://web.archive.org/web/20210918052901/http://hyperandroid.com/2020/02/12/v8-inspector-from-an-embedder-standpoint
1517+
1518+
// Utils
1519+
1520+
static inline v8_inspector::StringView toStringView(const std::string &str) {
1521+
auto* stringView = reinterpret_cast<const uint8_t*>(str.c_str());
1522+
return { stringView, str.length() };
1523+
}
1524+
1525+
static inline std::string fromStringView(v8::Isolate* isolate, const v8_inspector::StringView stringView) {
1526+
int length = static_cast<int>(stringView.length());
1527+
v8::Local<v8::String> message = (
1528+
stringView.is8Bit()
1529+
? v8::String::NewFromOneByte(isolate, reinterpret_cast<const uint8_t*>(stringView.characters8()), v8::NewStringType::kNormal, length)
1530+
: v8::String::NewFromTwoByte(isolate, reinterpret_cast<const uint16_t*>(stringView.characters16()), v8::NewStringType::kNormal, length)
1531+
).ToLocalChecked();
1532+
v8::String::Utf8Value result(isolate, message);
1533+
return *result;
1534+
}
1535+
1536+
// Inspector
1537+
1538+
v8_inspector::V8Inspector *v8_inspector__Inspector__Create(
1539+
v8::Isolate* isolate, v8_inspector__Client__IMPL *client) {
1540+
std::unique_ptr<v8_inspector::V8Inspector> u =
1541+
v8_inspector::V8Inspector::create(isolate, client);
1542+
return u.release();
1543+
}
1544+
void v8_inspector__Inspector__DELETE(v8_inspector::V8Inspector* self) {
1545+
delete self;
1546+
}
1547+
v8_inspector::V8InspectorSession *v8_inspector__Inspector__Connect(
1548+
v8_inspector::V8Inspector *self, int contextGroupId,
1549+
v8_inspector__Channel__IMPL *channel,
1550+
v8_inspector::V8Inspector::ClientTrustLevel client_trust_level) {
1551+
auto state = v8_inspector::StringView();
1552+
std::unique_ptr<v8_inspector::V8InspectorSession> u =
1553+
self->connect(contextGroupId, channel, state, client_trust_level);
1554+
return u.release();
1555+
}
1556+
void v8_inspector__Inspector__ContextCreated(v8_inspector::V8Inspector *self,
1557+
const char *name, int name_len,
1558+
const char *origin, int origin_len,
1559+
const char *auxData, int auxData_len,
1560+
int contextGroupId,
1561+
const v8::Context &ctx) {
1562+
// create context info
1563+
std::string name_str;
1564+
name_str.assign(name, name_len);
1565+
v8_inspector::StringView name_view(toStringView(name_str));
1566+
auto context = ptr_to_local(&ctx);
1567+
v8_inspector::V8ContextInfo info(context, contextGroupId, name_view);
1568+
1569+
// add origin to context info
1570+
std::string origin_str;
1571+
origin_str.assign(origin, origin_len);
1572+
info.origin = toStringView(origin_str);
1573+
1574+
// add auxData to context info
1575+
std::string auxData_str;
1576+
auxData_str.assign(auxData, auxData_len);
1577+
info.auxData = toStringView(auxData_str);
1578+
1579+
// call contextCreated
1580+
self->contextCreated(info);
1581+
}
1582+
1583+
// InspectorSession
1584+
1585+
void v8_inspector__Session__dispatchProtocolMessage(
1586+
v8_inspector::V8InspectorSession *session, v8::Isolate *isolate,
1587+
const char *msg, int msg_len) {
1588+
std::string message;
1589+
message.assign(msg, msg_len);
1590+
auto str_view = toStringView(message);
1591+
session->dispatchProtocolMessage(str_view);
1592+
}
1593+
1594+
// InspectorChannel
1595+
1596+
v8_inspector__Channel__IMPL * v8_inspector__Channel__IMPL__CREATE(v8::Isolate *isolate) {
1597+
auto channel = new v8_inspector__Channel__IMPL();
1598+
channel->isolate = isolate;
1599+
return channel;
1600+
}
1601+
void v8_inspector__Channel__IMPL__DELETE(v8_inspector__Channel__IMPL *self) {
1602+
delete self;
1603+
}
1604+
void v8_inspector__Channel__IMPL__SET_DATA(v8_inspector__Channel__IMPL *self, void *data) {
1605+
self->data = data;
1606+
}
1607+
1608+
// declaration of functions implementations
1609+
// NOTE: zig project should provide those implementations with C-ABI functions
1610+
void v8_inspector__Channel__IMPL__sendResponse(
1611+
v8_inspector__Channel__IMPL* self, void* data,
1612+
int callId, const char* message, size_t length);
1613+
void v8_inspector__Channel__IMPL__sendNotification(
1614+
v8_inspector__Channel__IMPL* self, void *data,
1615+
const char* msg, size_t length);
1616+
void v8_inspector__Channel__IMPL__flushProtocolNotifications(
1617+
v8_inspector__Channel__IMPL* self, void *data);
1618+
1619+
// c++ implementation (just wrappers around the C/zig functions)
1620+
} // extern "C"
1621+
void v8_inspector__Channel__IMPL::sendResponse(
1622+
int callId, std::unique_ptr<v8_inspector::StringBuffer> message) {
1623+
const std::string resp = fromStringView(this->isolate, message->string());
1624+
return v8_inspector__Channel__IMPL__sendResponse(this, this->data, callId, resp.c_str(), resp.length());
1625+
}
1626+
void v8_inspector__Channel__IMPL::sendNotification(
1627+
std::unique_ptr<v8_inspector::StringBuffer> message) {
1628+
const std::string notif = fromStringView(this->isolate, message->string());
1629+
return v8_inspector__Channel__IMPL__sendNotification(this, this->data, notif.c_str(), notif.length());
1630+
}
1631+
void v8_inspector__Channel__IMPL::flushProtocolNotifications() {
1632+
return v8_inspector__Channel__IMPL__flushProtocolNotifications(this, this->data);
1633+
}
1634+
1635+
extern "C" {
1636+
1637+
// wrappers for the public API Interface
1638+
// NOTE: not sure it's useful to expose those
1639+
void v8_inspector__Channel__sendResponse(
1640+
v8_inspector::V8Inspector::Channel* self, int callId,
1641+
v8_inspector::StringBuffer* message) {
1642+
self->sendResponse(
1643+
callId,
1644+
static_cast<std::unique_ptr<v8_inspector::StringBuffer>>(message));
1645+
}
1646+
void v8_inspector__Channel__sendNotification(
1647+
v8_inspector::V8Inspector::Channel* self,
1648+
v8_inspector::StringBuffer* message) {
1649+
self->sendNotification(
1650+
static_cast<std::unique_ptr<v8_inspector::StringBuffer>>(message));
1651+
}
1652+
void v8_inspector__Channel__flushProtocolNotifications(
1653+
v8_inspector::V8Inspector::Channel* self) {
1654+
self->flushProtocolNotifications();
1655+
}
1656+
1657+
// InspectorClient
1658+
1659+
v8_inspector__Client__IMPL *v8_inspector__Client__IMPL__CREATE() {
1660+
return new v8_inspector__Client__IMPL();
1661+
}
1662+
void v8_inspector__Client__IMPL__DELETE(v8_inspector__Client__IMPL *self) {
1663+
delete self;
1664+
}
1665+
void v8_inspector__Client__IMPL__SET_DATA(v8_inspector__Client__IMPL *self, void *data) {
1666+
self->data = data;
1667+
}
1668+
1669+
// declaration of functions implementations
1670+
// NOTE: zig project should provide those implementations with C-like functions
1671+
int64_t v8_inspector__Client__IMPL__generateUniqueId(v8_inspector__Client__IMPL* self, void* data);
1672+
void v8_inspector__Client__IMPL__runMessageLoopOnPause(
1673+
v8_inspector__Client__IMPL *self,
1674+
void* data, int contextGroupId);
1675+
void v8_inspector__Client__IMPL__quitMessageLoopOnPause(v8_inspector__Client__IMPL* self, void* data);
1676+
void v8_inspector__Client__IMPL__runIfWaitingForDebugger(
1677+
v8_inspector__Client__IMPL* self, void* data, int contextGroupId);
1678+
void v8_inspector__Client__IMPL__consoleAPIMessage(
1679+
v8_inspector__Client__IMPL* self, void* data, int contextGroupId,
1680+
v8::Isolate::MessageErrorLevel level,
1681+
const v8_inspector::StringView &message,
1682+
const v8_inspector::StringView &url, unsigned lineNumber,
1683+
unsigned columnNumber, v8_inspector::V8StackTrace *stackTrace);
1684+
1685+
// c++ implementation (just wrappers around the c/zig functions)
1686+
} // extern "C"
1687+
int64_t v8_inspector__Client__IMPL::generateUniqueId() {
1688+
return v8_inspector__Client__IMPL__generateUniqueId(this, this->data);
1689+
}
1690+
void v8_inspector__Client__IMPL::runMessageLoopOnPause(int contextGroupId) {
1691+
return v8_inspector__Client__IMPL__runMessageLoopOnPause(this, this->data, contextGroupId);
1692+
}
1693+
void v8_inspector__Client__IMPL::quitMessageLoopOnPause() {
1694+
return v8_inspector__Client__IMPL__quitMessageLoopOnPause(this, this->data);
1695+
}
1696+
void v8_inspector__Client__IMPL::runIfWaitingForDebugger(int contextGroupId) {
1697+
return v8_inspector__Client__IMPL__runIfWaitingForDebugger(this, this->data, contextGroupId);
1698+
}
1699+
void v8_inspector__Client__IMPL::consoleAPIMessage(
1700+
int contextGroupId, v8::Isolate::MessageErrorLevel level,
1701+
const v8_inspector::StringView &message,
1702+
const v8_inspector::StringView &url, unsigned lineNumber,
1703+
unsigned columnNumber, v8_inspector::V8StackTrace *stackTrace) {
1704+
return v8_inspector__Client__IMPL__consoleAPIMessage(
1705+
this, this->data, contextGroupId, level, message, url, lineNumber,
1706+
columnNumber, stackTrace);
15041707
}
1708+
1709+
extern "C" {
1710+
1711+
// wrappers for the public API Interface
1712+
// NOTE: not sure it's useful to expose those
1713+
int64_t v8_inspector__Client__generateUniqueId(
1714+
v8_inspector::V8InspectorClient *self) {
1715+
return self->generateUniqueId();
1716+
}
1717+
void v8_inspector__Client__runMessageLoopOnPause(
1718+
v8_inspector::V8InspectorClient* self, int contextGroupId) {
1719+
self->runMessageLoopOnPause(contextGroupId);
1720+
}
1721+
void v8_inspector__Client__quitMessageLoopOnPause(
1722+
v8_inspector::V8InspectorClient* self) {
1723+
self->quitMessageLoopOnPause();
1724+
}
1725+
void v8_inspector__Client__runIfWaitingForDebugger(
1726+
v8_inspector::V8InspectorClient* self, int contextGroupId) {
1727+
self->runIfWaitingForDebugger(contextGroupId);
1728+
}
1729+
void v8_inspector__Client__consoleAPIMessage(
1730+
v8_inspector::V8InspectorClient* self, int contextGroupId,
1731+
v8::Isolate::MessageErrorLevel level,
1732+
const v8_inspector::StringView& message,
1733+
const v8_inspector::StringView& url, unsigned lineNumber,
1734+
unsigned columnNumber, v8_inspector::V8StackTrace* stackTrace) {
1735+
self->consoleAPIMessage(contextGroupId, level, message, url, lineNumber,
1736+
columnNumber, stackTrace);
1737+
}
1738+
1739+
} // extern "C"

src/binding.h

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -895,3 +895,75 @@ const String* v8__JSON__Stringify(
895895

896896
// Misc.
897897
void v8__base__SetDcheckFunction(void (*func)(const char*, int, const char*));
898+
899+
// Inspector
900+
// ---------
901+
902+
typedef enum ClientTrustLevel {
903+
kUntrusted,
904+
kFullyTrusted,
905+
} ClientTrustLevel;
906+
907+
typedef struct StringView StringView;
908+
909+
// InspectorChannel
910+
911+
typedef struct InspectorChannel InspectorChannel;
912+
typedef struct InspectorChannelImpl {
913+
void* data;
914+
} InspectorChannelImpl;
915+
InspectorChannelImpl *v8_inspector__Channel__IMPL__CREATE(Isolate *isolate);
916+
void v8_inspector__Channel__IMPL__DELETE(InspectorChannelImpl *self);
917+
void v8_inspector__Channel__IMPL__SET_DATA(InspectorChannelImpl* self, void *data);
918+
919+
void v8_inspector__Channel__IMPL__sendResponse(
920+
InspectorChannelImpl *self, void *data,
921+
int callId, char *message, size_t length);
922+
void v8_inspector__Channel__IMPL__sendNotification(
923+
InspectorChannelImpl *self, void *data,
924+
char *message, size_t length);
925+
void v8_inspector__Channel__IMPL__flushProtocolNotifications(
926+
InspectorChannelImpl *self, void *data);
927+
928+
// InspectorClient
929+
930+
typedef struct InspectorClient InspectorClient;
931+
typedef struct InspectorClientImpl {
932+
void* data;
933+
} InspectorClientImpl;
934+
InspectorClientImpl *v8_inspector__Client__IMPL__CREATE();
935+
void v8_inspector__Client__IMPL__DELETE(InspectorClientImpl *self);
936+
void v8_inspector__Client__IMPL__SET_DATA(InspectorClientImpl* self, void *data);
937+
938+
int64_t v8_inspector__Client__IMPL__generateUniqueId(InspectorClientImpl *self);
939+
void v8_inspector__Client__IMPL__runMessageLoopOnPause(
940+
InspectorClientImpl *self, int contextGroupId);
941+
void v8_inspector__Client__IMPL__quitMessageLoopOnPause(
942+
InspectorClientImpl *self);
943+
void v8_inspector__Client__IMPL__runIfWaitingForDebugger(
944+
InspectorClientImpl *self, int contextGroupId);
945+
void v8_inspector__Client__IMPL__consoleAPIMessage(
946+
InspectorClientImpl *self, int contextGroupId, MessageErrorLevel level,
947+
StringView *message, StringView *url, unsigned lineNumber,
948+
unsigned columnNumber, StackTrace *StackTrace);
949+
950+
// InspectorSession
951+
952+
typedef struct InspectorSession InspectorSession;
953+
void v8_inspector__Session__dispatchProtocolMessage(InspectorSession *session, Isolate *isolate, const char* msg, usize msg_len);
954+
955+
// Inspector
956+
typedef struct Inspector Inspector;
957+
Inspector* v8_inspector__Inspector__Create(Isolate* isolate, InspectorClientImpl* client);
958+
void v8_inspector__Inspector__DELETE(Inspector *self);
959+
960+
InspectorSession* v8_inspector__Inspector__Connect(
961+
Inspector *self, int contextGroupId,
962+
InspectorChannelImpl *channel,
963+
ClientTrustLevel level);
964+
void v8_inspector__Inspector__ContextCreated(Inspector *self, const char *name,
965+
usize name_len, const char *origin,
966+
usize origin_len,
967+
const char *auxData, const usize auxData_len,
968+
int contextGroupId,
969+
const Context* context);

src/inspector.h

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
#include "include/v8-inspector.h"
2+
3+
#ifndef V8INSPECTORIMPL_H
4+
#define V8INSPECTORIMPLH
5+
6+
// InspectorChannel Implementation
7+
struct v8_inspector__Channel__IMPL
8+
: public v8_inspector::V8Inspector::Channel {
9+
using v8_inspector::V8Inspector::Channel::Channel;
10+
11+
public:
12+
v8::Isolate *isolate;
13+
void *data;
14+
15+
private:
16+
void sendResponse(int callId,
17+
std::unique_ptr<v8_inspector::StringBuffer> message) override;
18+
void sendNotification(std::unique_ptr<v8_inspector::StringBuffer> message) override;
19+
void flushProtocolNotifications() override;
20+
};
21+
22+
// InspectorClient Implementation
23+
class v8_inspector__Client__IMPL
24+
: public v8_inspector::V8InspectorClient {
25+
using v8_inspector::V8InspectorClient::V8InspectorClient;
26+
27+
public:
28+
void *data;
29+
30+
private:
31+
int64_t generateUniqueId() override;
32+
void runMessageLoopOnPause(int contextGroupId) override;
33+
void quitMessageLoopOnPause() override;
34+
void runIfWaitingForDebugger(int contextGroupId) override;
35+
void consoleAPIMessage(int contextGroupId,
36+
v8::Isolate::MessageErrorLevel level,
37+
const v8_inspector::StringView& message,
38+
const v8_inspector::StringView& url,
39+
unsigned lineNumber, unsigned columnNumber,
40+
v8_inspector::V8StackTrace* stackTrace) override;
41+
};
42+
43+
#endif // V8INSPECTORIMPL_H

0 commit comments

Comments
 (0)