diff --git a/doc/en/scripting/builtins/libnetwork.md b/doc/en/scripting/builtins/libnetwork.md index 3ceac9c84..c4e61837d 100644 --- a/doc/en/scripting/builtins/libnetwork.md +++ b/doc/en/scripting/builtins/libnetwork.md @@ -92,6 +92,21 @@ socket:recv_async( [optional] usetable: bool=false ) -> nil|table|Bytearray +-- `peek` and `peek_async` are analogous to the `recv` and `recv_async` methods +-- with the exception that `peek` and `peek_async` do not advance the socket buffer position +-- This means they do not remove bytes from the socket, so the bytes can be received after +socket:peek( + length: int, + [optional] usetable: boolean=false +) -> nil|table|Bytearray + +socket:peek_async( + length: int, + [optional] usetable: boolean=false +) -> nil|table|Bytearray + +Translated with DeepL.com (free version) + -- Closes the connection socket:close() diff --git a/doc/ru/scripting/builtins/libnetwork.md b/doc/ru/scripting/builtins/libnetwork.md index 46a3eded8..98c4e51e0 100644 --- a/doc/ru/scripting/builtins/libnetwork.md +++ b/doc/ru/scripting/builtins/libnetwork.md @@ -92,6 +92,19 @@ socket:recv_async( [опционально] usetable: boolean=false ) -> nil|table|Bytearray +-- `peek` и `peek_async` являются аналогами методов `recv` и `recv_async` +-- за тем исключением, что `peek` и `peek_async` не двигают позицию буфера сокета +-- Это означает, что они не удаляют байты из сокета, а значит байты могут быть прочитаны после +socket:peek( + length: int, + [опционально] usetable: boolean=false +) -> nil|table|Bytearray + +socket:peek_async( + length: int, + [опционально] usetable: boolean=false +) -> nil|table|Bytearray + -- Оборачивает сокет в io_stream (см. ../io_stream.md) socket:as_stream( [опционально] binary_mode: boolean=true diff --git a/res/scripts/classes.lua b/res/scripts/classes.lua index a057d52e6..280c5ddeb 100644 --- a/res/scripts/classes.lua +++ b/res/scripts/classes.lua @@ -39,6 +39,7 @@ end local Socket = {__index={ send=function(self, ...) return network.__send(self.id, ...) end, recv=function(self, ...) return network.__recv(self.id, ...) end, + peek=function(self, ...) return network.__peek(self.id, ...) end, recv_async=function(self, length, usetable) while self:is_alive() do local available = self:available() @@ -49,6 +50,16 @@ local Socket = {__index={ end return self:recv(length, usetable) end, + peek_async=function(self, length, usetable) + while self:is_alive() do + local available = self:available() + if available >= length then + return self:peek(length, usetable) + end + coroutine.yield() + end + return self:peek(length, usetable) + end, as_stream=network.__as_stream, close=function(self) return network.__close(self.id) end, available=function(self) return network.__available(self.id) or 0 end, diff --git a/src/logic/scripting/lua/libs/libnetwork.cpp b/src/logic/scripting/lua/libs/libnetwork.cpp index 7fbf6df8d..55db6e550 100644 --- a/src/logic/scripting/lua/libs/libnetwork.cpp +++ b/src/logic/scripting/lua/libs/libnetwork.cpp @@ -237,7 +237,7 @@ static int l_udp_server_send_to(lua::State* L, network::Network& network) { return 0; } -static int l_recv(lua::State* L, network::Network& network) { +static int read(lua::State* L, network::Network& network, int (*fn)(network::TcpConnection*, char*, int)) { u64id_t id = lua::tointeger(L, 1); int length = lua::tointeger(L, 2); @@ -248,11 +248,12 @@ static int l_recv(lua::State* L, network::Network& network) { } auto tcpConnection = dynamic_cast(connection); + auto tcp = dynamic_cast(connection); length = glm::min(length, tcpConnection->available()); util::Buffer buffer(length); - - int size = tcpConnection->recv(buffer.data(), length); + + int size = fn(tcp, buffer.data(), length); if (size == -1) { return 0; } @@ -268,6 +269,18 @@ static int l_recv(lua::State* L, network::Network& network) { } } +static int l_recv(lua::State* L, network::Network& network) { + return read(L, network, [](auto* tcp, char* buf, int len) { + return tcp->recv(buf, len); + }); +} + +static int l_peek(lua::State* L, network::Network& network) { + return read(L, network, [](auto* tcp, char* buf, int len) { + return tcp->peek(buf, len); + }); +} + static int l_available(lua::State* L, network::Network& network) { u64id_t id = lua::tointeger(L, 1); @@ -566,6 +579,7 @@ const luaL_Reg networklib[] = { {"__close", wrap}, {"__send", wrap}, {"__recv", wrap}, + {"__peek", wrap}, {"__available", wrap}, {"__is_alive", wrap}, {"__is_connected", wrap}, diff --git a/src/network/Sockets.cpp b/src/network/Sockets.cpp index 7db81849c..a0b575c44 100644 --- a/src/network/Sockets.cpp +++ b/src/network/Sockets.cpp @@ -196,15 +196,26 @@ public: }); } - int recv(char* buffer, size_t length) override { - std::lock_guard lock(mutex); - + int read(char* buffer, size_t length) { if (state != ConnectionState::CONNECTED && readBatch.empty()) { return -1; } int size = std::min(readBatch.size(), length); std::memcpy(buffer, readBatch.data(), size); - readBatch.erase(readBatch.begin(), readBatch.begin() + size); + return size; + } + + int peek(char* buffer, size_t length) override { + std::lock_guard lock(mutex); + return read(buffer, length); + } + + int recv(char* buffer, size_t length) override { + std::lock_guard lock(mutex); + int size = read(buffer, length); + if (size != -1) { + readBatch.erase(readBatch.begin(), readBatch.begin() + size); + } return size; } diff --git a/src/network/commons.hpp b/src/network/commons.hpp index 37fc1a01e..8b834bb3e 100644 --- a/src/network/commons.hpp +++ b/src/network/commons.hpp @@ -79,6 +79,7 @@ namespace network { class ReadableConnection : public Connection { public: virtual int recv(char* buffer, size_t length) = 0; + virtual int peek(char* buffer, size_t length) = 0; virtual int available() = 0; };