mirror of
https://github.com/BeamMP/BeamMP-Server.git
synced 2025-07-01 23:35:41 +00:00
Add simple command interface
This commit is contained in:
parent
1e0ab6bbb3
commit
768d0466f4
@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
namespace LuaAPI {
|
namespace LuaAPI {
|
||||||
int PanicHandler(lua_State* State);
|
int PanicHandler(lua_State* State);
|
||||||
|
std::string LuaToString(const sol::object Value, size_t Indent = 1, bool QuoteStrings = false);
|
||||||
void Print(sol::variadic_args);
|
void Print(sol::variadic_args);
|
||||||
namespace MP {
|
namespace MP {
|
||||||
extern TLuaEngine* Engine;
|
extern TLuaEngine* Engine;
|
||||||
|
@ -18,7 +18,14 @@ public:
|
|||||||
Commandline& Internal() { return mCommandline; }
|
Commandline& Internal() { return mCommandline; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void ChangeToLuaConsole();
|
||||||
|
void ChangeToRegularConsole();
|
||||||
|
|
||||||
Commandline mCommandline;
|
Commandline mCommandline;
|
||||||
|
std::vector<std::string> mCachedLuaHistory;
|
||||||
|
std::vector<std::string> mCachedRegularHistory;
|
||||||
TLuaEngine* mLuaEngine { nullptr };
|
TLuaEngine* mLuaEngine { nullptr };
|
||||||
|
bool mIsLuaConsole { false };
|
||||||
|
bool mFirstTime { true };
|
||||||
const std::string mStateId = "BEAMMP_SERVER_CONSOLE";
|
const std::string mStateId = "BEAMMP_SERVER_CONSOLE";
|
||||||
};
|
};
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
#define SOL_ALL_SAFETIES_ON 1
|
#define SOL_ALL_SAFETIES_ON 1
|
||||||
#include <sol/sol.hpp>
|
#include <sol/sol.hpp>
|
||||||
|
|
||||||
static std::string LuaToString(const sol::object Value, size_t Indent = 1, bool QuoteStrings = false) {
|
std::string LuaAPI::LuaToString(const sol::object Value, size_t Indent, bool QuoteStrings) {
|
||||||
if (Indent > 80) {
|
if (Indent > 80) {
|
||||||
return "[[possible recursion, refusing to keep printing]]";
|
return "[[possible recursion, refusing to keep printing]]";
|
||||||
}
|
}
|
||||||
|
110
src/TConsole.cpp
110
src/TConsole.cpp
@ -2,11 +2,23 @@
|
|||||||
#include "Common.h"
|
#include "Common.h"
|
||||||
#include "Compat.h"
|
#include "Compat.h"
|
||||||
|
|
||||||
|
#include "LuaAPI.h"
|
||||||
#include "TLuaEngine.h"
|
#include "TLuaEngine.h"
|
||||||
|
|
||||||
#include <ctime>
|
#include <ctime>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
|
static inline std::string TrimString(std::string S) {
|
||||||
|
S.erase(S.begin(), std::find_if(S.begin(), S.end(), [](unsigned char ch) {
|
||||||
|
return !std::isspace(ch);
|
||||||
|
}));
|
||||||
|
S.erase(std::find_if(S.rbegin(), S.rend(), [](unsigned char ch) {
|
||||||
|
return !std::isspace(ch);
|
||||||
|
}).base(),
|
||||||
|
S.end());
|
||||||
|
return S;
|
||||||
|
}
|
||||||
|
|
||||||
std::string GetDate() {
|
std::string GetDate() {
|
||||||
std::chrono::system_clock::time_point now = std::chrono::system_clock::now();
|
std::chrono::system_clock::time_point now = std::chrono::system_clock::now();
|
||||||
time_t tt = std::chrono::system_clock::to_time_t(now);
|
time_t tt = std::chrono::system_clock::to_time_t(now);
|
||||||
@ -79,6 +91,26 @@ void TConsole::BackupOldLog() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TConsole::ChangeToLuaConsole() {
|
||||||
|
if (!mIsLuaConsole) {
|
||||||
|
mIsLuaConsole = true;
|
||||||
|
beammp_info("Entered Lua console. To exit, type `exit()`");
|
||||||
|
mCachedRegularHistory = mCommandline.history();
|
||||||
|
mCommandline.set_history(mCachedLuaHistory);
|
||||||
|
mCommandline.set_prompt("lua> ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TConsole::ChangeToRegularConsole() {
|
||||||
|
if (mIsLuaConsole) {
|
||||||
|
mIsLuaConsole = false;
|
||||||
|
beammp_info("Left Lua console.");
|
||||||
|
mCachedLuaHistory = mCommandline.history();
|
||||||
|
mCommandline.set_history(mCachedRegularHistory);
|
||||||
|
mCommandline.set_prompt("> ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
TConsole::TConsole() {
|
TConsole::TConsole() {
|
||||||
mCommandline.enable_history();
|
mCommandline.enable_history();
|
||||||
mCommandline.set_history_limit(20);
|
mCommandline.set_history_limit(20);
|
||||||
@ -89,25 +121,75 @@ TConsole::TConsole() {
|
|||||||
beammp_error("unable to open file for writing: \"Server.log\"");
|
beammp_error("unable to open file for writing: \"Server.log\"");
|
||||||
}
|
}
|
||||||
mCommandline.on_command = [this](Commandline& c) {
|
mCommandline.on_command = [this](Commandline& c) {
|
||||||
auto cmd = c.get_command();
|
try {
|
||||||
mCommandline.write("> " + cmd);
|
auto cmd = c.get_command();
|
||||||
if (cmd == "exit") {
|
cmd = TrimString(cmd);
|
||||||
beammp_info("gracefully shutting down");
|
mCommandline.write(mCommandline.prompt() + cmd);
|
||||||
Application::GracefullyShutdown();
|
|
||||||
} else if (cmd == "clear" || cmd == "cls") {
|
|
||||||
// TODO: clear screen
|
|
||||||
} else {
|
|
||||||
if (!mLuaEngine) {
|
if (!mLuaEngine) {
|
||||||
beammp_info("Lua not started yet, please try again in a second");
|
beammp_info("Lua not started yet, please try again in a second");
|
||||||
} else {
|
} else {
|
||||||
auto Future = mLuaEngine->EnqueueScript(mStateId, { std::make_shared<std::string>(cmd), "", "" });
|
if (mIsLuaConsole) {
|
||||||
while (!Future->Ready) {
|
if (cmd == "exit()") {
|
||||||
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
ChangeToRegularConsole();
|
||||||
}
|
} else {
|
||||||
if (Future->Error) {
|
auto Future = mLuaEngine->EnqueueScript(mStateId, { std::make_shared<std::string>(cmd), "", "" });
|
||||||
beammp_lua_error(Future->ErrorMessage);
|
while (!Future->Ready) {
|
||||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(1)); // TODO: Add a timeout
|
||||||
|
}
|
||||||
|
if (Future->Error) {
|
||||||
|
beammp_lua_error(Future->ErrorMessage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (cmd == "exit") {
|
||||||
|
beammp_info("gracefully shutting down");
|
||||||
|
Application::GracefullyShutdown();
|
||||||
|
} else if (cmd == "lua") {
|
||||||
|
ChangeToLuaConsole();
|
||||||
|
} else if (!cmd.empty()) {
|
||||||
|
auto FutureIsNonNil =
|
||||||
|
[](const std::shared_ptr<TLuaResult>& Future) {
|
||||||
|
auto Type = Future->Result.get_type();
|
||||||
|
return Type != sol::type::lua_nil && Type != sol::type::none;
|
||||||
|
};
|
||||||
|
std::vector<std::shared_ptr<TLuaResult>> NonNilFutures;
|
||||||
|
{ // Futures scope
|
||||||
|
auto Futures = mLuaEngine->TriggerEvent("onConsoleInput", "", cmd);
|
||||||
|
TLuaEngine::WaitForAll(Futures);
|
||||||
|
size_t Count = 0;
|
||||||
|
for (auto& Future : Futures) {
|
||||||
|
if (!Future->Error) {
|
||||||
|
++Count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (const auto& Future : Futures) {
|
||||||
|
if (FutureIsNonNil(Future)) {
|
||||||
|
NonNilFutures.push_back(Future);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (NonNilFutures.size() == 0) {
|
||||||
|
Application::Console().WriteRaw("Error: Unknown command: '" + cmd + "'");
|
||||||
|
} else {
|
||||||
|
std::stringstream Reply;
|
||||||
|
if (NonNilFutures.size() > 1) {
|
||||||
|
for (size_t i = 0; i < NonNilFutures.size(); ++i) {
|
||||||
|
Reply << NonNilFutures[i]->StateId << ": \n"
|
||||||
|
<< LuaAPI::LuaToString(NonNilFutures[i]->Result);
|
||||||
|
if (i < NonNilFutures.size() - 1) {
|
||||||
|
Reply << "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Reply << LuaAPI::LuaToString(NonNilFutures[0]->Result);
|
||||||
|
}
|
||||||
|
Application::Console().WriteRaw(Reply.str());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} catch (const std::exception& e) {
|
||||||
|
beammp_error("Console died with: " + std::string(e.what()) + ". This could be a fatal error and could cause the server to terminate.");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -77,6 +77,9 @@ void TLuaEngine::operator()() {
|
|||||||
// event loop
|
// event loop
|
||||||
auto Before = std::chrono::high_resolution_clock::now();
|
auto Before = std::chrono::high_resolution_clock::now();
|
||||||
while (!mShutdown) {
|
while (!mShutdown) {
|
||||||
|
if (mLuaStates.size() == 0) {
|
||||||
|
std::this_thread::sleep_for(std::chrono::seconds(500));
|
||||||
|
}
|
||||||
{ // Timed Events Scope
|
{ // Timed Events Scope
|
||||||
std::unique_lock Lock(mTimedEventsMutex);
|
std::unique_lock Lock(mTimedEventsMutex);
|
||||||
for (auto& Timer : mTimedEvents) {
|
for (auto& Timer : mTimedEvents) {
|
||||||
|
@ -203,7 +203,7 @@ void TNetwork::HandleDownload(SOCKET TCPSock) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void TNetwork::Authentication(const TConnection& ClientConnection) {
|
void TNetwork:: Authentication(const TConnection& ClientConnection) {
|
||||||
auto Client = CreateClient(ClientConnection.Socket);
|
auto Client = CreateClient(ClientConnection.Socket);
|
||||||
char AddrBuf[64];
|
char AddrBuf[64];
|
||||||
// TODO: IPv6 would need this to be changed
|
// TODO: IPv6 would need this to be changed
|
||||||
|
Loading…
x
Reference in New Issue
Block a user