mirror of
https://github.com/SantaSpeen/BeamMP-Server.git
synced 2026-02-16 13:00:40 +00:00
Compare commits
33 Commits
release-3-
...
rc-v3.0.1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
daa674f448 | ||
|
|
a85fef15c2 | ||
|
|
359faee696 | ||
|
|
299004b14e | ||
|
|
b09f5a401d | ||
|
|
8ce3be03a3 | ||
|
|
687b4e4235 | ||
|
|
86ad28abdc | ||
|
|
a982d54202 | ||
|
|
5553aca0bb | ||
|
|
beaea4f624 | ||
|
|
a4f07c9a4d | ||
|
|
dada8fe6bf | ||
|
|
36853ca683 | ||
|
|
d969c4a2c2 | ||
|
|
f26ca6b40d | ||
|
|
b72de4bd0a | ||
|
|
9494bc70fb | ||
|
|
5c44a307bc | ||
|
|
754053e73f | ||
|
|
29f8d29e33 | ||
|
|
e043361abb | ||
|
|
fca5bbcec9 | ||
|
|
2a588954be | ||
|
|
cd4129e05d | ||
|
|
c42c748b37 | ||
|
|
179b33a7ab | ||
|
|
1b14206a3c | ||
|
|
0cf81cf3f4 | ||
|
|
801780bcb1 | ||
|
|
84d52578e0 | ||
|
|
c3ab4b729a | ||
|
|
464aa3b59f |
11
.github/workflows/cmake-windows.yml
vendored
11
.github/workflows/cmake-windows.yml
vendored
@@ -44,4 +44,15 @@ jobs:
|
||||
name: 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
|
||||
|
||||
|
||||
5
.gitmodules
vendored
5
.gitmodules
vendored
@@ -21,4 +21,7 @@
|
||||
url = https://github.com/nih-at/libzip
|
||||
[submodule "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
|
||||
|
||||
@@ -8,12 +8,15 @@ project(BeamMP-Server
|
||||
HOMEPAGE_URL https://beammp.com
|
||||
LANGUAGES CXX C)
|
||||
|
||||
set(HTTPLIB_REQUIRE_OPENSSL ON)
|
||||
|
||||
include_directories("${PROJECT_SOURCE_DIR}/deps/asio/asio/include")
|
||||
include_directories("${PROJECT_SOURCE_DIR}/deps/rapidjson/include")
|
||||
include_directories("${PROJECT_SOURCE_DIR}/deps/websocketpp")
|
||||
include_directories("${PROJECT_SOURCE_DIR}/deps/commandline")
|
||||
include_directories("${PROJECT_SOURCE_DIR}/deps/sol2/include")
|
||||
include_directories("${PROJECT_SOURCE_DIR}/deps/cpp-httplib")
|
||||
include_directories("${PROJECT_SOURCE_DIR}/deps/json/single_include")
|
||||
include_directories("${PROJECT_SOURCE_DIR}/deps")
|
||||
|
||||
add_compile_definitions(CPPHTTPLIB_OPENSSL_SUPPORT)
|
||||
@@ -38,9 +41,25 @@ set(SENTRY_BUILD_SHARED_LIBS OFF)
|
||||
if (MSVC)
|
||||
set(SENTRY_BUILD_RUNTIMESTATIC ON)
|
||||
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")
|
||||
|
||||
if (MSVC)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /bigobj")
|
||||
endif ()
|
||||
|
||||
message(STATUS "Setting compiler flags")
|
||||
if (WIN32)
|
||||
|
||||
@@ -58,17 +77,6 @@ elseif (UNIX)
|
||||
endif (SANITIZE)
|
||||
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")
|
||||
# this has to happen before -DDEBUG since it wont compile properly with -DDEBUG
|
||||
|
||||
12
Changelog.md
12
Changelog.md
@@ -1,4 +1,14 @@
|
||||
# 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 moved *almost all* Lua functions into MP.\*
|
||||
|
||||
65
README.md
65
README.md
@@ -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/).
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
**__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)).
|
||||
|
||||
@@ -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/).
|
||||
|
||||
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.
|
||||
|
||||
- `git`
|
||||
- `make`
|
||||
- `cmake`
|
||||
- `g++`
|
||||
- `libcurl4-openssl-dev` or similar (search for `libcurl` and look for one with `-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).
|
||||
- `liblua5.3-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
|
||||
Runtime dependencies for **linux** are (debian/ubuntu):
|
||||
```
|
||||
libz-dev
|
||||
rapidjson-dev
|
||||
liblua5.3
|
||||
libssl-dev
|
||||
libwebsocketpp-dev
|
||||
libcurl4-openssl-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
|
||||
Build-time dependencies for **linux** are:
|
||||
```
|
||||
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
|
||||
|
||||
@@ -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
|
||||
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`.
|
||||
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 `.`)
|
||||
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.
|
||||
|
||||
2
deps/commandline
vendored
2
deps/commandline
vendored
Submodule deps/commandline updated: 3d11606d02...71240f634b
2
deps/cpp-httplib
vendored
2
deps/cpp-httplib
vendored
Submodule deps/cpp-httplib updated: 301faa074c...b324921c1a
1
deps/json
vendored
Submodule
1
deps/json
vendored
Submodule
Submodule deps/json added at eb21824147
@@ -42,7 +42,7 @@ public:
|
||||
std::string Key {};
|
||||
std::string SSLKeyPath { "./.ssl/HttpServer/key.pem" };
|
||||
std::string SSLCertPath { "./.ssl/HttpServer/cert.pem" };
|
||||
bool HTTPServerEnabled { true };
|
||||
bool HTTPServerEnabled { false };
|
||||
int MaxPlayers { 10 };
|
||||
bool Private { true };
|
||||
int MaxCars { 1 };
|
||||
@@ -74,10 +74,15 @@ public:
|
||||
|
||||
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 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 void CheckForUpdates();
|
||||
static std::array<uint8_t, 3> VersionStrToInts(const std::string& str);
|
||||
@@ -114,7 +119,7 @@ private:
|
||||
static inline std::mutex mShutdownHandlersMutex {};
|
||||
static inline std::deque<TShutdownHandler> mShutdownHandlers {};
|
||||
|
||||
static inline Version mVersion { 3, 0, 0 };
|
||||
static inline Version mVersion { 3, 0, 1 };
|
||||
};
|
||||
|
||||
std::string ThreadName(bool DebugModeOverride = false);
|
||||
|
||||
@@ -25,7 +25,7 @@ constexpr size_t RSA_DEFAULT_KEYLENGTH { 2048 };
|
||||
|
||||
namespace Http {
|
||||
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 {
|
||||
std::string ToString(int code);
|
||||
}
|
||||
|
||||
@@ -149,6 +149,7 @@ public:
|
||||
void CancelEventTimers(const std::string& EventName, TLuaStateId StateId);
|
||||
sol::state_view GetStateForPlugin(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";
|
||||
|
||||
|
||||
@@ -99,25 +99,31 @@ void Application::CheckForUpdates() {
|
||||
Application::SetSubsystemStatus("UpdateCheck", Application::Status::Starting);
|
||||
// checks current version against latest version
|
||||
std::regex VersionRegex { R"(\d+\.\d+\.\d+\n*)" };
|
||||
auto Response = Http::GET(GetBackendHostname(), 443, "/v/s");
|
||||
bool Matches = std::regex_match(Response, VersionRegex);
|
||||
if (Matches) {
|
||||
auto MyVersion = ServerVersion();
|
||||
auto RemoteVersion = Version(VersionStrToInts(Response));
|
||||
if (IsOutdated(MyVersion, RemoteVersion)) {
|
||||
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));
|
||||
for (const auto& url : GetBackendUrlsInOrder()) {
|
||||
auto Response = Http::GET(GetBackendUrlsInOrder().at(0), 443, "/v/s");
|
||||
bool Matches = std::regex_match(Response, VersionRegex);
|
||||
if (Matches) {
|
||||
auto MyVersion = ServerVersion();
|
||||
auto RemoteVersion = Version(VersionStrToInts(Response));
|
||||
if (IsOutdated(MyVersion, RemoteVersion)) {
|
||||
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 {
|
||||
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 {
|
||||
beammp_warn("Unable to fetch version 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);
|
||||
}
|
||||
if (Application::GetSubsystemStatuses().at("UpdateCheck") == Application::Status::Bad) {
|
||||
beammp_warn("Unable to fetch version info from backend.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include "Common.h"
|
||||
#include "CustomAssert.h"
|
||||
#include "LuaAPI.h"
|
||||
#include "httplib.h"
|
||||
|
||||
#include <map>
|
||||
#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);
|
||||
client.set_read_timeout(std::chrono::seconds(10));
|
||||
beammp_assert(client.is_valid());
|
||||
client.enable_server_certificate_verification(false);
|
||||
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 (status) {
|
||||
*status = res->status;
|
||||
}
|
||||
return res->body;
|
||||
} else {
|
||||
beammp_debug("POST failed: " + httplib::to_string(res.error()));
|
||||
return Http::ErrorString;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -369,10 +369,6 @@ TConsole::TConsole() {
|
||||
mCommandline.set_history_limit(20);
|
||||
mCommandline.set_prompt("> ");
|
||||
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) {
|
||||
try {
|
||||
auto cmd = c.get_command();
|
||||
@@ -386,7 +382,7 @@ TConsole::TConsole() {
|
||||
} else {
|
||||
auto Future = mLuaEngine->EnqueueScript(mStateId, { std::make_shared<std::string>(cmd), "", "" });
|
||||
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) {
|
||||
beammp_lua_error(Future->ErrorMessage);
|
||||
|
||||
@@ -54,43 +54,76 @@ void THeartbeatThread::operator()() {
|
||||
|
||||
auto Target = "/heartbeat";
|
||||
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) {
|
||||
beammp_trace("got " + T + " from backend");
|
||||
Application::SetSubsystemStatus("Heartbeat", Application::Status::Bad);
|
||||
SentryReportError(Application::GetBackendHostname() + Target, ResponseCode);
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(500));
|
||||
T = Http::POST(Application::GetBackup1Hostname(), 443, Target, Body, "application/x-www-form-urlencoded", &ResponseCode);
|
||||
if ((T.substr(0, 2) != "20" && ResponseCode != 200) || ResponseCode != 200) {
|
||||
SentryReportError(Application::GetBackup1Hostname() + Target, ResponseCode);
|
||||
Application::SetSubsystemStatus("Heartbeat", Application::Status::Bad);
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(500));
|
||||
T = Http::POST(Application::GetBackup2Hostname(), 443, Target, Body, "application/x-www-form-urlencoded", &ResponseCode);
|
||||
if ((T.substr(0, 2) != "20" && ResponseCode != 200) || ResponseCode != 200) {
|
||||
beammp_warn("Backend system refused server! Server will not show in the public server list.");
|
||||
Application::SetSubsystemStatus("Heartbeat", Application::Status::Bad);
|
||||
isAuth = false;
|
||||
SentryReportError(Application::GetBackup2Hostname() + Target, ResponseCode);
|
||||
} else {
|
||||
Application::SetSubsystemStatus("Heartbeat", Application::Status::Good);
|
||||
}
|
||||
json::Document Doc;
|
||||
bool Ok = false;
|
||||
for (const auto& Url : Application::GetBackendUrlsInOrder()) {
|
||||
T = Http::POST(Url, 443, Target, Body, "application/x-www-form-urlencoded", &ResponseCode, { { "api-v", "2" } });
|
||||
beammp_trace(T);
|
||||
Doc.Parse(T.data(), T.size());
|
||||
if (Doc.HasParseError() || !Doc.IsObject()) {
|
||||
beammp_error("Backend response failed to parse as valid json");
|
||||
beammp_debug("Response was: `" + T + "`");
|
||||
Sentry.SetContext("JSON Response", { { "reponse", T } });
|
||||
SentryReportError(Url + Target, ResponseCode);
|
||||
} else if (ResponseCode != 200) {
|
||||
SentryReportError(Url + Target, ResponseCode);
|
||||
} 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 (T == "2000") {
|
||||
if (Ok && !isAuth) {
|
||||
if (Status == "2000") {
|
||||
beammp_info(("Authenticated!"));
|
||||
isAuth = true;
|
||||
} else if (T == "200") {
|
||||
} else if (Status == "200") {
|
||||
beammp_info(("Resumed authenticated session!"));
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -54,25 +54,17 @@ void TLuaEngine::operator()() {
|
||||
auto ResultCheckThread = std::thread([&] {
|
||||
RegisterThread("ResultCheckThread");
|
||||
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);
|
||||
if (!mResultsToCheck.empty()) {
|
||||
auto Res = mResultsToCheck.front();
|
||||
mResultsToCheck.pop();
|
||||
Lock.unlock();
|
||||
|
||||
size_t Waited = 0;
|
||||
while (!Res->Ready) {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
||||
Waited++;
|
||||
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->Ready) {
|
||||
Lock.lock();
|
||||
mResultsToCheck.push(Res);
|
||||
Lock.unlock();
|
||||
}
|
||||
if (Res->Error) {
|
||||
if (Res->ErrorMessage != BeamMPFnNotFoundError) {
|
||||
@@ -80,13 +72,14 @@ void TLuaEngine::operator()() {
|
||||
}
|
||||
}
|
||||
}
|
||||
std::this_thread::yield();
|
||||
}
|
||||
});
|
||||
// event loop
|
||||
auto Before = std::chrono::high_resolution_clock::now();
|
||||
while (!mShutdown) {
|
||||
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
|
||||
std::unique_lock Lock(mTimedEventsMutex);
|
||||
@@ -149,6 +142,11 @@ TLuaStateId TLuaEngine::GetStateIDForPlugin(const fs::path& PluginPath) {
|
||||
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) {
|
||||
for (const auto& Result : Results) {
|
||||
bool Cancelled = false;
|
||||
@@ -705,6 +703,7 @@ void TLuaEngine::StateThreadData::AddPath(const fs::path& Path) {
|
||||
|
||||
void TLuaResult::WaitUntilReady() {
|
||||
while (!Ready) {
|
||||
std::this_thread::yield();
|
||||
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 Res = mEngine.EnqueueScript(StateID, Chunk);
|
||||
// TODO: call onInit
|
||||
while (!Res->Ready) {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||
}
|
||||
if (Res->Error) {
|
||||
beammp_lua_error(Res->ErrorMessage);
|
||||
}
|
||||
mEngine.AddResultToCheck(Res);
|
||||
} else {
|
||||
// TODO: trigger onFileChanged event
|
||||
beammp_trace("Change detected in file \"" + Pair.first + "\", event trigger not implemented yet");
|
||||
|
||||
@@ -187,7 +187,11 @@ void TNetwork::Identify(const TConnection& client) {
|
||||
} else if (Code == 'D') {
|
||||
HandleDownload(client.Socket);
|
||||
} 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);
|
||||
#endif
|
||||
CloseSocketProper(client.Socket);
|
||||
return;
|
||||
} 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) {
|
||||
intmax_t Sent = 0;
|
||||
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);
|
||||
#endif
|
||||
if (Temp < 1) {
|
||||
beammp_info("Socket Closed! " + std::to_string(socket));
|
||||
CloseSocketProper(socket);
|
||||
|
||||
@@ -21,8 +21,8 @@ TPPSMonitor::TPPSMonitor(TServer& Server)
|
||||
void TPPSMonitor::operator()() {
|
||||
RegisterThread("PPSMonitor");
|
||||
while (!mNetwork) {
|
||||
// hard spi
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
||||
// hard(-ish) spin
|
||||
std::this_thread::yield();
|
||||
}
|
||||
beammp_debug("PPSMonitor starting");
|
||||
Application::SetSubsystemStatus("PPSMonitor", Application::Status::Good);
|
||||
|
||||
@@ -7,14 +7,14 @@
|
||||
#include <any>
|
||||
#include <sstream>
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
#include "LuaAPI.h"
|
||||
|
||||
#undef GetObject // Fixes Windows
|
||||
|
||||
#include "Json.h"
|
||||
|
||||
namespace json = rapidjson;
|
||||
|
||||
TServer::TServer(const std::vector<std::string_view>& Arguments) {
|
||||
beammp_info("BeamMP Server v" + Application::ServerVersionString());
|
||||
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) {
|
||||
rapidjson::Document Car;
|
||||
Car.Parse(CarJson.c_str(), CarJson.size());
|
||||
if (Car.HasParseError()) {
|
||||
beammp_error("Failed to parse vehicle data -> " + CarJson);
|
||||
} else if (Car["jbm"].IsString() && std::string(Car["jbm"].GetString()) == "unicycle") {
|
||||
return true;
|
||||
try {
|
||||
auto Car = nlohmann::json::parse(CarJson);
|
||||
const std::string jbm = "jbm";
|
||||
if (Car.contains(jbm) && Car[jbm].is_string() && Car[jbm] == "unicycle") {
|
||||
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;
|
||||
}
|
||||
|
||||
bool TServer::ShouldSpawn(TClient& c, const std::string& CarJson, int ID) {
|
||||
|
||||
if (c.GetUnicycleID() > -1 && (c.GetCarCount() - 1) < Application::Settings.MaxCars) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (IsUnicycle(c, CarJson)) {
|
||||
if (IsUnicycle(c, CarJson) && c.GetUnicycleID() < 0) {
|
||||
c.SetUnicycleID(ID);
|
||||
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) {
|
||||
|
||||
12
src/main.cpp
12
src/main.cpp
@@ -78,10 +78,6 @@ int main(int argc, char** argv) {
|
||||
int BeamMPServerMain(MainArguments Arguments) {
|
||||
setlocale(LC_ALL, "C");
|
||||
Application::InitializeConsole();
|
||||
Application::SetSubsystemStatus("Main", Application::Status::Starting);
|
||||
|
||||
SetupSignalHandlers();
|
||||
|
||||
ArgsParser Parser;
|
||||
Parser.RegisterArgument({ "help" }, 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;
|
||||
Application::RegisterShutdownHandler([&Shutdown] {
|
||||
Application::SetSubsystemStatus("Main", Application::Status::ShuttingDown);
|
||||
|
||||
Reference in New Issue
Block a user