Compare commits

...

44 Commits

Author SHA1 Message Date
Lion Kortlepel 588242822c CMake: Remove socketio link, forgot 2021-09-09 12:33:59 +03:00
Lion Kortlepel 58da200901 Client: fix socklen_t compile error 2021-09-09 12:32:33 +03:00
Lion Kortlepel f4ccf6c177 add sentry native db folder to gitignore 2021-09-09 12:26:26 +03:00
Lion Kortlepel 27103a73a9 remove socket.io module 2021-09-09 12:26:03 +03:00
Lion Kortlepel 2727f90430 Remove Socket.io for now
it is being built every time and we dont need it
2021-09-09 12:25:08 +03:00
Lion Kortlepel 2a96546c8c Lua: Add GetPluginName, GetPluginPath 2021-09-09 12:15:57 +03:00
Lion Kortlepel 6462636b29 Multiple merge fixes, rebase, working Https::GET 2021-09-09 12:15:55 +03:00
Lion Kortlepel 5742ab0dad possible windows compiler fix 2021-09-09 12:15:19 +03:00
Lion Kortlepel 0087205d55 fix issues caused by rebase 2021-09-09 12:15:17 +03:00
Lion Kortlepel d16843e45d TNetwork: clarify error messages 2021-09-09 12:14:32 +03:00
Lion Kortlepel 24516dbfd7 TNetwork: setsockopt: cast optval to void* 2021-09-09 12:14:32 +03:00
Lion Kortlepel a311d58e11 TNetwork: reuseaddr instead of reuseport 2021-09-09 12:14:32 +03:00
Lion Kortlepel 1444d91e7e Common: missed semicolon 2021-09-09 12:14:32 +03:00
Lion Kortlepel 1e2f060107 improve error reporting, remove duplicate code 2021-09-09 12:14:32 +03:00
Lion Kortlepel fdb5da2ed6 CMake: remove mentions of luasocket again 2021-09-09 12:14:32 +03:00
Lion Kortlepel de57613326 remove luasocket-cmake 2021-09-09 12:14:32 +03:00
Lion Kortlepel b49782e8a3 Common: Add sstream include for std::stringstream 2021-09-09 12:14:32 +03:00
Lion Kortlepel ff80b4cf63 CMake: include luasocket after finding lua 2021-09-09 12:14:32 +03:00
Lion Kortlepel 4c23b78f84 add luasocket 2021-09-09 12:14:32 +03:00
Lion Kortlepel aca3c52c20 remove luasocket again 2021-09-09 12:14:32 +03:00
Lion Kortlepel 51d6c4fb0a add CMakeLists for lib/ 2021-09-09 12:14:32 +03:00
Lion Kortlepel 2af9491fd6 add luasocket submodule 2021-09-09 12:14:32 +03:00
Lion Kortlepel 95c036836e add ws2tcpip.h 2021-09-09 12:14:32 +03:00
Lion Kortlepel a7f2f85e45 fix version printing 2021-09-09 12:14:32 +03:00
Lion Kortlepel 42c5aaad5a use inet_ntop instead of inet_ntoa (STILL BROKEN THOUGH) 2021-09-09 12:14:32 +03:00
Lion Kortlepel 88684bd9af clarify installation 2021-09-09 12:14:32 +03:00
Lion Kortlepel c6457f7df4 Add Settings enum, better print 2021-09-09 12:14:32 +03:00
Lion Kortlepel ba3fd0e144 add GetServerVersion 2021-09-09 12:14:30 +03:00
Lion Kortlepel e3b6fd7998 use fake version for lua update for now 2021-09-09 12:13:45 +03:00
Lion Kortlepel 943159cd40 Lua: add onShutdown 2021-09-09 12:13:37 +03:00
Lion Kortlepel 9423831937 add ip to identifiers, changed value format 2021-09-09 12:13:34 +03:00
Lion Kortlepel 95188042c5 fix luatable in GetPlayerIdentifiers 2021-09-09 12:12:54 +03:00
Lion Kortlepel a0a7b8ecce fix comment 2021-09-09 12:12:54 +03:00
Lion Kortlepel 53617abae4 Add printRaw
Same as print() but does not prefix with time, date, filename, etc.
Use with care.
2021-09-09 12:12:54 +03:00
Lion Kortlepel 853b078124 add MP.HttpsGET, MP.HttpsPOST 2021-09-09 12:12:54 +03:00
Anonymous-275 549517c518 TODO edit 2021-09-09 12:12:54 +03:00
Anonymous-275 2be4b8fd91 Fully working lua_Register 2021-09-09 12:12:54 +03:00
Lion Kortlepel 2cfb27820a switch to toml11
it's better, believe me
2021-09-09 12:12:54 +03:00
Anonymous-275 1ff12cb2bf simpler lua_Register 2021-09-09 12:12:54 +03:00
Lion Kortlepel 518cb0664e rebase 2021-09-09 12:12:54 +03:00
Lion Kortlepel 80432eb718 implement GetOSName, start working on HttpsPOST 2021-09-09 12:12:54 +03:00
Anonymous-275 b1caf5c29a lua Register 2021-09-09 12:12:54 +03:00
Lion Kortlepel 950cee9fd0 README: fix git submodule update command 2021-09-09 12:12:54 +03:00
Lion Kortlepel 046097579e README: ensure that submodules are initialized recursively 2021-09-09 12:12:53 +03:00
28 changed files with 592 additions and 553 deletions
+1
View File
@@ -1,4 +1,5 @@
.idea/
.sentry-native/
*.orig
*.toml
boost_*
+4 -7
View File
@@ -1,18 +1,15 @@
[submodule "include/commandline"]
path = include/commandline
url = https://github.com/lionkor/commandline
[submodule "socket.io-client-cpp"]
path = socket.io-client-cpp
url = https://github.com/socketio/socket.io-client-cpp
[submodule "asio"]
path = asio
url = https://github.com/chriskohlhoff/asio
[submodule "rapidjson"]
path = rapidjson
url = https://github.com/Tencent/rapidjson
[submodule "include/tomlplusplus"]
path = include/tomlplusplus
url = https://github.com/marzer/tomlplusplus
[submodule "include/toml11"]
path = include/toml11
url = https://github.com/ToruNiina/toml11
[submodule "include/sentry-native"]
path = include/sentry-native
url = https://github.com/getsentry/sentry-native
url = https://github.com/getsentry/sentry-native
+11 -4
View File
@@ -1,5 +1,10 @@
cmake_minimum_required(VERSION 3.0)
message(STATUS "You can find build instructions and a list of dependencies in the README at \
https://github.com/BeamMP/BeamMP-Server")
@@ -25,6 +30,7 @@ add_subdirectory("include/sentry-native")
message(STATUS "Setting compiler flags")
if (WIN32)
#-DCMAKE_TOOLCHAIN_FILE=C:/vcpkg/scripts/buildsystems/vcpkg.cmake -DVCPKG_TARGET_TRIPLET=x64-windows-static
set(VcpkgRoot ${_VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET})
include_directories(${VcpkgRoot}/include)
@@ -56,10 +62,12 @@ message(STATUS "Adding local source dependencies")
include_directories("asio/asio/include")
include_directories("rapidjson/include")
include_directories("websocketpp")
add_subdirectory("socket.io-client-cpp")
add_subdirectory("include/commandline")
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DDEBUG")
message(STATUS "Looking for Boost")
@@ -95,12 +103,13 @@ target_include_directories(BeamMP-Server PUBLIC
${Boost_INCLUDE_DIRS}
${LUA_INCLUDE_DIR}
${CURL_INCLUDE_DIRS}
"socket.io-client-cpp/src"
"include/tomlplusplus"
"include/sentry-native/include"
"include/curl/include")
message(STATUS "Looking for SSL")
find_package(OpenSSL REQUIRED)
message(STATUS "CURL IS ${CURL_LIBRARIES}")
@@ -114,7 +123,6 @@ if (UNIX)
crypto
${OPENSSL_LIBRARIES}
commandline
sioclient_tls
sentry)
elseif (WIN32)
include(FindLua)
@@ -129,6 +137,5 @@ elseif (WIN32)
${LUA_LIBRARIES}
${OPENSSL_LIBRARIES}
commandline
sioclient_tls
sentry)
endif ()
+7 -1
View File
@@ -75,12 +75,18 @@ These package names are in the debian / ubuntu style. Feel free to PR your own g
**If** you're building it from source, you'll need `libboost1.70-all-dev` or `libboost1.71-all-dev` or higher as well.
If you can't find this version of boost (only 1.6x, for example), you can either update to a newer version of your distro, build boost yourself, or use an unstable rolling release (like Debian `sid` aka `unstable`).
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 libboost1.71-all-dev
```
### How to build
On windows, use git-bash for these commands. On Linux, these should work in your shell.
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`**. Now change into the cloned directory by running `cd 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`.
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).
5. Run `cmake .` (with `.`)
+14 -3
View File
@@ -12,6 +12,17 @@
class TServer;
#ifdef WIN32
// for socklen_t
#include <WS2tcpip.h>
#endif // WIN32
struct TConnection final {
SOCKET Socket;
struct sockaddr SockAddr;
socklen_t SockAddrLen;
};
class TClient final {
public:
using TSetOfVehicleData = std::vector<TVehicleData>;
@@ -30,7 +41,7 @@ public:
TVehicleDataLockPair GetAllCars();
void SetName(const std::string& Name) { mName = Name; }
void SetRoles(const std::string& Role) { mRole = Role; }
void AddIdentifier(const std::string& ID) { mIdentifiers.insert(ID); };
void SetIdentifier(const std::string& key, const std::string& value) { mIdentifiers[key] = value; }
std::string GetCarData(int Ident);
void SetUDPAddr(sockaddr_in Addr) { mUDPAddress = Addr; }
void SetDownSock(SOCKET CSock) { mSocket[1] = CSock; }
@@ -38,7 +49,7 @@ public:
void SetStatus(int Status) { mStatus = Status; }
// locks
void DeleteCar(int Ident);
[[nodiscard]] std::set<std::string> GetIdentifiers() const { return mIdentifiers; }
[[nodiscard]] const std::unordered_map<std::string, std::string>& GetIdentifiers() const { return mIdentifiers; }
[[nodiscard]] sockaddr_in GetUDPAddr() const { return mUDPAddress; }
[[nodiscard]] SOCKET GetDownSock() const { return mSocket[1]; }
[[nodiscard]] SOCKET GetTCPSock() const { return mSocket[0]; }
@@ -78,7 +89,7 @@ private:
bool mIsSyncing = false;
mutable std::mutex mMissedPacketsMutex;
std::queue<std::string> mPacketsSync;
std::set<std::string> mIdentifiers;
std::unordered_map<std::string, std::string> mIdentifiers;
bool mIsGuest = false;
std::mutex mVehicleDataMutex;
TSetOfVehicleData mVehicleData;
+23 -4
View File
@@ -5,13 +5,26 @@ extern TSentry Sentry;
#include <array>
#include <atomic>
#include <cstring>
#include <deque>
#include <functional>
#include <memory>
#include <mutex>
#include <sstream>
#include "Compat.h"
#include "TConsole.h"
struct Version {
uint8_t major;
uint8_t minor;
uint8_t patch;
Version(uint8_t major, uint8_t minor, uint8_t patch);
Version(const std::array<uint8_t, 3>& v);
std::string AsString();
};
// static class handling application start, shutdown, etc.
// yes, static classes, singletons, globals are all pretty
// bad idioms. In this case we need a central way to access
@@ -44,6 +57,7 @@ public:
std::string CustomIP;
[[nodiscard]] bool HasCustomIP() const { return !CustomIP.empty(); }
};
using TShutdownHandler = std::function<void()>;
// methods
@@ -54,8 +68,9 @@ public:
// Causes all threads to finish up and exit gracefull gracefully
static void GracefullyShutdown();
static TConsole& Console() { return *mConsole; }
static std::string ServerVersion() { return "2.3.1"; }
static std::string ClientVersion() { return "2.0"; }
static std::string ServerVersionString();
static const Version& ServerVersion() { return mVersion; }
static std::string ClientVersionString() { return "2.0"; }
static std::string PPS() { return mPPS; }
static void SetPPS(const std::string& NewPPS) { mPPS = NewPPS; }
@@ -67,14 +82,16 @@ public:
static std::string GetBackup2Hostname() { return "backup2.beammp.com"; }
static std::string GetBackendUrlForSocketIO() { return "https://backend.beammp.com"; }
static void CheckForUpdates();
static std::array<int, 3> VersionStrToInts(const std::string& str);
static bool IsOutdated(const std::array<int, 3>& Current, const std::array<int, 3>& Newest);
static std::array<uint8_t, 3> VersionStrToInts(const std::string& str);
static bool IsOutdated(const Version& Current, const Version& Newest);
private:
static inline std::string mPPS;
static std::unique_ptr<TConsole> mConsole;
static inline std::mutex mShutdownHandlersMutex {};
static inline std::deque<TShutdownHandler> mShutdownHandlers {};
static inline Version mVersion { 2, 4, 0 };
};
std::string ThreadName(bool DebugModeOverride = false);
@@ -146,3 +163,5 @@ void LogChatMessage(const std::string& name, int id, const std::string& msg);
#define Biggest 30000
std::string Comp(std::string Data);
std::string DeComp(std::string Compressed);
std::string GetPlatformAgnosticErrorString();
+3 -1
View File
@@ -7,6 +7,7 @@
#include <sys/socket.h>
#include <termios.h>
#include <unistd.h>
#include <errno.h>
using SOCKET = int;
using DWORD = unsigned long;
using PDWORD = unsigned long*;
@@ -26,6 +27,7 @@ inline void CloseSocketProper(int TheSocket) {
inline void CloseSocketProper(SOCKET TheSocket) {
shutdown(TheSocket, 2); // 2 == SD_BOTH
closesocket(TheSocket);
}
#endif // WIN32
@@ -33,4 +35,4 @@ inline void CloseSocketProper(SOCKET TheSocket) {
#if !defined(WIN32) && !defined(__unix)
#error "OS not supported"
#endif
#endif
+2 -1
View File
@@ -5,8 +5,9 @@
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, const std::string& target, const std::unordered_map<std::string, std::string>& fields, const std::string& body, bool json, int* status = nullptr);
std::string POST(const std::string& host, int port, const std::string& target, const std::unordered_map<std::string, std::string>& fields, const std::string& body, const std::string& ContentType, unsigned int* status = nullptr);
namespace Status {
std::string ToString(int code);
}
const std::string ErrorString = "-1";
}
-69
View File
@@ -1,69 +0,0 @@
#pragma once
#include <atomic>
#include <deque>
#include <mutex>
#include <sio_client.h>
#include <thread>
#include <memory>
/*
* We send relevant server events over socket.io to the backend.
*
* We send all events to `backend.beammp.com`, to the room `/key`
* where `key` is the currently active auth-key.
*/
enum class SocketIOEvent {
ConsoleOut,
CPUUsage,
MemoryUsage,
NetworkUsage,
PlayerList,
};
enum class SocketIORoom {
None,
Stats,
Player,
Info,
Console,
};
class SocketIO final {
private:
struct Event;
public:
enum class EventType {
};
// Singleton pattern
static SocketIO& Get();
void Emit(SocketIOEvent Event, const std::string& Data);
~SocketIO();
void SetAuthenticated(bool auth) { mAuthenticated = auth; }
private:
SocketIO() noexcept;
void ThreadMain();
struct Event {
std::string Name;
std::string Data;
};
bool mAuthenticated { false };
sio::client mClient;
std::thread mThread;
std::atomic_bool mCloseThread { false };
std::mutex mQueueMutex;
std::deque<Event> mQueue;
friend std::unique_ptr<SocketIO> std::make_unique<SocketIO>();
};
+2
View File
@@ -10,6 +10,8 @@ public:
[[nodiscard]] bool Failed() const { return mFailed; }
void FlushToFile();
private:
void CreateConfigFile(std::string_view name);
void ParseFromFile(std::string_view name);
+1 -1
View File
@@ -18,4 +18,4 @@ private:
bool mShutdown = false;
TResourceManager& mResourceManager;
TServer& mServer;
};
};
+3 -1
View File
@@ -4,10 +4,11 @@
#include "IThreaded.h"
#include "TLuaFile.h"
#include "TServer.h"
#include <optional>
#include <lua.hpp>
#include <memory>
#include <optional>
#include <set>
#include <unordered_map>
class TLuaEngine : public IThreaded {
public:
@@ -25,6 +26,7 @@ public:
std::optional<std::reference_wrapper<TLuaFile>> GetScript(lua_State* L);
static std::unordered_map<std::string, lua_State*> mGlobals;
private:
void FolderList(const std::string& Path, bool HotSwap);
void RegisterFiles(const fs::path& Path, bool HotSwap);
+7 -6
View File
@@ -37,12 +37,13 @@ public:
~TLuaFile();
void SetStopThread(bool StopThread) { mStopThread = StopThread; }
TLuaEngine& Engine() { return mEngine; }
[[nodiscard]] std::string GetPluginName() const;
[[nodiscard]] std::string GetFileName() const;
[[nodiscard]] const lua_State* GetState() const;
[[nodiscard]] bool GetStopThread() const { return mStopThread; }
[[nodiscard]] const TLuaEngine& Engine() const { return mEngine; }
[[nodiscard]] std::string GetRegistered(const std::string& Event) const;
std::string GetPluginPath() const;
std::string GetPluginName() const;
std::string GetFileName() const;
const lua_State* GetState() const;
bool GetStopThread() const { return mStopThread; }
const TLuaEngine& Engine() const { return mEngine; }
std::string GetRegistered(const std::string& Event) const;
private:
TLuaEngine& mEngine;
+4 -2
View File
@@ -4,6 +4,8 @@
#include "TResourceManager.h"
#include "TServer.h"
struct TConnection;
class TNetwork {
public:
TNetwork(TServer& Server, TPPSMonitor& PPSMonitor, TResourceManager& ResourceManager);
@@ -15,8 +17,8 @@ public:
std::string TCPRcv(TClient& c);
void ClientKick(TClient& c, const std::string& R);
[[nodiscard]] bool SyncClient(const std::weak_ptr<TClient>& c);
void Identify(SOCKET TCPSock);
void Authentication(SOCKET TCPSock);
void Identify(const TConnection& client);
void Authentication(const TConnection& ClientConnection);
[[nodiscard]] bool CheckBytes(TClient& c, int32_t BytesRcv);
void SyncResources(TClient& c);
[[nodiscard]] bool UDPSend(TClient& Client, std::string Data) const;
+1
Submodule include/toml11 added at 647381020e
+57 -13
View File
@@ -30,10 +30,14 @@ void Application::GracefullyShutdown() {
}
}
std::array<int, 3> Application::VersionStrToInts(const std::string& str) {
std::array<int, 3> Version;
std::string Application::ServerVersionString() {
return mVersion.AsString();
}
std::array<uint8_t, 3> Application::VersionStrToInts(const std::string& str) {
std::array<uint8_t, 3> Version;
std::stringstream ss(str);
for (int& i : Version) {
for (uint8_t& i : Version) {
std::string Part;
std::getline(ss, Part, '.');
std::from_chars(&*Part.begin(), &*Part.begin() + Part.size(), i);
@@ -41,12 +45,13 @@ std::array<int, 3> Application::VersionStrToInts(const std::string& str) {
return Version;
}
bool Application::IsOutdated(const std::array<int, 3>& Current, const std::array<int, 3>& Newest) {
if (Newest[0] > Current[0]) {
// FIXME: This should be used by operator< on Version
bool Application::IsOutdated(const Version& Current, const Version& Newest) {
if (Newest.major > Current.major) {
return true;
} else if (Newest[0] == Current[0] && Newest[1] > Current[1]) {
} else if (Newest.major == Current.major && Newest.minor > Current.minor) {
return true;
} else if (Newest[0] == Current[0] && Newest[1] == Current[1] && Newest[2] > Current[2]) {
} else if (Newest.major == Current.major && Newest.minor == Current.minor && Newest.patch > Current.patch) {
return true;
} else {
return false;
@@ -59,12 +64,10 @@ void Application::CheckForUpdates() {
auto Response = Http::GET(GetBackendHostname(), 443, "/v/s");
bool Matches = std::regex_match(Response, VersionRegex);
if (Matches) {
auto MyVersion = VersionStrToInts(ServerVersion());
auto RemoteVersion = VersionStrToInts(Response);
auto MyVersion = ServerVersion();
auto RemoteVersion = Version(VersionStrToInts(Response));
if (IsOutdated(MyVersion, RemoteVersion)) {
std::string RealVersionString = std::to_string(RemoteVersion[0]) + ".";
RealVersionString += std::to_string(RemoteVersion[1]) + ".";
RealVersionString += std::to_string(RemoteVersion[2]);
std::string RealVersionString = RemoteVersion.AsString();
warn(std::string(ANSI_YELLOW_BOLD) + "NEW VERSION OUT! There's a new version (v" + RealVersionString + ") of the BeamMP-Server available! For info on how to update your server, visit https://wiki.beammp.com/en/home/server-maintenance#updating-the-server." + std::string(ANSI_RESET));
} else {
info("Server up-to-date!");
@@ -144,6 +147,21 @@ void RegisterThread(const std::string& str) {
threadNameMap[std::this_thread::get_id()] = str;
}
Version::Version(uint8_t major, uint8_t minor, uint8_t patch)
: major(major)
, minor(minor)
, patch(patch) { }
Version::Version(const std::array<uint8_t, 3>& v)
: Version(v[0], v[1], v[2]) {
}
std::string Version::AsString() {
std::stringstream ss {};
ss << int(major) << "." << int(minor) << "." << int(patch);
return ss.str();
}
void LogChatMessage(const std::string& name, int id, const std::string& msg) {
std::stringstream ss;
ss << "[CHAT] ";
@@ -153,5 +171,31 @@ void LogChatMessage(const std::string& name, int id, const std::string& msg) {
ss << name << "";
}
ss << msg;
Application::Console().Write(ss.str());
}
std::string GetPlatformAgnosticErrorString() {
#ifdef WIN32
// This will provide us with the error code and an error message, all in one.
int err;
char msgbuf[256];
msgbuf[0] = '\0';
err = GetLastError();
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
nullptr,
err,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
msgbuf,
sizeof(msgbuf),
nullptr);
if (*msgbuf) {
return std::to_string(GetLastError()) + " - " + std::string(msgbuf);
} else {
return std::to_string(GetLastError());
}
#else // posix
return std::strerror(errno);
#endif
}
+21 -88
View File
@@ -15,85 +15,7 @@ namespace net = boost::asio; // from <boost/asio.hpp>
namespace ssl = net::ssl; // from <boost/asio/ssl.hpp>
using tcp = net::ip::tcp; // from <boost/asio/ip/tcp.hpp>
std::string Http::GET(const std::string& host, int port, const std::string& target, unsigned int* status) {
try {
// Check command line arguments.
int version = 11;
// The io_context is required for all I/O
net::io_context ioc;
// The SSL context is required, and holds certificates
ssl::context ctx(ssl::context::tlsv12_client);
// This holds the root certificate used for verification
// we don't do / have this
// load_root_certificates(ctx);
// Verify the remote server's certificate
ctx.set_verify_mode(ssl::verify_none);
// These objects perform our I/O
tcp::resolver resolver(ioc);
beast::ssl_stream<beast::tcp_stream> stream(ioc, ctx);
// Set SNI Hostname (many hosts need this to handshake successfully)
if (!SSL_set_tlsext_host_name(stream.native_handle(), host.c_str())) {
beast::error_code ec { static_cast<int>(::ERR_get_error()), net::error::get_ssl_category() };
throw beast::system_error { ec };
}
// Look up the domain name
auto const results = resolver.resolve(host.c_str(), std::to_string(port));
// Make the connection on the IP address we get from a lookup
beast::get_lowest_layer(stream).connect(results);
// Perform the SSL handshake
stream.handshake(ssl::stream_base::client);
// Set up an HTTP GET request message
http::request<http::string_body> req { http::verb::get, target, version };
req.set(http::field::host, host);
req.set(http::field::user_agent, BOOST_BEAST_VERSION_STRING);
// Send the HTTP request to the remote host
http::write(stream, req);
// This buffer is used for reading and must be persisted
beast::flat_buffer buffer;
// Declare a container to hold the response
http::response<http::string_body> res;
// Receive the HTTP response
http::read(stream, buffer, res);
// Gracefully close the stream
beast::error_code ec;
stream.shutdown(ec);
if (ec == net::error::eof) {
// Rationale:
// http://stackoverflow.com/questions/25587403/boost-asio-ssl-async-shutdown-always-finishes-with-an-error
ec = {};
}
if (status) {
*status = res.base().result_int();
}
// ignore ec
// If we get here then the connection is closed gracefully
return std::string(res.body());
} catch (std::exception const& e) {
Application::Console().Write(__func__ + std::string(": ") + e.what());
return "-1";
}
}
std::string Http::POST(const std::string& host, const std::string& target, const std::unordered_map<std::string, std::string>& fields, const std::string& body, bool json, int* status) {
std::string GenericRequest(http::verb verb, const std::string& host, int port, const std::string& target, const std::unordered_map<std::string, std::string>& fields, const std::string& body, const std::string& ContentType, unsigned int* status) {
try {
net::io_context io;
@@ -107,7 +29,7 @@ std::string Http::POST(const std::string& host, const std::string& target, const
decltype(resolver)::results_type results;
auto try_connect_with_protocol = [&](tcp protocol) {
try {
results = resolver.resolve(protocol, host, std::to_string(443));
results = resolver.resolve(protocol, host, std::to_string(port));
if (!SSL_set_tlsext_host_name(stream.native_handle(), host.c_str())) {
boost::system::error_code ec { static_cast<int>(::ERR_get_error()), boost::asio::error::get_ssl_category() };
// FIXME: we could throw and crash, if we like
@@ -131,15 +53,13 @@ std::string Http::POST(const std::string& host, const std::string& target, const
}
//}
stream.handshake(ssl::stream_base::client);
http::request<http::string_body> req { http::verb::post, target, 11 /* http 1.1 */ };
http::request<http::string_body> req { verb, target, 11 /* http 1.1 */ };
req.set(http::field::host, host);
if (!body.empty()) {
if (json) {
req.set(http::field::content_type, "application/json");
} else {
req.set(http::field::content_type, "application/x-www-form-urlencoded");
}
req.set(http::field::content_type, ContentType); // "application/json"
// "application/x-www-form-urlencoded"
req.set(http::field::content_length, std::to_string(body.size()));
req.body() = body;
// info("body is " + body + " (" + req.body() + ")");
@@ -187,6 +107,10 @@ std::string Http::POST(const std::string& host, const std::string& target, const
}
Sentry.SetContext("https-post-response-data", response_data);
if (status) {
*status = response.base().result_int();
}
std::stringstream result;
result << response;
@@ -197,15 +121,24 @@ std::string Http::POST(const std::string& host, const std::string& target, const
// info(result.str());
std::string debug_response_str;
std::getline(result, debug_response_str);
//debug("POST " + host + target + ": " + debug_response_str);
return std::string(response.body());
} catch (const std::exception& e) {
Application::Console().Write(e.what());
return "-1";
Application::Console().Write(__func__ + std::string(": ") + e.what());
return Http::ErrorString;
}
}
std::string Http::GET(const std::string& host, int port, const std::string& target, unsigned int* status) {
return GenericRequest(http::verb::get, host, port, target, {}, {}, {}, status);
}
std::string Http::POST(const std::string& host, int port, const std::string& target, const std::unordered_map<std::string, std::string>& fields, const std::string& body, const std::string& ContentType, unsigned int* status) {
return GenericRequest(http::verb::post, host, port, target, fields, body, ContentType, status);
}
// RFC 2616, RFC 7231
static std::map<size_t, const char*> Map = {
{ 100, "Continue" },
-98
View File
@@ -1,98 +0,0 @@
#include "SocketIO.h"
#include "Common.h"
#include <iostream>
//TODO Default disabled with config option
static std::unique_ptr<SocketIO> SocketIOInstance = std::make_unique<SocketIO>();
SocketIO& SocketIO::Get() {
return *SocketIOInstance;
}
SocketIO::SocketIO() noexcept
: mThread([this] { ThreadMain(); }) {
mClient.socket()->on("network", [&](sio::event&e) {
if(e.get_message()->get_string() == "Welcome"){
info("SocketIO Authenticated!");
mAuthenticated = true;
}
});
mClient.socket()->on("welcome", [&](sio::event&) {
info("Got welcome from backend! Authenticating SocketIO...");
mClient.socket()->emit("onInitConnection", Application::Settings.Key);
});
mClient.set_logs_quiet();
mClient.set_reconnect_delay(10000);
mClient.connect(Application::GetBackendUrlForSocketIO());
}
SocketIO::~SocketIO() {
mCloseThread.store(true);
mThread.join();
}
static constexpr auto EventNameFromEnum(SocketIOEvent Event) {
switch (Event) {
case SocketIOEvent::CPUUsage:
return "cpu usage";
case SocketIOEvent::MemoryUsage:
return "memory usage";
case SocketIOEvent::ConsoleOut:
return "console out";
case SocketIOEvent::NetworkUsage:
return "network usage";
case SocketIOEvent::PlayerList:
return "player list";
default:
error("unreachable code reached (developer error)");
abort();
}
}
void SocketIO::Emit(SocketIOEvent Event, const std::string& Data) {
if (!mAuthenticated) {
debug("trying to emit a socket.io event when not yet authenticated");
return;
}
std::string EventName = EventNameFromEnum(Event);
debug("emitting event \"" + EventName + "\" with data: \"" + Data);
std::unique_lock Lock(mQueueMutex);
mQueue.push_back({EventName, Data });
debug("queue now has " + std::to_string(mQueue.size()) + " events");
}
void SocketIO::ThreadMain() {
while (!mCloseThread.load()) {
bool empty;
{ // queue lock scope
std::unique_lock Lock(mQueueMutex);
empty = mQueue.empty();
} // end queue lock scope
if (empty || !mClient.opened()) {
std::this_thread::sleep_for(std::chrono::milliseconds(100));
continue;
} else {
Event TheEvent;
{ // queue lock scope
std::unique_lock Lock(mQueueMutex);
TheEvent = mQueue.front();
mQueue.pop_front();
} // end queue lock scope
debug("sending \"" + TheEvent.Name + "\" event");
mClient.socket()->emit(TheEvent.Name, TheEvent.Data);
debug("sent \"" + TheEvent.Name + "\" event");
}
}
// using std::cout as this happens during static destruction and the logger might be dead already
std::cout << "closing " + std::string(__func__) << std::endl;
mClient.sync_close();
mClient.clear_con_listeners();
std::cout << "closed" << std::endl;
}
+47 -70
View File
@@ -1,4 +1,6 @@
#include <toml.hpp> // header-only version of TOML++
#define TOML11_PRESERVE_COMMENTS_BY_DEFAULT
#include <toml11/toml.hpp> // header-only version of TOML++
#include "TConfig.h"
#include <fstream>
@@ -32,6 +34,23 @@ TConfig::TConfig() {
}
}
void TConfig::FlushToFile() {
auto data = toml::parse(ConfigFileName);
data["General"] = toml::table();
data["General"][StrAuthKey.data()] = Application::Settings.Key;
data["General"][StrDebug.data()] = Application::Settings.DebugModeEnabled;
data["General"][StrPrivate.data()] = Application::Settings.Private;
data["General"][StrPort.data()] = Application::Settings.Port;
data["General"][StrName.data()] = Application::Settings.ServerName;
data["General"][StrMaxCars.data()] = Application::Settings.MaxCars;
data["General"][StrMaxPlayers.data()] = Application::Settings.MaxPlayers;
data["General"][StrMap.data()] = Application::Settings.MapName;
data["General"][StrDescription.data()] = Application::Settings.ServerDesc;
data["General"][StrResourceFolder.data()] = Application::Settings.Resource;
std::ofstream Stream(ConfigFileName);
Stream << data << std::flush;
}
void TConfig::CreateConfigFile(std::string_view name) {
// build from old config Server.cfg
@@ -44,32 +63,31 @@ void TConfig::CreateConfigFile(std::string_view name) {
error("an error occurred and was ignored during config transfer: " + std::string(e.what()));
}
toml::table tbl { {
{ // create file context
std::ofstream ofs(name.data());
}
{ "General",
toml::table { {
auto data = toml::parse<toml::preserve_comments>(name.data());
{ StrDebug, Application::Settings.DebugModeEnabled },
{ StrPrivate, Application::Settings.Private },
{ StrPort, Application::Settings.Port },
{ StrMaxCars, Application::Settings.MaxCars },
{ StrMaxPlayers, Application::Settings.MaxPlayers },
{ StrMap, Application::Settings.MapName },
{ StrName, Application::Settings.ServerName },
{ StrDescription, Application::Settings.ServerDesc },
{ StrResourceFolder, Application::Settings.Resource },
{ StrAuthKey, Application::Settings.Key },
data["General"] = toml::table();
data["General"][StrAuthKey.data()] = Application::Settings.Key;
data["General"][StrDebug.data()] = Application::Settings.DebugModeEnabled;
data["General"][StrPrivate.data()] = Application::Settings.Private;
data["General"][StrPort.data()] = Application::Settings.Port;
data["General"][StrName.data()] = Application::Settings.ServerName;
data["General"][StrMaxCars.data()] = Application::Settings.MaxCars;
data["General"][StrMaxPlayers.data()] = Application::Settings.MaxPlayers;
data["General"][StrMap.data()] = Application::Settings.MapName;
data["General"][StrDescription.data()] = Application::Settings.ServerDesc;
data["General"][StrResourceFolder.data()] = Application::Settings.Resource;
} } },
} };
std::ofstream ofs { std::string(name) };
if (ofs.good()) {
ofs << "# 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://beammp.com/k/dashboard` on the left under \"Keys\"\n"
<< '\n';
ofs << tbl << '\n';
ofs << data << '\n';
error("There was no \"" + std::string(ConfigFileName) + "\" file (this is normal for the first time running the server), so one was generated for you. It was automatically filled with the settings from your Server.cfg, if you have one. Please open ServerConfig.toml and ensure your AuthKey and other settings are filled in and correct, then restart the server. The old Server.cfg file will no longer be used and causes a warning if it exists from now on.");
mFailed = true;
} else {
@@ -80,58 +98,17 @@ void TConfig::CreateConfigFile(std::string_view name) {
void TConfig::ParseFromFile(std::string_view name) {
try {
toml::table FullTable = toml::parse_file(name);
toml::table GeneralTable = *FullTable["General"].as_table();
if (auto val = GeneralTable[StrDebug].value<bool>(); val.has_value()) {
Application::Settings.DebugModeEnabled = val.value();
} else {
throw std::runtime_error(std::string(StrDebug));
}
if (auto val = GeneralTable[StrPrivate].value<bool>(); val.has_value()) {
Application::Settings.Private = val.value();
} else {
throw std::runtime_error(std::string(StrPrivate));
}
if (auto val = GeneralTable[StrPort].value<int>(); val.has_value()) {
Application::Settings.Port = val.value();
} else {
throw std::runtime_error(std::string(StrPort));
}
if (auto val = GeneralTable[StrMaxCars].value<int>(); val.has_value()) {
Application::Settings.MaxCars = val.value();
} else {
throw std::runtime_error(std::string(StrMaxCars));
}
if (auto val = GeneralTable[StrMaxPlayers].value<int>(); val.has_value()) {
Application::Settings.MaxPlayers = val.value();
} else {
throw std::runtime_error(std::string(StrMaxPlayers));
}
if (auto val = GeneralTable[StrMap].value<std::string>(); val.has_value()) {
Application::Settings.MapName = val.value();
} else {
throw std::runtime_error(std::string(StrMap));
}
if (auto val = GeneralTable[StrName].value<std::string>(); val.has_value()) {
Application::Settings.ServerName = val.value();
} else {
throw std::runtime_error(std::string(StrName));
}
if (auto val = GeneralTable[StrDescription].value<std::string>(); val.has_value()) {
Application::Settings.ServerDesc = val.value();
} else {
throw std::runtime_error(std::string(StrDescription));
}
if (auto val = GeneralTable[StrResourceFolder].value<std::string>(); val.has_value()) {
Application::Settings.Resource = val.value();
} else {
throw std::runtime_error(std::string(StrResourceFolder));
}
if (auto val = GeneralTable[StrAuthKey].value<std::string>(); val.has_value()) {
Application::Settings.Key = val.value();
} else {
throw std::runtime_error(std::string(StrAuthKey));
}
toml::value data = toml::parse<toml::preserve_comments>(name.data());
Application::Settings.DebugModeEnabled = data["General"][StrDebug.data()].as_boolean();
Application::Settings.Private = data["General"][StrPrivate.data()].as_boolean();
Application::Settings.Port = data["General"][StrPort.data()].as_integer();
Application::Settings.MaxCars = data["General"][StrMaxCars.data()].as_integer();
Application::Settings.MaxPlayers = data["General"][StrMaxPlayers.data()].as_integer();
Application::Settings.MapName = data["General"][StrMap.data()].as_string();
Application::Settings.ServerName = data["General"][StrName.data()].as_string();
Application::Settings.ServerDesc = data["General"][StrDescription.data()].as_string();
Application::Settings.Resource = data["General"][StrResourceFolder.data()].as_string();
Application::Settings.Key = data["General"][StrAuthKey.data()].as_string();
} catch (const std::exception& err) {
error("Error parsing config file value: " + std::string(err.what()));
mFailed = true;
+8 -6
View File
@@ -39,6 +39,7 @@ void THeartbeatThread::operator()() {
if (status < 0) {
status = 0;
}
auto Lock = Sentry.CreateExclusiveContext();
Sentry.SetContext("heartbeat",
{ { "response-body", T },
@@ -49,20 +50,21 @@ void THeartbeatThread::operator()() {
};
auto Target = "/heartbeat";
int ResponseCode = -1;
T = Http::POST(Application::GetBackendHostname(), Target, {}, Body, false, &ResponseCode);
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) {
trace("got " + T + " from backend");
SentryReportError(Application::GetBackendHostname() + Target, ResponseCode);
std::this_thread::sleep_for(std::chrono::milliseconds(500));
T = Http::POST(Application::GetBackup1Hostname(), Target, {}, Body, false, &ResponseCode);
T = Http::POST(Application::GetBackup1Hostname(), 443, Target, {}, Body, "application/x-www-form-urlencoded", &ResponseCode);
if (T.substr(0, 2) != "20" || ResponseCode != 200) {
SentryReportError(Application::GetBackup1Hostname() + Target, ResponseCode);
std::this_thread::sleep_for(std::chrono::milliseconds(500));
T = Http::POST(Application::GetBackup2Hostname(), Target, {}, Body, false, &ResponseCode);
T = Http::POST(Application::GetBackup2Hostname(), 443, Target, {}, Body, "application/x-www-form-urlencoded", &ResponseCode);
if (T.substr(0, 2) != "20" || ResponseCode != 200) {
warn("Backend system refused server! Server will not show in the public server list.");
isAuth = false;
SentryReportError(Application::GetBackup2Hostname() + Target, ResponseCode);
}
@@ -92,8 +94,8 @@ std::string THeartbeatThread::GenerateCall() {
<< "&port=" << Application::Settings.Port
<< "&map=" << Application::Settings.MapName
<< "&private=" << (Application::Settings.Private ? "true" : "false")
<< "&version=" << Application::ServerVersion()
<< "&clientversion=" << Application::ClientVersion()
<< "&version=" << Application::ServerVersionString()
<< "&clientversion=" << Application::ClientVersionString()
<< "&name=" << Application::Settings.ServerName
<< "&modlist=" << mResourceManager.TrimmedList()
<< "&modstotalsize=" << mResourceManager.MaxModSize()
+2
View File
@@ -6,6 +6,8 @@
namespace fs = std::filesystem;
std::unordered_map<std::string, lua_State*> TLuaEngine::mGlobals;
// necessary as lua relies on global state
TLuaEngine* TheEngine;
+318 -58
View File
@@ -3,14 +3,44 @@
#include "Common.h"
#include "CustomAssert.h"
#include "Defer.h"
#include "Http.h"
#include "TLuaEngine.h"
#include "TNetwork.h"
#include "TServer.h"
#include <functional>
#include <future>
#include <thread>
// TODO: REWRITE
namespace LuaTable {
void Begin(lua_State* L) {
lua_newtable(L);
}
void End(lua_State* L, const std::string& name) {
lua_setglobal(L, name.c_str());
}
void BeginEntry(lua_State* L, const std::string& name) {
lua_pushstring(L, name.c_str());
}
void EndEntry(lua_State* L) {
lua_settable(L, -3);
}
void InsertFunction(lua_State* L, const std::string& name, lua_CFunction func) {
BeginEntry(L, name);
lua_pushcfunction(L, func);
EndEntry(L);
}
void InsertInteger(lua_State* L, const std::string& name, lua_Integer i) {
BeginEntry(L, name);
lua_pushinteger(L, i);
EndEntry(L);
}
}
void SendError(TLuaEngine& Engine, lua_State* L, const std::string& msg);
std::any CallFunction(TLuaFile* lua, const std::string& FuncName, std::shared_ptr<TLuaArg> Arg);
@@ -40,11 +70,13 @@ std::shared_ptr<TLuaArg> CreateArg(lua_State* L, int T, int S) {
}
return temp;
}
void ClearStack(lua_State* L) {
lua_settop(L, 0);
}
std::any Trigger(TLuaFile* lua, const std::string& R, std::shared_ptr<TLuaArg> arg) {
std::lock_guard<std::mutex> lockGuard(lua->Lock);
std::packaged_task<std::any(std::shared_ptr<TLuaArg>)> task([lua, R](std::shared_ptr<TLuaArg> arg) { return CallFunction(lua, R, arg); });
std::future<std::any> f1 = task.get_future();
@@ -198,6 +230,7 @@ void ExecuteAsync(TLuaFile* lua, const std::string& FuncName) {
}
void CallAsync(TLuaFile* lua, const std::string& Func, int U) {
lua->SetStopThread(false);
int D = 1000 / U;
while (!lua->GetStopThread()) {
@@ -348,11 +381,11 @@ int lua_GetIdentifiers(lua_State* L) {
auto IDs = MaybeClient.value().lock()->GetIdentifiers();
if (IDs.empty())
return 0;
lua_newtable(L);
for (const std::string& ID : IDs) {
lua_pushstring(L, ID.substr(0, ID.find(':')).c_str());
lua_pushstring(L, ID.c_str());
lua_settable(L, -3);
LuaTable::Begin(L);
for (const auto& Pair : IDs) {
LuaTable::BeginEntry(L, Pair.first);
lua_pushstring(L, Pair.second.c_str());
LuaTable::EndEntry(L);
}
} else
return 0;
@@ -532,49 +565,49 @@ int lua_Set(lua_State* L) {
case 0: //debug
if (lua_isboolean(L, 2)) {
Application::Settings.DebugModeEnabled = lua_toboolean(L, 2);
info(Name + (" | Debug -> ") + (Application::Settings.DebugModeEnabled ? "true" : "false"));
info(Name + (" | Set `Debug` to ") + (Application::Settings.DebugModeEnabled ? "true" : "false"));
} else
SendError(Engine(), L, ("set invalid argument [2] expected boolean for ID : 0"));
break;
case 1: //private
if (lua_isboolean(L, 2)) {
Application::Settings.Private = lua_toboolean(L, 2);
info(Name + (" | Private -> ") + (Application::Settings.Private ? "true" : "false"));
info(Name + (" | Set `Private` to ") + (Application::Settings.Private ? "true" : "false"));
} else
SendError(Engine(), L, ("set invalid argument [2] expected boolean for ID : 1"));
break;
case 2: //max cars
if (lua_isnumber(L, 2)) {
Application::Settings.MaxCars = int(lua_tointeger(L, 2));
info(Name + (" | MaxCars -> ") + std::to_string(Application::Settings.MaxCars));
info(Name + (" | Set `MaxCars` to ") + std::to_string(Application::Settings.MaxCars));
} else
SendError(Engine(), L, ("set invalid argument [2] expected number for ID : 2"));
break;
case 3: //max players
if (lua_isnumber(L, 2)) {
Application::Settings.MaxPlayers = int(lua_tointeger(L, 2));
info(Name + (" | MaxPlayers -> ") + std::to_string(Application::Settings.MaxPlayers));
info(Name + (" | Set `MaxPlayers` to ") + std::to_string(Application::Settings.MaxPlayers));
} else
SendError(Engine(), L, ("set invalid argument [2] expected number for ID : 3"));
break;
case 4: //Map
if (lua_isstring(L, 2)) {
Application::Settings.MapName = lua_tostring(L, 2);
info(Name + (" | MapName -> ") + Application::Settings.MapName);
info(Name + (" | Set `Map` to ") + Application::Settings.MapName);
} else
SendError(Engine(), L, ("set invalid argument [2] expected string for ID : 4"));
break;
case 5: //Name
if (lua_isstring(L, 2)) {
Application::Settings.ServerName = lua_tostring(L, 2);
info(Name + (" | ServerName -> ") + Application::Settings.ServerName);
info(Name + (" | Set `Name` to ") + Application::Settings.ServerName);
} else
SendError(Engine(), L, ("set invalid argument [2] expected string for ID : 5"));
break;
case 6: //Desc
if (lua_isstring(L, 2)) {
Application::Settings.ServerDesc = lua_tostring(L, 2);
info(Name + (" | ServerDesc -> ") + Application::Settings.ServerDesc);
info(Name + (" | Set `Description` to ") + Application::Settings.ServerDesc);
} else
SendError(Engine(), L, ("set invalid argument [2] expected string for ID : 6"));
break;
@@ -582,12 +615,11 @@ int lua_Set(lua_State* L) {
warn(("Invalid config ID : ") + std::to_string(C));
break;
}
return 0;
}
extern "C" {
int lua_Print(lua_State* L) {
int InternalLuaPrint(lua_State* L, bool pretty) {
int Arg = lua_gettop(L);
std::string to_print;
for (int i = 1; i <= Arg; i++) {
@@ -620,12 +652,78 @@ int lua_Print(lua_State* L) {
to_print += "\t";
}
}
luaprint(to_print);
if (pretty) {
luaprint(to_print);
} else {
Application::Console().WriteRaw(to_print);
}
return 0;
}
int lua_Print(lua_State* L) {
return InternalLuaPrint(L, true);
}
int lua_PrintRaw(lua_State* L) {
return InternalLuaPrint(L, false);
}
}
int lua_TempFix(lua_State* L);
int lua_TempFix(lua_State* L) {
if (lua_isnumber(L, 1)) {
int ID = int(lua_tonumber(L, 1));
auto MaybeClient = GetClient(Engine().Server(), ID);
if (!MaybeClient || MaybeClient.value().expired())
return 0;
std::string Ret;
auto c = MaybeClient.value().lock();
if (c->IsGuest()) {
Ret = "Guest-" + c->GetName();
} else
Ret = c->GetName();
lua_pushstring(L, Ret.c_str());
} else
SendError(Engine(), L, "GetDID not enough arguments");
return 1;
}
int lua_Registered(lua_State* L) {
lua_Debug info;
lua_getstack(L, 0, &info);
lua_getinfo(L, "n", &info);
if (auto it = TLuaEngine::mGlobals.find(info.name); it != TLuaEngine::mGlobals.end()) {
lua_getglobal(it->second, info.name);
if (lua_isfunction(it->second, -1)) {
lua_pcall(it->second, 0, 0, 0); //TODO revisit to allow arguments and return also we need to mutex this
}
return 0;
}
SendError(Engine(), L, "Cannot find global '" + std::string(info.name) + "\'");
return 0;
}
int lua_Register(lua_State* L) {
if (lua_isstring(L, 1)) {
std::string Name(lua_tolstring(L, 1, nullptr));
lua_getglobal(L, Name.c_str());
if (lua_isfunction(L, -1)) {
TLuaEngine::mGlobals.emplace(Name, L);
for (auto& Script : Engine().LuaFiles()) {
if (Script->GetState() != L) {
lua_register(Script->GetState(), Name.c_str(), lua_Registered);
}
}
} else {
SendError(Engine(), L, Name + " is not a global function!");
ClearStack(L);
}
} else {
SendError(Engine(), L, "Wrong arguments to `Register`, expected string");
}
return 0;
}
void TLuaFile::Init(const std::string& PluginName, const std::string& FileName, fs::file_time_type LastWrote) {
auto Lock = std::unique_lock(mInitMutex);
@@ -670,6 +768,7 @@ std::string TLuaFile::GetOrigin() {
}
std::any CallFunction(TLuaFile* lua, const std::string& FuncName, std::shared_ptr<TLuaArg> Arg) {
lua_State* luaState = lua->GetState();
lua_getglobal(luaState, FuncName.c_str());
if (lua_isfunction(luaState, -1)) {
@@ -703,31 +802,203 @@ void TLuaFile::SetFileName(const std::string& Name) {
mFileName = Name;
}
// GetOSName() -> Linux || Windows || Other
int lua_GetOSName(lua_State* L) {
#if defined(__linux) || defined(__linux__)
lua_pushstring(L, "Linux");
#elif defined(WIN32)
lua_pushstring(L, "Windows");
#else
lua_pushstring(L, "Unknown");
#endif
return 1;
}
int lua_GetServerVersion(lua_State* L) {
const auto& ver = Application::ServerVersion();
lua_pushinteger(L, ver.major);
lua_pushinteger(L, ver.minor);
lua_pushinteger(L, ver.patch);
return 3;
}
// status, body = HttpsGET(host, port, target)
// example usage:
// send a GET https://example.com:443/index.html:
// status, body = MP.HttpGET("example.com", 443, "/index.html")
int lua_HttpsGET(lua_State* L) {
if (!lua_isstring(L, 1)) {
SendError(Engine(), L, "`HttpsGET` expects host (type string) as first argument.");
ClearStack(L);
return 0;
}
if (!lua_isnumber(L, 2)) {
SendError(Engine(), L, "`HttpsGET` expects port (type number) as second argument.");
ClearStack(L);
return 0;
}
if (!lua_isstring(L, 3)) {
SendError(Engine(), L, "`HttpsGET` expects target (type string) as third argument.");
ClearStack(L);
return 0;
}
auto Host = lua_tostring(L, 1);
auto Port = int(lua_tointeger(L, 2));
auto Target = lua_tostring(L, 3);
ClearStack(L);
unsigned int Status;
auto Body = Http::GET(Host, Port, Target, &Status);
lua_pushinteger(L, Status);
auto PrettyRemote = "https://" + std::string(Host) + ":" + std::to_string(Port) + std::string(Target);
if (Body == Http::ErrorString) {
SendError(Engine(), L, "HTTPS GET " + PrettyRemote + " failed status " + std::to_string(Status) + ". Check the console or log for more info.");
return 1;
} else {
debug("GET " + PrettyRemote + " completed status " + std::to_string(Status));
}
lua_pushstring(L, Body.c_str());
return 2;
}
// status, body = HttpsPOST(host, port, target, body, content_type)
int lua_HttpsPOST(lua_State* L) {
if (!lua_isstring(L, 1)) {
SendError(Engine(), L, "`HttpsPOST` expects host (type string) as 1. argument.");
ClearStack(L);
return 0;
}
if (!lua_isnumber(L, 2)) {
SendError(Engine(), L, "`HttpsPOST` expects port (type number) as 2. argument.");
ClearStack(L);
return 0;
}
if (!lua_isstring(L, 3)) {
SendError(Engine(), L, "`HttpsPOST` expects target (type string) as 3. argument.");
ClearStack(L);
return 0;
}
if (!lua_isstring(L, 4)) {
SendError(Engine(), L, "`HttpsPOST` expects body (type string) as 4. argument.");
ClearStack(L);
return 0;
}
if (!lua_isstring(L, 5)) {
SendError(Engine(), L, "`HttpsPOST` expects content_type (type string) as 5. argument.");
ClearStack(L);
return 0;
}
auto Host = lua_tostring(L, 1);
auto Port = int(lua_tointeger(L, 2));
auto Target = lua_tostring(L, 3);
auto RequestBody = lua_tostring(L, 4);
auto ContentType = lua_tostring(L, 5);
ClearStack(L);
// build fields
std::unordered_map<std::string, std::string> Fields;
unsigned int Status;
auto ResponseBody = Http::POST(Host, Port, Target, {}, RequestBody, ContentType, &Status);
lua_pushinteger(L, Status);
auto PrettyRemote = "https://" + std::string(Host) + ":" + std::to_string(Port) + std::string(Target);
if (ResponseBody == Http::ErrorString) {
SendError(Engine(), L, "HTTPS POST " + PrettyRemote + " failed status " + std::to_string(Status) + ". Check the console or log for more info.");
return 1;
} else {
debug("POST " + PrettyRemote + " completed status " + std::to_string(Status));
}
lua_pushstring(L, ResponseBody.c_str());
return 2;
}
int lua_GetPluginName(lua_State* L) {
auto MaybeFile = Engine().GetScript(L);
if (MaybeFile) {
lua_pushstring(L, MaybeFile.value().get().GetPluginName().c_str());
return 1;
} else {
warn("no plugin associated with this state");
return 0;
}
}
int lua_GetPluginPath(lua_State* L) {
auto MaybeFile = Engine().GetScript(L);
if (MaybeFile) {
lua_pushstring(L, MaybeFile.value().get().GetPluginPath().c_str());
return 1;
} else {
warn("no plugin associated with this state");
return 0;
}
}
int lua_Dump(lua_State* L) {
}
void TLuaFile::Load() {
Assert(mLuaState);
luaL_openlibs(mLuaState);
lua_register(mLuaState, "GetPlayerIdentifiers", lua_GetIdentifiers);
lua_register(mLuaState, "TriggerGlobalEvent", lua_TriggerEventG);
lua_register(mLuaState, "TriggerLocalEvent", lua_TriggerEventL);
lua_register(mLuaState, "TriggerClientEvent", lua_RemoteEvent);
lua_register(mLuaState, "GetPlayerCount", lua_GetPlayerCount);
lua_register(mLuaState, "isPlayerConnected", lua_isConnected);
lua_register(mLuaState, "RegisterEvent", lua_RegisterEvent);
lua_register(mLuaState, "GetPlayerName", lua_GetPlayerName);
lua_register(mLuaState, "RemoveVehicle", lua_RemoveVehicle);
lua_register(mLuaState, "GetPlayerDiscordID", lua_TempFix);
lua_register(mLuaState, "CreateThread", lua_CreateThread);
lua_register(mLuaState, "GetPlayerVehicles", lua_GetCars);
lua_register(mLuaState, "SendChatMessage", lua_sendChat);
lua_register(mLuaState, "GetPlayers", lua_GetAllPlayers);
lua_register(mLuaState, "GetPlayerGuest", lua_GetGuest);
lua_register(mLuaState, "StopThread", lua_StopThread);
lua_register(mLuaState, "DropPlayer", lua_dropPlayer);
lua_register(mLuaState, "GetPlayerHWID", lua_HWID);
lua_register(mLuaState, "exit", lua_ServerExit);
lua_register(mLuaState, "Sleep", lua_Sleep);
LuaTable::Begin(mLuaState);
LuaTable::BeginEntry(mLuaState, "Settings");
LuaTable::Begin(mLuaState);
// put Settings enums here
LuaTable::InsertInteger(mLuaState, "Debug", 0);
LuaTable::InsertInteger(mLuaState, "Private", 1);
LuaTable::InsertInteger(mLuaState, "MaxCars", 2);
LuaTable::InsertInteger(mLuaState, "MaxPlayers", 3);
LuaTable::InsertInteger(mLuaState, "Map", 4);
LuaTable::InsertInteger(mLuaState, "Name", 5);
LuaTable::InsertInteger(mLuaState, "Description", 6);
LuaTable::EndEntry(mLuaState);
LuaTable::InsertFunction(mLuaState, "GetPlayerIdentifiers", lua_GetIdentifiers);
LuaTable::InsertFunction(mLuaState, "TriggerGlobalEvent", lua_TriggerEventG);
LuaTable::InsertFunction(mLuaState, "TriggerLocalEvent", lua_TriggerEventL);
LuaTable::InsertFunction(mLuaState, "TriggerClientEvent", lua_RemoteEvent);
LuaTable::InsertFunction(mLuaState, "GetPlayerCount", lua_GetPlayerCount);
LuaTable::InsertFunction(mLuaState, "IsPlayerConnected", lua_isConnected);
LuaTable::InsertFunction(mLuaState, "RegisterEvent", lua_RegisterEvent);
LuaTable::InsertFunction(mLuaState, "GetPlayerName", lua_GetPlayerName);
LuaTable::InsertFunction(mLuaState, "RemoveVehicle", lua_RemoveVehicle);
LuaTable::InsertFunction(mLuaState, "GetPlayerDiscordID", lua_TempFix);
LuaTable::InsertFunction(mLuaState, "CreateThread", lua_CreateThread);
LuaTable::InsertFunction(mLuaState, "GetPlayerVehicles", lua_GetCars);
LuaTable::InsertFunction(mLuaState, "SendChatMessage", lua_sendChat);
LuaTable::InsertFunction(mLuaState, "GetPlayers", lua_GetAllPlayers);
LuaTable::InsertFunction(mLuaState, "GetPlayerGuest", lua_GetGuest);
LuaTable::InsertFunction(mLuaState, "StopThread", lua_StopThread);
LuaTable::InsertFunction(mLuaState, "DropPlayer", lua_dropPlayer);
LuaTable::InsertFunction(mLuaState, "Register", lua_Register);
LuaTable::InsertFunction(mLuaState, "GetPlayerHWID", lua_HWID);
LuaTable::InsertFunction(mLuaState, "Sleep", lua_Sleep);
LuaTable::InsertFunction(mLuaState, "Set", lua_Set);
LuaTable::InsertFunction(mLuaState, "GetOSName", lua_GetOSName);
LuaTable::InsertFunction(mLuaState, "HttpsGET", lua_HttpsGET);
LuaTable::InsertFunction(mLuaState, "HttpsPOST", lua_HttpsPOST);
LuaTable::InsertFunction(mLuaState, "GetServerVersion", lua_GetServerVersion);
LuaTable::InsertFunction(mLuaState, "GetPluginName", lua_GetPluginName);
LuaTable::InsertFunction(mLuaState, "GetPluginPath", lua_GetPluginPath);
LuaTable::End(mLuaState, "MP");
lua_register(mLuaState, "print", lua_Print);
lua_register(mLuaState, "Set", lua_Set);
lua_register(mLuaState, "printRaw", lua_PrintRaw);
lua_register(mLuaState, "dump", lua_Dump);
lua_register(mLuaState, "exit", lua_ServerExit);
if (!mConsole)
Reload();
}
@@ -789,6 +1060,13 @@ TLuaFile::~TLuaFile() {
lua_close(mLuaState);
}
std::string TLuaFile::GetPluginPath() const {
auto path = fs::path(Application::Settings.Resource);
path /= "Server";
path /= mPluginName;
return path.string();
}
void SendError(TLuaEngine& Engine, lua_State* L, const std::string& msg) {
Assert(L);
auto MaybeS = Engine.GetScript(L);
@@ -799,25 +1077,7 @@ void SendError(TLuaEngine& Engine, lua_State* L, const std::string& msg) {
TLuaFile& S = MaybeS.value();
a = fs::path(S.GetFileName()).filename().string();
}
warn(a + (" | Incorrect Call of ") + msg);
}
int lua_TempFix(lua_State* L) {
if (lua_isnumber(L, 1)) {
int ID = int(lua_tonumber(L, 1));
auto MaybeClient = GetClient(Engine().Server(), ID);
if (!MaybeClient || MaybeClient.value().expired())
return 0;
std::string Ret;
auto c = MaybeClient.value().lock();
if (c->IsGuest()) {
Ret = "Guest-" + c->GetName();
} else
Ret = c->GetName();
lua_pushstring(L, Ret.c_str());
} else
SendError(Engine(), L, "GetDID not enough arguments");
return 1;
warn(a + (" | Error in MP Lua call: ") + msg);
}
void TLuaArg::PushArgs(lua_State* State) {
+53 -115
View File
@@ -46,22 +46,7 @@ void TNetwork::UDPServerMain() {
error(("Can't start Winsock!"));
//return;
}
mUDPSock = socket(AF_INET, SOCK_DGRAM, 0);
// Create a server hint structure for the server
sockaddr_in serverAddr {};
serverAddr.sin_addr.S_un.S_addr = ADDR_ANY; //Any Local
serverAddr.sin_family = AF_INET; // Address format is IPv4
serverAddr.sin_port = htons(Application::Settings.Port); // Convert from little to big endian
// Try and bind the socket to the IP and port
if (bind(mUDPSock, (sockaddr*)&serverAddr, sizeof(serverAddr)) == SOCKET_ERROR) {
error(("Can't bind socket!") + std::to_string(WSAGetLastError()));
std::this_thread::sleep_for(std::chrono::seconds(5));
exit(-1);
//return;
}
#else // unix
#endif // WIN32
mUDPSock = socket(AF_INET, SOCK_DGRAM, 0);
// Create a server hint structure for the server
sockaddr_in serverAddr {};
@@ -71,12 +56,11 @@ void TNetwork::UDPServerMain() {
// Try and bind the socket to the IP and port
if (bind(mUDPSock, (sockaddr*)&serverAddr, sizeof(serverAddr)) != 0) {
error(("Can't bind socket!") + std::string(strerror(errno)));
error("bind() failed: " + GetPlatformAgnosticErrorString());
std::this_thread::sleep_for(std::chrono::seconds(5));
exit(-1);
//return;
}
#endif
info(("Vehicle data network online on port ") + std::to_string(Application::Settings.Port) + (" with a Max of ")
+ std::to_string(Application::Settings.MaxPlayers) + (" Clients"));
@@ -123,13 +107,23 @@ void TNetwork::TCPServerMain() {
error("Can't start Winsock!");
return;
}
SOCKET client, Listener = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
#endif // WIN32
TConnection client {};
SOCKET Listener = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
int optval = 1;
#ifdef WIN32
const char* optval_ptr = reinterpret_cast<const char*>(&optval);
#else
void* optval_ptr = reinterpret_cast<void*>(&optval);
#endif
setsockopt(Listener, SOL_SOCKET, SO_REUSEADDR, optval_ptr, sizeof(optval));
// TODO: check optval or return value idk
sockaddr_in addr {};
addr.sin_addr.S_un.S_addr = ADDR_ANY;
addr.sin_addr.s_addr = INADDR_ANY;
addr.sin_family = AF_INET;
addr.sin_port = htons(Application::Settings.Port);
if (bind(Listener, (sockaddr*)&addr, sizeof(addr)) == SOCKET_ERROR) {
error("Can't bind socket! " + std::to_string(WSAGetLastError()));
addr.sin_port = htons(uint16_t(Application::Settings.Port));
if (bind(Listener, (sockaddr*)&addr, sizeof(addr)) != 0) {
error("bind() failed: " + GetPlatformAgnosticErrorString());
std::this_thread::sleep_for(std::chrono::seconds(5));
exit(-1);
}
@@ -137,53 +131,9 @@ void TNetwork::TCPServerMain() {
error("Invalid listening socket");
return;
}
if (listen(Listener, SOMAXCONN)) {
error("listener failed " + std::to_string(GetLastError()));
//TODO Fix me leak for Listener socket
return;
}
info("Vehicle event network online");
do {
try {
client = accept(Listener, nullptr, nullptr);
if (client == -1) {
warn("Got an invalid client socket on connect! Skipping...");
continue;
}
std::thread ID(&TNetwork::Identify, this, client);
ID.detach();
} catch (const std::exception& e) {
error("fatal: " + std::string(e.what()));
}
} while (client);
CloseSocketProper(client);
WSACleanup();
#else // unix
// wondering why we need slightly different implementations of this?
// ask ms.
SOCKET client = -1;
SOCKET Listener = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
int optval = 1;
setsockopt(Listener, SOL_SOCKET, SO_REUSEPORT, &optval, sizeof(optval));
// TODO: check optval or return value idk
sockaddr_in addr {};
addr.sin_addr.s_addr = INADDR_ANY;
addr.sin_family = AF_INET;
addr.sin_port = htons(uint16_t(Application::Settings.Port));
if (bind(Listener, (sockaddr*)&addr, sizeof(addr)) != 0) {
error(("Can't bind socket! ") + std::string(strerror(errno)));
std::this_thread::sleep_for(std::chrono::seconds(5));
exit(-1);
}
if (Listener == -1) {
error(("Invalid listening socket"));
return;
}
if (listen(Listener, SOMAXCONN)) {
error(("listener failed ") + std::string(strerror(errno)));
//TODO fix me leak Listener
error("listen() failed: " + GetPlatformAgnosticErrorString());
// FIXME leak Listener
return;
}
info(("Vehicle event network online"));
@@ -193,8 +143,9 @@ void TNetwork::TCPServerMain() {
debug("shutdown during TCP wait for accept loop");
break;
}
client = accept(Listener, nullptr, nullptr);
if (client == -1) {
client.SockAddrLen = sizeof(client.SockAddr);
client.Socket = accept(Listener, &client.SockAddr, &client.SockAddrLen);
if (client.Socket == -1) {
warn(("Got an invalid client socket on connect! Skipping..."));
continue;
}
@@ -203,12 +154,15 @@ void TNetwork::TCPServerMain() {
} catch (const std::exception& e) {
error(("fatal: ") + std::string(e.what()));
}
} while (client);
} while (client.Socket);
debug("all ok, arrived at " + std::string(__func__) + ":" + std::to_string(__LINE__));
CloseSocketProper(client.Socket);
#ifdef WIN32
CloseSocketProper(client);
#endif
WSACleanup();
#endif // WIN32
}
#undef GetObject //Fixes Windows
@@ -216,19 +170,19 @@ void TNetwork::TCPServerMain() {
#include "Json.h"
namespace json = rapidjson;
void TNetwork::Identify(SOCKET TCPSock) {
void TNetwork::Identify(const TConnection& client) {
RegisterThreadAuto();
char Code;
if (recv(TCPSock, &Code, 1, 0) != 1) {
CloseSocketProper(TCPSock);
if (recv(client.Socket, &Code, 1, 0) != 1) {
CloseSocketProper(client.Socket);
return;
}
if (Code == 'C') {
Authentication(TCPSock);
Authentication(client);
} else if (Code == 'D') {
HandleDownload(TCPSock);
HandleDownload(client.Socket);
} else {
CloseSocketProper(TCPSock);
CloseSocketProper(client.Socket);
}
}
@@ -251,17 +205,21 @@ void TNetwork::HandleDownload(SOCKET TCPSock) {
});
}
void TNetwork::Authentication(SOCKET TCPSock) {
auto Client = CreateClient(TCPSock);
void TNetwork::Authentication(const TConnection& ClientConnection) {
auto Client = CreateClient(ClientConnection.Socket);
char AddrBuf[30];
inet_ntoa(reinterpret_cast<const struct sockaddr_in*>(&ClientConnection.SockAddr)->sin_addr);
auto str = inet_ntop(AF_INET, static_cast<const void*>(reinterpret_cast<const struct sockaddr_in*>(&ClientConnection.SockAddr)), AddrBuf, sizeof(struct sockaddr_in));
Client->SetIdentifier("ip", str);
std::string Rc;
info("Identifying new client...");
info("Identifying new ClientConnection...");
Rc = TCPRcv(*Client);
if (Rc.size() > 3 && Rc.substr(0, 2) == "VC") {
Rc = Rc.substr(2);
if (Rc.length() > 4 || Rc != Application::ClientVersion()) {
if (Rc.length() > 4 || Rc != Application::ClientVersionString()) {
ClientKick(*Client, "Outdated Version!");
return;
}
@@ -283,14 +241,14 @@ void TNetwork::Authentication(SOCKET TCPSock) {
auto RequestString = R"({"key":")" + Rc + "\"}";
auto Target = "/pkToUser";
int ResponseCode = -1;
unsigned int ResponseCode = 0;
if (!Rc.empty()) {
Rc = Http::POST(Application::GetBackendUrlForAuth(), Target, {}, RequestString, true, &ResponseCode);
Rc = Http::POST(Application::GetBackendUrlForAuth(), 443, Target, {}, RequestString, "application/json", &ResponseCode);
}
json::Document AuthResponse;
AuthResponse.Parse(Rc.c_str());
if (Rc == "-1" || AuthResponse.HasParseError()) {
if (Rc == Http::ErrorString || AuthResponse.HasParseError()) {
ClientKick(*Client, "Invalid key! Please restart your game.");
return;
}
@@ -323,7 +281,9 @@ void TNetwork::Authentication(SOCKET TCPSock) {
Client->SetRoles(AuthResponse["roles"].GetString());
Client->SetIsGuest(AuthResponse["guest"].GetBool());
for (const auto& ID : AuthResponse["identifiers"].GetArray()) {
Client->AddIdentifier(ID.GetString());
auto Raw = std::string(ID.GetString());
auto SepIndex = Raw.find(':');
Client->SetIdentifier(Raw.substr(0, SepIndex), Raw.substr(SepIndex + 1));
}
} else {
ClientKick(*Client, "Invalid authentication data!");
@@ -399,12 +359,12 @@ bool TNetwork::TCPSend(TClient& c, const std::string& Data, bool IsSync) {
int32_t Temp = send(c.GetTCPSock(), &Send[Sent], Size - Sent, MSG_NOSIGNAL);
#endif //WIN32
if (Temp == 0) {
debug("send() == 0: " + std::string(std::strerror(errno)));
debug("send() == 0: " + GetPlatformAgnosticErrorString());
if (c.GetStatus() > -1)
c.SetStatus(-1);
return false;
} else if (Temp < 0) {
debug("send() < 0: " + std::string(std::strerror(errno))); //TODO fix it was spamming yet everyone stayed on the server
debug("send() < 0: " + GetPlatformAgnosticErrorString()); //TODO fix it was spamming yet everyone stayed on the server
if (c.GetStatus() > -1)
c.SetStatus(-1);
CloseSocketProper(c.GetTCPSock());
@@ -423,11 +383,7 @@ bool TNetwork::CheckBytes(TClient& c, int32_t BytesRcv) {
c.SetStatus(-1);
return false;
} else if (BytesRcv < 0) {
#ifdef WIN32
debug(("(TCP) recv failed with error: ") + std::to_string(WSAGetLastError()));
#else // unix
debug(("(TCP) recv failed with error: ") + std::string(strerror(errno)));
#endif // WIN32
debug("(TCP) recv() failed: " + GetPlatformAgnosticErrorString());
if (c.GetStatus() > -1)
c.SetStatus(-1);
CloseSocketProper(c.GetTCPSock());
@@ -946,31 +902,17 @@ bool TNetwork::UDPSend(TClient& Client, std::string Data) const {
#endif // WIN32
sendOk = sendto(mUDPSock, Data.c_str(), len, 0, (sockaddr*)&Addr, int(AddrSize));
#ifdef WIN32
if (sendOk == -1) {
debug(("(UDP) Send Failed Code : ") + std::to_string(WSAGetLastError()));
debug("(UDP) sendto() failed: " + GetPlatformAgnosticErrorString());
if (Client.GetStatus() > -1)
Client.SetStatus(-1);
return false;
} else if (sendOk == 0) {
debug(("(UDP) sendto returned 0"));
debug(("(UDP) sendto() returned 0"));
if (Client.GetStatus() > -1)
Client.SetStatus(-1);
return false;
}
#else // unix
if (sendOk == -1) {
debug(("(UDP) Send Failed Code : ") + std::string(strerror(errno)));
if (Client.GetStatus() > -1)
Client.SetStatus(-1);
return false;
} else if (sendOk == 0) {
debug(("(UDP) sendto returned 0"));
if (Client.GetStatus() > -1)
Client.SetStatus(-1);
return false;
}
#endif // WIN32
return true;
}
@@ -984,11 +926,7 @@ std::string TNetwork::UDPRcvFromClient(sockaddr_in& client) const {
#endif // WIN32
if (Rcv == -1) {
#ifdef WIN32
error(("(UDP) Error receiving from Client! Code : ") + std::to_string(WSAGetLastError()));
#else // unix
error(("(UDP) Error receiving from Client! Code : ") + std::string(strerror(errno)));
#endif // WIN32
error("(UDP) Error receiving from client! recvfrom() failed: " + GetPlatformAgnosticErrorString());
return "";
}
return std::string(Ret.begin(), Ret.begin() + Rcv);
+1 -2
View File
@@ -17,9 +17,8 @@ TSentry::TSentry() {
mValid = true;
sentry_options_t* options = sentry_options_new();
sentry_options_set_dsn(options, SECRET_SENTRY_URL);
sentry_options_set_debug(options, false); // needs to always be false
auto ReleaseString = "BeamMP-Server@" + Application::ServerVersionString();
sentry_options_set_symbolize_stacktraces(options, true);
auto ReleaseString = "BeamMP-Server@" + Application::ServerVersion();
sentry_options_set_release(options, ReleaseString.c_str());
sentry_options_set_max_breadcrumbs(options, 10);
sentry_init(options);
+1 -1
View File
@@ -14,7 +14,7 @@
namespace json = rapidjson;
TServer::TServer(int argc, char** argv) {
info("BeamMP Server v" + Application::ServerVersion());
info("BeamMP Server v" + Application::ServerVersionString());
if (argc > 1) {
Application::Settings.CustomIP = argv[1];
size_t n = std::count(Application::Settings.CustomIP.begin(), Application::Settings.CustomIP.end(), '.');
+1
View File
@@ -55,6 +55,7 @@ int main(int argc, char** argv) try {
bool Shutdown = false;
Application::RegisterShutdownHandler([&Shutdown] { Shutdown = true; });
Application::RegisterShutdownHandler([] { TriggerLuaEvent("onShutdown", false, nullptr, {}, true); });
TServer Server(argc, argv);
TConfig Config;