See More

#include "quickjs_debugger.h" #include "core/io/stream_peer_tcp.h" #define QJS_DEBUGGER_DEBUG_LOG 0 QuickJSDebugger::ConnectionConfig QuickJSDebugger::parse_address(const String &address) { int idx = address.rfind(":"); String address_str = address.substr(0, idx); if (address_str == "localhost") { address_str = "127.0.0.1"; } ConnectionConfig connect; connect.port = address.substr(idx + 1).to_int(); connect.address = IPAddress(address_str); return connect; } size_t QuickJSDebugger::transport_read(void *udata, char *buffer, size_t length) { QuickJSDebugger *debugger = static_cast(udata); ERR_FAIL_COND_V(debugger == nullptr || debugger->peer.is_null() || debugger->peer->get_status() != StreamPeerTCP::STATUS_CONNECTED, -1); ERR_FAIL_COND_V(length == 0, -2); ERR_FAIL_NULL_V(buffer, -3); int ret = length; Error err = debugger->peer->get_data((uint8_t *)buffer, length); #if QJS_DEBUGGER_DEBUG_LOG print_line(vformat("[read] %d %s", length, buffer)); #endif ERR_FAIL_COND_V(err != OK, -err); ERR_FAIL_COND_V(ret < 0, -4); ERR_FAIL_COND_V(ret > (ssize_t)length, -6); return ret; } size_t QuickJSDebugger::transport_write(void *udata, const char *buffer, size_t length) { QuickJSDebugger *debugger = static_cast(udata); ERR_FAIL_COND_V(debugger == nullptr || debugger->peer.is_null() || debugger->peer->get_status() != StreamPeerTCP::STATUS_CONNECTED, -1); ERR_FAIL_COND_V(length == 0, -2); ERR_FAIL_NULL_V(buffer, -3); int ret = length; Error err = debugger->peer->put_data((uint8_t *)buffer, length); #if QJS_DEBUGGER_DEBUG_LOG print_line(vformat("[write] %d %s", length, buffer)); #endif ERR_FAIL_COND_V(err != OK, -err); ERR_FAIL_COND_V(ret <= 0 || ret > (ssize_t)length, -4); return ret; } size_t QuickJSDebugger::transport_peek(void *udata) { QuickJSDebugger *debugger = static_cast(udata); ERR_FAIL_COND_V(debugger == NULL || debugger->peer.is_null() || debugger->peer->get_status() != StreamPeerTCP::STATUS_CONNECTED, -1); StreamPeerTCP::Status status = debugger->peer->get_status(); #if QJS_DEBUGGER_DEBUG_LOG print_line(vformat("[peek] %d", debugger->peer->get_available_bytes())); #endif if (status != StreamPeerTCP::STATUS_CONNECTED && status != StreamPeerTCP::STATUS_CONNECTING) { return -2; } return debugger->peer->get_available_bytes(); } void QuickJSDebugger::transport_close(JSRuntime *rt, void *udata) { QuickJSDebugger *debugger = static_cast(udata); ERR_FAIL_COND(debugger == NULL || debugger->peer.is_null()); debugger->peer->disconnect_from_host(); debugger->peer = Ref(); #if QJS_DEBUGGER_DEBUG_LOG print_line(vformat("[transport_close]")); #endif } Error QuickJSDebugger::attach_js_debugger(JSContext *ctx, Ref p_peer) { ERR_FAIL_NULL_V(ctx, ERR_CANT_CONNECT); if (p_peer.is_valid() && p_peer->get_status() == StreamPeerTCP::STATUS_CONNECTED) { this->peer = p_peer; js_debugger_attach(ctx, transport_read, transport_write, transport_peek, transport_close, this); return OK; } return ERR_CANT_CONNECT; } Error QuickJSDebugger::connect(JSContext *ctx, const String &address) { this->ctx = ctx; this->runtime = JS_GetRuntime(ctx); ConnectionConfig c = parse_address(address); Ref peer = memnew(StreamPeerTCP); Error err = peer->connect_to_host(c.address, c.port); if (OK == err) { while (peer->get_status() == StreamPeerTCP::STATUS_CONNECTING) ; // wait until connected to the debugger return attach_js_debugger(ctx, peer); } return err; } Error QuickJSDebugger::listen(JSContext *ctx, const String &address) { this->ctx = ctx; this->runtime = JS_GetRuntime(ctx); if (server.is_valid() && server->is_listening()) { server->stop(); } server.instantiate(); ConnectionConfig c = parse_address(address); Error err = server->listen(c.port, c.address); return err; } void QuickJSDebugger::poll() { if (server.is_valid()) { if (server->is_connection_available()) { attach_js_debugger(ctx, server->take_connection()); } } if (peer.is_valid() && server.is_valid() && server->is_listening()) { if (peer->get_status() == StreamPeerTCP::STATUS_NONE || peer->get_status() == StreamPeerTCP::STATUS_ERROR) { JSDebuggerInfo *info = js_debugger_info(runtime); js_debugger_free(runtime, info); } } } QuickJSDebugger::QuickJSDebugger() { ctx = NULL; runtime = NULL; } QuickJSDebugger::~QuickJSDebugger() { if (server.is_valid() && server->is_listening()) { server->stop(); } }