diff --git a/source/proxy-dll/component/demonware.cpp b/source/proxy-dll/component/demonware.cpp index 0022788..f8bc73b 100644 --- a/source/proxy-dll/component/demonware.cpp +++ b/source/proxy-dll/component/demonware.cpp @@ -9,6 +9,7 @@ #include "demonware/servers/auth3_server.hpp" #include "demonware/servers/stun_server.hpp" #include "demonware/servers/umbrella_server.hpp" +#include "demonware/servers/fileshare_server.hpp" #include "demonware/server_registry.hpp" #define TCP_BLOCKING true @@ -477,6 +478,7 @@ namespace demonware tcp_servers.create("ops4-pc-auth3.prod.demonware.net"); tcp_servers.create("ops4-pc-lobby.prod.demonware.net"); tcp_servers.create("prod.umbrella.demonware.net"); + tcp_servers.create("ops4-fileshare.prod.schild.net"); } void pre_start() override diff --git a/source/proxy-dll/demonware/fileshare.cpp b/source/proxy-dll/demonware/fileshare.cpp new file mode 100644 index 0000000..b0b6071 --- /dev/null +++ b/source/proxy-dll/demonware/fileshare.cpp @@ -0,0 +1,268 @@ +#include +#include "fileshare.hpp" +#include "component/platform.hpp" + +#include +#include +#include + +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 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(jsonDocument["status"].GetInt()); + } + + if (jsonDocument.HasMember("category") && jsonDocument["category"].IsInt()) { + this->category = static_cast(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 fileshare_list_demo_ids() + { + std::vector results; + + std::vector 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; + } +} diff --git a/source/proxy-dll/demonware/fileshare.hpp b/source/proxy-dll/demonware/fileshare.hpp new file mode 100644 index 0000000..2064b96 --- /dev/null +++ b/source/proxy-dll/demonware/fileshare.hpp @@ -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 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 fileshare_list_demo_ids(); +} diff --git a/source/proxy-dll/demonware/servers/fileshare_server.cpp b/source/proxy-dll/demonware/servers/fileshare_server.cpp new file mode 100644 index 0000000..9571068 --- /dev/null +++ b/source/proxy-dll/demonware/servers/fileshare_server.cpp @@ -0,0 +1,111 @@ +#include +#include "fileshare_server.hpp" + +#include "../fileshare.hpp" +#include +#include + +std::string fileshare_upload_file_name{}; +std::vector 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 = "404 Not Found

Not Found

The requested URL was not found on this server.

"; + + 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& 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"; + } +} \ No newline at end of file diff --git a/source/proxy-dll/demonware/servers/fileshare_server.hpp b/source/proxy-dll/demonware/servers/fileshare_server.hpp new file mode 100644 index 0000000..19ba52e --- /dev/null +++ b/source/proxy-dll/demonware/servers/fileshare_server.hpp @@ -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& buffer); + }; +} diff --git a/source/proxy-dll/demonware/services/bdPooledStorage.cpp b/source/proxy-dll/demonware/services/bdPooledStorage.cpp index 96423c8..39835bc 100644 --- a/source/proxy-dll/demonware/services/bdPooledStorage.cpp +++ b/source/proxy-dll/demonware/services/bdPooledStorage.cpp @@ -1,5 +1,9 @@ #include #include "../services.hpp" +#include "../fileshare.hpp" +#include "component/platform.hpp" + +#include namespace demonware { @@ -18,24 +22,90 @@ namespace demonware 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 requested_files; + buffer->read_array(10, &requested_files); + 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(); } - 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(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(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 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(); } - 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 result = new bdUInt64Result; + result->value = fileID; + reply->add(result); + reply->send(); } @@ -48,21 +118,53 @@ namespace demonware void bdPooledStorage::_preDownload(service_server* server, byte_buffer* buffer) const { - // TODO: - auto reply = server->create_reply(this->task_id()); - reply->send(); + uint64_t fileID; + buffer->read_uint64(&fileID); + + 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: - auto reply = server->create_reply(this->task_id()); + uint64_t fileID{}; uint32_t fileSize{}; + //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(); } void bdPooledStorage::_postUploadSummary(service_server* server, byte_buffer* /*buffer*/) const { - // TODO: auto reply = server->create_reply(this->task_id()); reply->send(); } diff --git a/source/proxy-dll/demonware/services/bdTags.cpp b/source/proxy-dll/demonware/services/bdTags.cpp index 7478e9f..65a3a3f 100644 --- a/source/proxy-dll/demonware/services/bdTags.cpp +++ b/source/proxy-dll/demonware/services/bdTags.cpp @@ -1,5 +1,6 @@ #include #include "../services.hpp" +#include "../fileshare.hpp" namespace demonware { @@ -42,8 +43,19 @@ namespace demonware void bdTags::searchByTagsBase(service_server* server, byte_buffer* /*buffer*/) const { - // TODO: + std::vector demo_ids = fileshare::fileshare_list_demo_ids(); + 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(demo_ids.size())); + reply->send(); } }