MetaCore/Source/MetaCoreRuntimeData/Private/MetaCoreRuntimeDataProject.cpp

208 lines
7.6 KiB
C++

#include "MetaCoreRuntimeData/MetaCoreRuntimeDataProject.h"
#include <algorithm>
#include <fstream>
#include <unordered_set>
namespace MetaCore {
namespace {
template <typename T>
[[nodiscard]] bool MetaCoreWriteBinaryDocument(
const std::filesystem::path& path,
const T& document,
const MetaCoreTypeRegistry& registry
) {
const auto bytes = MetaCoreSerializeToBytes(document, registry);
if (!bytes.has_value()) {
return false;
}
std::filesystem::create_directories(path.parent_path());
std::ofstream output(path, std::ios::binary | std::ios::trunc);
if (!output.is_open()) {
return false;
}
if (!bytes->empty()) {
output.write(reinterpret_cast<const char*>(bytes->data()), static_cast<std::streamsize>(bytes->size()));
}
return output.good();
}
template <typename T>
[[nodiscard]] std::optional<T> MetaCoreReadBinaryDocument(
const std::filesystem::path& path,
const MetaCoreTypeRegistry& registry
) {
std::ifstream input(path, std::ios::binary);
if (!input.is_open()) {
return std::nullopt;
}
input.seekg(0, std::ios::end);
const auto size = static_cast<std::size_t>(input.tellg());
input.seekg(0, std::ios::beg);
std::vector<std::byte> bytes(size);
if (size > 0 && !input.read(reinterpret_cast<char*>(bytes.data()), static_cast<std::streamsize>(size))) {
return std::nullopt;
}
T document{};
if (!MetaCoreDeserializeFromBytes(std::span<const std::byte>(bytes.data(), bytes.size()), document, registry)) {
return std::nullopt;
}
return document;
}
} // namespace
bool MetaCoreWriteRuntimeDataSourcesDocument(
const std::filesystem::path& path,
const MetaCoreRuntimeDataSourcesDocument& document,
const MetaCoreTypeRegistry& registry
) {
return MetaCoreWriteBinaryDocument(path, document, registry);
}
bool MetaCoreWriteRuntimeBindingsDocument(
const std::filesystem::path& path,
const MetaCoreRuntimeBindingsDocument& document,
const MetaCoreTypeRegistry& registry
) {
return MetaCoreWriteBinaryDocument(path, document, registry);
}
std::optional<MetaCoreRuntimeDataSourcesDocument> MetaCoreReadRuntimeDataSourcesDocument(
const std::filesystem::path& path,
const MetaCoreTypeRegistry& registry
) {
return MetaCoreReadBinaryDocument<MetaCoreRuntimeDataSourcesDocument>(path, registry);
}
std::optional<MetaCoreRuntimeBindingsDocument> MetaCoreReadRuntimeBindingsDocument(
const std::filesystem::path& path,
const MetaCoreTypeRegistry& registry
) {
return MetaCoreReadBinaryDocument<MetaCoreRuntimeBindingsDocument>(path, registry);
}
bool MetaCoreWriteRuntimeProjectDocument(
const std::filesystem::path& path,
const MetaCoreRuntimeProjectDocument& document,
const MetaCoreTypeRegistry& registry
) {
return MetaCoreWriteBinaryDocument(path, document, registry);
}
std::optional<MetaCoreRuntimeProjectDocument> MetaCoreReadRuntimeProjectDocument(
const std::filesystem::path& path,
const MetaCoreTypeRegistry& registry
) {
return MetaCoreReadBinaryDocument<MetaCoreRuntimeProjectDocument>(path, registry);
}
bool MetaCoreWriteRuntimeDiagnosticsSnapshot(
const std::filesystem::path& path,
const MetaCoreRuntimeDiagnosticsSnapshot& snapshot,
const MetaCoreTypeRegistry& registry
) {
return MetaCoreWriteBinaryDocument(path, snapshot, registry);
}
std::optional<MetaCoreRuntimeDiagnosticsSnapshot> MetaCoreReadRuntimeDiagnosticsSnapshot(
const std::filesystem::path& path,
const MetaCoreTypeRegistry& registry
) {
return MetaCoreReadBinaryDocument<MetaCoreRuntimeDiagnosticsSnapshot>(path, registry);
}
std::vector<MetaCoreRuntimeConfigIssue> MetaCoreValidateRuntimeDataDocuments(
const MetaCoreRuntimeDataSourcesDocument& sourcesDocument,
const MetaCoreRuntimeBindingsDocument& bindingsDocument
) {
std::vector<MetaCoreRuntimeConfigIssue> issues;
std::unordered_set<std::string> sourceIds;
for (const auto& source : sourcesDocument.Sources) {
if (source.Id.empty()) {
issues.push_back({MetaCoreRuntimeConfigIssueSeverity::Error, "Source", "存在空的 SourceId"});
continue;
}
if (!sourceIds.insert(source.Id).second) {
issues.push_back({MetaCoreRuntimeConfigIssueSeverity::Error, source.Id, "SourceId 重复"});
}
if (source.AdapterType.empty()) {
issues.push_back({MetaCoreRuntimeConfigIssueSeverity::Error, source.Id, "AdapterType 不能为空"});
}
if (source.AdapterType == "file_replay") {
const auto filePathSetting = std::find_if(
source.ConnectionSettings.begin(),
source.ConnectionSettings.end(),
[](const MetaCoreDataSourceSetting& setting) {
return setting.Key == "file_path";
}
);
if (filePathSetting == source.ConnectionSettings.end() || filePathSetting->Value.empty()) {
issues.push_back({MetaCoreRuntimeConfigIssueSeverity::Error, source.Id, "file_replay 缺少 file_path"});
}
}
if (source.AdapterType == "tcp") {
const auto portSetting = std::find_if(
source.ConnectionSettings.begin(),
source.ConnectionSettings.end(),
[](const MetaCoreDataSourceSetting& setting) {
return setting.Key == "port";
}
);
if (portSetting == source.ConnectionSettings.end() || portSetting->Value.empty()) {
issues.push_back({MetaCoreRuntimeConfigIssueSeverity::Error, source.Id, "tcp 缺少 port"});
}
}
}
std::unordered_set<std::string> dataPointIds;
for (const auto& dataPoint : sourcesDocument.DataPoints) {
if (dataPoint.Id.empty()) {
issues.push_back({MetaCoreRuntimeConfigIssueSeverity::Error, "DataPoint", "存在空的 DataPointId"});
continue;
}
if (!dataPointIds.insert(dataPoint.Id).second) {
issues.push_back({MetaCoreRuntimeConfigIssueSeverity::Error, dataPoint.Id, "DataPointId 重复"});
}
if (dataPoint.SourceId.empty() || !sourceIds.contains(dataPoint.SourceId)) {
issues.push_back({MetaCoreRuntimeConfigIssueSeverity::Error, dataPoint.Id, "DataPoint 引用了不存在的 SourceId"});
}
if (dataPoint.ExternalAddress.empty()) {
issues.push_back({MetaCoreRuntimeConfigIssueSeverity::Warning, dataPoint.Id, "ExternalAddress 为空"});
}
}
std::unordered_set<std::string> bindingIds;
for (const auto& binding : bindingsDocument.Bindings) {
if (binding.BindingId.empty()) {
issues.push_back({MetaCoreRuntimeConfigIssueSeverity::Error, "Binding", "存在空的 BindingId"});
continue;
}
if (!bindingIds.insert(binding.BindingId).second) {
issues.push_back({MetaCoreRuntimeConfigIssueSeverity::Error, binding.BindingId, "BindingId 重复"});
}
if (binding.DataPointId.empty() || !dataPointIds.contains(binding.DataPointId)) {
issues.push_back({MetaCoreRuntimeConfigIssueSeverity::Error, binding.BindingId, "Binding 引用了不存在的 DataPointId"});
}
if (binding.TargetObjectId == 0) {
issues.push_back({MetaCoreRuntimeConfigIssueSeverity::Error, binding.BindingId, "Binding 缺少 TargetObjectId"});
}
}
if (sourcesDocument.Sources.empty()) {
issues.push_back({MetaCoreRuntimeConfigIssueSeverity::Warning, "Runtime", "当前没有任何 Source"});
}
return issues;
}
} // namespace MetaCore