Compare commits

..

2 Commits

Author SHA1 Message Date
Lion cd893de7c2 Update feature.md 2023-12-10 12:58:37 +01:00
Lion bf3bef232a Update and rename feature_request.md to feature.md 2023-12-10 12:54:42 +01:00
21 changed files with 330 additions and 213 deletions
+1
View File
@@ -1,6 +1,7 @@
---
name: Bug report
about: Create a report to help us improve
title: "[Bug] Enter issue title here"
labels: bug
assignees: ''
+19
View File
@@ -0,0 +1,19 @@
---
name: Feature
about: Suggest an idea for this project
title: "[Feature Request]"
labels: enhancement
assignees: ''
---
#### **Describe the feature you'd like in detail**
A clear and concise description of what you want to happen. Also supply OS information if relevant, for example "*On Linux*, I would like to be able to...".
#### **Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
#### **Acceptance Criteria**
- [ ] *Only fill this out if you're a developer, otherwise leave as-is*
-19
View File
@@ -1,19 +0,0 @@
---
name: Feature request
about: Suggest an idea for this project
labels: feature
assignees: ''
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. For example: "I'm always frustrated when ...".
**Describe the solution you'd like**
A clear and concise description of what you want to happen. Also supply OS information if relevant, for example "*On Linux*, I would like to be able to...".
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context about the feature request here.
+47 -19
View File
@@ -47,20 +47,14 @@ jobs:
name: BeamMP-Server-debian
path: ./bin/BeamMP-Server
- name: Archive server debug info artifact
uses: actions/upload-artifact@v2
with:
name: BeamMP-Server-debian.debug
path: ./bin/BeamMP-Server.debug
- name: Build Tests
run: bash ./scripts/debian-11/3-build-tests.sh
- name: Install Runtime Dependencies
run: bash ./scripts/debian-11/4-install-runtime-deps.sh
- name: Test
run: ./bin/BeamMP-Server-tests
- name: Archive server tests artifact
uses: actions/upload-artifact@v2
with:
name: BeamMP-Server-debian-tests
path: ./bin/BeamMP-Server-tests
ubuntu-22-04-build:
runs-on: ubuntu-latest
@@ -107,17 +101,51 @@ jobs:
name: BeamMP-Server-ubuntu
path: ./bin/BeamMP-Server
- name: Archive server debug info artifact
uses: actions/upload-artifact@v2
with:
name: BeamMP-Server-ubuntu.debug
path: ./bin/BeamMP-Server.debug
- name: Build Tests
run: bash ./scripts/ubuntu-22.04/3-build-tests.sh
- name: Archive server tests artifact
uses: actions/upload-artifact@v2
with:
name: BeamMP-Server-ubuntu-tests
path: ./bin/BeamMP-Server-tests
run-debian-11-tests:
needs: debian-11-build
runs-on: ubuntu-latest
container:
image: debian:11
steps:
- uses: actions/download-artifact@master
with:
name: BeamMP-Server-debian-tests
- name: Install Runtime Dependencies
run: bash ./scripts/ubuntu-22.04/4-install-runtime-deps.sh
run: |
apt-get update -y
apt-get install -y liblua5.3-0
- name: Test
run: ./bin/BeamMP-Server-tests
run: |
chmod +x ./BeamMP-Server-tests
./BeamMP-Server-tests
run-ubuntu-22-04-tests:
needs: ubuntu-22-04-build
runs-on: ubuntu-latest
container:
image: ubuntu:22.04
steps:
- uses: actions/download-artifact@master
with:
name: BeamMP-Server-ubuntu-tests
- name: Install Runtime Dependencies
run: |
apt-get update -y
apt-get install -y liblua5.3-0
- name: Test
run: |
chmod +x ./BeamMP-Server-tests
./BeamMP-Server-tests
-22
View File
@@ -83,17 +83,6 @@ jobs:
asset_path: ./bin/BeamMP-Server
asset_name: BeamMP-Server-debian
asset_content_type: application/x-elf
- name: Upload Debug Info
id: upload-debug-info
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ needs.create-release.outputs.upload_url }}
asset_path: ./bin/BeamMP-Server.debug
asset_name: debuginfo-debian.debug
asset_content_type: application/x-elf
upload-release-files-ubuntu-22-04:
name: Build and upload Ubuntu 22.04 Release Files
@@ -142,17 +131,6 @@ jobs:
asset_name: BeamMP-Server-ubuntu
asset_content_type: application/x-elf
- name: Upload Debug Info
id: upload-debug-info
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ needs.create-release.outputs.upload_url }}
asset_path: ./bin/BeamMP-Server.debug
asset_name: debuginfo-ubuntu.debug
asset_content_type: application/x-elf
upload-release-files-windows:
name: Build and upload Windows Release Files
runs-on: windows-latest
+156
View File
@@ -0,0 +1,156 @@
# v3.1.1
- FIXED bug which caused GetPlayerIdentifiers, GetPlayerName, etc not to work in `onPlayerDisconnect`
- FIXED some issues which could cause the server to crash when receiving malformed data
- FIXED a bug which caused a server to crash during authentication when receiving malformed data
- FIXED minor vulnerability in chat message handling
- FIXED a minor formatting bug in the `status` command
# v3.1.0
- ADDED Tab autocomplete in console, smart tab autocomplete (understands lua tables and types) in the lua console
- ADDED lua debug facilities (type `:help` when attached to lua via `lua`)
- ADDED Util.JsonEncode() and Util.JsonDecode(), which turn lua tables into json and vice-versa
- ADDED FS.ListFiles and FS.ListDirectories
- ADDED onFileChanged event, triggered when a server plugin file changes
- ADDED MP.GetPositionRaw(), which can be used to retrieve the latest position packet per player, per vehicle
- ADDED error messages to some lua functions
- ADDED HOME and END button working in console
- ADDED `MP.TriggerClientEventJson()` which takes a table as the data argument and sends it as JSON
- ADDED identifiers (beammp id, ip) to onPlayerAuth (4th argument)
- ADDED more network debug logging
- CHANGED all networking to be more stable, performant, and safe
- FIXED `ip` in MP.GetPlayerIdentifiers
- FIXED issue with client->server events which contain `:`
- FIXED a fatal exception on LuaEngine startup if Resources/Server is a symlink
- FIXED onInit not being called on hot-reload
- FIXED incorrect timing calculation of Lua EventTimer loop
- FIXED bug which caused hot-reload not to report syntax errors
- FIXED missing error messages on some event handler calls
- FIXED vehicles not deleting for all players if an edit was cancelled by Lua
- FIXED server not handling binary UDP packets properly
- REMOVED "Backend response failed to parse as valid json" message
# v3.0.2
- ADDED Periodic update message if a new server is released
- ADDED Config setting for the IP the http server listens on
- CHANGED Default MaxPlayers to 8
- CHANGED Default http server listen IP to localhost
- FIXED `MP.CreateEventTimer` filling up the queue (see <https://wiki.beammp.com/en/Scripting/new-lua-scripting#mpcreateeventtimerevent_name-string-interval_ms-number-strategy-number-since-v302>)
- FIXED `MP.TriggerClientEvent` not kicking the client if it failed
- FIXED Lua result queue handling not checking all results
- FIXED bug which caused ServerConfig.toml to generate incorrectly
# v3.0.1
- ADDED Backup URLs to UpdateCheck (will fail less often now)
- ADDED console cursor left and right movement (with arrow keys) and working HOME and END key (via github.com/lionkor/commandline)
- FIXED infinite snowmen / infinite unicycle spawning bug
- FIXED a bug where, when run with --working-directory, the Server.log would still be in the original directory
- FIXED a bug which could cause the plugin reload thread to spin at 100% if the reloaded plugin's didn't terminate
- FIXED an issue which would cause servers to crash on mod download via SIGPIPE on POSIX
- FIXED an issue which would cause servers to crash when checking if a vehicle is a unicycle
# v3.0.0
- CHANGED entire plugin Lua implementation (rewrite)
- CHANGED moved *almost all* Lua functions into MP.\*
- CHANGED console to use a custom language (type `help`, `list`, or `status`!)
- CHANGED all files of a Lua plugin to share a Lua state (no more state-per-file)
- ADDED many new Lua API functions, which can be found at <https://wiki.beammp.com/en/Scripting/functions>
- ADDED Commandline options. Run with `--help` to see all options.
- ADDED HTTP(S) Server (OpenAPI spec coming soon!)
- ADDED plugin directories to `package.path` and `package.cpath` before `onInit`
- ADDED ability to add `PluginConfig.toml` to your plugin folder to change some settings
- ADDED ability to share a lua state with other plugins via `StateId` setting in `PluginConfig.toml`
- ADDED ability to see name-to-thread-ID association in debug mode
- ADDED dumping tables with `print()` (try it with `print(MP)`)
- ADDED `MP.GetOSName()`, `MP.CreateTimer()`, `MP.GetLuaMemoryUsage()` and many more (see <https://wiki.beammp.com/en/Scripting/functions>)
- ADDED `MP.Settings` table to make usage of `MP.Set()` easier
- ADDED `FS.*` table with common filesystem operations (do `print(FS)` to see them!)
- FIXED i/o thread spin when stdout is /dev/null on linux
- FIXED removed extra whitespace infront of onChatMessage message
# v2.3.3
- CHANGED servers to be private by default
# v2.3.2
- ADDED Ctrl+C causes a graceful shutdown on windows (did already on linux)
- ADDED more meaningful shutdown messages
- ADDED even better backend connection error reporting
- ADDED `SendErrors` config in `ServerConfig.toml` to opt-out of error reporting
- ADDED hard-shutdown if Ctrl+C pressed 3 times
- FIXED issue with shells like bash being unusable after server exit
# v2.3.1
- CHANGED join/sync timeout to 20 minutes, players wont drop if loading takes >5 mins
# v2.3.0
- ADDED version check - the server will now let you know when a new release is out
- ADDED logging of various errors, crashes and exceptions to the backend
- ADDED chat messages are now logged to the server console as [CHAT]
- ADDED debug message telling you when the server heartbeats to the backend
- REMOVED various [DEBUG] messages which were confusing (such as "breaking client loop")
- FIXED various crashes and issues with handling unexpected backend responses
- FIXED minor bugs due to code correctness
# v2.2.0
- FIXED major security flaw
- FIXED minor bugs
# v2.1.4
- ADDED debug heartbeat print
- ADDED kicking every player before shutdown
- FIXED rare bug which led to violent crash
- FIXED minor bugs
# v2.1.3
- FIXED Lua events not cancelling properly on Linux
# v2.1.2
- CHANGED default map to gridmap v2
- FIXED version number display
# v2.1.1
# v2.1.0 (pre-v2.1.1)
# v2.0.4 (pre-v2.1.0)
- REMOVED boost as a runtime dependency
- FIXED Lua plugins on Linux
- FIXED console history on Windows
- CHANGED to new config format TOML
# v2.0.3
- WORKAROUND for timeout bug / ghost player bug
- FIXED 100% CPU spin when stdin is /dev/null.
# v2.0.2
- ADDED fully new commandline
- ADDED new backend
- ADDED automated build system
- ADDED lua GetPlayerIdentifiers
- ADDED lots of debug info
- ADDED better POSTing and GETing
- ADDED a license
- FIXED ghost players in player list issue
- FIXED ghost vehicle after joining issue
- FIXED missing vehicle after joining issue
- FIXED a lot of desync issues
- FIXED some memory leaks
- FIXED various crashes
- FIXED various data-races
- FIXED some linux-specific crashes
- FIXED some linux-specific issues
- FIXED bug which caused kicking to be logged as leaving
- FIXED various internal developer quality-of-life things
+1
View File
@@ -12,6 +12,7 @@ The server is the point through which all clients communicate. You can write Lua
Feel free to ask any questions via the following channels:
- **IRC**: `#beammp` on [irc.libera.chat](https://web.libera.chat/)
- **Discord**: [click for invite](https://discord.gg/beammp)
- **BeamMP Forum**: [BeamMP Forum Support](https://forum.beammp.com/c/support/33)
+6 -7
View File
@@ -43,7 +43,6 @@ public:
struct TSettings {
std::string ServerName { "BeamMP Server" };
std::string ServerDesc { "BeamMP Default Description" };
std::string ServerTags { "Freeroam" };
std::string Resource { "Resources" };
std::string MapName { "/levels/gridmap_v2/info.json" };
std::string Key {};
@@ -76,7 +75,7 @@ public:
static void RegisterShutdownHandler(const TShutdownHandler& Handler);
// Causes all threads to finish up and exit gracefull gracefully
static void GracefullyShutdown();
static TConsole& Console() { return mConsole; }
static TConsole& Console() { return *mConsole; }
static std::string ServerVersionString();
static const Version& ServerVersion() { return mVersion; }
static uint8_t ClientMajorVersion() { return 2; }
@@ -102,7 +101,9 @@ public:
static void SleepSafeSeconds(size_t Seconds);
static void InitializeConsole() {
mConsole.InitializeCommandline();
if (!mConsole) {
mConsole = std::make_unique<TConsole>();
}
}
enum class Status {
@@ -128,17 +129,15 @@ private:
static inline SystemStatusMap mSystemStatusMap {};
static inline std::mutex mSystemStatusMapMutex {};
static inline std::string mPPS;
static inline TConsole mConsole;
static inline std::unique_ptr<TConsole> mConsole;
static inline std::shared_mutex mShutdownMtx {};
static inline bool mShutdown { false };
static inline std::mutex mShutdownHandlersMutex {};
static inline std::deque<TShutdownHandler> mShutdownHandlers {};
static inline Version mVersion { 3, 2, 1 };
static inline Version mVersion { 3, 1, 3 };
};
void SplitString(std::string const& str, const char delim, std::vector<std::string>& out);
std::string ThreadName(bool DebugModeOverride = false);
void RegisterThread(const std::string& str);
#define RegisterThreadAuto() RegisterThread(__func__)
+3 -4
View File
@@ -22,12 +22,11 @@ private:
void CreateConfigFile();
void ParseFromFile(std::string_view name);
void PrintDebug();
void TryReadValue(toml::value& Table, const std::string& Category, const std::string_view& Key, const std::string_view& Env, std::string& OutValue);
void TryReadValue(toml::value& Table, const std::string& Category, const std::string_view& Key, const std::string_view& Env, bool& OutValue);
void TryReadValue(toml::value& Table, const std::string& Category, const std::string_view& Key, const std::string_view& Env, int& OutValue);
void TryReadValue(toml::value& Table, const std::string& Category, const std::string_view& Key, std::string& OutValue);
void TryReadValue(toml::value& Table, const std::string& Category, const std::string_view& Key, bool& OutValue);
void TryReadValue(toml::value& Table, const std::string& Category, const std::string_view& Key, int& OutValue);
void ParseOldFormat();
std::string TagsAsPrettyArray() const;
bool IsDefault();
bool mFailed { false };
std::string mConfigFileName;
+2 -5
View File
@@ -17,15 +17,12 @@ class TConsole {
public:
TConsole();
// Initializes the commandline app to take over I/O
void InitializeCommandline();
void Write(const std::string& str);
void WriteRaw(const std::string& str);
void InitializeLuaConsole(TLuaEngine& Engine);
void BackupOldLog();
void StartLoggingToFile();
Commandline& Internal() { return *mCommandline; }
Commandline& Internal() { return mCommandline; }
private:
void RunAsCommand(const std::string& cmd, bool IgnoreNotACommand = false);
@@ -59,7 +56,7 @@ private:
{ "say", [this](const auto&, const auto&) { Command_Say(""); } }, // shouldn't actually be called
};
std::unique_ptr<Commandline> mCommandline { nullptr };
Commandline mCommandline;
std::vector<std::string> mCachedLuaHistory;
std::vector<std::string> mCachedRegularHistory;
TLuaEngine* mLuaEngine { nullptr };
+1 -1
View File
@@ -2,4 +2,4 @@
set -ex
cmake . -B bin $1 -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_FLAGS="-O3 -g -Wl,-z,norelro -Wl,--hash-style=gnu -Wl,--build-id=none -Wl,-z,noseparate-code -ffunction-sections -fdata-sections -Wl,--gc-sections" -DBeamMP-Server_ENABLE_LTO=ON
cmake . -B bin $1 -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_FLAGS="-O3 -s -Wl,-z,norelro -Wl,--hash-style=gnu -Wl,--build-id=none -Wl,-z,noseparate-code -ffunction-sections -fdata-sections -Wl,--gc-sections" -DBeamMP-Server_ENABLE_LTO=ON
-5
View File
@@ -3,8 +3,3 @@
set -ex
cmake --build bin --parallel -t BeamMP-Server
objcopy --only-keep-debug bin/BeamMP-Server bin/BeamMP-Server.debug
objcopy --add-gnu-debuglink bin/BeamMP-Server bin/BeamMP-Server.debug
strip -s bin/BeamMP-Server
+1 -1
View File
@@ -2,4 +2,4 @@
set -ex
cmake . -B bin $1 -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_FLAGS="-O3 -g -Wl,-z,norelro -Wl,--hash-style=gnu -Wl,--build-id=none -Wl,-z,noseparate-code -ffunction-sections -fdata-sections -Wl,--gc-sections" -DBeamMP-Server_ENABLE_LTO=ON
cmake . -B bin $1 -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_FLAGS="-O3 -s -Wl,-z,norelro -Wl,--hash-style=gnu -Wl,--build-id=none -Wl,-z,noseparate-code -ffunction-sections -fdata-sections -Wl,--gc-sections" -DBeamMP-Server_ENABLE_LTO=ON
-5
View File
@@ -3,8 +3,3 @@
set -ex
cmake --build bin --parallel -t BeamMP-Server
objcopy --only-keep-debug bin/BeamMP-Server bin/BeamMP-Server.debug
objcopy --add-gnu-debuglink bin/BeamMP-Server bin/BeamMP-Server.debug
strip -s bin/BeamMP-Server
-11
View File
@@ -348,14 +348,3 @@ std::string GetPlatformAgnosticErrorString() {
return "(no human-readable errors on this platform)";
#endif
}
// TODO: add unit tests to SplitString
void SplitString(const std::string& str, const char delim, std::vector<std::string>& out) {
size_t start;
size_t end = 0;
while ((start = str.find_first_not_of(delim, end)) != std::string::npos) {
end = str.find(delim, start);
out.push_back(str.substr(start, end - start));
}
}
+49 -66
View File
@@ -1,7 +1,6 @@
#include "Common.h"
#include "TConfig.h"
#include <cstdlib>
#include <fstream>
#include <iostream>
#include <istream>
@@ -9,29 +8,16 @@
// General
static constexpr std::string_view StrDebug = "Debug";
static constexpr std::string_view EnvStrDebug = "BEAMMP_DEBUG";
static constexpr std::string_view StrPrivate = "Private";
static constexpr std::string_view EnvStrPrivate = "BEAMMP_PRIVATE";
static constexpr std::string_view StrPort = "Port";
static constexpr std::string_view EnvStrPort = "BEAMMP_PORT";
static constexpr std::string_view StrMaxCars = "MaxCars";
static constexpr std::string_view EnvStrMaxCars = "BEAMMP_MAX_CARS";
static constexpr std::string_view StrMaxPlayers = "MaxPlayers";
static constexpr std::string_view EnvStrMaxPlayers = "BEAMMP_MAX_PLAYERS";
static constexpr std::string_view StrMap = "Map";
static constexpr std::string_view EnvStrMap = "BEAMMP_MAP";
static constexpr std::string_view StrName = "Name";
static constexpr std::string_view EnvStrName = "BEAMMP_NAME";
static constexpr std::string_view StrDescription = "Description";
static constexpr std::string_view EnvStrDescription = "BEAMMP_DESCRIPTION";
static constexpr std::string_view StrTags = "Tags";
static constexpr std::string_view EnvStrTags = "BEAMMP_TAGS";
static constexpr std::string_view StrResourceFolder = "ResourceFolder";
static constexpr std::string_view EnvStrResourceFolder = "BEAMMP_RESOURCE_FOLDER";
static constexpr std::string_view StrAuthKey = "AuthKey";
static constexpr std::string_view EnvStrAuthKey = "BEAMMP_AUTH_KEY";
static constexpr std::string_view StrLogChat = "LogChat";
static constexpr std::string_view EnvStrLogChat = "BEAMMP_LOG_CHAT";
static constexpr std::string_view StrPassword = "Password";
// Misc
@@ -39,6 +25,14 @@ static constexpr std::string_view StrSendErrors = "SendErrors";
static constexpr std::string_view StrSendErrorsMessageEnabled = "SendErrorsShowMessage";
static constexpr std::string_view StrHideUpdateMessages = "ImScaredOfUpdates";
// HTTP
static constexpr std::string_view StrHTTPServerEnabled = "HTTPServerEnabled";
static constexpr std::string_view StrHTTPServerUseSSL = "UseSSL";
static constexpr std::string_view StrSSLKeyPath = "SSLKeyPath";
static constexpr std::string_view StrSSLCertPath = "SSLCertPath";
static constexpr std::string_view StrHTTPServerPort = "HTTPServerPort";
static constexpr std::string_view StrHTTPServerIP = "HTTPServerIP";
TEST_CASE("TConfig::TConfig") {
const std::string CfgFile = "beammp_server_testconfig.toml";
fs::remove(CfgFile);
@@ -62,6 +56,7 @@ TEST_CASE("TConfig::TConfig") {
const auto table = toml::parse(CfgFile);
CHECK(table.at("General").is_table());
CHECK(table.at("Misc").is_table());
CHECK(table.at("HTTP").is_table());
fs::remove(CfgFile);
}
@@ -107,8 +102,6 @@ void TConfig::FlushToFile() {
data["General"][StrPrivate.data()] = Application::Settings.Private;
data["General"][StrPort.data()] = Application::Settings.Port;
data["General"][StrName.data()] = Application::Settings.ServerName;
SetComment(data["General"][StrTags.data()].comments(), " Add custom identifying tags to your server to make it easier to find. Format should be TagA,TagB,TagC. Note the comma seperation.");
data["General"][StrTags.data()] = Application::Settings.ServerTags;
data["General"][StrMaxCars.data()] = Application::Settings.MaxCars;
data["General"][StrMaxPlayers.data()] = Application::Settings.MaxPlayers;
data["General"][StrMap.data()] = Application::Settings.MapName;
@@ -123,10 +116,20 @@ void TConfig::FlushToFile() {
SetComment(data["Misc"][StrSendErrors.data()].comments(), " You can turn on/off the SendErrors message you get on startup here");
data["Misc"][StrSendErrorsMessageEnabled.data()] = Application::Settings.SendErrorsMessageEnabled;
SetComment(data["Misc"][StrSendErrorsMessageEnabled.data()].comments(), " If SendErrors is `true`, the server will send helpful info about crashes and other issues back to the BeamMP developers. This info may include your config, who is on your server at the time of the error, and similar general information. This kind of data is vital in helping us diagnose and fix issues faster. This has no impact on server performance. You can opt-out of this system by setting this to `false`");
// HTTP
data["HTTP"][StrSSLKeyPath.data()] = Application::Settings.SSLKeyPath;
data["HTTP"][StrSSLCertPath.data()] = Application::Settings.SSLCertPath;
data["HTTP"][StrHTTPServerPort.data()] = Application::Settings.HTTPServerPort;
SetComment(data["HTTP"][StrHTTPServerIP.data()].comments(), " Which IP to listen on. Pick 0.0.0.0 for a public-facing server with no specific IP, and 127.0.0.1 or 'localhost' for a local server.");
data["HTTP"][StrHTTPServerIP.data()] = Application::Settings.HTTPServerIP;
data["HTTP"][StrHTTPServerUseSSL.data()] = Application::Settings.HTTPServerUseSSL;
SetComment(data["HTTP"][StrHTTPServerUseSSL.data()].comments(), " Recommended to have enabled for servers which face the internet. With SSL the server will serve https and requires valid key and cert files");
data["HTTP"][StrHTTPServerEnabled.data()] = Application::Settings.HTTPServerEnabled;
SetComment(data["HTTP"][StrHTTPServerEnabled.data()].comments(), " Enables the internal HTTP server");
std::stringstream Ss;
Ss << "# This is the BeamMP-Server config file.\n"
"# Help & Documentation: `https://wiki.beammp.com/en/home/server-maintenance`\n"
"# IMPORTANT: Fill in the AuthKey with the key you got from `https://keymaster.beammp.com/` on the left under \"Keys\"\n"
"# IMPORTANT: Fill in the AuthKey with the key you got from `https://beammp.com/k/dashboard` on the left under \"Keys\"\n"
<< data;
auto File = std::fopen(mConfigFileName.c_str(), "w+");
if (!File) {
@@ -156,38 +159,19 @@ void TConfig::CreateConfigFile() {
FlushToFile();
}
void TConfig::TryReadValue(toml::value& Table, const std::string& Category, const std::string_view& Key, const std::string_view& Env, std::string& OutValue) {
if (!Env.empty()) {
if (const char* envp = std::getenv(Env.data()); envp != nullptr && std::strcmp(envp, "") != 0) {
OutValue = std::string(envp);
return;
}
}
void TConfig::TryReadValue(toml::value& Table, const std::string& Category, const std::string_view& Key, std::string& OutValue) {
if (Table[Category.c_str()][Key.data()].is_string()) {
OutValue = Table[Category.c_str()][Key.data()].as_string();
}
}
void TConfig::TryReadValue(toml::value& Table, const std::string& Category, const std::string_view& Key, const std::string_view& Env, bool& OutValue) {
if (!Env.empty()) {
if (const char* envp = std::getenv(Env.data()); envp != nullptr && std::strcmp(envp, "") != 0) {
auto Str = std::string(envp);
OutValue = Str == "1" || Str == "true";
return;
}
}
void TConfig::TryReadValue(toml::value& Table, const std::string& Category, const std::string_view& Key, bool& OutValue) {
if (Table[Category.c_str()][Key.data()].is_boolean()) {
OutValue = Table[Category.c_str()][Key.data()].as_boolean();
}
}
void TConfig::TryReadValue(toml::value& Table, const std::string& Category, const std::string_view& Key, const std::string_view& Env, int& OutValue) {
if (!Env.empty()) {
if (const char* envp = std::getenv(Env.data()); envp != nullptr && std::strcmp(envp, "") != 0) {
OutValue = int(std::strtol(envp, nullptr, 10));
return;
}
}
void TConfig::TryReadValue(toml::value& Table, const std::string& Category, const std::string_view& Key, int& OutValue) {
if (Table[Category.c_str()][Key.data()].is_integer()) {
OutValue = int(Table[Category.c_str()][Key.data()].as_integer());
}
@@ -197,23 +181,29 @@ void TConfig::ParseFromFile(std::string_view name) {
try {
toml::value data = toml::parse<toml::preserve_comments>(name.data());
// GENERAL
TryReadValue(data, "General", StrDebug, EnvStrDebug, Application::Settings.DebugModeEnabled);
TryReadValue(data, "General", StrPrivate, EnvStrPrivate, Application::Settings.Private);
TryReadValue(data, "General", StrPort, EnvStrPort, Application::Settings.Port);
TryReadValue(data, "General", StrMaxCars, EnvStrMaxCars, Application::Settings.MaxCars);
TryReadValue(data, "General", StrMaxPlayers, EnvStrMaxPlayers, Application::Settings.MaxPlayers);
TryReadValue(data, "General", StrMap, EnvStrMap, Application::Settings.MapName);
TryReadValue(data, "General", StrName, EnvStrName, Application::Settings.ServerName);
TryReadValue(data, "General", StrDescription, EnvStrDescription, Application::Settings.ServerDesc);
TryReadValue(data, "General", StrTags, EnvStrTags, Application::Settings.ServerTags);
TryReadValue(data, "General", StrResourceFolder, EnvStrResourceFolder, Application::Settings.Resource);
TryReadValue(data, "General", StrAuthKey, EnvStrAuthKey, Application::Settings.Key);
TryReadValue(data, "General", StrLogChat, EnvStrLogChat, Application::Settings.LogChat);
TryReadValue(data, "General", StrPassword, "", Application::Settings.Password);
TryReadValue(data, "General", StrDebug, Application::Settings.DebugModeEnabled);
TryReadValue(data, "General", StrPrivate, Application::Settings.Private);
TryReadValue(data, "General", StrPort, Application::Settings.Port);
TryReadValue(data, "General", StrMaxCars, Application::Settings.MaxCars);
TryReadValue(data, "General", StrMaxPlayers, Application::Settings.MaxPlayers);
TryReadValue(data, "General", StrMap, Application::Settings.MapName);
TryReadValue(data, "General", StrName, Application::Settings.ServerName);
TryReadValue(data, "General", StrDescription, Application::Settings.ServerDesc);
TryReadValue(data, "General", StrResourceFolder, Application::Settings.Resource);
TryReadValue(data, "General", StrAuthKey, Application::Settings.Key);
TryReadValue(data, "General", StrLogChat, Application::Settings.LogChat);
TryReadValue(data, "General", StrPassword, Application::Settings.Password);
// Misc
TryReadValue(data, "Misc", StrSendErrors, "", Application::Settings.SendErrors);
TryReadValue(data, "Misc", StrHideUpdateMessages, "", Application::Settings.HideUpdateMessages);
TryReadValue(data, "Misc", StrSendErrorsMessageEnabled, "", Application::Settings.SendErrorsMessageEnabled);
TryReadValue(data, "Misc", StrSendErrors, Application::Settings.SendErrors);
TryReadValue(data, "Misc", StrHideUpdateMessages, Application::Settings.HideUpdateMessages);
TryReadValue(data, "Misc", StrSendErrorsMessageEnabled, Application::Settings.SendErrorsMessageEnabled);
// HTTP
TryReadValue(data, "HTTP", StrSSLKeyPath, Application::Settings.SSLKeyPath);
TryReadValue(data, "HTTP", StrSSLCertPath, Application::Settings.SSLCertPath);
TryReadValue(data, "HTTP", StrHTTPServerPort, Application::Settings.HTTPServerPort);
TryReadValue(data, "HTTP", StrHTTPServerIP, Application::Settings.HTTPServerIP);
TryReadValue(data, "HTTP", StrHTTPServerEnabled, Application::Settings.HTTPServerEnabled);
TryReadValue(data, "HTTP", StrHTTPServerUseSSL, Application::Settings.HTTPServerUseSSL);
} catch (const std::exception& err) {
beammp_error("Error parsing config file value: " + std::string(err.what()));
mFailed = true;
@@ -246,9 +236,12 @@ void TConfig::PrintDebug() {
beammp_debug(std::string(StrMap) + ": \"" + Application::Settings.MapName + "\"");
beammp_debug(std::string(StrName) + ": \"" + Application::Settings.ServerName + "\"");
beammp_debug(std::string(StrDescription) + ": \"" + Application::Settings.ServerDesc + "\"");
beammp_debug(std::string(StrTags) + ": " + TagsAsPrettyArray());
beammp_debug(std::string(StrLogChat) + ": \"" + (Application::Settings.LogChat ? "true" : "false") + "\"");
beammp_debug(std::string(StrResourceFolder) + ": \"" + Application::Settings.Resource + "\"");
beammp_debug(std::string(StrSSLKeyPath) + ": \"" + Application::Settings.SSLKeyPath + "\"");
beammp_debug(std::string(StrSSLCertPath) + ": \"" + Application::Settings.SSLCertPath + "\"");
beammp_debug(std::string(StrHTTPServerPort) + ": \"" + std::to_string(Application::Settings.HTTPServerPort) + "\"");
beammp_debug(std::string(StrHTTPServerIP) + ": \"" + Application::Settings.HTTPServerIP + "\"");
// special!
beammp_debug("Key Length: " + std::to_string(Application::Settings.Key.length()) + "");
beammp_debug("Password Protected: " + std::string(Application::Settings.Password.empty() ? "false" : "true"));
@@ -306,13 +299,3 @@ void TConfig::ParseOldFormat() {
Str >> std::ws;
}
}
std::string TConfig::TagsAsPrettyArray() const {
std::vector<std::string> TagsArray = {};
SplitString(Application::Settings.ServerTags, ',', TagsArray);
std::string Pretty = {};
for (size_t i = 0; i < TagsArray.size() - 1; ++i) {
Pretty += '\"' + TagsArray[i] + "\", ";
}
Pretty += '\"' + TagsArray.at(TagsArray.size()-1) + "\"";
return Pretty;
}
+27 -30
View File
@@ -52,6 +52,17 @@ TEST_CASE("TrimString") {
CHECK(TrimString("") == "");
}
// TODO: add unit tests to SplitString
static inline void SplitString(std::string const& str, const char delim, std::vector<std::string>& out) {
size_t start;
size_t end = 0;
while ((start = str.find_first_not_of(delim, end)) != std::string::npos) {
end = str.find(delim, start);
out.push_back(str.substr(start, end - start));
}
}
static std::string GetDate() {
std::chrono::system_clock::time_point now = std::chrono::system_clock::now();
time_t tt = std::chrono::system_clock::to_time_t(now);
@@ -146,13 +157,13 @@ void TConsole::ChangeToLuaConsole(const std::string& LuaStateId) {
mIsLuaConsole = true;
if (mStateId != mDefaultStateId) {
Application::Console().WriteRaw("Attached to Lua state '" + mStateId + "'. For help, type `:help`. To detach, type `:exit`");
mCommandline->set_prompt("lua @" + LuaStateId + "> ");
mCommandline.set_prompt("lua @" + LuaStateId + "> ");
} else {
Application::Console().WriteRaw("Attached to Lua. For help, type `:help`. To detach, type `:exit`");
mCommandline->set_prompt("lua> ");
mCommandline.set_prompt("lua> ");
}
mCachedRegularHistory = mCommandline->history();
mCommandline->set_history(mCachedLuaHistory);
mCachedRegularHistory = mCommandline.history();
mCommandline.set_history(mCachedLuaHistory);
}
}
@@ -164,9 +175,9 @@ void TConsole::ChangeToRegularConsole() {
} else {
Application::Console().WriteRaw("Detached from Lua.");
}
mCachedLuaHistory = mCommandline->history();
mCommandline->set_history(mCachedRegularHistory);
mCommandline->set_prompt("> ");
mCachedLuaHistory = mCommandline.history();
mCommandline.set_history(mCachedRegularHistory);
mCommandline.set_prompt("> ");
mStateId = mDefaultStateId;
}
}
@@ -246,7 +257,7 @@ void TConsole::Command_Clear(const std::string&, const std::vector<std::string>&
if (!EnsureArgsCount(args, 0, size_t(-1))) {
return;
}
mCommandline->write("\x1b[;H\x1b[2J");
mCommandline.write("\x1b[;H\x1b[2J");
}
void TConsole::Command_Kick(const std::string&, const std::vector<std::string>& args) {
@@ -578,20 +589,16 @@ Commands
}
TConsole::TConsole() {
}
void TConsole::InitializeCommandline() {
mCommandline = std::make_unique<Commandline>();
mCommandline->enable_history();
mCommandline->set_history_limit(20);
mCommandline->set_prompt("> ");
mCommandline.enable_history();
mCommandline.set_history_limit(20);
mCommandline.set_prompt("> ");
BackupOldLog();
mCommandline->on_command = [this](Commandline& c) {
mCommandline.on_command = [this](Commandline& c) {
try {
auto TrimmedCmd = c.get_command();
TrimmedCmd = TrimString(TrimmedCmd);
auto [cmd, args] = ParseCommand(TrimmedCmd);
mCommandline->write(mCommandline->prompt() + TrimmedCmd);
mCommandline.write(mCommandline.prompt() + TrimmedCmd);
if (mIsLuaConsole) {
if (!mLuaEngine) {
beammp_info("Lua not started yet, please try again in a second");
@@ -626,7 +633,7 @@ void TConsole::InitializeCommandline() {
beammp_error("Console died with: " + std::string(e.what()) + ". This could be a fatal error and could cause the server to terminate.");
}
};
mCommandline->on_autocomplete = [this](Commandline&, std::string stub, int) {
mCommandline.on_autocomplete = [this](Commandline&, std::string stub, int) {
std::vector<std::string> suggestions;
try {
if (mIsLuaConsole) { // if lua
@@ -696,21 +703,11 @@ void TConsole::InitializeCommandline() {
void TConsole::Write(const std::string& str) {
auto ToWrite = GetDate() + str;
// allows writing to stdout without an initialized console
if (mCommandline) {
mCommandline->write(ToWrite);
} else {
std::cout << ToWrite << std::endl;
}
mCommandline.write(ToWrite);
}
void TConsole::WriteRaw(const std::string& str) {
// allows writing to stdout without an initialized console
if (mCommandline) {
mCommandline->write(str);
} else {
std::cout << str << std::endl;
}
mCommandline.write(str);
}
void TConsole::InitializeLuaConsole(TLuaEngine& Engine) {
-1
View File
@@ -129,7 +129,6 @@ std::string THeartbeatThread::GenerateCall() {
<< "&version=" << Application::ServerVersionString()
<< "&clientversion=" << std::to_string(Application::ClientMajorVersion()) + ".0" // FIXME: Wtf.
<< "&name=" << Application::Settings.ServerName
<< "&tags=" << Application::Settings.ServerTags
<< "&modlist=" << mResourceManager.TrimmedList()
<< "&modstotalsize=" << mResourceManager.MaxModSize()
<< "&modstotal=" << mResourceManager.ModsLoaded()
+1 -2
View File
@@ -1,7 +1,6 @@
#include "TPluginMonitor.h"
#include "TLuaEngine.h"
#include <filesystem>
TPluginMonitor::TPluginMonitor(const fs::path& Path, std::shared_ptr<TLuaEngine> Engine)
: mEngine(Engine)
@@ -10,7 +9,7 @@ TPluginMonitor::TPluginMonitor(const fs::path& Path, std::shared_ptr<TLuaEngine>
if (!fs::exists(mPath)) {
fs::create_directories(mPath);
}
for (const auto& Entry : fs::recursive_directory_iterator(mPath, fs::directory_options::follow_directory_symlink)) {
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());
+15 -14
View File
@@ -69,6 +69,7 @@ int main(int argc, char** argv) {
int BeamMPServerMain(MainArguments Arguments) {
setlocale(LC_ALL, "C");
Application::InitializeConsole();
ArgsParser Parser;
Parser.RegisterArgument({ "help" }, ArgsParser::NONE);
Parser.RegisterArgument({ "version" }, ArgsParser::NONE);
@@ -79,10 +80,12 @@ int BeamMPServerMain(MainArguments Arguments) {
return 1;
}
if (Parser.FoundArgument({ "help" })) {
Application::Console().Internal().set_prompt("");
Application::Console().WriteRaw(sCommandlineArguments);
return 0;
}
if (Parser.FoundArgument({ "version" })) {
Application::Console().Internal().set_prompt("");
Application::Console().WriteRaw("BeamMP-Server v" + Application::ServerVersionString());
return 0;
}
@@ -106,22 +109,11 @@ int BeamMPServerMain(MainArguments Arguments) {
}
}
}
TConfig Config(ConfigPath);
if (Config.Failed()) {
beammp_info("Closing in 10 seconds");
// loop to make it possible to ctrl+c instead
for (size_t i = 0; i < 20; ++i) {
std::this_thread::sleep_for(std::chrono::milliseconds(500));
}
return 1;
}
Application::InitializeConsole();
Application::Console().StartLoggingToFile();
Application::SetSubsystemStatus("Main", Application::Status::Starting);
Application::Console().StartLoggingToFile();
SetupSignalHandlers();
bool Shutdown = false;
@@ -136,11 +128,20 @@ int BeamMPServerMain(MainArguments Arguments) {
});
TServer Server(Arguments.List);
TConfig Config(ConfigPath);
auto LuaEngine = std::make_shared<TLuaEngine>();
LuaEngine->SetServer(&Server);
Application::Console().InitializeLuaConsole(*LuaEngine);
if (Config.Failed()) {
beammp_info("Closing in 10 seconds");
// loop to make it possible to ctrl+c instead
for (size_t i = 0; i < 20; ++i) {
std::this_thread::sleep_for(std::chrono::milliseconds(500));
}
return 1;
}
RegisterThread("Main");
beammp_trace("Running in debug mode on a debug build");