diff --git a/03_Perun_Lua_Wrapper/CMakeLists.txt b/03_Perun_Lua_Wrapper/CMakeLists.txt index 1ef4ac9..e25aa2a 100644 --- a/03_Perun_Lua_Wrapper/CMakeLists.txt +++ b/03_Perun_Lua_Wrapper/CMakeLists.txt @@ -1,12 +1,18 @@ # CMakeList.txt : CMake project for perun_dll, include source and define # project specific logic here. # -cmake_minimum_required (VERSION 3.8) +cmake_minimum_required(VERSION 3.17) project ("parent") set(CMAKE_CXX_STANDARD 20) set_property(GLOBAL PROPERTY USE_FOLDERS ON) +if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 19.12.25835) + set(CMAKE_CXX20_STANDARD_COMPILE_OPTION "-std:c++latest") + set(CMAKE_CXX20_EXTENSION_COMPILE_OPTION "-std:c++latest") +endif() + add_subdirectory(lua-5.1.5) -add_subdirectory(perun) \ No newline at end of file +add_subdirectory(perun) +add_subdirectory(experimental) \ No newline at end of file diff --git a/03_Perun_Lua_Wrapper/experimental/CMakeLists.txt b/03_Perun_Lua_Wrapper/experimental/CMakeLists.txt new file mode 100644 index 0000000..a7203f8 --- /dev/null +++ b/03_Perun_Lua_Wrapper/experimental/CMakeLists.txt @@ -0,0 +1,18 @@ +cmake_minimum_required(VERSION 3.17) +project(experimental) + +set(CMAKE_CXX_STANDARD 20) + +set (EXPERIMENTAL_SOURCES + "src/main.cpp" + ) + +add_executable(experimental ${EXPERIMENTAL_SOURCES}) + +target_link_libraries( + lua-5.1.5 + ws2_32 +) + +target_include_directories (pierog PUBLIC) +#set_target_properties(main PROPERTIES OUTPUT_NAME "perun") \ No newline at end of file diff --git a/03_Perun_Lua_Wrapper/lua-5.1.5/CmakeLists.txt b/03_Perun_Lua_Wrapper/lua-5.1.5/CmakeLists.txt index a227577..0e417fb 100644 --- a/03_Perun_Lua_Wrapper/lua-5.1.5/CmakeLists.txt +++ b/03_Perun_Lua_Wrapper/lua-5.1.5/CmakeLists.txt @@ -28,7 +28,7 @@ set (LUA_RUNTIME_SOURCES "src/lua.h" "src/lualib.h" "src/lzio.c" "src/lzio.h" -) + ../experimental/src/main.cpp) add_library( lua-5.1.5 ${LUA_RUNTIME_SOURCES} ) diff --git a/03_Perun_Lua_Wrapper/perun/CmakeLists.txt b/03_Perun_Lua_Wrapper/perun/CmakeLists.txt index 5264b6f..7f06655 100644 --- a/03_Perun_Lua_Wrapper/perun/CmakeLists.txt +++ b/03_Perun_Lua_Wrapper/perun/CmakeLists.txt @@ -1,9 +1,9 @@ cmake_minimum_required(VERSION 3.17) -project(perun) +project(pierog) set(CMAKE_CXX_STANDARD 20) -set (PERUN_DLL_SOURCES +set (PIEROG_DLL_SOURCES "src/library.h" "src/library.cpp" "src/Connection.h" @@ -11,13 +11,12 @@ set (PERUN_DLL_SOURCES ) include (GenerateExportHeader) -add_library(perun SHARED ${PERUN_DLL_SOURCES}) +add_library(pierog SHARED ${PIEROG_DLL_SOURCES}) target_link_libraries( - perun + pierog lua-5.1.5 ws2_32 ) -target_include_directories (perun PUBLIC) -#set_target_properties(main PROPERTIES OUTPUT_NAME "perun") \ No newline at end of file +target_include_directories (pierog PUBLIC) \ No newline at end of file diff --git a/03_Perun_Lua_Wrapper/perun/src/Connection.cpp b/03_Perun_Lua_Wrapper/perun/src/Connection.cpp index 9faf2d5..cc9127b 100644 --- a/03_Perun_Lua_Wrapper/perun/src/Connection.cpp +++ b/03_Perun_Lua_Wrapper/perun/src/Connection.cpp @@ -1,30 +1,25 @@ #include "Connection.h" -SocketWrapper::SocketWrapper(std::string name): outputFile(name, std::ofstream::app) { - tcpSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); +#include +#include + +SocketWrapper::SocketWrapper(std::string logPath, + std::string host, + const int port): path(std::move(logPath)), tcpHost(std::move(host)), tcpPort(port){ + this->tcpSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + + startNewRecording(); } SocketWrapper::~SocketWrapper() { } -int SocketWrapper::getAndResetReconnected() { - int result = this->flagReconnected; - - this->flagReconnected = 0; - - return result; -} - -int SocketWrapper::getFlagConnected() { - return this->connectionState; -} - void SocketWrapper::tcpConnect() { // Create socket address object from TCP port and host SOCKADDR_IN socketAddress; socketAddress.sin_family = AF_INET; socketAddress.sin_port = htons(u_short(this->tcpPort)); - socketAddress.sin_addr.s_addr = *((unsigned long*)gethostbyname(this->tcpHost->c_str())->h_addr); + socketAddress.sin_addr.s_addr = *((unsigned long*)gethostbyname(this->tcpHost.c_str())->h_addr); if (connect(tcpSocket, (sockaddr*)&socketAddress, sizeof(SOCKADDR_IN)) == 0) { this->connectionState = CONNECTED; @@ -32,33 +27,54 @@ void SocketWrapper::tcpConnect() { } } -void SocketWrapper::createConnection(std::string* host, const int* port) { +void SocketWrapper::startNewRecording() { + if(outputFile != nullptr && outputFile->is_open() && outputFile->good()) { + outputFile->flush(); + outputFile->close(); + delete outputFile; + } + + auto const now = std::chrono::system_clock::now(); + auto const gmt = std::chrono::locate_zone("Etc/GMT"); + auto const filename = std::format("pierog.{:%FT_%H%M%S}.log", std::chrono::zoned_time{gmt, floor(now)}); + + std::filesystem::path dir(this->path); + std::filesystem::path file(filename); + auto fullPath = (dir / file).string(); + + outputFile = new std::ofstream(fullPath, std::ofstream::app | std::ios::out); + + // clean the network buffer if nothing was ever sent + if(sentCounter > 0) { + mutexLock.lock(); + dataBuffer.clear(); + sendQueue.clear(); + mutexLock.unlock(); + } +} + +void SocketWrapper::createConnection() { // TCP connection - ConnectTo - this->tcpHost = host; - this->tcpPort = *port; tcpConnect(); - // Create new thread std::thread thread_object([this]() { - // TCP sending loop + bool nothingToSend = false; - while (true) { + while (shouldRun) { if (connectionState == CONNECTED && mutexLock.try_lock()) { if (sendQueue.empty()) { nothingToSend = true; } else { // Payload in queue auto payload = sendQueue.front(); - - outputFile.write(payload->c_str(), payload->length()); - outputFile.flush(); int bytesSent = send(tcpSocket, payload->c_str(), payload->length(), 0); if (bytesSent == payload->length()) { // All payload was sent sendQueue.pop_front(); delete payload; + sentCounter += bytesSent; } else { // Remaining paylad if (bytesSent > 0) { @@ -67,6 +83,7 @@ void SocketWrapper::createConnection(std::string* host, const int* port) { sendQueue.pop_front(); sendQueue.push_front(&shortened); delete payload; + sentCounter += bytesSent; } else { // Payload was not sent - handle error switch (WSAGetLastError()) { @@ -110,16 +127,38 @@ void SocketWrapper::disconnect() { } void SocketWrapper::enqueueForSending(std::string* payload) { + if(outputFile == nullptr) { + startNewRecording(); + } + + if(outputFile != nullptr) { + outputFile->write(payload->c_str(), payload->length()); + if(payload->length() > 50) { + outputFile->flush(); + } + } if (mutexLock.try_lock()) { while (!dataBuffer.empty()) { // Shift buffer to queue sendQueue.push_back(dataBuffer.front()); - dataBuffer.pop(); + dataBuffer.pop_front(); } sendQueue.push_back(payload); mutexLock.unlock(); } else { - dataBuffer.push(payload); + dataBuffer.push_back(payload); } +} + +int SocketWrapper::getAndResetReconnected() { + int result = this->flagReconnected; + + this->flagReconnected = 0; + + return result; +} + +int SocketWrapper::getFlagConnected() { + return this->connectionState; } \ No newline at end of file diff --git a/03_Perun_Lua_Wrapper/perun/src/Connection.h b/03_Perun_Lua_Wrapper/perun/src/Connection.h index 8e7ad32..5f8e417 100644 --- a/03_Perun_Lua_Wrapper/perun/src/Connection.h +++ b/03_Perun_Lua_Wrapper/perun/src/Connection.h @@ -17,32 +17,36 @@ enum enumConnectionState { class SocketWrapper { public: - SocketWrapper(std::string name); - ~SocketWrapper(); + SocketWrapper(std::string logPath, + std::string host, + const int port); + + ~SocketWrapper(); void disconnect(); - void createConnection(std::string* host, const int* port); + void createConnection(); + void startNewRecording(); void enqueueForSending(std::string* payload); int getAndResetReconnected(); int getFlagConnected(); private: -// SocketWrapper(const SocketWrapper&); -// SocketWrapper& operator=(const SocketWrapper&); - SOCKET tcpSocket; - std::string* tcpHost; - int tcpPort; + const std::string path; + const std::string tcpHost = "localhost"; + const int tcpPort = 0; int flagReconnected = 0; volatile enumConnectionState connectionState = DISCONNECTED; + std::atomic sentCounter; + std::atomic shouldRun = true; - std::queue dataBuffer; + std::deque dataBuffer; std::deque sendQueue; std::mutex mutexLock; - std::ofstream outputFile; + std::ofstream * outputFile = nullptr; void reconnect(); void tcpConnect(); diff --git a/03_Perun_Lua_Wrapper/perun/src/library.cpp b/03_Perun_Lua_Wrapper/perun/src/library.cpp index c6c5e2b..dd347af 100644 --- a/03_Perun_Lua_Wrapper/perun/src/library.cpp +++ b/03_Perun_Lua_Wrapper/perun/src/library.cpp @@ -1,7 +1,13 @@ #include "library.h" +#include +#include static SocketWrapper * tcpConnection = nullptr; +static std::string *startingDelimiter = nullptr; +static std::string *endingDelimiter = nullptr; +static std::string lastObservedHash = std::string(""); + /* this method exists for comments */ static int valuesToReturn(int input) { return input; @@ -10,13 +16,14 @@ static int valuesToReturn(int input) { static int appStartHook(lua_State* luaState) { // Starting the app - prepare if(tcpConnection == nullptr) { - auto nowMillis = std::chrono::time_point_cast(std::chrono::system_clock::now()); - auto millis = nowMillis.time_since_epoch().count(); - char buffer[50]; - sprintf_s(buffer, "c:/temp/perun.%llu.log", millis); + int i = 1; + const std::string path = std::string(lua_tolstring(luaState, i++, 0)); + const std::string host = std::string(lua_tolstring(luaState, i++, 0)); + const int port = (int) lua_tointeger(luaState, i++); - tcpConnection = new SocketWrapper(std::string(buffer)); + tcpConnection = new SocketWrapper(path, host, port); + tcpConnection->createConnection(); } lua_pushinteger(luaState, 1); // First return value: confirmation that app was started @@ -34,14 +41,20 @@ static int appEndHook(lua_State* luaState) { return valuesToReturn(0); } -static int tcpConnect(lua_State* luaState) { - // Connect to the TCP socket +static int setDelimiters(lua_State* luaState) { + startingDelimiter = new std::string(lua_tolstring(luaState, 1, 0)); + endingDelimiter = new std::string(lua_tolstring(luaState, 2, 0)); - if(tcpConnection != nullptr) { - auto *host = new std::string(lua_tolstring(luaState, 1, 0)); - const int *port = new int(lua_tointeger(luaState, 2)); + return valuesToReturn(0); +} - tcpConnection->createConnection(host, port); +static int markMissionStart(lua_State* luaState) { + + std::string missionHash = std::string(lua_tolstring(luaState, 1, 0)); + + if(tcpConnection != nullptr && missionHash ==lastObservedHash) { + tcpConnection->startNewRecording(); + lastObservedHash = missionHash; } return valuesToReturn(0); @@ -51,7 +64,13 @@ static int tcpSend(lua_State* luaState) { // Send frame over TCP socket if(tcpConnection != nullptr) { + if(startingDelimiter != nullptr) { + tcpConnection->enqueueForSending(new std::string(*startingDelimiter)); + } tcpConnection->enqueueForSending(new std::string(lua_tolstring(luaState, 1, 0))); + if(endingDelimiter != nullptr) { + tcpConnection->enqueueForSending(new std::string(*endingDelimiter)); + } lua_pushinteger(luaState, tcpConnection->getFlagConnected()); // First return value: information if there is TCP connection @@ -65,17 +84,18 @@ static int tcpSend(lua_State* luaState) { return valuesToReturn(2); } -extern "C" int __declspec(dllexport) luaopen_perun(lua_State * L) { +extern "C" int __declspec(dllexport) luaopen_pierog(lua_State * L) { static const luaL_Reg Map[] = { - {"StartOfApp", appStartHook}, // Called at the begining of the session - {"EndOfApp", appEndHook }, // Called at the end of the session out of LuaExportStop + {"StartOfApp", appStartHook}, // Called at the begining of the session + {"EndOfApp", appEndHook }, // Called at the end of the session out of LuaExportStop {"tcpSend", tcpSend}, // Called to send data from lua over TCP - {"tcpConnect", tcpConnect}, // Create connection + {"delimiters", setDelimiters }, + {"markMissionStart", markMissionStart }, { NULL, NULL } }; // Register the list of functions for lua - luaL_register(L, "perun", Map); + luaL_register(L, "pierog", Map); return 1; } \ No newline at end of file