Theater server emulation
This commit is contained in:
parent
e584075243
commit
b77d42d869
@ -9,6 +9,7 @@
|
|||||||
#include "demonware/servers/auth3_server.hpp"
|
#include "demonware/servers/auth3_server.hpp"
|
||||||
#include "demonware/servers/stun_server.hpp"
|
#include "demonware/servers/stun_server.hpp"
|
||||||
#include "demonware/servers/umbrella_server.hpp"
|
#include "demonware/servers/umbrella_server.hpp"
|
||||||
|
#include "demonware/servers/fileshare_server.hpp"
|
||||||
#include "demonware/server_registry.hpp"
|
#include "demonware/server_registry.hpp"
|
||||||
|
|
||||||
#define TCP_BLOCKING true
|
#define TCP_BLOCKING true
|
||||||
@ -477,6 +478,7 @@ namespace demonware
|
|||||||
tcp_servers.create<auth3_server>("ops4-pc-auth3.prod.demonware.net");
|
tcp_servers.create<auth3_server>("ops4-pc-auth3.prod.demonware.net");
|
||||||
tcp_servers.create<lobby_server>("ops4-pc-lobby.prod.demonware.net");
|
tcp_servers.create<lobby_server>("ops4-pc-lobby.prod.demonware.net");
|
||||||
tcp_servers.create<umbrella_server>("prod.umbrella.demonware.net");
|
tcp_servers.create<umbrella_server>("prod.umbrella.demonware.net");
|
||||||
|
tcp_servers.create<fileshare_server>("ops4-fileshare.prod.schild.net");
|
||||||
}
|
}
|
||||||
|
|
||||||
void pre_start() override
|
void pre_start() override
|
||||||
|
268
source/proxy-dll/demonware/fileshare.cpp
Normal file
268
source/proxy-dll/demonware/fileshare.cpp
Normal file
@ -0,0 +1,268 @@
|
|||||||
|
#include <std_include.hpp>
|
||||||
|
#include "fileshare.hpp"
|
||||||
|
#include "component/platform.hpp"
|
||||||
|
|
||||||
|
#include <utilities/io.hpp>
|
||||||
|
#include <utilities/string.hpp>
|
||||||
|
#include <utilities/cryptography.hpp>
|
||||||
|
|
||||||
|
namespace demonware::fileshare
|
||||||
|
{
|
||||||
|
const char* get_fileshare_host_name()
|
||||||
|
{
|
||||||
|
return "ops4-fileshare.prod.schild.net";
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* get_category_extension(fileshareCategory_e cat)
|
||||||
|
{
|
||||||
|
switch (cat)
|
||||||
|
{
|
||||||
|
case fileshareCategory_e::FILESHARE_CATEGORY_FILM:
|
||||||
|
return "demo";
|
||||||
|
case fileshareCategory_e::FILESHARE_CATEGORY_SCREENSHOT_PRIVATE:
|
||||||
|
return "jpg";
|
||||||
|
default:
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fileshareCategory_e get_extension_category(const char* ext)
|
||||||
|
{
|
||||||
|
if (!strcmp(ext, "demo")) {
|
||||||
|
return fileshareCategory_e::FILESHARE_CATEGORY_FILM;
|
||||||
|
}
|
||||||
|
else if (!strcmp(ext, "jpg")) {
|
||||||
|
return fileshareCategory_e::FILESHARE_CATEGORY_SCREENSHOT_PRIVATE;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return fileshareCategory_e::FILESHARE_CATEGORY_ALL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string get_fileshare_directory()
|
||||||
|
{
|
||||||
|
return std::format("players/fileshare-{}", platform::bnet_get_userid());
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string get_file_name(const uint64_t fileID, fileshareCategory_e category)
|
||||||
|
{
|
||||||
|
const char* extension = get_category_extension(category);
|
||||||
|
|
||||||
|
if(!extension || !strlen(extension)) return std::to_string(fileID);
|
||||||
|
|
||||||
|
return std::format("{}.{}", fileID, extension);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string get_file_url(const std::string& file)
|
||||||
|
{
|
||||||
|
return std::format("http://{}/{}", get_fileshare_host_name(), utilities::io::file_name(file));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string get_file_path(const std::string& file)
|
||||||
|
{
|
||||||
|
return std::format("{}/{}", get_fileshare_directory(), utilities::io::file_name(file));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string get_metadata_path(const std::string& file)
|
||||||
|
{
|
||||||
|
return std::format("{}/{}.metadata", get_fileshare_directory(), utilities::io::file_stem(file));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string FileMetadata::SerializeMetaJSON()
|
||||||
|
{
|
||||||
|
rapidjson::Document jsonDocument(rapidjson::kObjectType);
|
||||||
|
rapidjson::Document::AllocatorType& allocator = jsonDocument.GetAllocator();
|
||||||
|
|
||||||
|
jsonDocument.AddMember("status", this->status, allocator);
|
||||||
|
jsonDocument.AddMember("category", this->category, allocator);
|
||||||
|
jsonDocument.AddMember("fileName", this->fileName, allocator);
|
||||||
|
if (this->status == FILE_STATUS_UPLOADED || this->status == FILE_STATUS_DESCRIBED) {
|
||||||
|
jsonDocument.AddMember("fileSize", this->fileSize, allocator);
|
||||||
|
}
|
||||||
|
|
||||||
|
rapidjson::Value fileInfo(rapidjson::kObjectType);
|
||||||
|
fileInfo.AddMember("id", this->file.id, allocator);
|
||||||
|
fileInfo.AddMember("name", this->file.name, allocator);
|
||||||
|
if (this->status == FILE_STATUS_UPLOADED || this->status == FILE_STATUS_DESCRIBED) {
|
||||||
|
fileInfo.AddMember("size", this->file.size, allocator);
|
||||||
|
}
|
||||||
|
fileInfo.AddMember("timestamp", this->file.timestamp, allocator);
|
||||||
|
jsonDocument.AddMember("file", fileInfo, allocator);
|
||||||
|
|
||||||
|
rapidjson::Value fileAuthor(rapidjson::kObjectType);
|
||||||
|
fileAuthor.AddMember("name", this->author.name, allocator);
|
||||||
|
fileAuthor.AddMember("xuid", this->author.xuid, allocator);
|
||||||
|
jsonDocument.AddMember("author", fileAuthor, allocator);
|
||||||
|
|
||||||
|
if (this->status == FILE_STATUS_DESCRIBED) {
|
||||||
|
rapidjson::Value fileTags(rapidjson::kObjectType);
|
||||||
|
for (const auto& tag : this->tags)
|
||||||
|
{
|
||||||
|
rapidjson::Value key(std::to_string(tag.first), allocator);
|
||||||
|
fileTags.AddMember(key, tag.second, allocator);
|
||||||
|
}
|
||||||
|
jsonDocument.AddMember("tags", fileTags, allocator);
|
||||||
|
|
||||||
|
jsonDocument.AddMember("metadata", utilities::cryptography::base64::encode(ddl_metadata), allocator);
|
||||||
|
}
|
||||||
|
|
||||||
|
rapidjson::StringBuffer strbuf;
|
||||||
|
rapidjson::PrettyWriter<rapidjson::StringBuffer> writer(strbuf);
|
||||||
|
jsonDocument.Accept(writer);
|
||||||
|
|
||||||
|
return std::string(strbuf.GetString(), strbuf.GetLength());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FileMetadata::ParseMetaJSON(const std::string& MetaDoc)
|
||||||
|
{
|
||||||
|
rapidjson::Document jsonDocument;
|
||||||
|
jsonDocument.Parse(MetaDoc);
|
||||||
|
|
||||||
|
if (jsonDocument.HasMember("status") && jsonDocument["status"].IsInt()) {
|
||||||
|
this->status = static_cast<file_status>(jsonDocument["status"].GetInt());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (jsonDocument.HasMember("category") && jsonDocument["category"].IsInt()) {
|
||||||
|
this->category = static_cast<fileshareCategory_e>(jsonDocument["category"].GetInt());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (jsonDocument.HasMember("fileName") && jsonDocument["fileName"].IsString()) {
|
||||||
|
this->fileName = jsonDocument["fileName"].GetString();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((this->status == FILE_STATUS_UPLOADED || this->status == FILE_STATUS_DESCRIBED)
|
||||||
|
&& jsonDocument.HasMember("fileSize") && jsonDocument["fileSize"].IsUint64())
|
||||||
|
{
|
||||||
|
this->fileSize = jsonDocument["fileSize"].GetUint64();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (jsonDocument.HasMember("file") && jsonDocument["file"].IsObject())
|
||||||
|
{
|
||||||
|
rapidjson::Value& fileInfo = jsonDocument["file"];
|
||||||
|
if (fileInfo.HasMember("id") && fileInfo["id"].IsUint64()
|
||||||
|
&& fileInfo.HasMember("name") && fileInfo["name"].IsString()
|
||||||
|
&& fileInfo.HasMember("timestamp") && fileInfo["timestamp"].IsUint())
|
||||||
|
{
|
||||||
|
this->file.id = fileInfo["id"].GetUint64();
|
||||||
|
this->file.name = fileInfo["name"].GetString();
|
||||||
|
this->file.timestamp = fileInfo["timestamp"].GetUint();
|
||||||
|
}
|
||||||
|
if ((this->status == FILE_STATUS_UPLOADED || this->status == FILE_STATUS_DESCRIBED)
|
||||||
|
&& fileInfo.HasMember("size") && fileInfo["size"].IsUint())
|
||||||
|
{
|
||||||
|
this->file.size = fileInfo["size"].GetUint();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (jsonDocument.HasMember("author") && jsonDocument["author"].IsObject())
|
||||||
|
{
|
||||||
|
rapidjson::Value& fileAuthor = jsonDocument["author"];
|
||||||
|
if (fileAuthor.HasMember("name") && fileAuthor["name"].IsString()
|
||||||
|
&& fileAuthor.HasMember("xuid") && fileAuthor["xuid"].IsUint64())
|
||||||
|
{
|
||||||
|
this->author.name = fileAuthor["name"].GetString();
|
||||||
|
this->author.xuid = fileAuthor["xuid"].GetUint64();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this->status == FILE_STATUS_DESCRIBED) {
|
||||||
|
if (jsonDocument.HasMember("tags") && jsonDocument["tags"].IsObject())
|
||||||
|
{
|
||||||
|
rapidjson::Value& fileTags = jsonDocument["tags"];
|
||||||
|
|
||||||
|
for (rapidjson::Value::ConstMemberIterator itr =
|
||||||
|
fileTags.MemberBegin(); itr != fileTags.MemberEnd(); ++itr)
|
||||||
|
{
|
||||||
|
this->tags.insert({ atoi(itr->name.GetString()), itr->value.GetUint64() });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (jsonDocument.HasMember("metadata") && jsonDocument["metadata"].IsString())
|
||||||
|
{
|
||||||
|
rapidjson::Value& ddl_field = jsonDocument["metadata"];
|
||||||
|
std::string metadata_b64(ddl_field.GetString(), ddl_field.GetStringLength());
|
||||||
|
this->ddl_metadata = utilities::cryptography::base64::decode(metadata_b64);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this->status == FILE_STATUS_DESCRIBED) {
|
||||||
|
return (this->fileName.size() && this->file.id && this->ddl_metadata.size());
|
||||||
|
}
|
||||||
|
else if (this->status == FILE_STATUS_UPLOADED) {
|
||||||
|
return (this->fileName.size() && this->file.id && this->fileSize);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return (this->fileName.size() && this->file.id && this->file.name.size());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FileMetadata::MetadataTaskResult(bdFileMetaData* output, bool download)
|
||||||
|
{
|
||||||
|
if (this->status == FILE_STATUS_DESCRIBED)
|
||||||
|
{
|
||||||
|
output->m_fileID = this->file.id;
|
||||||
|
output->m_createTime = this->file.timestamp;
|
||||||
|
output->m_modifedTime = output->m_createTime;
|
||||||
|
output->m_fileSize = this->fileSize;
|
||||||
|
output->m_ownerID = this->author.xuid;
|
||||||
|
output->m_ownerName = this->author.name;
|
||||||
|
output->m_fileSlot = 0;
|
||||||
|
output->m_fileName = this->file.name;
|
||||||
|
output->m_category = this->category;
|
||||||
|
output->m_metaData = this->ddl_metadata;
|
||||||
|
output->m_summaryFileSize = 0; // what!?
|
||||||
|
|
||||||
|
if (download) {
|
||||||
|
output->m_url = get_file_url(this->fileName);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
output->m_tags = this->tags;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FileMetadata::ReadMetaDataJson(const std::string& file, file_status expect)
|
||||||
|
{
|
||||||
|
std::string json;
|
||||||
|
if (utilities::io::read_file(file, &json))
|
||||||
|
{
|
||||||
|
return (this->ParseMetaJSON(json)
|
||||||
|
&& (this->status == expect || expect == FILE_STATUS_UNKNOWN));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FileMetadata::WriteMetaDataJson(const std::string& file, file_status status)
|
||||||
|
{
|
||||||
|
if(status != FILE_STATUS_UNKNOWN) this->status = status;
|
||||||
|
return utilities::io::write_file(file, this->SerializeMetaJSON());
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<uint64_t> fileshare_list_demo_ids()
|
||||||
|
{
|
||||||
|
std::vector<uint64_t> results;
|
||||||
|
|
||||||
|
std::vector<std::string> files = utilities::io::list_files(get_fileshare_directory());
|
||||||
|
|
||||||
|
for (auto& file : files)
|
||||||
|
{
|
||||||
|
std::string rawName = utilities::io::file_stem(file);
|
||||||
|
|
||||||
|
if (utilities::string::is_integer(rawName)
|
||||||
|
&& utilities::string::ends_with(file, ".demo")
|
||||||
|
&& utilities::io::file_exists(get_metadata_path(rawName)))
|
||||||
|
{
|
||||||
|
results.push_back(std::stoull(rawName));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
}
|
103
source/proxy-dll/demonware/fileshare.hpp
Normal file
103
source/proxy-dll/demonware/fileshare.hpp
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "data_types.hpp"
|
||||||
|
|
||||||
|
namespace demonware::fileshare
|
||||||
|
{
|
||||||
|
const char* get_fileshare_host_name();
|
||||||
|
|
||||||
|
enum fileshareCategory_e
|
||||||
|
{
|
||||||
|
FILESHARE_CATEGORY_ALL = 0,
|
||||||
|
FILESHARE_CATEGORY_CONTENT_SERVER_START = 1,
|
||||||
|
FILESHARE_CATEGORY_EMBLEM = 1,
|
||||||
|
FILESHARE_CATEGORY_PAINTJOB = 2,
|
||||||
|
FILESHARE_CATEGORY_VARIANT = 3,
|
||||||
|
FILESHARE_CATEGORY_DECAL = 4,
|
||||||
|
FILESHARE_CATEGORY_GUNRENDER = 5,
|
||||||
|
FILESHARE_CATEGORY_CLIP = 6,
|
||||||
|
FILESHARE_CATEGORY_EMBLEMIMAGE = 7,
|
||||||
|
FILESHARE_CATEGORY_FILM = 10,
|
||||||
|
FILESHARE_CATEGORY_SCREENSHOT = 11,
|
||||||
|
FILESHARE_CATEGORY_CUSTOM_GAME_MODE = 12,
|
||||||
|
FILESHARE_CATEGORY_CONTENT_SERVER_END = 12,
|
||||||
|
FILESHARE_CATEGORY_CLIP_PRIVATE = 14,
|
||||||
|
FILESHARE_CATEGORY_SCREENSHOT_PRIVATE = 15,
|
||||||
|
FILESHARE_CATEGORY_CUSTOM_GAME_MODE_PRIVATE = 16,
|
||||||
|
FILESHARE_CATEGORY_INGAMESTORE_START = 100,
|
||||||
|
FILESHARE_CATEGORY_INGAMESTORE_MAPPACKS = 100,
|
||||||
|
FILESHARE_CATEGORY_INGAMESTORE_THEMES = 101,
|
||||||
|
FILESHARE_CATEGORY_INGAMESTORE_AVATARS = 102,
|
||||||
|
FILESHARE_CATEGORY_INGAMESTORE_WEAPONPACKS = 103,
|
||||||
|
FILESHARE_CATEGORY_INGAMESTORE_CALLINGCARDPACKS = 104,
|
||||||
|
FILESHARE_CATEGORY_INGAMESTORE_STORAGEPACKS = 105,
|
||||||
|
FILESHARE_CATEGORY_INGAMESTORE_END = 105,
|
||||||
|
FILESHARE_CATEGORY_MOTD_IMAGES = 120,
|
||||||
|
FILESHARE_CATEGORY_VOTE_IMAGES = 130,
|
||||||
|
FILESHARE_CATEGORY_MDLC = 1000,
|
||||||
|
FILESHARE_CATEGORY_MDLC_DEDICATED = 1001,
|
||||||
|
FILESHARE_CATEGORY_MDLC_LAST = 1999,
|
||||||
|
FILESHARE_CATEGORY_AVI = 32768,
|
||||||
|
FILESHARE_CATEGORY_EXEMONITOR = 32769,
|
||||||
|
FILESHARE_CATEGORY_INVALID = -1
|
||||||
|
};
|
||||||
|
|
||||||
|
const char* get_category_extension(fileshareCategory_e cat);
|
||||||
|
fileshareCategory_e get_extension_category(const char* ext);
|
||||||
|
|
||||||
|
|
||||||
|
std::string get_fileshare_directory();
|
||||||
|
std::string get_file_name(const uint64_t fileID,
|
||||||
|
fileshareCategory_e category = FILESHARE_CATEGORY_INVALID);
|
||||||
|
std::string get_file_url(const std::string& file);
|
||||||
|
std::string get_file_path(const std::string& file);
|
||||||
|
std::string get_metadata_path(const std::string& file);
|
||||||
|
|
||||||
|
|
||||||
|
class FileMetadata final
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
FileMetadata() = default;
|
||||||
|
~FileMetadata() = default;
|
||||||
|
|
||||||
|
enum file_status
|
||||||
|
{
|
||||||
|
FILE_STATUS_UNKNOWN = 0,
|
||||||
|
FILE_STATUS_INVALID = -1,
|
||||||
|
FILE_STATUS_UPLOADING = 1,
|
||||||
|
FILE_STATUS_UPLOADED = 2,
|
||||||
|
FILE_STATUS_DESCRIBED = 3
|
||||||
|
} status{};
|
||||||
|
|
||||||
|
struct file_info
|
||||||
|
{
|
||||||
|
uint64_t id;
|
||||||
|
std::string name;
|
||||||
|
uint32_t size;
|
||||||
|
uint32_t timestamp;
|
||||||
|
} file{};
|
||||||
|
|
||||||
|
struct author_info
|
||||||
|
{
|
||||||
|
uint64_t xuid;
|
||||||
|
std::string name;
|
||||||
|
} author{};
|
||||||
|
|
||||||
|
fileshareCategory_e category = FILESHARE_CATEGORY_ALL;
|
||||||
|
std::string fileName = "";
|
||||||
|
size_t fileSize = 0;
|
||||||
|
std::string ddl_metadata = "";
|
||||||
|
std::map<uint64_t, uint64_t> tags;
|
||||||
|
|
||||||
|
bool MetadataTaskResult(bdFileMetaData* output, bool download);
|
||||||
|
|
||||||
|
bool ReadMetaDataJson(const std::string& file, file_status expect = FILE_STATUS_UNKNOWN);
|
||||||
|
bool WriteMetaDataJson(const std::string& file, file_status status = FILE_STATUS_UNKNOWN);
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string SerializeMetaJSON();
|
||||||
|
bool ParseMetaJSON(const std::string& input);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector<uint64_t> fileshare_list_demo_ids();
|
||||||
|
}
|
111
source/proxy-dll/demonware/servers/fileshare_server.cpp
Normal file
111
source/proxy-dll/demonware/servers/fileshare_server.cpp
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
#include <std_include.hpp>
|
||||||
|
#include "fileshare_server.hpp"
|
||||||
|
|
||||||
|
#include "../fileshare.hpp"
|
||||||
|
#include <utilities/string.hpp>
|
||||||
|
#include <utilities/io.hpp>
|
||||||
|
|
||||||
|
std::string fileshare_upload_file_name{};
|
||||||
|
std::vector<byte> fileshare_upload_buffer{};
|
||||||
|
|
||||||
|
namespace demonware
|
||||||
|
{
|
||||||
|
void fileshare_server::handle(const std::string& packet)
|
||||||
|
{
|
||||||
|
static bool upload_in_progress = false;
|
||||||
|
|
||||||
|
if (packet.starts_with("GET"))
|
||||||
|
{
|
||||||
|
std::string file = utilities::string::split(utilities::string::split(packet, '\n')[0], ' ')[1].substr(1, std::string::npos);
|
||||||
|
|
||||||
|
this->send(download_file(file));
|
||||||
|
}
|
||||||
|
else if (packet.starts_with("PUT"))
|
||||||
|
{
|
||||||
|
fileshare_upload_file_name = utilities::string::split(utilities::string::split(packet, '\n')[0], ' ')[1].substr(1, std::string::npos);
|
||||||
|
fileshare_upload_buffer.clear();
|
||||||
|
|
||||||
|
logger::write(logger::LOG_TYPE_DEBUG, "[DW]: [fileshare]: upload stream started for '%s'\n", fileshare_upload_file_name.data());
|
||||||
|
|
||||||
|
this->send("");
|
||||||
|
upload_in_progress = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!upload_in_progress)
|
||||||
|
{
|
||||||
|
std::string http_response = "HTTP/1.1 501 Not Implemented\r\n";
|
||||||
|
http_response.append("Connection: close\r\n\r\n");
|
||||||
|
|
||||||
|
return this->send(http_response);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string chunk_header = utilities::string::split(packet, "\r\n")[0];
|
||||||
|
size_t chunk_length = std::stoul(chunk_header, nullptr, 16);
|
||||||
|
|
||||||
|
if (chunk_length != 0)
|
||||||
|
{
|
||||||
|
fileshare_upload_buffer.insert(fileshare_upload_buffer.end(), &packet[chunk_header.length() + 2], &packet[chunk_header.length() + 2 + chunk_length]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
std::string response = finalize_upload_file(fileshare_upload_file_name, fileshare_upload_buffer);
|
||||||
|
upload_in_progress = false;
|
||||||
|
this->send(response);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string fileshare_server::http_header_time()
|
||||||
|
{
|
||||||
|
// header time
|
||||||
|
char date[64];
|
||||||
|
const auto now = time(nullptr);
|
||||||
|
tm gmtm{};
|
||||||
|
gmtime_s(&gmtm, &now);
|
||||||
|
strftime(date, 64, "%a, %d %b %G %T", &gmtm);
|
||||||
|
|
||||||
|
return std::format("{} GMT", date);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string fileshare_server::download_file(const std::string& file)
|
||||||
|
{
|
||||||
|
std::string http_response{}, file_buffer{};
|
||||||
|
|
||||||
|
if (utilities::io::read_file(fileshare::get_file_path(file), &file_buffer))
|
||||||
|
{
|
||||||
|
logger::write(logger::LOG_TYPE_DEBUG, "[DW]: [fileshare]: hosting requested file '%s'\n", file.data());
|
||||||
|
|
||||||
|
http_response.append("HTTP/1.1 200 OK\r\n");
|
||||||
|
http_response.append("Server: Apache/0.0.0 (Win64)\r\n");
|
||||||
|
http_response.append("Content-Type: application/octet-stream\r\n");
|
||||||
|
http_response.append(utilities::string::va("Date: %s\r\n", http_header_time().data()));
|
||||||
|
http_response.append(utilities::string::va("Content-Length: %d\r\n\r\n", file_buffer.length()));
|
||||||
|
http_response.append(file_buffer);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
logger::write(logger::LOG_TYPE_DEBUG, "[DW]: [fileshare]: couldnt find requested file '%s'\n", file.data());
|
||||||
|
|
||||||
|
file_buffer = "<html><head><title>404 Not Found</title></head><body><h1>Not Found</h1><p>The requested URL was not found on this server.</p></body></html>";
|
||||||
|
|
||||||
|
http_response.append("HTTP/1.1 404 Not Found\r\n");
|
||||||
|
http_response.append("Server: Apache/0.0.0 (Win64)\r\n");
|
||||||
|
http_response.append("Content-Type: text/html\r\n");
|
||||||
|
http_response.append(utilities::string::va("Date: %s\r\n", http_header_time().data()));
|
||||||
|
http_response.append(utilities::string::va("Content-Length: %d\r\n\r\n", file_buffer.length()));
|
||||||
|
}
|
||||||
|
|
||||||
|
return http_response;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string fileshare_server::finalize_upload_file(const std::string& file, const std::vector<byte>& buffer)
|
||||||
|
{
|
||||||
|
if(utilities::io::write_file(fileshare::get_file_path(file), std::string(buffer.begin(), buffer.end())))
|
||||||
|
logger::write(logger::LOG_TYPE_DEBUG, "[DW]: [fileshare]: file upload finalized; saved as '%s'\n", fileshare_upload_file_name.data());
|
||||||
|
else
|
||||||
|
logger::write(logger::LOG_TYPE_DEBUG, "[DW]: [fileshare]: error on saving uploaded file '%s'\n", fileshare_upload_file_name.data());
|
||||||
|
|
||||||
|
return "HTTP/1.1 201 Created\r\nContent-Length: 0\r\n\r\n";
|
||||||
|
}
|
||||||
|
}
|
19
source/proxy-dll/demonware/servers/fileshare_server.hpp
Normal file
19
source/proxy-dll/demonware/servers/fileshare_server.hpp
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "tcp_server.hpp"
|
||||||
|
|
||||||
|
namespace demonware
|
||||||
|
{
|
||||||
|
class fileshare_server : public tcp_server
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using tcp_server::tcp_server;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void handle(const std::string& packet) override;
|
||||||
|
|
||||||
|
std::string http_header_time();
|
||||||
|
std::string download_file(const std::string& file);
|
||||||
|
std::string finalize_upload_file(const std::string& file, const std::vector<byte>& buffer);
|
||||||
|
};
|
||||||
|
}
|
@ -1,5 +1,9 @@
|
|||||||
#include <std_include.hpp>
|
#include <std_include.hpp>
|
||||||
#include "../services.hpp"
|
#include "../services.hpp"
|
||||||
|
#include "../fileshare.hpp"
|
||||||
|
#include "component/platform.hpp"
|
||||||
|
|
||||||
|
#include <utilities/io.hpp>
|
||||||
|
|
||||||
namespace demonware
|
namespace demonware
|
||||||
{
|
{
|
||||||
@ -18,24 +22,90 @@ namespace demonware
|
|||||||
this->register_task(22, &bdPooledStorage::_preDownloadMultiPart);
|
this->register_task(22, &bdPooledStorage::_preDownloadMultiPart);
|
||||||
}
|
}
|
||||||
|
|
||||||
void bdPooledStorage::getPooledMetaDataByID(service_server* server, byte_buffer* /*buffer*/) const
|
void bdPooledStorage::getPooledMetaDataByID(service_server* server, byte_buffer* buffer) const
|
||||||
{
|
{
|
||||||
// TODO:
|
std::vector<uint64_t> requested_files;
|
||||||
|
buffer->read_array(10, &requested_files);
|
||||||
|
|
||||||
auto reply = server->create_reply(this->task_id());
|
auto reply = server->create_reply(this->task_id());
|
||||||
|
|
||||||
|
for (auto fileID : requested_files)
|
||||||
|
{
|
||||||
|
std::string metafile = fileshare::get_metadata_path(fileshare::get_file_name(fileID));
|
||||||
|
|
||||||
|
fileshare::FileMetadata metadata;
|
||||||
|
if (metadata.ReadMetaDataJson(metafile, metadata.FILE_STATUS_DESCRIBED)
|
||||||
|
&& utilities::io::file_exists(fileshare::get_file_path(metadata.fileName)))
|
||||||
|
{
|
||||||
|
auto taskResult = new bdFileMetaData;
|
||||||
|
metadata.MetadataTaskResult(taskResult, false);
|
||||||
|
|
||||||
|
reply->add(taskResult);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
reply->send();
|
reply->send();
|
||||||
}
|
}
|
||||||
|
|
||||||
void bdPooledStorage::_preUpload(service_server* server, byte_buffer* /*buffer*/) const
|
void bdPooledStorage::_preUpload(service_server* server, byte_buffer* buffer) const
|
||||||
{
|
{
|
||||||
// TODO:
|
std::string filename; uint16_t category;
|
||||||
|
buffer->read_string(&filename);
|
||||||
|
buffer->read_uint16(&category);
|
||||||
|
|
||||||
|
uint32_t timestamp = static_cast<uint32_t>(time(nullptr));
|
||||||
|
|
||||||
|
fileshare::FileMetadata metadata;
|
||||||
|
metadata.file.id = timestamp;
|
||||||
|
metadata.file.name = filename;
|
||||||
|
metadata.file.timestamp = timestamp;
|
||||||
|
|
||||||
|
metadata.author.xuid = platform::bnet_get_userid();
|
||||||
|
metadata.author.name = platform::bnet_get_username();
|
||||||
|
|
||||||
|
metadata.category = static_cast<fileshare::fileshareCategory_e>(category);
|
||||||
|
metadata.fileName = fileshare::get_file_name(metadata.file.id, metadata.category);
|
||||||
|
|
||||||
|
metadata.WriteMetaDataJson(fileshare::get_metadata_path(metadata.fileName), metadata.FILE_STATUS_UPLOADING);
|
||||||
|
|
||||||
auto reply = server->create_reply(this->task_id());
|
auto reply = server->create_reply(this->task_id());
|
||||||
|
|
||||||
|
auto result = new bdURL;
|
||||||
|
result->m_url = fileshare::get_file_url(metadata.fileName);
|
||||||
|
result->m_serverType = 8;
|
||||||
|
result->m_serverIndex = "fs";
|
||||||
|
result->m_fileID = metadata.file.id;
|
||||||
|
|
||||||
|
reply->add(result);
|
||||||
reply->send();
|
reply->send();
|
||||||
}
|
}
|
||||||
|
|
||||||
void bdPooledStorage::_postUploadFile(service_server* server, byte_buffer* /*buffer*/) const
|
void bdPooledStorage::_postUploadFile(service_server* server, byte_buffer* buffer) const
|
||||||
{
|
{
|
||||||
// TODO:
|
uint64_t fileID; uint32_t fileSize;
|
||||||
|
uint16_t serverType; std::string serverIndex;
|
||||||
|
|
||||||
|
buffer->read_uint64(&fileID);
|
||||||
|
buffer->read_uint16(&serverType);
|
||||||
|
buffer->read_string(&serverIndex);
|
||||||
|
buffer->read_uint32(&fileSize);
|
||||||
|
|
||||||
|
auto metafile = fileshare::get_metadata_path(fileshare::get_file_name(fileID));
|
||||||
|
|
||||||
|
fileshare::FileMetadata metadata;
|
||||||
|
if (metadata.ReadMetaDataJson(metafile)) {
|
||||||
|
metadata.file.size = fileSize;
|
||||||
|
metadata.fileSize = utilities::io::file_size(fileshare::get_file_path(metadata.fileName));
|
||||||
|
|
||||||
|
metadata.WriteMetaDataJson(metafile, metadata.FILE_STATUS_UPLOADED);
|
||||||
|
}
|
||||||
|
|
||||||
auto reply = server->create_reply(this->task_id());
|
auto reply = server->create_reply(this->task_id());
|
||||||
|
|
||||||
|
auto result = new bdUInt64Result;
|
||||||
|
result->value = fileID;
|
||||||
|
reply->add(result);
|
||||||
|
|
||||||
reply->send();
|
reply->send();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -48,21 +118,53 @@ namespace demonware
|
|||||||
|
|
||||||
void bdPooledStorage::_preDownload(service_server* server, byte_buffer* buffer) const
|
void bdPooledStorage::_preDownload(service_server* server, byte_buffer* buffer) const
|
||||||
{
|
{
|
||||||
// TODO:
|
uint64_t fileID;
|
||||||
auto reply = server->create_reply(this->task_id());
|
buffer->read_uint64(&fileID);
|
||||||
reply->send();
|
|
||||||
|
std::string metafile = fileshare::get_metadata_path(fileshare::get_file_name(fileID));
|
||||||
|
|
||||||
|
fileshare::FileMetadata metadata;
|
||||||
|
if (metadata.ReadMetaDataJson(metafile, metadata.FILE_STATUS_DESCRIBED)
|
||||||
|
&& utilities::io::file_exists(fileshare::get_file_path(metadata.fileName)))
|
||||||
|
{
|
||||||
|
auto reply = server->create_reply(this->task_id());
|
||||||
|
|
||||||
|
auto taskResult = new bdFileMetaData;
|
||||||
|
metadata.MetadataTaskResult(taskResult, true);
|
||||||
|
reply->add(taskResult);
|
||||||
|
|
||||||
|
reply->send();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto reply = server->create_reply(this->task_id(), 2000/*BD_CONTENTSTREAMING_FILE_NOT_AVAILABLE*/);
|
||||||
|
reply->send();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void bdPooledStorage::_preUploadSummary(service_server* server, byte_buffer* /*buffer*/) const
|
void bdPooledStorage::_preUploadSummary(service_server* server, byte_buffer* buffer) const
|
||||||
{
|
{
|
||||||
// TODO:
|
uint64_t fileID{}; uint32_t fileSize{};
|
||||||
auto reply = server->create_reply(this->task_id());
|
//std::string DDL_MetaData;
|
||||||
|
buffer->read_uint64(&fileID);
|
||||||
|
buffer->read_uint32(&fileSize);
|
||||||
|
|
||||||
|
auto metafile = fileshare::get_metadata_path(fileshare::get_file_name(fileID));
|
||||||
|
|
||||||
|
fileshare::FileMetadata metadata;
|
||||||
|
if (metadata.ReadMetaDataJson(metafile)) {
|
||||||
|
buffer->read_blob(&metadata.ddl_metadata);
|
||||||
|
buffer->read_array(10, &metadata.tags);
|
||||||
|
|
||||||
|
metadata.WriteMetaDataJson(metafile, metadata.FILE_STATUS_DESCRIBED);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto reply = server->create_reply(this->task_id(), 108/*BD_SERVICE_NOT_AVAILABLE*/);
|
||||||
reply->send();
|
reply->send();
|
||||||
}
|
}
|
||||||
|
|
||||||
void bdPooledStorage::_postUploadSummary(service_server* server, byte_buffer* /*buffer*/) const
|
void bdPooledStorage::_postUploadSummary(service_server* server, byte_buffer* /*buffer*/) const
|
||||||
{
|
{
|
||||||
// TODO:
|
|
||||||
auto reply = server->create_reply(this->task_id());
|
auto reply = server->create_reply(this->task_id());
|
||||||
reply->send();
|
reply->send();
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
#include <std_include.hpp>
|
#include <std_include.hpp>
|
||||||
#include "../services.hpp"
|
#include "../services.hpp"
|
||||||
|
#include "../fileshare.hpp"
|
||||||
|
|
||||||
namespace demonware
|
namespace demonware
|
||||||
{
|
{
|
||||||
@ -42,8 +43,19 @@ namespace demonware
|
|||||||
|
|
||||||
void bdTags::searchByTagsBase(service_server* server, byte_buffer* /*buffer*/) const
|
void bdTags::searchByTagsBase(service_server* server, byte_buffer* /*buffer*/) const
|
||||||
{
|
{
|
||||||
// TODO:
|
std::vector<uint64_t> demo_ids = fileshare::fileshare_list_demo_ids();
|
||||||
|
|
||||||
auto reply = server->create_reply(this->task_id());
|
auto reply = server->create_reply(this->task_id());
|
||||||
|
|
||||||
|
for (auto id : demo_ids)
|
||||||
|
{
|
||||||
|
auto result = new bdUInt64Result;
|
||||||
|
result->value = id;
|
||||||
|
reply->add(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
logger::write(logger::LOG_TYPE_DEBUG, "[bdTags::searchByTagsBase] Listed Total %u Demos", static_cast<uint32_t>(demo_ids.size()));
|
||||||
|
|
||||||
reply->send();
|
reply->send();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user