implement mod hashing + new download

This commit is contained in:
Lion Kortlepel 2024-09-29 00:32:52 +02:00
parent 7f69e336a9
commit a4b62d013c
No known key found for this signature in database
GPG Key ID: 4322FF2B4C71259B
4 changed files with 104 additions and 10 deletions

View File

@ -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;
}; };

View File

@ -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;

View File

@ -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());
}
}
}

View File

@ -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);