From 98e4ece06603913a4476046778d6dce2e2daf3cb Mon Sep 17 00:00:00 2001 From: MCJack123 Date: Sat, 30 Dec 2023 01:22:14 -0500 Subject: [PATCH] Fixed #327 (hopefully), closed #337 Also fixed keys repeating after holding Ctrl+R/S/T. The WebSocket server API now uses a new function, `websocketServer`. This function initiates a server on the specified port, and returns a handle for listening and closing the server. The server no longer automatically closes when clients disconnect - the server must close itself through the handle. Clients are detected through the websocket_server_connect event, which the server handle's `listen` function wraps around. This event contains the port of the server that was connected, and the handle for this connection. The handle has the same methods as a normal handle, but also contains a `clientID` field that uniquely identifies this connection/client. When a server connection receives a message, it sends the `websocket_server_message` event, which consists of the client ID, the message, and whether the message is a binary message. Likewise, when the connection is closed, the `websocket_server_closed` message is sent with the client ID, and optionally the code the connection was closed with. --- api/Computer.hpp | 2 +- api/peripheral.hpp | 2 - craftos2-lua | 2 +- src/Computer.cpp | 20 ++- src/apis/http.cpp | 331 ++++++++++++++++++++++++------------ src/apis/mounter.cpp | 2 + src/peripheral/debugger.cpp | 6 + src/peripheral/debugger.hpp | 1 + src/plugin.cpp | 2 +- src/runtime.cpp | 2 + src/termsupport.cpp | 5 +- src/util.hpp | 2 +- 12 files changed, 259 insertions(+), 118 deletions(-) diff --git a/api/Computer.hpp b/api/Computer.hpp index 26f79559..738fa001 100644 --- a/api/Computer.hpp +++ b/api/Computer.hpp @@ -132,7 +132,7 @@ struct Computer { std::mutex openWebsocketsMutex; std::vector> startupCallbacks; // List of functions to call when starting up + a userdata to pass as the first argument - // The following fields are available in API version 10.9 and later. + // The following fields are available in API version 12.0 and later. std::vector droppedFiles; // List of files that were dropped in the current drop set private: diff --git a/api/peripheral.hpp b/api/peripheral.hpp index 91bace3a..7a02bbf3 100644 --- a/api/peripheral.hpp +++ b/api/peripheral.hpp @@ -56,9 +56,7 @@ class peripheral { virtual int call(lua_State *L, const char * method)=0; // This function is deprecated, and no longer works. In fact, it did not work // in any version of the API. Just leave this as-is. -#if __cplusplus >= 201402L [[deprecated]] -#endif virtual void update() {} // This function should return a library_t containing the names of all of the // methods available to the peripheral. Only the keys, name, and size members diff --git a/craftos2-lua b/craftos2-lua index 69b8370a..23a41108 160000 --- a/craftos2-lua +++ b/craftos2-lua @@ -1 +1 @@ -Subproject commit 69b8370a245972e0744d4d039e1aab02082ec047 +Subproject commit 23a41108e84c59a28c542a5ef5306ef79a849fbe diff --git a/src/Computer.cpp b/src/Computer.cpp index 3a14da19..91ca8560 100644 --- a/src/Computer.cpp +++ b/src/Computer.cpp @@ -547,6 +547,8 @@ void runComputer(Computer * self, const path_t& bios_name, const std::string& bi lua_setfield(L, -2, "addListener"); lua_pushnil(L); lua_setfield(L, -2, "removeListener"); + lua_pushnil(L); + lua_setfield(L, -2, "websocketServer"); lua_pop(L, 1); } lua_getglobal(L, "debug"); @@ -557,14 +559,20 @@ void runComputer(Computer * self, const path_t& bios_name, const std::string& bi lua_pop(L, 1); } if (config.serverMode) { - lua_getglobal(L, "http"); - lua_pushnil(L); - lua_setfield(L, -2, "addListener"); - lua_pushnil(L); - lua_setfield(L, -2, "removeListener"); - lua_pop(L, 1); + if (config.http_enable) { + lua_getglobal(L, "http"); + lua_pushnil(L); + lua_setfield(L, -2, "addListener"); + lua_pushnil(L); + lua_setfield(L, -2, "removeListener"); + lua_pushnil(L); + lua_setfield(L, -2, "websocketServer"); + lua_pop(L, 1); + } lua_pushnil(L); lua_setglobal(L, "mounter"); + lua_pushnil(L); + lua_setglobal(L, "config"); } // Set default globals diff --git a/src/apis/http.cpp b/src/apis/http.cpp index 81667eb8..0971203b 100644 --- a/src/apis/http.cpp +++ b/src/apis/http.cpp @@ -743,6 +743,7 @@ static int http_removeListener(lua_State *L) { extern int os_startTimer(lua_State *L); struct ws_handle { + bool isServer; std::string url; WebSocket * ws; std::mutex lock; @@ -769,6 +770,7 @@ struct websocket_closed_data { std::string url; std::string reason; uint16_t code; + void* clientID = NULL; }; static std::string websocket_failure(lua_State *L, void* userp) { @@ -792,18 +794,6 @@ static std::string websocket_closed(lua_State *L, void* userp) { return "websocket_closed"; } -static std::string websocket_closed_server(lua_State *L, void* userp) { - ws_handle * wsh = (ws_handle*)userp; - lua_pushnumber(L, wsh->port); - lua_pushlightuserdata(L, wsh->clientID); - return "websocket_closed"; -} - -static std::string websocket_server_closed(lua_State *L, void* userp) { - lua_pushnumber(L, (ptrdiff_t)userp); - return "websocket_server_closed"; -} - // WebSocket handle functions static int websocket_free(lua_State *L) { lastCFunction = __func__; @@ -852,20 +842,27 @@ static int websocket_receive(lua_State *L) { } std::string * ev = new std::string(lua_tostring(L, 1)); std::string * url = new std::string(); - int port = 0; - if (lua_isnumber(L, 2)) port = lua_tointeger(L, 2); + int tmid = 0; + if (lua_isnumber(L, 2)) tmid = lua_tointeger(L, 2); else if (lua_isstring(L, 2)) { delete url; url = new std::string(lua_tostring(L, 2)); } - if (*ev == "websocket_message" && (ws->url.empty() ? port == ws->port : *url == ws->url) && (ws->clientID == NULL || (lua_islightuserdata(L, 5) && lua_touserdata(L, 5) == ws->clientID))) { + if (*ev == "websocket_message" && !ws->isServer && *url == ws->url) { + lua_pushvalue(L, 3); + lua_pushvalue(L, 4); + delete ev; + delete url; + return 2; + } else if (*ev == "websocket_server_message" && ws->isServer && lua_touserdata(L, 2) == ws->clientID) { lua_pushvalue(L, 3); lua_pushvalue(L, 4); delete ev; delete url; return 2; - } else if ((*ev == "websocket_closed" && *url == ws->url && ws->ws == NULL) || - (tm > 0 && *ev == "timer" && lua_isnumber(L, 2) && lua_tointeger(L, 2) == tm)) { + } else if ((*ev == "websocket_closed" && !ws->isServer && *url == ws->url && ws->ws == NULL) || + (*ev == "websocket_server_closed" && ws->isServer && lua_touserdata(L, 2) == ws->clientID && ws->ws == NULL) || + (tm > 0 && *ev == "timer" && lua_isnumber(L, 2) && tmid == tm)) { lua_pushnil(L); delete ev; delete url; @@ -894,55 +891,80 @@ static int websocket_receive(lua_State *L) { return lua_yieldk(L, 0, tm, websocket_receive); } +static luaL_Reg websocket_funcs[] = { + {"close", websocket_close}, + {"receive", websocket_receive}, + {"send", websocket_send}, + {NULL, NULL} +}; + static std::string websocket_success(lua_State *L, void* userp) { ws_handle ** wsh = (ws_handle**)userp; luaL_checkstack(L, 10, "Could not grow stack for websocket_success"); - if ((*wsh)->url.empty()) lua_pushnumber(L, (*wsh)->port); - else lua_pushstring(L, (*wsh)->url.c_str()); - + lua_pushstring(L, (*wsh)->url.c_str()); + lua_createtable(L, 0, 4); ws_handle ** ws = (ws_handle**)lua_newuserdata(L, sizeof(ws_handle*)); *ws = *wsh; (*wsh)->ud = ws; - int pos = lua_gettop(L); lua_createtable(L, 0, 1); lua_pushstring(L, "__gc"); lua_pushcfunction(L, websocket_free); lua_settable(L, -3); lua_setmetatable(L, -2); - - lua_createtable(L, 0, 4); - - lua_pushstring(L, "close"); - lua_pushvalue(L, pos); - lua_pushcclosure(L, websocket_close, 1); - lua_settable(L, -3); - - lua_pushstring(L, "receive"); - lua_pushvalue(L, pos); - lua_pushcclosure(L, websocket_receive, 1); - lua_settable(L, -3); - - lua_pushstring(L, "send"); - lua_pushvalue(L, pos); - lua_pushcclosure(L, websocket_send, 1); - lua_settable(L, -3); - - lua_remove(L, pos); - if ((*ws)->clientID) lua_pushlightuserdata(L, (*ws)->clientID); + luaL_setfuncs(L, websocket_funcs, 1); return "websocket_success"; } static std::string websocket_message(lua_State *L, void* userp) { ws_message * message = (ws_message*)userp; - if (message->url.empty()) lua_pushinteger(L, message->port); - else lua_pushstring(L, message->url.c_str()); + lua_pushstring(L, message->url.c_str()); pushstring(L, message->data); lua_pushboolean(L, message->binary); - if (message->clientID) lua_pushlightuserdata(L, message->clientID); delete message; return "websocket_message"; } +// websocket_server_connect: port, handle +// handles have an additional clientID member +static std::string websocket_server_connect(lua_State *L, void* userp) { + ws_handle ** wsh = (ws_handle**)userp; + luaL_checkstack(L, 10, "Could not grow stack for websocket_server_connect"); + lua_pushnumber(L, (*wsh)->port); + lua_createtable(L, 0, 4); + ws_handle ** ws = (ws_handle**)lua_newuserdata(L, sizeof(ws_handle*)); + *ws = *wsh; + (*wsh)->ud = ws; + lua_createtable(L, 0, 1); + lua_pushstring(L, "__gc"); + lua_pushcfunction(L, websocket_free); + lua_settable(L, -3); + lua_setmetatable(L, -2); + luaL_setfuncs(L, websocket_funcs, 1); + lua_pushlightuserdata(L, (*ws)->clientID); + lua_setfield(L, -2, "clientID"); + return "websocket_server_connect"; +} + +static std::string websocket_server_message(lua_State *L, void* userp) { + ws_message * message = (ws_message*)userp; + lua_pushlightuserdata(L, message->clientID); + pushstring(L, message->data); + lua_pushboolean(L, message->binary); + delete message; + return "websocket_server_message"; +} + +static std::string websocket_server_closed(lua_State *L, void* userp) { + websocket_closed_data * data = (websocket_closed_data*)userp; + lua_pushlightuserdata(L, data->clientID); + if (data->code != 0) { + pushstring(L, data->reason); + lua_pushinteger(L, data->code); + } + delete data; + return "websocket_server_closed"; +} + class websocket_server: public HTTPRequestHandler { public: Computer * comp; @@ -955,13 +977,6 @@ class websocket_server: public HTTPRequestHandler { try { ws = new WebSocket(request, response); } catch (NetException &e) { - websocket_failure_data * data = new websocket_failure_data; - data->url = ""; - data->reason = e.message(); - data->port = srv->port(); - queueEvent(comp, websocket_failure, data); - delete ws; - if (srv != NULL) { try {srv->stop();} catch (...) {} delete srv; } return; } (*retainCount)++; @@ -972,14 +987,14 @@ class websocket_server: public HTTPRequestHandler { ws_handle ws_orig; ws_handle * wsh = &ws_orig; wsh->ws = ws; - wsh->url = ""; + wsh->isServer = true; wsh->port = srv->port(); wsh->clientID = &request; { std::lock_guard lock(comp->openWebsocketsMutex); comp->openWebsockets.push_back(&wsh); } - queueEvent(comp, websocket_success, &wsh); + queueEvent(comp, websocket_server_connect, &wsh); char * buf = new char[config.http_max_websocket_message]; while (wsh->ws) { int flags = 0; @@ -988,34 +1003,49 @@ class websocket_server: public HTTPRequestHandler { res = ws->receiveFrame(buf, config.http_max_websocket_message, flags); if (res < 0 || (res == 0 && flags == 0)) { wsh->ws = NULL; - queueEvent(comp, websocket_closed_server, wsh); + websocket_closed_data * d = new websocket_closed_data; + d->clientID = wsh->clientID; + d->code = 0; + queueEvent(comp, websocket_server_closed, d); break; } } catch (Poco::TimeoutException &e) { if (!wsh->ws) { - queueEvent(comp, websocket_closed_server, wsh); + websocket_closed_data * d = new websocket_closed_data; + d->clientID = wsh->clientID; + d->code = 1006; + d->reason = "Timed out"; + queueEvent(comp, websocket_server_closed, d); break; } continue; } catch (NetException &e) { wsh->ws = NULL; - queueEvent(comp, websocket_closed_server, wsh); + websocket_closed_data * d = new websocket_closed_data; + d->clientID = wsh->clientID; + d->code = 1006; + d->reason = e.message(); + queueEvent(comp, websocket_server_closed, d); break; } if ((flags & 0x0f) == WebSocket::FRAME_OP_CLOSE) { wsh->ws = NULL; - queueEvent(comp, websocket_closed_server, wsh); + websocket_closed_data * d = new websocket_closed_data; + d->clientID = wsh->clientID; + if (res >= 2) { + d->code = (((uint8_t*)buf)[0] << 8) | ((uint8_t*)buf)[1]; + d->reason = std::string(buf + 2, res - 2); + } else d->code = 0; + queueEvent(comp, websocket_server_closed, d); break; } else if ((flags & 0x0f) == WebSocket::FRAME_OP_PING) { ws->sendFrame(buf, res, WebSocket::FRAME_FLAG_FIN | WebSocket::FRAME_OP_PONG); } else { ws_message * message = new ws_message; - message->url = ""; - message->port = wsh->port; + message->clientID = wsh->clientID; message->binary = (flags & WebSocket::FRAME_OP_BITMASK) == WebSocket::FRAME_OP_BINARY; message->data = std::string((const char*)buf, res); - message->clientID = &request; - queueEvent(comp, websocket_message, message); + queueEvent(comp, websocket_server_message, message); } std::this_thread::yield(); } @@ -1025,17 +1055,6 @@ class websocket_server: public HTTPRequestHandler { if (it != comp->openWebsockets.end()) comp->openWebsockets.erase(it); } try {ws->shutdown();} catch (...) {} - if (--(*retainCount) == 0 && srv != NULL) { - try {srv->stop();} - catch (...) {} - delete srv; - srv = NULL; - { - std::lock_guard lock(comp->openWebsocketsMutex); - comp->openWebsocketServers.erase(wsh->port); - } - queueEvent(comp, websocket_server_closed, (void*)(ptrdiff_t)wsh->port); - } std::lock_guard lock(wsh->lock); wsh->ws = NULL; if (wsh->ud != NULL) *wsh->ud = NULL; @@ -1151,6 +1170,7 @@ static void websocket_client_thread(Computer *comp, const std::string& str, cons #endif ws_handle wsh_orig; ws_handle * wsh = &wsh_orig; + wsh->isServer = false; wsh->url = str; wsh->ws = ws; { @@ -1166,7 +1186,6 @@ static void websocket_client_thread(Computer *comp, const std::string& str, cons res = ws->receiveFrame(buf, config.http_max_websocket_message, flags); if (res < 0 || (res == 0 && flags == 0)) { wsh->ws = NULL; - wsh->url = ""; websocket_closed_data * d = new websocket_closed_data; d->url = str; d->code = 0; @@ -1185,7 +1204,6 @@ static void websocket_client_thread(Computer *comp, const std::string& str, cons continue; } catch (NetException &e) { wsh->ws = NULL; - wsh->url = ""; websocket_closed_data * d = new websocket_closed_data; d->url = str; d->code = 1006; @@ -1195,7 +1213,6 @@ static void websocket_client_thread(Computer *comp, const std::string& str, cons } if ((flags & 0x0f) == WebSocket::FRAME_OP_CLOSE) { wsh->ws = NULL; - wsh->url = ""; websocket_closed_data * d = new websocket_closed_data; d->url = str; if (res >= 2) { @@ -1221,7 +1238,6 @@ static void websocket_client_thread(Computer *comp, const std::string& str, cons auto it = std::find(comp->openWebsockets.begin(), comp->openWebsockets.end(), (void*)&wsh); if (it != comp->openWebsockets.end()) comp->openWebsockets.erase(it); } - wsh->url = ""; try {ws->shutdown();} catch (...) {} std::lock_guard lock(wsh->lock); wsh->ws = NULL; @@ -1236,35 +1252,7 @@ static int http_websocket(lua_State *L) { Computer * comp = get_comp(L); if (comp->openWebsockets.size() >= (size_t)config.http_max_websockets) return luaL_error(L, "Too many websockets already open"); if (!(config.serverMode || config.vanilla) && (lua_isnoneornil(L, 1) || lua_isnumber(L, 1))) { - int port = luaL_optinteger(L, 1, 80); - if (port < 0 || port > 65535) luaL_error(L, "bad argument #1 (port out of range)"); - if (comp->openWebsocketServers.find(port) != comp->openWebsocketServers.end()) { - // if there's already an open server, reuse that - lua_pushboolean(L, true); - return 1; - } - std::unordered_map headers; - if (lua_istable(L, 2)) { - lua_pushvalue(L, 2); - lua_pushnil(L); - for (int i = 0; lua_next(L, -2); i++) { - size_t keyn = 0, valn = 0; - const char * key = lua_tolstring(L, -2, &keyn), *val = lua_tolstring(L, -1, &valn); - if (key && val) headers[std::string(key, keyn)] = std::string(val, valn); - lua_pop(L, 2); - } - lua_pop(L, 1); - } else if (!lua_isnoneornil(L, 2)) luaL_error(L, "bad argument #2 (expected table, got %s)", lua_typename(L, lua_type(L, 2))); - websocket_server::Factory * f = new websocket_server::Factory(comp, headers); - try {f->srv = new HTTPServer(f, port);} - catch (Poco::Exception& e) { - fprintf(stderr, "Could not open server: %s\n", e.displayText().c_str()); - lua_pushboolean(L, false); - lua_pushstring(L, e.displayText().c_str()); - return 2; - } - comp->openWebsocketServers.insert(port); - f->srv->start(); + luaL_error(L, "function has been replaced with http.websocketServer"); } else if (lua_istable(L, 1)) { Computer * comp = get_comp(L); if (config.http_max_websockets > 0 && comp->openWebsockets.size() >= (unsigned)config.http_max_websockets) luaL_error(L, "Too many websockets already open"); @@ -1316,6 +1304,138 @@ static int http_websocket(lua_State *L) { return 1; } +/** + * Listens for a new connection on the server, and returns its handle. + * @param timeout (number, optional) The amount of time to wait + * @return The WebSocket handle for the connection, or nil on timeout. + * @note Server handles are the same as client handles, but with an additional + * clientID member for identifying events. + */ +static int websocket_server_listen(lua_State *L) { + lastCFunction = __func__; + websocket_server::Factory * f = *(websocket_server::Factory**)lua_touserdata(L, lua_upvalueindex(1)); + int tm = 0; + if (lua_getctx(L, &tm) == LUA_YIELD) { + if (lua_isstring(L, 1)) { + // haha, another string scoping issue :DDD + // can M$ PLEASE fix this? (maybe I need to repro & report? :thinking:) + if (f == NULL) { + lua_pushnil(L); + return 1; + } + std::string * ev = new std::string(lua_tostring(L, 1)); + if (lua_isnumber(L, 2)) { + int id = lua_tointeger(L, 2); + if (*ev == "websocket_server_connect" && id == f->srv->port()) { + lua_pushvalue(L, 3); + delete ev; + return 1; + } else if (tm > 0 && *ev == "timer" && id == tm) { + lua_pushnil(L); + delete ev; + return 1; + } else if (*ev == "terminate") { + delete ev; + return luaL_error(L, "Terminated"); + } + } + delete ev; + } + } else { + if (f == NULL) luaL_error(L, "attempt to use a closed file"); + // instead of using native timer routines, we're using os.startTimer so we can be resumed + if (!lua_isnoneornil(L, 1)) { + luaL_checknumber(L, 1); + lua_pushcfunction(L, os_startTimer); + lua_pushvalue(L, 1); + lua_call(L, 1, 1); + tm = lua_tointeger(L, -1); + lua_pop(L, 1); + } else tm = -1; + } + lua_settop(L, 0); + return lua_yieldk(L, 0, tm, websocket_server_listen); +} + +/** + * Closes the WebSocket server. + */ +static int websocket_server_close(lua_State *L) { + lastCFunction = __func__; + websocket_server::Factory * f = *(websocket_server::Factory**)lua_touserdata(L, lua_upvalueindex(1)); + if (f == NULL) return 0; + f->srv->stop(); + delete f->srv; + delete f; + *(websocket_server::Factory**)lua_touserdata(L, lua_upvalueindex(1)) = NULL; + return 0; +} + +static int websocket_server_free(lua_State *L) { + lastCFunction = __func__; + websocket_server::Factory * f = *(websocket_server::Factory**)lua_touserdata(L, 1); + if (f == NULL) return 0; + f->srv->stop(); + delete f->srv; + delete f; + *(websocket_server::Factory**)lua_touserdata(L, 1) = NULL; + return 0; +} + +static luaL_Reg websocket_server_funcs[] = { + {"listen", websocket_server_listen}, + {"close", websocket_server_close}, + {NULL, NULL} +}; + +/** + * Creates a new WebSocket server. + * @param port (number) The port to listen on + * @return Either a WebSocketServer handle, or nil + error + */ +static int http_websocketServer(lua_State *L) { + if (config.serverMode) return 0; + Computer * comp = get_comp(L); + int port = luaL_checkinteger(L, 1); + if (port < 0 || port > 65535) luaL_error(L, "bad argument #1 (port out of range)"); + if (comp->openWebsocketServers.find(port) != comp->openWebsocketServers.end()) { + // if there's already an open server, reuse that + lua_pushnil(L); + lua_pushliteral(L, "Port already in use"); + return 2; + } + std::unordered_map headers; + if (lua_istable(L, 2)) { + lua_pushvalue(L, 2); + lua_pushnil(L); + for (int i = 0; lua_next(L, -2); i++) { + size_t keyn = 0, valn = 0; + const char * key = lua_tolstring(L, -2, &keyn), *val = lua_tolstring(L, -1, &valn); + if (key && val) headers[std::string(key, keyn)] = std::string(val, valn); + lua_pop(L, 2); + } + lua_pop(L, 1); + } else if (!lua_isnoneornil(L, 2)) luaL_error(L, "bad argument #2 (expected table, got %s)", lua_typename(L, lua_type(L, 2))); + websocket_server::Factory * f = new websocket_server::Factory(comp, headers); + try {f->srv = new HTTPServer(f, port);} + catch (Poco::Exception& e) { + fprintf(stderr, "Could not open server: %s\n", e.displayText().c_str()); + lua_pushnil(L); + lua_pushstring(L, e.displayText().c_str()); + return 2; + } + comp->openWebsocketServers.insert(port); + f->srv->start(); + lua_createtable(L, 0, 2); + *(websocket_server::Factory**)lua_newuserdata(L, sizeof(websocket_server::Factory*)) = f; + lua_createtable(L, 0, 1); + lua_pushcfunction(L, websocket_server_free); + lua_setfield(L, -2, "__gc"); + lua_setmetatable(L, -2); + luaL_setfuncs(L, websocket_server_funcs, 1); + return 1; +} + #ifdef __INTELLISENSE__ #pragma endregion #endif @@ -1326,6 +1446,7 @@ static luaL_Reg http_reg[] = { {"addListener", http_addListener}, {"removeListener", http_removeListener}, {"websocket", http_websocket}, + {"websocketServer", http_websocketServer}, {NULL, NULL} }; diff --git a/src/apis/mounter.cpp b/src/apis/mounter.cpp index 0f457de6..a5e6c7ae 100644 --- a/src/apis/mounter.cpp +++ b/src/apis/mounter.cpp @@ -12,6 +12,7 @@ #include #include #include +#include "../peripheral/debugger.hpp" #include "../platform.hpp" #include "../runtime.hpp" #include "../terminal/SDLTerminal.hpp" @@ -62,6 +63,7 @@ static int mounter_unmount(lua_State *L) { if (it == computer->mounts.end()) break; } } + if (found && computer->debugger && !computer->isDebugger) ((debugger*)computer->debugger)->resetMounts(); lua_pushboolean(L, found); return 1; } diff --git a/src/peripheral/debugger.cpp b/src/peripheral/debugger.cpp index d0460110..1a7d1830 100644 --- a/src/peripheral/debugger.cpp +++ b/src/peripheral/debugger.cpp @@ -832,6 +832,7 @@ debugger::debugger(lua_State *L, const char * side) { } delete p; monitor->debugger = createDebuggerLibrary(); + for (const auto mount : computer->mounts) monitor->mounts.push_back(mount); { LockGuard lock(computers); computers->push_back(monitor); @@ -898,6 +899,11 @@ int debugger::_deinit(lua_State *L) { return 0; } +void debugger::resetMounts() { + monitor->mounts.clear(); + for (const auto mount : computer->mounts) monitor->mounts.push_back(mount); +} + static luaL_Reg debugger_reg[] = { {"stop", NULL}, {"setBreakpoint", NULL}, diff --git a/src/peripheral/debugger.hpp b/src/peripheral/debugger.hpp index bf843ca6..b7c48733 100644 --- a/src/peripheral/debugger.hpp +++ b/src/peripheral/debugger.hpp @@ -74,6 +74,7 @@ class debugger: public peripheral { virtual int call(lua_State *L, const char * method) override; library_t getMethods() const override {return methods;} void reinitialize(lua_State *L) override; + void resetMounts(); }; #endif \ No newline at end of file diff --git a/src/plugin.cpp b/src/plugin.cpp index fe1dc283..d935bc11 100644 --- a/src/plugin.cpp +++ b/src/plugin.cpp @@ -73,7 +73,7 @@ extern bool checkIAPEligibility(const char * identifier); static const PluginFunctions function_map = { PLUGIN_VERSION, - 8, + 0, CRAFTOSPC_VERSION, selectedRenderer, &config, diff --git a/src/runtime.cpp b/src/runtime.cpp index d9eeb3e3..57cde0ed 100644 --- a/src/runtime.cpp +++ b/src/runtime.cpp @@ -22,6 +22,7 @@ #include #include "main.hpp" #include "runtime.hpp" +#include "peripheral/debugger.hpp" #include "platform.hpp" #include "terminal/SDLTerminal.hpp" #include "terminal/CLITerminal.hpp" @@ -392,6 +393,7 @@ bool addMount(Computer *comp, const path_t& real_path, const std::string& comp_p if (!selected) return false; } comp->mounts.push_back(std::make_tuple(std::list(pathc), real_path, read_only)); + if (comp->debugger && !comp->isDebugger) ((debugger*)comp->debugger)->resetMounts(); return true; } diff --git a/src/termsupport.cpp b/src/termsupport.cpp index 579cea3a..f56f76b1 100644 --- a/src/termsupport.cpp +++ b/src/termsupport.cpp @@ -714,6 +714,7 @@ std::string termGetEvent(lua_State *L) { computer->waitingForTerminate &= ~1; return "terminate"; } else if ((computer->waitingForTerminate & 3) == 0) computer->waitingForTerminate |= 1; + else return ""; } else if (((selectedRenderer == 0 || selectedRenderer == 5) ? e.key.keysym.sym == SDLK_s : e.key.keysym.sym == 31) && (e.key.keysym.mod & KMOD_CTRL)) { if (computer->waitingForTerminate & 4) { computer->waitingForTerminate |= 8; @@ -721,6 +722,7 @@ std::string termGetEvent(lua_State *L) { computer->running = 0; return "terminate"; } else if ((computer->waitingForTerminate & 12) == 0) computer->waitingForTerminate |= 4; + else return ""; } else if (((selectedRenderer == 0 || selectedRenderer == 5) ? e.key.keysym.sym == SDLK_r : e.key.keysym.sym == 19) && (e.key.keysym.mod & KMOD_CTRL)) { if (computer->waitingForTerminate & 16) { computer->waitingForTerminate |= 32; @@ -728,6 +730,7 @@ std::string termGetEvent(lua_State *L) { computer->running = 2; return "terminate"; } else if ((computer->waitingForTerminate & 48) == 0) computer->waitingForTerminate |= 16; + else return ""; } else if (e.key.keysym.sym == SDLK_v && (e.key.keysym.mod & KMOD_SYSMOD) && SDL_HasClipboardText()) { char * text = SDL_GetClipboardText(); std::string str; @@ -753,7 +756,7 @@ std::string termGetEvent(lua_State *L) { std::string str; try {str = utf8_to_string(e.text.text, std::locale("C"));} catch (std::exception &ignored) {str = "?";} - if (!str.empty()) { + if (!str.empty() && !(computer->waitingForTerminate & 0x2A)) { #if defined(__ANDROID__) || defined(__IPHONEOS__) mobileResetModifiers(); #endif diff --git a/src/util.hpp b/src/util.hpp index 1914148e..4d87d700 100644 --- a/src/util.hpp +++ b/src/util.hpp @@ -27,7 +27,7 @@ extern "C" { #include #define CRAFTOSPC_VERSION "v2.8" -#define CRAFTOSPC_CC_VERSION "1.109.0" +#define CRAFTOSPC_CC_VERSION "1.109.2" #define CRAFTOSPC_INDEV true using path_t = std::filesystem::path;