mirror of
https://github.com/BeamMP/BeamMP-Server.git
synced 2025-07-02 07:45:26 +00:00
Move PluginMonitor out of TLuaEngine
This commit is contained in:
parent
f06f31c2a0
commit
36547d1e9e
@ -120,6 +120,7 @@ set(BeamMP_Sources
|
|||||||
include/TScopedTimer.h src/TScopedTimer.cpp
|
include/TScopedTimer.h src/TScopedTimer.cpp
|
||||||
include/SignalHandling.h src/SignalHandling.cpp
|
include/SignalHandling.h src/SignalHandling.cpp
|
||||||
include/ArgsParser.h src/ArgsParser.cpp
|
include/ArgsParser.h src/ArgsParser.cpp
|
||||||
|
include/TPluginMonitor.h src/TPluginMonitor.cpp
|
||||||
include/Environment.h
|
include/Environment.h
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -16,6 +16,8 @@ extern TSentry Sentry;
|
|||||||
#include <zlib.h>
|
#include <zlib.h>
|
||||||
|
|
||||||
#include <doctest/doctest.h>
|
#include <doctest/doctest.h>
|
||||||
|
#include <filesystem>
|
||||||
|
namespace fs = std::filesystem;
|
||||||
|
|
||||||
#include "Compat.h"
|
#include "Compat.h"
|
||||||
|
|
||||||
|
@ -60,20 +60,7 @@ struct TLuaChunk {
|
|||||||
std::string PluginPath;
|
std::string PluginPath;
|
||||||
};
|
};
|
||||||
|
|
||||||
class TPluginMonitor : IThreaded {
|
class TLuaEngine : public std::enable_shared_from_this<TLuaEngine>, IThreaded {
|
||||||
public:
|
|
||||||
TPluginMonitor(const fs::path& Path, TLuaEngine& Engine, std::atomic_bool& Shutdown);
|
|
||||||
|
|
||||||
void operator()();
|
|
||||||
|
|
||||||
private:
|
|
||||||
TLuaEngine& mEngine;
|
|
||||||
fs::path mPath;
|
|
||||||
std::atomic_bool& mShutdown;
|
|
||||||
std::unordered_map<std::string, fs::file_time_type> mFileTimes;
|
|
||||||
};
|
|
||||||
|
|
||||||
class TLuaEngine : IThreaded, public std::enable_shared_from_this<TLuaEngine> {
|
|
||||||
public:
|
public:
|
||||||
enum CallStrategy : int {
|
enum CallStrategy : int {
|
||||||
BestEffort,
|
BestEffort,
|
||||||
@ -245,7 +232,6 @@ private:
|
|||||||
|
|
||||||
TNetwork* mNetwork;
|
TNetwork* mNetwork;
|
||||||
TServer* mServer;
|
TServer* mServer;
|
||||||
TPluginMonitor mPluginMonitor;
|
|
||||||
std::atomic_bool mShutdown { false };
|
std::atomic_bool mShutdown { false };
|
||||||
fs::path mResourceServerPath;
|
fs::path mResourceServerPath;
|
||||||
std::vector<std::shared_ptr<TLuaPlugin>> mLuaPlugins;
|
std::vector<std::shared_ptr<TLuaPlugin>> mLuaPlugins;
|
||||||
|
23
include/TPluginMonitor.h
Normal file
23
include/TPluginMonitor.h
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Common.h"
|
||||||
|
#include "IThreaded.h"
|
||||||
|
|
||||||
|
#include <atomic>
|
||||||
|
#include <memory>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
|
class TLuaEngine;
|
||||||
|
|
||||||
|
class TPluginMonitor : IThreaded, public std::enable_shared_from_this<TPluginMonitor> {
|
||||||
|
public:
|
||||||
|
TPluginMonitor(const fs::path& Path, std::shared_ptr<TLuaEngine> Engine);
|
||||||
|
|
||||||
|
void operator()();
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::shared_ptr<TLuaEngine> mEngine;
|
||||||
|
fs::path mPath;
|
||||||
|
std::atomic_bool mShutdown;
|
||||||
|
std::unordered_map<std::string, fs::file_time_type> mFileTimes;
|
||||||
|
};
|
@ -15,8 +15,7 @@
|
|||||||
|
|
||||||
TLuaEngine* LuaAPI::MP::Engine;
|
TLuaEngine* LuaAPI::MP::Engine;
|
||||||
|
|
||||||
TLuaEngine::TLuaEngine()
|
TLuaEngine::TLuaEngine() {
|
||||||
: mPluginMonitor(fs::path(Application::Settings.Resource) / "Server", *this, mShutdown) {
|
|
||||||
Application::SetSubsystemStatus("LuaEngine", Application::Status::Starting);
|
Application::SetSubsystemStatus("LuaEngine", Application::Status::Starting);
|
||||||
LuaAPI::MP::Engine = this;
|
LuaAPI::MP::Engine = this;
|
||||||
if (!fs::exists(Application::Settings.Resource)) {
|
if (!fs::exists(Application::Settings.Resource)) {
|
||||||
@ -35,7 +34,7 @@ TLuaEngine::TLuaEngine()
|
|||||||
}
|
}
|
||||||
Application::SetSubsystemStatus("LuaEngine", Application::Status::Shutdown);
|
Application::SetSubsystemStatus("LuaEngine", Application::Status::Shutdown);
|
||||||
});
|
});
|
||||||
Start();
|
IThreaded::Start();
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("TLuaEngine ctor & dtor") {
|
TEST_CASE("TLuaEngine ctor & dtor") {
|
||||||
@ -988,69 +987,3 @@ bool TLuaEngine::TimedEvent::Expired() {
|
|||||||
void TLuaEngine::TimedEvent::Reset() {
|
void TLuaEngine::TimedEvent::Reset() {
|
||||||
LastCompletion = std::chrono::high_resolution_clock::now();
|
LastCompletion = std::chrono::high_resolution_clock::now();
|
||||||
}
|
}
|
||||||
|
|
||||||
TPluginMonitor::TPluginMonitor(const fs::path& Path, TLuaEngine& Engine, std::atomic_bool& Shutdown)
|
|
||||||
: mEngine(Engine)
|
|
||||||
, mPath(Path)
|
|
||||||
, mShutdown(Shutdown) {
|
|
||||||
if (!fs::exists(mPath)) {
|
|
||||||
fs::create_directories(mPath);
|
|
||||||
}
|
|
||||||
for (const auto& Entry : fs::recursive_directory_iterator(mPath)) {
|
|
||||||
// TODO: trigger an event when a subfolder file changes
|
|
||||||
if (Entry.is_regular_file()) {
|
|
||||||
mFileTimes[Entry.path().string()] = fs::last_write_time(Entry.path());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Start();
|
|
||||||
}
|
|
||||||
|
|
||||||
void TPluginMonitor::operator()() {
|
|
||||||
RegisterThread("PluginMonitor");
|
|
||||||
beammp_info("PluginMonitor started");
|
|
||||||
while (!mShutdown) {
|
|
||||||
std::this_thread::sleep_for(std::chrono::seconds(3));
|
|
||||||
std::vector<std::string> ToRemove;
|
|
||||||
for (const auto& Pair : mFileTimes) {
|
|
||||||
try {
|
|
||||||
auto CurrentTime = fs::last_write_time(Pair.first);
|
|
||||||
if (CurrentTime != Pair.second) {
|
|
||||||
mFileTimes[Pair.first] = CurrentTime;
|
|
||||||
// grandparent of the path should be Resources/Server
|
|
||||||
if (fs::equivalent(fs::path(Pair.first).parent_path().parent_path(), mPath)) {
|
|
||||||
beammp_info("File \"" + Pair.first + "\" changed, reloading");
|
|
||||||
// is in root folder, so reload
|
|
||||||
std::ifstream FileStream(Pair.first, std::ios::in | std::ios::binary);
|
|
||||||
auto Size = std::filesystem::file_size(Pair.first);
|
|
||||||
auto Contents = std::make_shared<std::string>();
|
|
||||||
Contents->resize(Size);
|
|
||||||
FileStream.read(Contents->data(), Contents->size());
|
|
||||||
TLuaChunk Chunk(Contents, Pair.first, fs::path(Pair.first).parent_path().string());
|
|
||||||
auto StateID = mEngine.GetStateIDForPlugin(fs::path(Pair.first).parent_path());
|
|
||||||
auto Res = mEngine.EnqueueScript(StateID, Chunk);
|
|
||||||
// TODO: call onInit
|
|
||||||
mEngine.AddResultToCheck(Res);
|
|
||||||
} else {
|
|
||||||
// TODO: trigger onFileChanged event
|
|
||||||
beammp_trace("Change detected in file \"" + Pair.first + "\", event trigger not implemented yet");
|
|
||||||
/*
|
|
||||||
// is in subfolder, dont reload, just trigger an event
|
|
||||||
auto Results = mEngine.TriggerEvent("onFileChanged", "", Pair.first);
|
|
||||||
mEngine.WaitForAll(Results);
|
|
||||||
for (const auto& Result : Results) {
|
|
||||||
if (Result->Error) {
|
|
||||||
beammp_lua_error(Result->ErrorMessage);
|
|
||||||
}
|
|
||||||
}*/
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (const std::exception& e) {
|
|
||||||
ToRemove.push_back(Pair.first);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (const auto& File : ToRemove) {
|
|
||||||
mFileTimes.erase(File);
|
|
||||||
beammp_warn("file '" + File + "' couldn't be accessed, so it was removed from plugin hot reload monitor (probably got deleted)");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
78
src/TPluginMonitor.cpp
Normal file
78
src/TPluginMonitor.cpp
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
#include "TPluginMonitor.h"
|
||||||
|
|
||||||
|
#include "TLuaEngine.h"
|
||||||
|
|
||||||
|
TPluginMonitor::TPluginMonitor(const fs::path& Path, std::shared_ptr<TLuaEngine> Engine)
|
||||||
|
: mEngine(Engine)
|
||||||
|
, mPath(Path) {
|
||||||
|
if (!fs::exists(mPath)) {
|
||||||
|
fs::create_directories(mPath);
|
||||||
|
}
|
||||||
|
for (const auto& Entry : fs::recursive_directory_iterator(mPath)) {
|
||||||
|
// TODO: trigger an event when a subfolder file changes
|
||||||
|
if (Entry.is_regular_file()) {
|
||||||
|
mFileTimes[Entry.path().string()] = fs::last_write_time(Entry.path());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Application::RegisterShutdownHandler([this] {
|
||||||
|
mShutdown = true;
|
||||||
|
if (mThread.joinable()) {
|
||||||
|
mThread.join();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Start();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TPluginMonitor::operator()() {
|
||||||
|
RegisterThread("PluginMonitor");
|
||||||
|
beammp_info("PluginMonitor started");
|
||||||
|
while (!mShutdown) {
|
||||||
|
std::vector<std::string> ToRemove;
|
||||||
|
for (const auto& Pair : mFileTimes) {
|
||||||
|
try {
|
||||||
|
auto CurrentTime = fs::last_write_time(Pair.first);
|
||||||
|
if (CurrentTime != Pair.second) {
|
||||||
|
mFileTimes[Pair.first] = CurrentTime;
|
||||||
|
// grandparent of the path should be Resources/Server
|
||||||
|
if (fs::equivalent(fs::path(Pair.first).parent_path().parent_path(), mPath)) {
|
||||||
|
beammp_info("File \"" + Pair.first + "\" changed, reloading");
|
||||||
|
// is in root folder, so reload
|
||||||
|
std::ifstream FileStream(Pair.first, std::ios::in | std::ios::binary);
|
||||||
|
auto Size = std::filesystem::file_size(Pair.first);
|
||||||
|
auto Contents = std::make_shared<std::string>();
|
||||||
|
Contents->resize(Size);
|
||||||
|
FileStream.read(Contents->data(), Contents->size());
|
||||||
|
TLuaChunk Chunk(Contents, Pair.first, fs::path(Pair.first).parent_path().string());
|
||||||
|
auto StateID = mEngine->GetStateIDForPlugin(fs::path(Pair.first).parent_path());
|
||||||
|
auto Res = mEngine->EnqueueScript(StateID, Chunk);
|
||||||
|
// TODO: call onInit
|
||||||
|
mEngine->AddResultToCheck(Res);
|
||||||
|
} else {
|
||||||
|
// TODO: trigger onFileChanged event
|
||||||
|
beammp_trace("Change detected in file \"" + Pair.first + "\", event trigger not implemented yet");
|
||||||
|
/*
|
||||||
|
// is in subfolder, dont reload, just trigger an event
|
||||||
|
auto Results = mEngine.TriggerEvent("onFileChanged", "", Pair.first);
|
||||||
|
mEngine.WaitForAll(Results);
|
||||||
|
for (const auto& Result : Results) {
|
||||||
|
if (Result->Error) {
|
||||||
|
beammp_lua_error(Result->ErrorMessage);
|
||||||
|
}
|
||||||
|
}*/
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (const std::exception& e) {
|
||||||
|
ToRemove.push_back(Pair.first);
|
||||||
|
}
|
||||||
|
for (size_t i = 0; i < 3 && !mShutdown; ++i) {
|
||||||
|
std::this_thread::sleep_for(std::chrono::seconds(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (const auto& File : ToRemove) {
|
||||||
|
mFileTimes.erase(File);
|
||||||
|
beammp_warn("file '" + File + "' couldn't be accessed, so it was removed from plugin hot reload monitor (probably got deleted)");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -11,6 +11,7 @@
|
|||||||
#include "TLuaEngine.h"
|
#include "TLuaEngine.h"
|
||||||
#include "TNetwork.h"
|
#include "TNetwork.h"
|
||||||
#include "TPPSMonitor.h"
|
#include "TPPSMonitor.h"
|
||||||
|
#include "TPluginMonitor.h"
|
||||||
#include "TResourceManager.h"
|
#include "TResourceManager.h"
|
||||||
#include "TScopedTimer.h"
|
#include "TScopedTimer.h"
|
||||||
#include "TServer.h"
|
#include "TServer.h"
|
||||||
@ -159,6 +160,8 @@ int BeamMPServerMain(MainArguments Arguments) {
|
|||||||
PPSMonitor.SetNetwork(Network);
|
PPSMonitor.SetNetwork(Network);
|
||||||
Application::CheckForUpdates();
|
Application::CheckForUpdates();
|
||||||
|
|
||||||
|
TPluginMonitor PluginMonitor(fs::path(Application::Settings.Resource) / "Server", LuaEngine);
|
||||||
|
|
||||||
if (Application::Settings.HTTPServerEnabled) {
|
if (Application::Settings.HTTPServerEnabled) {
|
||||||
Http::Server::THttpServerInstance HttpServerInstance {};
|
Http::Server::THttpServerInstance HttpServerInstance {};
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user