mirror of
https://github.com/DaKerboul/perun.git
synced 2026-08-09 20:15:39 +02:00
renamed to pierog, extracted socket and file writers
This commit is contained in:
25
03_Perun_Lua_Wrapper/pierog/CmakeLists.txt
Normal file
25
03_Perun_Lua_Wrapper/pierog/CmakeLists.txt
Normal file
@@ -0,0 +1,25 @@
|
||||
cmake_minimum_required(VERSION 3.17)
|
||||
project(pierog)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 20)
|
||||
|
||||
set(PIEROG_DLL_SOURCES
|
||||
"src/library.h"
|
||||
"src/library.cpp"
|
||||
src/RotatingFileOutput.cpp
|
||||
src/SocketOutput.cpp
|
||||
src/DataDistributor.cpp
|
||||
src/RotatingFileOutput.h
|
||||
src/SocketOutput.h
|
||||
src/DataDistributor.h)
|
||||
|
||||
include(GenerateExportHeader)
|
||||
add_library(pierog SHARED ${PIEROG_DLL_SOURCES})
|
||||
|
||||
target_link_libraries(
|
||||
pierog
|
||||
lua-5.1.5
|
||||
ws2_32
|
||||
)
|
||||
|
||||
target_include_directories(pierog PUBLIC ${PIEROG_DLL_SOURCES})
|
||||
102
03_Perun_Lua_Wrapper/pierog/src/DataDistributor.cpp
Normal file
102
03_Perun_Lua_Wrapper/pierog/src/DataDistributor.cpp
Normal file
@@ -0,0 +1,102 @@
|
||||
#include "DataDistributor.h"
|
||||
|
||||
#include <utility>
|
||||
|
||||
DataDistributor::DataDistributor(std::string logPath,
|
||||
std::string host,
|
||||
int port) {
|
||||
|
||||
fileOutput = new RotatingFileOutput(std::move(logPath));
|
||||
socketOutput = new SocketOutput(std::move(host), port);
|
||||
}
|
||||
|
||||
DataDistributor::~DataDistributor() = default;
|
||||
|
||||
void DataDistributor::start() {
|
||||
if(running) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::thread thread_object([this]() {
|
||||
bool anythingToSend = true;
|
||||
long KEEP_ALIVE = 1000;
|
||||
auto now = std::chrono::system_clock::now();
|
||||
|
||||
while(shouldRun) {
|
||||
if(lock.try_lock()) {
|
||||
if(sendQueue.empty()) {
|
||||
auto delay = std::chrono::duration_cast<std::chrono::milliseconds>(now - lastSent);
|
||||
if(delay.count() > KEEP_ALIVE) {
|
||||
sendQueue.push_front(new std::string(" "));
|
||||
} else {
|
||||
anythingToSend = false;
|
||||
}
|
||||
} else {
|
||||
auto payload = sendQueue.front();
|
||||
int sent = socketOutput->write(payload);
|
||||
|
||||
if(sent > 0) {
|
||||
everSentViaSocket = true;
|
||||
sendQueue.pop_front();
|
||||
if(sent == payload->length()) {
|
||||
delete payload;
|
||||
} else {
|
||||
auto shortened = payload->substr(sent, payload->length() - sent);
|
||||
sendQueue.push_front(&shortened);
|
||||
delete payload;
|
||||
}
|
||||
lastSent = std::chrono::system_clock::now();
|
||||
} else {
|
||||
// failed to send
|
||||
}
|
||||
}
|
||||
|
||||
lock.unlock();
|
||||
}
|
||||
|
||||
if(anythingToSend) {
|
||||
Sleep(10);
|
||||
} else {
|
||||
Sleep(100);
|
||||
}
|
||||
}
|
||||
});
|
||||
thread_object.detach();
|
||||
|
||||
shouldRun = true;
|
||||
running = true;
|
||||
}
|
||||
|
||||
void DataDistributor::stop() {
|
||||
shouldRun = false;
|
||||
}
|
||||
|
||||
void DataDistributor::enqueueForSending(std::string *payload) {
|
||||
fileOutput->write(payload);
|
||||
if (lock.try_lock()) {
|
||||
while (!dataBuffer.empty()) {
|
||||
// Shift buffer to queue
|
||||
sendQueue.push_back(dataBuffer.front());
|
||||
dataBuffer.pop_front();
|
||||
}
|
||||
sendQueue.push_back(payload);
|
||||
lock.unlock();
|
||||
}
|
||||
else {
|
||||
dataBuffer.push_back(payload);
|
||||
}
|
||||
}
|
||||
|
||||
void DataDistributor::markNewRecording() {
|
||||
fileOutput->markNewRecording();
|
||||
if(!everSentViaSocket) {
|
||||
lock.lock();
|
||||
sendQueue.clear();
|
||||
dataBuffer.clear();
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
int DataDistributor::isConnected() {
|
||||
return socketOutput->isConnected();
|
||||
}
|
||||
40
03_Perun_Lua_Wrapper/pierog/src/DataDistributor.h
Normal file
40
03_Perun_Lua_Wrapper/pierog/src/DataDistributor.h
Normal file
@@ -0,0 +1,40 @@
|
||||
#ifndef PARENT_DATADISTRIBUTOR_H
|
||||
#define PARENT_DATADISTRIBUTOR_H
|
||||
|
||||
#include <string>
|
||||
#include <queue>
|
||||
#include "SocketOutput.h"
|
||||
#include "RotatingFileOutput.h"
|
||||
|
||||
class DataDistributor {
|
||||
public:
|
||||
DataDistributor(std::string logPath,
|
||||
std::string host,
|
||||
int port);
|
||||
|
||||
virtual ~DataDistributor();
|
||||
|
||||
void enqueueForSending(std::string* payload);
|
||||
void markNewRecording();
|
||||
|
||||
void start();
|
||||
void stop();
|
||||
|
||||
int isConnected();
|
||||
|
||||
private:
|
||||
std::atomic<boolean> shouldRun = true;
|
||||
std::atomic<boolean> running = false;
|
||||
std::atomic<boolean> everSentViaSocket = false;
|
||||
std::deque<std::string*> dataBuffer;
|
||||
std::deque<std::string*> sendQueue;
|
||||
std::mutex lock;
|
||||
|
||||
std::chrono::time_point<std::chrono::system_clock> lastSent = std::chrono::system_clock::now();
|
||||
|
||||
SocketOutput* socketOutput;
|
||||
RotatingFileOutput* fileOutput;
|
||||
};
|
||||
|
||||
|
||||
#endif //PARENT_DATADISTRIBUTOR_H
|
||||
41
03_Perun_Lua_Wrapper/pierog/src/RotatingFileOutput.cpp
Normal file
41
03_Perun_Lua_Wrapper/pierog/src/RotatingFileOutput.cpp
Normal file
@@ -0,0 +1,41 @@
|
||||
#include "RotatingFileOutput.h"
|
||||
|
||||
RotatingFileOutput::~RotatingFileOutput() = default;
|
||||
|
||||
RotatingFileOutput::RotatingFileOutput(std::string outputPath): path(std::move(outputPath)) {
|
||||
|
||||
}
|
||||
|
||||
void RotatingFileOutput::markNewRecording() {
|
||||
if(outputFile != nullptr && outputFile->good()) {
|
||||
outputFile->flush();
|
||||
outputFile->close();
|
||||
delete outputFile;
|
||||
outputFile = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void RotatingFileOutput::write(std::string *payload) {
|
||||
if (outputFile == nullptr) {
|
||||
std::string fileName = generateFileName();
|
||||
outputFile = new std::ofstream(fileName, std::ofstream::app | std::ios::out);
|
||||
}
|
||||
|
||||
outputFile->write(payload->c_str(), payload->length());
|
||||
bytesWritten += (long) payload->length();
|
||||
if (payload->length() > 50) {
|
||||
outputFile->flush();
|
||||
}
|
||||
}
|
||||
|
||||
std::string RotatingFileOutput::generateFileName() {
|
||||
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<std::chrono::milliseconds>(now)});
|
||||
|
||||
std::filesystem::path dir(this->path);
|
||||
std::filesystem::path file(filename);
|
||||
return (dir / file).string();
|
||||
}
|
||||
|
||||
27
03_Perun_Lua_Wrapper/pierog/src/RotatingFileOutput.h
Normal file
27
03_Perun_Lua_Wrapper/pierog/src/RotatingFileOutput.h
Normal file
@@ -0,0 +1,27 @@
|
||||
#ifndef PARENT_ROTATINGFILEOUTPUT_H
|
||||
#define PARENT_ROTATINGFILEOUTPUT_H
|
||||
|
||||
#include <mutex>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <filesystem>
|
||||
|
||||
class RotatingFileOutput {
|
||||
public:
|
||||
RotatingFileOutput(std::string outputPath);
|
||||
virtual ~RotatingFileOutput();
|
||||
|
||||
void markNewRecording();
|
||||
void write(std::string* payload);
|
||||
|
||||
private:
|
||||
const std::string path;
|
||||
|
||||
std::atomic<long long> bytesWritten;
|
||||
std::ofstream * outputFile = nullptr;
|
||||
|
||||
std::string generateFileName();
|
||||
};
|
||||
|
||||
|
||||
#endif //PARENT_ROTATINGFILEOUTPUT_H
|
||||
60
03_Perun_Lua_Wrapper/pierog/src/SocketOutput.cpp
Normal file
60
03_Perun_Lua_Wrapper/pierog/src/SocketOutput.cpp
Normal file
@@ -0,0 +1,60 @@
|
||||
#include "SocketOutput.h"
|
||||
|
||||
SocketOutput::SocketOutput(std::string host,
|
||||
const int port): tcpHost(std::move(host)), tcpPort(port) {
|
||||
|
||||
address = new SOCKADDR_IN;
|
||||
address->sin_family = AF_INET;
|
||||
address->sin_port = htons(u_short(this->tcpPort));
|
||||
address->sin_addr.s_addr = *((unsigned long*)gethostbyname(this->tcpHost.c_str())->h_addr);
|
||||
}
|
||||
|
||||
SocketOutput::~SocketOutput() = default;
|
||||
|
||||
int SocketOutput::write(std::string *payload) {
|
||||
|
||||
if(!(isConnected() || _connect())) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bytesSent = send(tcpSocket, payload->c_str(), payload->length(), 0);
|
||||
if(bytesSent == payload->length()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(bytesSent > 0) {
|
||||
return bytesSent;
|
||||
} else {
|
||||
switch (WSAGetLastError()) {
|
||||
case WSAECONNRESET: // Connection reset
|
||||
case WSAECONNABORTED: // Connection aborted
|
||||
case WSAESHUTDOWN: // Connection closed
|
||||
disconnect();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
bool SocketOutput::isConnected() {
|
||||
return connectionState == CONNECTED;
|
||||
}
|
||||
|
||||
bool SocketOutput::_connect() {
|
||||
if(tcpSocket == INVALID_SOCKET) {
|
||||
tcpSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||
}
|
||||
if(connectionState != CONNECTED) {
|
||||
if (connect(tcpSocket, (sockaddr *) address, sizeof(SOCKADDR_IN)) == 0) {
|
||||
connectionState = CONNECTED;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void SocketOutput::disconnect() {
|
||||
closesocket(tcpSocket);
|
||||
tcpSocket = INVALID_SOCKET;
|
||||
connectionState = DISCONNECTED;
|
||||
}
|
||||
99
03_Perun_Lua_Wrapper/pierog/src/library.cpp
Normal file
99
03_Perun_Lua_Wrapper/pierog/src/library.cpp
Normal file
@@ -0,0 +1,99 @@
|
||||
#include "library.h"
|
||||
#include "DataDistributor.h"
|
||||
#include <format>
|
||||
#include <filesystem>
|
||||
|
||||
static DataDistributor * dataDistributor = 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;
|
||||
}
|
||||
|
||||
static int appStartHook(lua_State* luaState) {
|
||||
// Starting the app - prepare
|
||||
if(dataDistributor == nullptr) {
|
||||
|
||||
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++);
|
||||
|
||||
dataDistributor = new DataDistributor(path, host, port);
|
||||
dataDistributor->start();
|
||||
}
|
||||
|
||||
lua_pushinteger(luaState, 1); // First return value: confirmation that app was started
|
||||
|
||||
return valuesToReturn(1);
|
||||
}
|
||||
|
||||
static int appEndHook(lua_State* luaState) {
|
||||
// Closing the app - clean up
|
||||
|
||||
if(dataDistributor != nullptr) {
|
||||
dataDistributor->stop();
|
||||
}
|
||||
|
||||
return valuesToReturn(0);
|
||||
}
|
||||
|
||||
static int setDelimiters(lua_State* luaState) {
|
||||
startingDelimiter = new std::string(lua_tolstring(luaState, 1, 0));
|
||||
endingDelimiter = new std::string(lua_tolstring(luaState, 2, 0));
|
||||
|
||||
return valuesToReturn(0);
|
||||
}
|
||||
|
||||
static int markMissionStart(lua_State* luaState) {
|
||||
|
||||
std::string missionHash = std::string(lua_tolstring(luaState, 1, 0));
|
||||
|
||||
if(dataDistributor != nullptr && missionHash != lastObservedHash) {
|
||||
dataDistributor->markNewRecording();
|
||||
lastObservedHash = missionHash;
|
||||
}
|
||||
|
||||
return valuesToReturn(0);
|
||||
}
|
||||
|
||||
static int tcpSend(lua_State* luaState) {
|
||||
// Send frame over TCP socket
|
||||
|
||||
if(dataDistributor != nullptr) {
|
||||
if(startingDelimiter != nullptr) {
|
||||
dataDistributor->enqueueForSending(new std::string(*startingDelimiter));
|
||||
}
|
||||
dataDistributor->enqueueForSending(new std::string(lua_tolstring(luaState, 1, 0)));
|
||||
if(endingDelimiter != nullptr) {
|
||||
dataDistributor->enqueueForSending(new std::string(*endingDelimiter));
|
||||
}
|
||||
|
||||
lua_pushinteger(luaState,
|
||||
dataDistributor->isConnected()); // First return value: information if there is TCP connection
|
||||
} else {
|
||||
lua_pushinteger(luaState, 0);
|
||||
}
|
||||
|
||||
return valuesToReturn(1);
|
||||
}
|
||||
|
||||
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
|
||||
{"tcpSend", tcpSend}, // Called to send data from lua over TCP
|
||||
{"delimiters", setDelimiters },
|
||||
{"markMissionStart", markMissionStart },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
// Register the list of functions for lua
|
||||
luaL_register(L, "pierog", Map);
|
||||
|
||||
return 1;
|
||||
}
|
||||
16
03_Perun_Lua_Wrapper/pierog/src/library.h
Normal file
16
03_Perun_Lua_Wrapper/pierog/src/library.h
Normal file
@@ -0,0 +1,16 @@
|
||||
#ifndef PERUN_LIBRARY_H
|
||||
#define PERUN_LIBRARY_H
|
||||
|
||||
extern "C" {
|
||||
#include "lua.h"
|
||||
#include "lualib.h"
|
||||
#include "lauxlib.h"
|
||||
}
|
||||
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <chrono>
|
||||
#include <queue>
|
||||
|
||||
#endif //PERUN_LIBRARY_H
|
||||
Reference in New Issue
Block a user