mirror of
https://github.com/BeamMP/BeamMP-Server.git
synced 2025-08-16 16:26:26 +00:00
implement mod hashing + new download
This commit is contained in:
parent
7f69e336a9
commit
a4b62d013c
@ -19,6 +19,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "Common.h"
|
#include "Common.h"
|
||||||
|
#include <nlohmann/json.hpp>
|
||||||
|
|
||||||
class TResourceManager {
|
class TResourceManager {
|
||||||
public:
|
public:
|
||||||
@ -30,10 +31,17 @@ public:
|
|||||||
[[nodiscard]] std::string FileSizes() const { return mFileSizes; }
|
[[nodiscard]] std::string FileSizes() const { return mFileSizes; }
|
||||||
[[nodiscard]] int ModsLoaded() const { return mModsLoaded; }
|
[[nodiscard]] int ModsLoaded() const { return mModsLoaded; }
|
||||||
|
|
||||||
|
[[nodiscard]] std::string NewFileList() const;
|
||||||
|
|
||||||
|
void RefreshFiles();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
size_t mMaxModSize = 0;
|
size_t mMaxModSize = 0;
|
||||||
std::string mFileSizes;
|
std::string mFileSizes;
|
||||||
std::string mFileList;
|
std::string mFileList;
|
||||||
std::string mTrimmedList;
|
std::string mTrimmedList;
|
||||||
int mModsLoaded = 0;
|
int mModsLoaded = 0;
|
||||||
|
|
||||||
|
std::mutex mModsMutex;
|
||||||
|
nlohmann::json mMods;
|
||||||
};
|
};
|
||||||
|
@ -758,11 +758,11 @@ void TNetwork::Parse(TClient& c, const std::vector<uint8_t>& Packet) {
|
|||||||
case 'S':
|
case 'S':
|
||||||
if (SubCode == 'R') {
|
if (SubCode == 'R') {
|
||||||
beammp_debug("Sending Mod Info");
|
beammp_debug("Sending Mod Info");
|
||||||
std::string ToSend = mResourceManager.FileList() + mResourceManager.FileSizes();
|
std::string ToSend = mResourceManager.NewFileList();
|
||||||
if (ToSend.empty())
|
beammp_debugf("Mod Info: {}", ToSend);
|
||||||
ToSend = "-";
|
|
||||||
if (!TCPSend(c, StringToVector(ToSend))) {
|
if (!TCPSend(c, StringToVector(ToSend))) {
|
||||||
// TODO: error
|
ClientKick(c, "TCP Send 'SY' failed");
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
|
@ -17,9 +17,14 @@
|
|||||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
#include "TResourceManager.h"
|
#include "TResourceManager.h"
|
||||||
|
#include "Common.h"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
|
#include <fmt/core.h>
|
||||||
|
#include <ios>
|
||||||
|
#include <nlohmann/json.hpp>
|
||||||
|
#include <openssl/evp.h>
|
||||||
|
|
||||||
namespace fs = std::filesystem;
|
namespace fs = std::filesystem;
|
||||||
|
|
||||||
@ -52,3 +57,83 @@ TResourceManager::TResourceManager() {
|
|||||||
|
|
||||||
Application::SetSubsystemStatus("ResourceManager", Application::Status::Good);
|
Application::SetSubsystemStatus("ResourceManager", Application::Status::Good);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string TResourceManager::NewFileList() const {
|
||||||
|
return mMods.dump();
|
||||||
|
}
|
||||||
|
void TResourceManager::RefreshFiles() {
|
||||||
|
mMods.clear();
|
||||||
|
std::unique_lock Lock(mModsMutex);
|
||||||
|
|
||||||
|
std::string Path = Application::Settings.getAsString(Settings::Key::General_ResourceFolder) + "/Client";
|
||||||
|
for (const auto& entry : fs::directory_iterator(Path)) {
|
||||||
|
std::string File(entry.path().string());
|
||||||
|
|
||||||
|
if (entry.path().extension() != ".zip" || std::filesystem::is_directory(entry.path())) {
|
||||||
|
beammp_warnf("'{}' is not a ZIP file and will be ignored", File);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
EVP_MD_CTX* mdctx;
|
||||||
|
const EVP_MD* md;
|
||||||
|
uint8_t sha256_value[EVP_MAX_MD_SIZE];
|
||||||
|
md = EVP_sha256();
|
||||||
|
if (md == nullptr) {
|
||||||
|
throw std::runtime_error("EVP_sha256() failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
mdctx = EVP_MD_CTX_new();
|
||||||
|
if (mdctx == nullptr) {
|
||||||
|
throw std::runtime_error("EVP_MD_CTX_new() failed");
|
||||||
|
}
|
||||||
|
if (!EVP_DigestInit_ex2(mdctx, md, NULL)) {
|
||||||
|
EVP_MD_CTX_free(mdctx);
|
||||||
|
throw std::runtime_error("EVP_DigestInit_ex2() failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
std::ifstream stream(File, std::ios::binary);
|
||||||
|
|
||||||
|
const size_t FileSize = std::filesystem::file_size(File);
|
||||||
|
size_t Read = 0;
|
||||||
|
std::vector<char> Data;
|
||||||
|
while (Read < FileSize) {
|
||||||
|
Data.resize(size_t(std::min<size_t>(FileSize - Read, 4096)));
|
||||||
|
size_t RealDataSize = Data.size();
|
||||||
|
stream.read(Data.data(), std::streamsize(Data.size()));
|
||||||
|
if (stream.eof() || stream.fail()) {
|
||||||
|
RealDataSize = size_t(stream.gcount());
|
||||||
|
}
|
||||||
|
Data.resize(RealDataSize);
|
||||||
|
if (RealDataSize == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (RealDataSize > 0 && !EVP_DigestUpdate(mdctx, Data.data(), Data.size())) {
|
||||||
|
EVP_MD_CTX_free(mdctx);
|
||||||
|
throw std::runtime_error("EVP_DigestUpdate() failed");
|
||||||
|
}
|
||||||
|
Read += RealDataSize;
|
||||||
|
}
|
||||||
|
unsigned int sha256_len = 0;
|
||||||
|
if (!EVP_DigestFinal_ex(mdctx, sha256_value, &sha256_len)) {
|
||||||
|
EVP_MD_CTX_free(mdctx);
|
||||||
|
throw std::runtime_error("EVP_DigestFinal_ex() failed");
|
||||||
|
}
|
||||||
|
EVP_MD_CTX_free(mdctx);
|
||||||
|
|
||||||
|
std::string result;
|
||||||
|
for (size_t i = 0; i < sha256_len; i++) {
|
||||||
|
result += fmt::format("{:02x}", sha256_value[i]);
|
||||||
|
}
|
||||||
|
beammp_debugf("sha256('{}'): {}", File, result);
|
||||||
|
mMods.push_back(nlohmann::json {
|
||||||
|
{ "file_name", File },
|
||||||
|
{ "file_size", Read },
|
||||||
|
{ "hash_algorithm", "sha256" },
|
||||||
|
{ "hash", result },
|
||||||
|
});
|
||||||
|
} catch (const std::exception& e) {
|
||||||
|
beammp_errorf("Sha256 hashing of '{}' failed: {}", File, e.what());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
13
src/main.cpp
13
src/main.cpp
@ -36,19 +36,19 @@
|
|||||||
#include <thread>
|
#include <thread>
|
||||||
|
|
||||||
static const std::string sCommandlineArguments = R"(
|
static const std::string sCommandlineArguments = R"(
|
||||||
USAGE:
|
USAGE:
|
||||||
BeamMP-Server [arguments]
|
BeamMP-Server [arguments]
|
||||||
|
|
||||||
ARGUMENTS:
|
ARGUMENTS:
|
||||||
--help
|
--help
|
||||||
Displays this help and exits.
|
Displays this help and exits.
|
||||||
--port=1234
|
--port=1234
|
||||||
Sets the server's listening TCP and
|
Sets the server's listening TCP and
|
||||||
UDP port. Overrides ENV and ServerConfig.
|
UDP port. Overrides ENV and ServerConfig.
|
||||||
--config=/path/to/ServerConfig.toml
|
--config=/path/to/ServerConfig.toml
|
||||||
Absolute or relative path to the
|
Absolute or relative path to the
|
||||||
Server Config file, including the
|
Server Config file, including the
|
||||||
filename. For paths and filenames with
|
filename. For paths and filenames with
|
||||||
spaces, put quotes around the path.
|
spaces, put quotes around the path.
|
||||||
--working-directory=/path/to/folder
|
--working-directory=/path/to/folder
|
||||||
Sets the working directory of the Server.
|
Sets the working directory of the Server.
|
||||||
@ -59,7 +59,7 @@ ARGUMENTS:
|
|||||||
|
|
||||||
EXAMPLES:
|
EXAMPLES:
|
||||||
BeamMP-Server --config=../MyWestCoastServerConfig.toml
|
BeamMP-Server --config=../MyWestCoastServerConfig.toml
|
||||||
Runs the BeamMP-Server and uses the server config file
|
Runs the BeamMP-Server and uses the server config file
|
||||||
which is one directory above it and is named
|
which is one directory above it and is named
|
||||||
'MyWestCoastServerConfig.toml'.
|
'MyWestCoastServerConfig.toml'.
|
||||||
)";
|
)";
|
||||||
@ -190,6 +190,7 @@ int BeamMPServerMain(MainArguments Arguments) {
|
|||||||
|
|
||||||
beammp_trace("Running in debug mode on a debug build");
|
beammp_trace("Running in debug mode on a debug build");
|
||||||
TResourceManager ResourceManager;
|
TResourceManager ResourceManager;
|
||||||
|
ResourceManager.RefreshFiles();
|
||||||
TPPSMonitor PPSMonitor(Server);
|
TPPSMonitor PPSMonitor(Server);
|
||||||
THeartbeatThread Heartbeat(ResourceManager, Server);
|
THeartbeatThread Heartbeat(ResourceManager, Server);
|
||||||
TNetwork Network(Server, PPSMonitor, ResourceManager);
|
TNetwork Network(Server, PPSMonitor, ResourceManager);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user