Skip to content

Commit 241bba4

Browse files
committed
feat: Re-add NativeScript inspector sources
These were removed in the upgrade to V8 10.3.22. Re-add them. Note that the ObjC++ files need to be compiled with -fobjc-arc or else connecting the inspector crashes.
1 parent cfc7adf commit 241bba4

File tree

8 files changed

+763
-75
lines changed

8 files changed

+763
-75
lines changed
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
#ifndef InspectorServer_h
2+
#define InspectorServer_h
3+
4+
#include <functional>
5+
#include <string>
6+
#include <sys/types.h>
7+
#include <dispatch/dispatch.h>
8+
9+
namespace v8_inspector {
10+
11+
class InspectorServer {
12+
public:
13+
static in_port_t Init(std::function<void (std::function<void (std::string)>)> onClientConnected, std::function<void (std::string)> onMessage);
14+
private:
15+
static void Send(dispatch_io_t channel, dispatch_queue_t queue, std::string message);
16+
};
17+
18+
}
19+
20+
#endif /* InspectorServer_h */
Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
#include "InspectorServer.h"
2+
#include <Foundation/Foundation.h>
3+
#include <netinet/in.h>
4+
#include <sys/socket.h>
5+
6+
namespace v8_inspector {
7+
8+
in_port_t InspectorServer::Init(std::function<void (std::function<void (std::string)>)> onClientConnected, std::function<void (std::string)> onMessage) {
9+
in_port_t listenPort = 18183;
10+
11+
int serverSocket = -1;
12+
if ((serverSocket = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
13+
assert(false);
14+
}
15+
16+
struct sockaddr_in serverAddress;
17+
memset(&serverAddress, 0, sizeof(serverAddress));
18+
serverAddress.sin_family = AF_INET;
19+
serverAddress.sin_addr.s_addr = htonl(INADDR_ANY);
20+
do {
21+
serverAddress.sin_port = htons(listenPort);
22+
} while (bind(serverSocket, (struct sockaddr *) &serverAddress, sizeof(serverAddress)) < 0 && ++listenPort);
23+
24+
// Make the socket non-blocking
25+
if (fcntl(serverSocket, F_SETFL, O_NONBLOCK) < 0) {
26+
shutdown(serverSocket, SHUT_RDWR);
27+
close(serverSocket);
28+
assert(false);
29+
}
30+
31+
// Set up the dispatch source that will alert us to new incoming connections
32+
dispatch_queue_t q = dispatch_queue_create("server_queue", DISPATCH_QUEUE_CONCURRENT);
33+
dispatch_source_t acceptSource = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, serverSocket, 0, q);
34+
dispatch_source_set_event_handler(acceptSource, ^{
35+
const unsigned long numPendingConnections = dispatch_source_get_data(acceptSource);
36+
for (unsigned long i = 0; i < numPendingConnections; i++) {
37+
int clientSocket = -1;
38+
struct sockaddr_in echoClntAddr;
39+
unsigned int clntLen = sizeof(echoClntAddr);
40+
41+
// Wait for a client to connect
42+
if ((clientSocket = accept(serverSocket, (struct sockaddr *) &echoClntAddr, &clntLen)) >= 0) {
43+
dispatch_io_t channel = dispatch_io_create(DISPATCH_IO_STREAM, clientSocket, q, ^(int error) {
44+
if (error) {
45+
NSLog(@"Error: %s", strerror(error));
46+
}
47+
close(clientSocket);
48+
});
49+
50+
onClientConnected([channel, q](std::string message) {
51+
Send(channel, q, message);
52+
});
53+
54+
__block dispatch_io_handler_t receiver = ^(bool done, dispatch_data_t data, int error) {
55+
if (error) {
56+
NSLog(@"Error: %s", strerror(error));
57+
}
58+
59+
const void* bytes = [(NSData*)data bytes];
60+
if (!bytes) {
61+
return;
62+
}
63+
64+
uint32_t length = ntohl(*(uint32_t*)bytes);
65+
66+
// Configure the channel...
67+
dispatch_io_set_low_water(channel, length);
68+
69+
// Setup read handler
70+
dispatch_io_read(channel, 0, length, q, ^(bool done, dispatch_data_t data, int error) {
71+
BOOL close = NO;
72+
if (error) {
73+
NSLog(@"Error: %s", strerror(error));
74+
close = YES;
75+
}
76+
77+
const size_t size = data ? dispatch_data_get_size(data) : 0;
78+
if (size) {
79+
NSString* payload = [[NSString alloc] initWithData:(NSData*)data encoding:NSUTF16LittleEndianStringEncoding];
80+
81+
onMessage([payload UTF8String]);
82+
83+
#pragma clang diagnostic push
84+
#pragma clang diagnostic ignored "-Warc-retain-cycles"
85+
dispatch_io_read(channel, 0, 4, q, receiver);
86+
#pragma clang diagnostic pop
87+
} else {
88+
close = YES;
89+
}
90+
91+
if (close) {
92+
dispatch_io_close(channel, DISPATCH_IO_STOP);
93+
}
94+
});
95+
};
96+
97+
if (channel) {
98+
dispatch_io_read(channel, 0, 4, q, receiver);
99+
}
100+
}
101+
else {
102+
NSLog(@"accept() failed;\n");
103+
}
104+
}
105+
});
106+
107+
// Resume the source so we're ready to accept once we listen()
108+
dispatch_resume(acceptSource);
109+
110+
// Listen() on the socket
111+
if (listen(serverSocket, SOMAXCONN) < 0) {
112+
shutdown(serverSocket, SHUT_RDWR);
113+
close(serverSocket);
114+
assert(false);
115+
}
116+
117+
return listenPort;
118+
}
119+
120+
void InspectorServer::Send(dispatch_io_t channel, dispatch_queue_t queue, std::string message) {
121+
NSString* str = [NSString stringWithUTF8String:message.c_str()];
122+
NSUInteger length = [str lengthOfBytesUsingEncoding:NSUTF16LittleEndianStringEncoding];
123+
124+
uint8_t* buffer = (uint8_t*)malloc(length + sizeof(uint32_t));
125+
126+
*(uint32_t*)buffer = htonl(length);
127+
128+
[str getBytes:&buffer[sizeof(uint32_t)]
129+
maxLength:length
130+
usedLength:NULL
131+
encoding:NSUTF16LittleEndianStringEncoding
132+
options:0
133+
range:NSMakeRange(0, str.length)
134+
remainingRange:NULL];
135+
136+
dispatch_data_t data = dispatch_data_create(buffer, length + sizeof(uint32_t), queue, ^{
137+
free(buffer);
138+
});
139+
140+
dispatch_io_write(channel, 0, data, queue, ^(bool done, dispatch_data_t data, int error) {
141+
if (error) {
142+
NSLog(@"Error: %s", strerror(error));
143+
}
144+
});
145+
}
146+
147+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
#include <stdio.h>
2+
#include "JsV8InspectorClient.h"
3+
#include "src/inspector/v8-inspector-session-impl.h"
4+
#include "Helpers.h"
5+
6+
using namespace v8;
7+
8+
namespace v8_inspector {
9+
10+
void JsV8InspectorClient::inspectorSendEventCallback(const FunctionCallbackInfo<Value>& args) {
11+
Local<External> data = args.Data().As<External>();
12+
v8_inspector::JsV8InspectorClient* client = static_cast<v8_inspector::JsV8InspectorClient*>(data->Value());
13+
Isolate* isolate = args.GetIsolate();
14+
Local<v8::String> arg = args[0].As<v8::String>();
15+
std::string message = tns::ToString(isolate, arg);
16+
17+
if (message.find("\"Network.") != std::string::npos) {
18+
// The Network domain is handled directly by the corresponding backend
19+
V8InspectorSessionImpl* session = (V8InspectorSessionImpl*)client->session_.get();
20+
session->networkArgent()->dispatch(message);
21+
return;
22+
}
23+
24+
if (message.find("\"DOM.") != std::string::npos) {
25+
// The DOM domain is handled directly by the corresponding backend
26+
V8InspectorSessionImpl* session = (V8InspectorSessionImpl*)client->session_.get();
27+
session->domArgent()->dispatch(message);
28+
return;
29+
}
30+
31+
client->dispatchMessage(message);
32+
}
33+
34+
}
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
#ifndef JsV8InspectorClient_h
2+
#define JsV8InspectorClient_h
3+
4+
#include <functional>
5+
#include <dispatch/dispatch.h>
6+
#include <string>
7+
#include <vector>
8+
#include <map>
9+
10+
#include "include/v8-inspector.h"
11+
#include "runtime/Runtime.h"
12+
13+
namespace v8_inspector {
14+
15+
class JsV8InspectorClient : V8InspectorClient, V8Inspector::Channel {
16+
public:
17+
JsV8InspectorClient(tns::Runtime* runtime);
18+
void init();
19+
void connect(int argc, char** argv);
20+
void createInspectorSession();
21+
void disconnect();
22+
void dispatchMessage(const std::string& message);
23+
24+
void sendResponse(int callId, std::unique_ptr<StringBuffer> message) override;
25+
void sendNotification(std::unique_ptr<StringBuffer> message) override;
26+
void flushProtocolNotifications() override;
27+
28+
void runMessageLoopOnPause(int contextGroupId) override;
29+
void quitMessageLoopOnPause() override;
30+
v8::Local<v8::Context> ensureDefaultContextInGroup(int contextGroupId) override;
31+
32+
void scheduleBreak();
33+
void registerModules();
34+
35+
static std::map<std::string, v8::Persistent<v8::Object>*> Domains;
36+
private:
37+
static int contextGroupId;
38+
bool isConnected_;
39+
std::unique_ptr<V8Inspector> inspector_;
40+
v8::Persistent<v8::Context> context_;
41+
std::unique_ptr<V8InspectorSession> session_;
42+
tns::Runtime* runtime_;
43+
bool terminated_;
44+
std::vector<std::string> messages_;
45+
bool runningNestedLoops_;
46+
dispatch_queue_t messagesQueue_;
47+
dispatch_queue_t messageLoopQueue_;
48+
dispatch_semaphore_t messageArrived_;
49+
std::function<void (std::string)> sender_;
50+
bool isWaitingForDebugger_;
51+
52+
void enableInspector(int argc, char** argv);
53+
void notify(std::unique_ptr<StringBuffer> message);
54+
void onFrontendConnected(std::function<void (std::string)> sender);
55+
void onFrontendMessageReceived(std::string message);
56+
template <class TypeName>
57+
static v8::Local<TypeName> PersistentToLocal(v8::Isolate* isolate, const v8::Persistent<TypeName>& persistent);
58+
std::string PumpMessage();
59+
static void registerDomainDispatcherCallback(const v8::FunctionCallbackInfo<v8::Value>& args);
60+
static void inspectorSendEventCallback(const v8::FunctionCallbackInfo<v8::Value>& args);
61+
static void inspectorTimestampCallback(const v8::FunctionCallbackInfo<v8::Value>& args);
62+
};
63+
64+
}
65+
66+
#endif /* JsV8InspectorClient_h */

0 commit comments

Comments
 (0)