Compare commits

..

37 Commits

Author SHA1 Message Date
Lion Kortlepel daa674f448 add infinite snowmen bug to changelog 2022-03-10 12:31:02 +01:00
Lion Kortlepel a85fef15c2 only use sentry if URL is specified, possibly fix stupid microsoft compiler error
hey @microsoft, maybe don't have a limit on the size of obj files.
2022-03-10 12:23:24 +01:00
Lion Kortlepel 359faee696 Fix Unicycle "infinite spawning" bug 2022-03-10 12:22:11 +01:00
Lion Kortlepel 299004b14e fix msvc /bigobj issue 2022-03-10 12:21:08 +01:00
Lion Kortlepel b09f5a401d update lionkor/commandline to 1.0.0 (adds cursor left- and right
movement)
2022-03-10 12:19:01 +01:00
Lion Kortlepel 8ce3be03a3 make bigobj a linker flag? 2022-02-17 12:00:03 +01:00
Lion Kortlepel 687b4e4235 add bigobj flag 2022-02-17 11:47:28 +01:00
Lion Kortlepel 86ad28abdc Microsoft (R) Windows (TM) needs deprecation 2022-02-17 11:29:51 +01:00
Lion Kortlepel a982d54202 add debug build to windows github actions 2022-02-17 11:13:07 +01:00
Lion Kortlepel 5553aca0bb set heartbeat status properly 2022-02-12 22:08:49 +01:00
Lion Kortlepel beaea4f624 Fix crash when giving commandline arguments with no console initialized 2022-02-11 11:57:01 +01:00
Lion a4f07c9a4d Merge pull request #86 from BeamMP/rc-v3.0.1
Release Candidate v3.0.1
2022-02-11 11:07:39 +01:00
Lion Kortlepel dada8fe6bf update changelog 2022-02-11 11:01:39 +01:00
Lion Kortlepel 36853ca683 add MSG_NOSIGNAL to all calls to send() to get rid of useless SIGPIPE signals 2022-02-11 10:59:17 +01:00
Lion Kortlepel d969c4a2c2 Use nlohmann/json for IsUnicycle 2022-02-11 10:36:10 +01:00
Lion Kortlepel f26ca6b40d add nlohmann/json
this will conflict with a change in the http branch, but i dont care
right now
2022-02-11 10:19:10 +01:00
Lion b72de4bd0a Merge pull request #82 from BeamMP/rc-v3.0.1
Release Candidate v3.0.1
2022-02-04 04:37:09 +01:00
Lion Kortlepel 9494bc70fb fix changelog 2022-02-03 19:46:31 +01:00
Lion Kortlepel 5c44a307bc update changelog 2022-02-03 19:03:21 +01:00
Lion Kortlepel 754053e73f Use yield() where possible
Replaced calls of this_thread::sleep_* with this_thread::yield(), which
yields the thread to the OS' scheduler.
2022-02-03 18:57:52 +01:00
Lion Kortlepel 29f8d29e33 Move commandline initialization after cwd setting
This fixes an issue where the log file is written to the original
directory, even if --working-directory=path was used. This can obviously
be pretty bad.
2022-02-03 18:31:18 +01:00
Lion Kortlepel e043361abb update libraries 2022-02-03 18:30:00 +01:00
Lion Kortlepel fca5bbcec9 UpdateCheck: Try all URLs 2022-01-21 14:26:42 +01:00
Lion Kortlepel 2a588954be advance to 3.0.1 2022-01-20 21:31:00 +01:00
Lion Kortlepel cd4129e05d add api-v header to heartbeat post 2022-01-20 16:09:08 +01:00
Lion Kortlepel c42c748b37 start fixing backend heartbeat 2022-01-20 15:46:13 +01:00
Lion 179b33a7ab Merge pull request #76 from BeamMP/patch-http-server-default
HTTP Server disabled by default
2021-12-23 14:28:33 +01:00
Lion Kortlepel 1b14206a3c HTTP Server disabled by default 2021-12-23 14:24:00 +01:00
Lion 0cf81cf3f4 Merge pull request #73 from BeamMP/lionkor-readme-patch
Patch README Dependency List, fix Changelog
2021-12-16 23:54:33 +01:00
Lion 801780bcb1 Update Changelog.md 2021-12-16 16:02:31 +01:00
Lion 84d52578e0 Merge pull request #75 from BeamMP/release-3-0-0-patch
Release v3.0.0 final patch
2021-12-15 18:26:08 +01:00
Lion Kortlepel 3555cec5fe Simplify fix for event argument bug 2021-12-13 13:48:18 +01:00
Lion Kortlepel 71efe30345 Bump to 3.0.0, possible fix for event argument bug 2021-12-13 13:22:58 +01:00
Lion 5df8aedf08 Update Changelog.md 2021-12-11 10:35:11 +01:00
Lion c3ab4b729a Update README.md 2021-12-09 14:15:50 +01:00
Lion 464aa3b59f Update README.md 2021-12-09 14:13:05 +01:00
Lion cfe63198c7 Merge pull request #50 from BeamMP/rewrite-lua
Rewrite Lua + New Lua Features + New Console + Commandline Args
2021-12-09 13:04:48 +01:00
20 changed files with 239 additions and 144 deletions
+11
View File
@@ -44,4 +44,15 @@ jobs:
name: BeamMP-Server.exe name: BeamMP-Server.exe
path: ${{github.workspace}}/build-windows/Release/BeamMP-Server.exe path: ${{github.workspace}}/build-windows/Release/BeamMP-Server.exe
- name: Build debug
working-directory: ${{github.workspace}}/build-windows
shell: bash
run: |
cmake --build . --config Debug
- name: Archive debug artifacts
uses: actions/upload-artifact@v2
with:
name: BeamMP-Server-debug.exe
path: ${{github.workspace}}/build-windows/Debug/BeamMP-Server.exe
+3
View File
@@ -22,3 +22,6 @@
[submodule "deps/cpp-httplib"] [submodule "deps/cpp-httplib"]
path = deps/cpp-httplib path = deps/cpp-httplib
url = https://github.com/yhirose/cpp-httplib url = https://github.com/yhirose/cpp-httplib
[submodule "deps/json"]
path = deps/json
url = https://github.com/nlohmann/json
+20 -12
View File
@@ -8,12 +8,15 @@ project(BeamMP-Server
HOMEPAGE_URL https://beammp.com HOMEPAGE_URL https://beammp.com
LANGUAGES CXX C) LANGUAGES CXX C)
set(HTTPLIB_REQUIRE_OPENSSL ON)
include_directories("${PROJECT_SOURCE_DIR}/deps/asio/asio/include") include_directories("${PROJECT_SOURCE_DIR}/deps/asio/asio/include")
include_directories("${PROJECT_SOURCE_DIR}/deps/rapidjson/include") include_directories("${PROJECT_SOURCE_DIR}/deps/rapidjson/include")
include_directories("${PROJECT_SOURCE_DIR}/deps/websocketpp") include_directories("${PROJECT_SOURCE_DIR}/deps/websocketpp")
include_directories("${PROJECT_SOURCE_DIR}/deps/commandline") include_directories("${PROJECT_SOURCE_DIR}/deps/commandline")
include_directories("${PROJECT_SOURCE_DIR}/deps/sol2/include") include_directories("${PROJECT_SOURCE_DIR}/deps/sol2/include")
include_directories("${PROJECT_SOURCE_DIR}/deps/cpp-httplib") include_directories("${PROJECT_SOURCE_DIR}/deps/cpp-httplib")
include_directories("${PROJECT_SOURCE_DIR}/deps/json/single_include")
include_directories("${PROJECT_SOURCE_DIR}/deps") include_directories("${PROJECT_SOURCE_DIR}/deps")
add_compile_definitions(CPPHTTPLIB_OPENSSL_SUPPORT) add_compile_definitions(CPPHTTPLIB_OPENSSL_SUPPORT)
@@ -38,9 +41,25 @@ set(SENTRY_BUILD_SHARED_LIBS OFF)
if (MSVC) if (MSVC)
set(SENTRY_BUILD_RUNTIMESTATIC ON) set(SENTRY_BUILD_RUNTIMESTATIC ON)
endif() endif()
set(SENTRY_BACKEND breakpad) message(STATUS "Checking for Sentry URL")
# this is set by the build system.
# IMPORTANT: if you're building from source, just leave this empty
if (NOT DEFINED BEAMMP_SECRET_SENTRY_URL)
message(WARNING "No sentry URL configured. Sentry logging is disabled for this build. \
This is not an error, and if you're building the BeamMP-Server yourself, this is expected and can be ignored.")
set(BEAMMP_SECRET_SENTRY_URL "")
set(SENTRY_BACKEND none)
else()
string(LENGTH ${BEAMMP_SECRET_SENTRY_URL} URL_LEN)
message(STATUS "Sentry URL is length ${URL_LEN}")
set(SENTRY_BACKEND breakpad)
endif()
add_subdirectory("deps/sentry-native") add_subdirectory("deps/sentry-native")
if (MSVC)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /bigobj")
endif ()
message(STATUS "Setting compiler flags") message(STATUS "Setting compiler flags")
if (WIN32) if (WIN32)
@@ -58,17 +77,6 @@ elseif (UNIX)
endif (SANITIZE) endif (SANITIZE)
endif () endif ()
message(STATUS "Checking for Sentry URL")
# this is set by the build system.
# IMPORTANT: if you're building from source, just leave this empty
if (NOT DEFINED BEAMMP_SECRET_SENTRY_URL)
message(WARNING "No sentry URL configured. Sentry logging is disabled for this build. \
This is not an error, and if you're building the BeamMP-Server yourself, this is expected and can be ignored.")
set(BEAMMP_SECRET_SENTRY_URL "")
else()
string(LENGTH ${BEAMMP_SECRET_SENTRY_URL} URL_LEN)
message(STATUS "Sentry URL is length ${URL_LEN}")
endif()
message(STATUS "Adding local source dependencies") message(STATUS "Adding local source dependencies")
# this has to happen before -DDEBUG since it wont compile properly with -DDEBUG # this has to happen before -DDEBUG since it wont compile properly with -DDEBUG
+13 -3
View File
@@ -1,7 +1,17 @@
# v2.4.0 # 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 entire plugin Lua implementation (rewrite)
- CHANGED moved *almost all* functions into MP.\* - CHANGED moved *almost all* Lua functions into MP.\*
- CHANGED console to use a custom language (type `help`, `list`, or `status`!) - 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) - 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 many new Lua API functions, which can be found at <https://wiki.beammp.com/en/Scripting/functions>
@@ -14,7 +24,7 @@
- ADDED dumping tables with `print()` (try it with `print(MP)`) - 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.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 `MP.Settings` table to make usage of `MP.Set()` easier
- ADDED `FS.*` table with common filesystem operations - 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 i/o thread spin when stdout is /dev/null on linux
- FIXED removed extra whitespace infront of onChatMessage message - FIXED removed extra whitespace infront of onChatMessage message
+38 -27
View File
@@ -6,6 +6,8 @@
This is the server for the multiplayer mod **[BeamMP](https://beammp.com/)** for the game [BeamNG.drive](https://www.beamng.com/). This is the server for the multiplayer mod **[BeamMP](https://beammp.com/)** for the game [BeamNG.drive](https://www.beamng.com/).
The server is the point throug which all clients communicate. You can write lua mods for the server, detailed instructions on the [BeamMP Wiki](https://wiki.beammp.com). The server is the point throug which all clients communicate. You can write lua mods for the server, detailed instructions on the [BeamMP Wiki](https://wiki.beammp.com).
**For Linux, you __need__ the runtime dependencies, listed below under "prerequisites".**
## Support + Contact ## Support + Contact
Feel free to ask any questions via the following channels: Feel free to ask any questions via the following channels:
@@ -48,7 +50,7 @@ You can find precompiled binaries under [Releases](https://github.com/BeamMP/Bea
## Build Instructions ## Build Instructions
**__Do not compile from `master`. Always build from a release tag, i.e. `tags/v2.0`!__** **__Do not compile from `master`. Always build from a release tag, i.e. `tags/v2.3.3`!__**
Currently only linux and windows are supported (generally). See [Releases](https://github.com/BeamMP/BeamMP-Server/releases/) for official binary releases. On systems to which we do not provide binaries (so anything but windows), you are allowed to compile the program and use it. Other restrictions, such as not being allowed to distribute those binaries, still apply (see [copyright notice](#copyright)). Currently only linux and windows are supported (generally). See [Releases](https://github.com/BeamMP/BeamMP-Server/releases/) for official binary releases. On systems to which we do not provide binaries (so anything but windows), you are allowed to compile the program and use it. Other restrictions, such as not being allowed to distribute those binaries, still apply (see [copyright notice](#copyright)).
@@ -58,38 +60,47 @@ Currently only linux and windows are supported (generally). See [Releases](https
Please use the prepackaged binaries in [Releases](https://github.com/BeamMP/BeamMP-Server/releases/). Please use the prepackaged binaries in [Releases](https://github.com/BeamMP/BeamMP-Server/releases/).
Dependencies for windows can be installed with `vcpkg`, in which case the current dependencies are the `x64-windows-static` versions of `lua`, `zlib`, `rapidjson`, and `openssl`. Dependencies for **windows** can be installed with `vcpkg`.
These are:
```
lua
zlib
rapidjson
openssl
websocketpp
curl
```
#### Linux / \*nix #### Linux
These package names are in the debian / ubuntu style. Feel free to PR your own guide for a different distro. These package names are in the debian / ubuntu style. Feel free to PR your own guide for a different distro.
- `git` Runtime dependencies for **linux** are (debian/ubuntu):
- `make` ```
- `cmake` libz-dev
- `g++` rapidjson-dev
- `libcurl4-openssl-dev` or similar (search for `libcurl` and look for one with `-dev`) liblua5.3
libssl-dev
Must support ISO C++17. If your distro's `g++` doesn't support C++17, chances are that it has a `g++-8` or `g++-10` package that does. If this is the case. you just need to run CMake with `-DCMAKE_CXX_COMPILER=g++-10` (replace `g++-10` with your compiler's name). libwebsocketpp-dev
- `liblua5.3-dev` libcurl4-openssl-dev
Any 5.x version should work, but 5.3 is what we officially use. Any other version might break in the future.
You can also use any version of `libluajit`, but the same applies regarding the version.
- `libz-dev`
- `rapidjson-dev`
- `libopenssl-dev` or `libssl-dev`
In the end you should end up with a command something like this:
```sh
sudo apt install git make cmake g++-10 liblua5.3 libz-dev rapidjson-dev libopenssl-dev
``` ```
In the end you should end up with a command something like this: Build-time dependencies for **linux** are:
```sh
sudo apt install git make cmake g++-10 liblua5.3 libz-dev rapidjson-dev libopenssl-dev
``` ```
git
make
cmake
g++
```
For other distributions (e.g. Arch) you want to find packages for:
- libz
- rapidjson
- lua5.3
- ssl / openssl
- websocketpp
- curl (with ssl support)
- \+ the build time dependencies from above
### How to build ### How to build
@@ -98,7 +109,7 @@ On windows, use git-bash for these commands. On Linux, these should work in your
1. Make sure you have all [prerequisites](#prerequisites) installed 1. Make sure you have all [prerequisites](#prerequisites) installed
2. Clone the repository in a location of your choice with `git clone --recurse-submodules https://github.com/BeamMP/BeamMP-Server`. 2. Clone the repository in a location of your choice with `git clone --recurse-submodules https://github.com/BeamMP/BeamMP-Server`.
3. Ensure that all submodules are initialized by running `git submodule update --init --recursive`. Then change into the cloned directory by running `cd BeamMP-Server`. 3. Ensure that all submodules are initialized by running `git submodule update --init --recursive`. Then change into the cloned directory by running `cd BeamMP-Server`.
4. Checkout the branch of the release you want to compile (`master` is often unstable), for example `git checkout tags/v1.20` for version 1.20. You can find the latest version [here](https://github.com/BeamMP/BeamMP-Server/tags). 4. Checkout the branch of the release you want to compile (`master` is often unstable), for example `git checkout tags/v2.3.3` for version 2.3.3. You can find the latest version [here](https://github.com/BeamMP/BeamMP-Server/tags).
5. Run `cmake . -DCMAKE_BUILD_TYPE=Release` (with `.`) 5. Run `cmake . -DCMAKE_BUILD_TYPE=Release` (with `.`)
6. Run `make` 6. Run `make`
7. You will now have a `BeamMP-Server` file in your directory, which is executable with `./BeamMP-Server` (`.\BeamMP-Server.exe` for windows). Follow the (windows or linux, doesnt matter) instructions on the [wiki](https://wiki.beammp.com/en/home/Server_Mod) for further setup after installation (which we just did), such as port-forwarding and getting a key to actually run the server. 7. You will now have a `BeamMP-Server` file in your directory, which is executable with `./BeamMP-Server` (`.\BeamMP-Server.exe` for windows). Follow the (windows or linux, doesnt matter) instructions on the [wiki](https://wiki.beammp.com/en/home/Server_Mod) for further setup after installation (which we just did), such as port-forwarding and getting a key to actually run the server.
Vendored Submodule
+1
Submodule deps/json added at eb21824147
+10 -5
View File
@@ -42,7 +42,7 @@ public:
std::string Key {}; std::string Key {};
std::string SSLKeyPath { "./.ssl/HttpServer/key.pem" }; std::string SSLKeyPath { "./.ssl/HttpServer/key.pem" };
std::string SSLCertPath { "./.ssl/HttpServer/cert.pem" }; std::string SSLCertPath { "./.ssl/HttpServer/cert.pem" };
bool HTTPServerEnabled { true }; bool HTTPServerEnabled { false };
int MaxPlayers { 10 }; int MaxPlayers { 10 };
bool Private { true }; bool Private { true };
int MaxCars { 1 }; int MaxCars { 1 };
@@ -74,10 +74,15 @@ public:
static TSettings Settings; static TSettings Settings;
static std::vector<std::string> GetBackendUrlsInOrder() {
return {
"backend.beammp.com",
"backup1.beammp.com",
"backup2.beammp.com"
};
}
static std::string GetBackendUrlForAuth() { return "auth.beammp.com"; } static std::string GetBackendUrlForAuth() { return "auth.beammp.com"; }
static std::string GetBackendHostname() { return "backend.beammp.com"; }
static std::string GetBackup1Hostname() { return "backup1.beammp.com"; }
static std::string GetBackup2Hostname() { return "backup2.beammp.com"; }
static std::string GetBackendUrlForSocketIO() { return "https://backend.beammp.com"; } static std::string GetBackendUrlForSocketIO() { return "https://backend.beammp.com"; }
static void CheckForUpdates(); static void CheckForUpdates();
static std::array<uint8_t, 3> VersionStrToInts(const std::string& str); static std::array<uint8_t, 3> VersionStrToInts(const std::string& str);
@@ -114,7 +119,7 @@ private:
static inline std::mutex mShutdownHandlersMutex {}; static inline std::mutex mShutdownHandlersMutex {};
static inline std::deque<TShutdownHandler> mShutdownHandlers {}; static inline std::deque<TShutdownHandler> mShutdownHandlers {};
static inline Version mVersion { 2, 4, 0 }; static inline Version mVersion { 3, 0, 1 };
}; };
std::string ThreadName(bool DebugModeOverride = false); std::string ThreadName(bool DebugModeOverride = false);
+1 -1
View File
@@ -25,7 +25,7 @@ constexpr size_t RSA_DEFAULT_KEYLENGTH { 2048 };
namespace Http { namespace Http {
std::string GET(const std::string& host, int port, const std::string& target, unsigned int* status = nullptr); std::string GET(const std::string& host, int port, const std::string& target, unsigned int* status = nullptr);
std::string POST(const std::string& host, int port, const std::string& target, const std::string& body, const std::string& ContentType, unsigned int* status = nullptr); std::string POST(const std::string& host, int port, const std::string& target, const std::string& body, const std::string& ContentType, unsigned int* status = nullptr, const httplib::Headers& headers = {});
namespace Status { namespace Status {
std::string ToString(int code); std::string ToString(int code);
} }
+4 -1
View File
@@ -133,10 +133,12 @@ public:
} }
std::vector<std::shared_ptr<TLuaResult>> Results; std::vector<std::shared_ptr<TLuaResult>> Results;
std::vector<TLuaArgTypes> Arguments { TLuaArgTypes { std::forward<ArgsT>(Args) }... };
for (const auto& Event : mLuaEvents.at(EventName)) { for (const auto& Event : mLuaEvents.at(EventName)) {
for (const auto& Function : Event.second) { for (const auto& Function : Event.second) {
if (Event.first != IgnoreId) { if (Event.first != IgnoreId) {
Results.push_back(EnqueueFunctionCall(Event.first, Function, { TLuaArgTypes { std::forward<ArgsT>(Args) }... })); Results.push_back(EnqueueFunctionCall(Event.first, Function, Arguments));
} }
} }
} }
@@ -147,6 +149,7 @@ public:
void CancelEventTimers(const std::string& EventName, TLuaStateId StateId); void CancelEventTimers(const std::string& EventName, TLuaStateId StateId);
sol::state_view GetStateForPlugin(const fs::path& PluginPath); sol::state_view GetStateForPlugin(const fs::path& PluginPath);
TLuaStateId GetStateIDForPlugin(const fs::path& PluginPath); TLuaStateId GetStateIDForPlugin(const fs::path& PluginPath);
void AddResultToCheck(const std::shared_ptr<TLuaResult>& Result);
static constexpr const char* BeamMPFnNotFoundError = "BEAMMP_FN_NOT_FOUND"; static constexpr const char* BeamMPFnNotFoundError = "BEAMMP_FN_NOT_FOUND";
+23 -17
View File
@@ -99,25 +99,31 @@ void Application::CheckForUpdates() {
Application::SetSubsystemStatus("UpdateCheck", Application::Status::Starting); Application::SetSubsystemStatus("UpdateCheck", Application::Status::Starting);
// checks current version against latest version // checks current version against latest version
std::regex VersionRegex { R"(\d+\.\d+\.\d+\n*)" }; std::regex VersionRegex { R"(\d+\.\d+\.\d+\n*)" };
auto Response = Http::GET(GetBackendHostname(), 443, "/v/s"); for (const auto& url : GetBackendUrlsInOrder()) {
bool Matches = std::regex_match(Response, VersionRegex); auto Response = Http::GET(GetBackendUrlsInOrder().at(0), 443, "/v/s");
if (Matches) { bool Matches = std::regex_match(Response, VersionRegex);
auto MyVersion = ServerVersion(); if (Matches) {
auto RemoteVersion = Version(VersionStrToInts(Response)); auto MyVersion = ServerVersion();
if (IsOutdated(MyVersion, RemoteVersion)) { auto RemoteVersion = Version(VersionStrToInts(Response));
std::string RealVersionString = RemoteVersion.AsString(); if (IsOutdated(MyVersion, RemoteVersion)) {
beammp_warn(std::string(ANSI_YELLOW_BOLD) + "NEW VERSION OUT! There's a new version (v" + RealVersionString + ") of the BeamMP-Server available! For more info visit https://wiki.beammp.com/en/home/server-maintenance#updating-the-server." + std::string(ANSI_RESET)); std::string RealVersionString = RemoteVersion.AsString();
beammp_warn(std::string(ANSI_YELLOW_BOLD) + "NEW VERSION OUT! There's a new version (v" + RealVersionString + ") of the BeamMP-Server available! For more info visit https://wiki.beammp.com/en/home/server-maintenance#updating-the-server." + std::string(ANSI_RESET));
} else {
beammp_info("Server up-to-date!");
}
Application::SetSubsystemStatus("UpdateCheck", Application::Status::Good);
break;
} else { } else {
beammp_info("Server up-to-date!"); beammp_debug("Failed to fetch version from: " + url);
beammp_trace("got " + Response);
auto Lock = Sentry.CreateExclusiveContext();
Sentry.SetContext("get-response", { { "response", Response } });
Sentry.LogError("failed to get server version", _file_basename, _line);
Application::SetSubsystemStatus("UpdateCheck", Application::Status::Bad);
} }
Application::SetSubsystemStatus("UpdateCheck", Application::Status::Good); }
} else { if (Application::GetSubsystemStatuses().at("UpdateCheck") == Application::Status::Bad) {
beammp_warn("Unable to fetch version from backend."); beammp_warn("Unable to fetch version info from backend.");
beammp_trace("got " + Response);
auto Lock = Sentry.CreateExclusiveContext();
Sentry.SetContext("get-response", { { "response", Response } });
Sentry.LogError("failed to get server version", _file_basename, _line);
Application::SetSubsystemStatus("UpdateCheck", Application::Status::Bad);
} }
} }
+6 -2
View File
@@ -4,6 +4,7 @@
#include "Common.h" #include "Common.h"
#include "CustomAssert.h" #include "CustomAssert.h"
#include "LuaAPI.h" #include "LuaAPI.h"
#include "httplib.h"
#include <map> #include <map>
#include <random> #include <random>
@@ -33,17 +34,20 @@ std::string Http::GET(const std::string& host, int port, const std::string& targ
} }
} }
std::string Http::POST(const std::string& host, int port, const std::string& target, const std::string& body, const std::string& ContentType, unsigned int* status) { std::string Http::POST(const std::string& host, int port, const std::string& target, const std::string& body, const std::string& ContentType, unsigned int* status, const httplib::Headers& headers) {
httplib::SSLClient client(host, port); httplib::SSLClient client(host, port);
client.set_read_timeout(std::chrono::seconds(10));
beammp_assert(client.is_valid());
client.enable_server_certificate_verification(false); client.enable_server_certificate_verification(false);
client.set_address_family(AF_INET); client.set_address_family(AF_INET);
auto res = client.Post(target.c_str(), body.c_str(), body.size(), ContentType.c_str()); auto res = client.Post(target.c_str(), headers, body.c_str(), body.size(), ContentType.c_str());
if (res) { if (res) {
if (status) { if (status) {
*status = res->status; *status = res->status;
} }
return res->body; return res->body;
} else { } else {
beammp_debug("POST failed: " + httplib::to_string(res.error()));
return Http::ErrorString; return Http::ErrorString;
} }
} }
+1 -5
View File
@@ -369,10 +369,6 @@ TConsole::TConsole() {
mCommandline.set_history_limit(20); mCommandline.set_history_limit(20);
mCommandline.set_prompt("> "); mCommandline.set_prompt("> ");
BackupOldLog(); BackupOldLog();
bool success = mCommandline.enable_write_to_file("Server.log");
if (!success) {
beammp_error("unable to open file for writing: \"Server.log\"");
}
mCommandline.on_command = [this](Commandline& c) { mCommandline.on_command = [this](Commandline& c) {
try { try {
auto cmd = c.get_command(); auto cmd = c.get_command();
@@ -386,7 +382,7 @@ TConsole::TConsole() {
} else { } else {
auto Future = mLuaEngine->EnqueueScript(mStateId, { std::make_shared<std::string>(cmd), "", "" }); auto Future = mLuaEngine->EnqueueScript(mStateId, { std::make_shared<std::string>(cmd), "", "" });
while (!Future->Ready) { while (!Future->Ready) {
std::this_thread::sleep_for(std::chrono::milliseconds(1)); // TODO: Add a timeout std::this_thread::yield(); // TODO: Add a timeout
} }
if (Future->Error) { if (Future->Error) {
beammp_lua_error(Future->ErrorMessage); beammp_lua_error(Future->ErrorMessage);
+59 -26
View File
@@ -54,43 +54,76 @@ void THeartbeatThread::operator()() {
auto Target = "/heartbeat"; auto Target = "/heartbeat";
unsigned int ResponseCode = 0; unsigned int ResponseCode = 0;
T = Http::POST(Application::GetBackendHostname(), 443, Target, Body, "application/x-www-form-urlencoded", &ResponseCode);
if ((T.substr(0, 2) != "20" && ResponseCode != 200) || ResponseCode != 200) { json::Document Doc;
beammp_trace("got " + T + " from backend"); bool Ok = false;
Application::SetSubsystemStatus("Heartbeat", Application::Status::Bad); for (const auto& Url : Application::GetBackendUrlsInOrder()) {
SentryReportError(Application::GetBackendHostname() + Target, ResponseCode); T = Http::POST(Url, 443, Target, Body, "application/x-www-form-urlencoded", &ResponseCode, { { "api-v", "2" } });
std::this_thread::sleep_for(std::chrono::milliseconds(500)); beammp_trace(T);
T = Http::POST(Application::GetBackup1Hostname(), 443, Target, Body, "application/x-www-form-urlencoded", &ResponseCode); Doc.Parse(T.data(), T.size());
if ((T.substr(0, 2) != "20" && ResponseCode != 200) || ResponseCode != 200) { if (Doc.HasParseError() || !Doc.IsObject()) {
SentryReportError(Application::GetBackup1Hostname() + Target, ResponseCode); beammp_error("Backend response failed to parse as valid json");
Application::SetSubsystemStatus("Heartbeat", Application::Status::Bad); beammp_debug("Response was: `" + T + "`");
std::this_thread::sleep_for(std::chrono::milliseconds(500)); Sentry.SetContext("JSON Response", { { "reponse", T } });
T = Http::POST(Application::GetBackup2Hostname(), 443, Target, Body, "application/x-www-form-urlencoded", &ResponseCode); SentryReportError(Url + Target, ResponseCode);
if ((T.substr(0, 2) != "20" && ResponseCode != 200) || ResponseCode != 200) { } else if (ResponseCode != 200) {
beammp_warn("Backend system refused server! Server will not show in the public server list."); SentryReportError(Url + Target, ResponseCode);
Application::SetSubsystemStatus("Heartbeat", Application::Status::Bad);
isAuth = false;
SentryReportError(Application::GetBackup2Hostname() + Target, ResponseCode);
} else {
Application::SetSubsystemStatus("Heartbeat", Application::Status::Good);
}
} else { } else {
Application::SetSubsystemStatus("Heartbeat", Application::Status::Good); // all ok
Ok = true;
break;
}
std::this_thread::sleep_for(std::chrono::milliseconds(500));
}
std::string Status {};
std::string Code {};
std::string Message {};
const auto StatusKey = "status";
const auto CodeKey = "code";
const auto MessageKey = "msg";
if (Ok) {
if (Doc.HasMember(StatusKey) && Doc[StatusKey].IsString()) {
Status = Doc[StatusKey].GetString();
} else {
Sentry.SetContext("JSON Response", { { StatusKey, "invalid string / missing" } });
Ok = false;
}
if (Doc.HasMember(CodeKey) && Doc[CodeKey].IsString()) {
Code = Doc[CodeKey].GetString();
} else {
Sentry.SetContext("JSON Response", { { CodeKey, "invalid string / missing" } });
Ok = false;
}
if (Doc.HasMember(MessageKey) && Doc[MessageKey].IsString()) {
Message = Doc[MessageKey].GetString();
} else {
Sentry.SetContext("JSON Response", { { MessageKey, "invalid string / missing" } });
Ok = false;
}
if (!Ok) {
beammp_error("Missing/invalid json members in backend response");
Sentry.LogError("Missing/invalid json members in backend response", __FILE__, std::to_string(__LINE__));
} }
} else {
Application::SetSubsystemStatus("Heartbeat", Application::Status::Good);
} }
if (!isAuth) { if (Ok && !isAuth) {
if (T == "2000") { if (Status == "2000") {
beammp_info(("Authenticated!")); beammp_info(("Authenticated!"));
isAuth = true; isAuth = true;
} else if (T == "200") { } else if (Status == "200") {
beammp_info(("Resumed authenticated session!")); beammp_info(("Resumed authenticated session!"));
isAuth = true; isAuth = true;
} else {
if (Message.empty()) {
Message = "Backend didn't provide a reason";
}
beammp_error("Backend REFUSED the auth key. " + Message);
} }
} }
if (isAuth) {
Application::SetSubsystemStatus("Heartbeat", Application::Status::Good);
}
} }
} }
+14 -20
View File
@@ -54,25 +54,17 @@ void TLuaEngine::operator()() {
auto ResultCheckThread = std::thread([&] { auto ResultCheckThread = std::thread([&] {
RegisterThread("ResultCheckThread"); RegisterThread("ResultCheckThread");
while (!mShutdown) { while (!mShutdown) {
std::this_thread::sleep_for(std::chrono::milliseconds(100)); std::this_thread::sleep_for(std::chrono::milliseconds(10));
std::unique_lock Lock(mResultsToCheckMutex); std::unique_lock Lock(mResultsToCheckMutex);
if (!mResultsToCheck.empty()) { if (!mResultsToCheck.empty()) {
auto Res = mResultsToCheck.front(); auto Res = mResultsToCheck.front();
mResultsToCheck.pop(); mResultsToCheck.pop();
Lock.unlock(); Lock.unlock();
size_t Waited = 0; if (!Res->Ready) {
while (!Res->Ready) { Lock.lock();
std::this_thread::sleep_for(std::chrono::milliseconds(1)); mResultsToCheck.push(Res);
Waited++; Lock.unlock();
if (Waited > 250) {
// FIXME: This should *eventually* timeout.
// beammp_lua_error(Res->Function + " in " + Res->StateId + " took >1s to respond, not printing possible errors");
Lock.lock();
mResultsToCheck.push(Res);
Lock.unlock();
break;
}
} }
if (Res->Error) { if (Res->Error) {
if (Res->ErrorMessage != BeamMPFnNotFoundError) { if (Res->ErrorMessage != BeamMPFnNotFoundError) {
@@ -80,13 +72,14 @@ void TLuaEngine::operator()() {
} }
} }
} }
std::this_thread::yield();
} }
}); });
// 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) { if (mLuaStates.size() == 0) {
std::this_thread::sleep_for(std::chrono::seconds(500)); std::this_thread::sleep_for(std::chrono::seconds(100));
} }
{ // Timed Events Scope { // Timed Events Scope
std::unique_lock Lock(mTimedEventsMutex); std::unique_lock Lock(mTimedEventsMutex);
@@ -149,6 +142,11 @@ TLuaStateId TLuaEngine::GetStateIDForPlugin(const fs::path& PluginPath) {
return ""; return "";
} }
void TLuaEngine::AddResultToCheck(const std::shared_ptr<TLuaResult>& Result) {
std::unique_lock Lock(mResultsToCheckMutex);
mResultsToCheck.push(Result);
}
void TLuaEngine::WaitForAll(std::vector<std::shared_ptr<TLuaResult>>& Results, const std::optional<std::chrono::high_resolution_clock::duration>& Max) { void TLuaEngine::WaitForAll(std::vector<std::shared_ptr<TLuaResult>>& Results, const std::optional<std::chrono::high_resolution_clock::duration>& Max) {
for (const auto& Result : Results) { for (const auto& Result : Results) {
bool Cancelled = false; bool Cancelled = false;
@@ -705,6 +703,7 @@ void TLuaEngine::StateThreadData::AddPath(const fs::path& Path) {
void TLuaResult::WaitUntilReady() { void TLuaResult::WaitUntilReady() {
while (!Ready) { while (!Ready) {
std::this_thread::yield();
std::this_thread::sleep_for(std::chrono::milliseconds(10)); std::this_thread::sleep_for(std::chrono::milliseconds(10));
} }
} }
@@ -762,12 +761,7 @@ void TPluginMonitor::operator()() {
auto StateID = mEngine.GetStateIDForPlugin(fs::path(Pair.first).parent_path()); auto StateID = mEngine.GetStateIDForPlugin(fs::path(Pair.first).parent_path());
auto Res = mEngine.EnqueueScript(StateID, Chunk); auto Res = mEngine.EnqueueScript(StateID, Chunk);
// TODO: call onInit // TODO: call onInit
while (!Res->Ready) { mEngine.AddResultToCheck(Res);
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
if (Res->Error) {
beammp_lua_error(Res->ErrorMessage);
}
} else { } else {
// TODO: trigger onFileChanged event // TODO: trigger onFileChanged event
beammp_trace("Change detected in file \"" + Pair.first + "\", event trigger not implemented yet"); beammp_trace("Change detected in file \"" + Pair.first + "\", event trigger not implemented yet");
+8
View File
@@ -187,7 +187,11 @@ void TNetwork::Identify(const TConnection& client) {
} else if (Code == 'D') { } else if (Code == 'D') {
HandleDownload(client.Socket); HandleDownload(client.Socket);
} else if (Code == 'P') { } else if (Code == 'P') {
#if defined(BEAMMP_LINUX) || defined(BEAMMP_APPLE)
send(client.Socket, "P", 1, MSG_NOSIGNAL);
#else
send(client.Socket, "P", 1, 0); send(client.Socket, "P", 1, 0);
#endif
CloseSocketProper(client.Socket); CloseSocketProper(client.Socket);
return; return;
} else { } else {
@@ -778,7 +782,11 @@ void TNetwork::SplitLoad(TClient& c, size_t Sent, size_t Size, bool D, const std
bool TNetwork::TCPSendRaw(TClient& C, SOCKET socket, char* Data, int32_t Size) { bool TNetwork::TCPSendRaw(TClient& C, SOCKET socket, char* Data, int32_t Size) {
intmax_t Sent = 0; intmax_t Sent = 0;
do { do {
#if defined(BEAMMP_LINUX) || defined(BEAMMP_APPLE)
intmax_t Temp = send(socket, &Data[Sent], int(Size - Sent), MSG_NOSIGNAL);
#else
intmax_t Temp = send(socket, &Data[Sent], int(Size - Sent), 0); intmax_t Temp = send(socket, &Data[Sent], int(Size - Sent), 0);
#endif
if (Temp < 1) { if (Temp < 1) {
beammp_info("Socket Closed! " + std::to_string(socket)); beammp_info("Socket Closed! " + std::to_string(socket));
CloseSocketProper(socket); CloseSocketProper(socket);
+2 -2
View File
@@ -21,8 +21,8 @@ TPPSMonitor::TPPSMonitor(TServer& Server)
void TPPSMonitor::operator()() { void TPPSMonitor::operator()() {
RegisterThread("PPSMonitor"); RegisterThread("PPSMonitor");
while (!mNetwork) { while (!mNetwork) {
// hard spi // hard(-ish) spin
std::this_thread::sleep_for(std::chrono::milliseconds(1)); std::this_thread::yield();
} }
beammp_debug("PPSMonitor starting"); beammp_debug("PPSMonitor starting");
Application::SetSubsystemStatus("PPSMonitor", Application::Status::Good); Application::SetSubsystemStatus("PPSMonitor", Application::Status::Good);
+14 -16
View File
@@ -7,14 +7,14 @@
#include <any> #include <any>
#include <sstream> #include <sstream>
#include <nlohmann/json.hpp>
#include "LuaAPI.h" #include "LuaAPI.h"
#undef GetObject // Fixes Windows #undef GetObject // Fixes Windows
#include "Json.h" #include "Json.h"
namespace json = rapidjson;
TServer::TServer(const std::vector<std::string_view>& Arguments) { TServer::TServer(const std::vector<std::string_view>& Arguments) {
beammp_info("BeamMP Server v" + Application::ServerVersionString()); beammp_info("BeamMP Server v" + Application::ServerVersionString());
Application::SetSubsystemStatus("Server", Application::Status::Starting); Application::SetSubsystemStatus("Server", Application::Status::Starting);
@@ -171,27 +171,25 @@ void TServer::HandleEvent(TClient& c, const std::string& Data) {
} }
} }
bool TServer::IsUnicycle(TClient& c, const std::string& CarJson) { bool TServer::IsUnicycle(TClient& c, const std::string& CarJson) {
rapidjson::Document Car; try {
Car.Parse(CarJson.c_str(), CarJson.size()); auto Car = nlohmann::json::parse(CarJson);
if (Car.HasParseError()) { const std::string jbm = "jbm";
beammp_error("Failed to parse vehicle data -> " + CarJson); if (Car.contains(jbm) && Car[jbm].is_string() && Car[jbm] == "unicycle") {
} else if (Car["jbm"].IsString() && std::string(Car["jbm"].GetString()) == "unicycle") { return true;
return true; }
} catch (const std::exception& e) {
beammp_error("Failed to parse vehicle data as json for client " + std::to_string(c.GetID()) + ": '" + CarJson + "'");
} }
return false; return false;
} }
bool TServer::ShouldSpawn(TClient& c, const std::string& CarJson, int ID) { bool TServer::ShouldSpawn(TClient& c, const std::string& CarJson, int ID) {
if (IsUnicycle(c, CarJson) && c.GetUnicycleID() < 0) {
if (c.GetUnicycleID() > -1 && (c.GetCarCount() - 1) < Application::Settings.MaxCars) {
return true;
}
if (IsUnicycle(c, CarJson)) {
c.SetUnicycleID(ID); c.SetUnicycleID(ID);
return true; return true;
} else {
return c.GetCarCount() < Application::Settings.MaxCars;
} }
return Application::Settings.MaxCars > c.GetCarCount();
} }
void TServer::ParseVehicle(TClient& c, const std::string& Pckt, TNetwork& Network) { void TServer::ParseVehicle(TClient& c, const std::string& Pckt, TNetwork& Network) {
+8 -4
View File
@@ -78,10 +78,6 @@ int main(int argc, char** argv) {
int BeamMPServerMain(MainArguments Arguments) { int BeamMPServerMain(MainArguments Arguments) {
setlocale(LC_ALL, "C"); setlocale(LC_ALL, "C");
Application::InitializeConsole(); Application::InitializeConsole();
Application::SetSubsystemStatus("Main", Application::Status::Starting);
SetupSignalHandlers();
ArgsParser Parser; ArgsParser Parser;
Parser.RegisterArgument({ "help" }, ArgsParser::NONE); Parser.RegisterArgument({ "help" }, ArgsParser::NONE);
Parser.RegisterArgument({ "version" }, ArgsParser::NONE); Parser.RegisterArgument({ "version" }, ArgsParser::NONE);
@@ -122,6 +118,14 @@ int BeamMPServerMain(MainArguments Arguments) {
} }
} }
Application::SetSubsystemStatus("Main", Application::Status::Starting);
bool Success = Application::Console().Internal().enable_write_to_file("Server.log");
if (!Success) {
beammp_error("unable to open file for writing: \"Server.log\"");
}
SetupSignalHandlers();
bool Shutdown = false; bool Shutdown = false;
Application::RegisterShutdownHandler([&Shutdown] { Application::RegisterShutdownHandler([&Shutdown] {
Application::SetSubsystemStatus("Main", Application::Status::ShuttingDown); Application::SetSubsystemStatus("Main", Application::Status::ShuttingDown);