flatbuffers::Parser::Parse 函数
parser->opts.strict_json = true; 置为JSON格式。
头文件:
#pragma once
#include "prerequisites.h"
#include "msg_define_generated.h"
#include "LoggerManager.h"
class MessageDefine final : private boost::noncopyable
{
public:
MessageDefine() = default;
~MessageDefine() = default;
static MessageDefine* instance();
void initialize();
std::shared_ptr findSchema(const std::string& name);
std::shared_ptr findRequestSchema(MSG_DEFINE id);
std::shared_ptr findReplySchema(MSG_DEFINE id);
template
inline const T* parseRequestMessage(MSG_DEFINE id, std::string& message, size_t offset)
{
if (message.size() <= offset)
{
LOG_WARNING(default, "Schema size < offset, id[{}]", EnumNameMSG_DEFINE(id));
return nullptr;
}
auto parser = MessageDefine::instance()->findRequestSchema(id);
if (!parser)
{
LOG_WARNING(default, "Schema not find, id[{}]", EnumNameMSG_DEFINE(id));
return nullptr;
}
if (!parser->Parse(message.c_str() + offset, nullptr))
{
LOG_WARNING(default, "Schema parse failed:{}, id[{}], error:{}", message, EnumNameMSG_DEFINE(id), parser->error_);
return nullptr;
}
flatbuffers::Verifier verifier(parser->builder_.GetBufferPointer(), parser->builder_.GetSize());
if (verifier.VerifyBuffer(nullptr))
{
message.resize(parser->builder_.GetSize() + offset);
memcpy((char*)(message.c_str() + offset), parser->builder_.GetBufferPointer(), parser->builder_.GetSize());
return flatbuffers::GetRoot(message.c_str() + offset);
}
return nullptr;
}
template
inline const T* parseReplyMessage(MSG_DEFINE id, std::string& message, size_t offset)
{
if (message.size() <= offset)
{
LOG_WARNING(default, "Schema size < offset, id[{}]", EnumNameMSG_DEFINE(id));
return nullptr;
}
auto parser = MessageDefine::instance()->findReplySchema(id);
if (!parser)
{
LOG_WARNING(default, "Schema not find, id[{}]", EnumNameMSG_DEFINE(id));
return nullptr;
}
if (!parser->Parse(message.c_str() + offset, nullptr))
{
LOG_WARNING(default, "Schema parse failed:{}, id[{}]", message, EnumNameMSG_DEFINE(id));
return nullptr;
}
flatbuffers::Verifier verifier(parser->builder_.GetBufferPointer(), parser->builder_.GetSize());
if (verifier.VerifyBuffer(nullptr))
{
message.resize(parser->builder_.GetSize() + offset);
memcpy((char*)(message.c_str() + offset), parser->builder_.GetBufferPointer(), parser->builder_.GetSize());
return flatbuffers::GetRoot(message.c_str() + offset);
}
return nullptr;
}
protected:
bool loadSchemaFile(std::string_view path, const std::string& filename, bool bStrict);
protected:
std::unordered_map> m_parsers;
std::unordered_map m_requestIdNames;
std::unordered_map m_replyIdNames;
};
template
inline const T* json2fb(const std::string& name, const char* message, std::string_view* outMessage)
{
auto parser = MessageDefine::instance()->findSchema(name);
if (!parser)
{
LOG_WARNING(default, "Schema:{} not find", name);
return nullptr;
}
if (!parser->Parse(message, nullptr))
{
LOG_WARNING(default, "Schema:{} parse failed:{}", name, message);
return nullptr;
}
flatbuffers::Verifier verifier(parser->builder_.GetBufferPointer(), parser->builder_.GetSize());
if (verifier.VerifyBuffer(nullptr))
{
if (outMessage)
*outMessage = std::string_view(reinterpret_cast(parser->builder_.GetBufferPointer()), parser->builder_.GetSize());
return flatbuffers::GetRoot(parser->builder_.GetBufferPointer());
}
return nullptr;
}
inline bool bin2json(const std::string& name, const void* message, std::string& jsongen)
{
auto parser = MessageDefine::instance()->findSchema(name);
if (!parser)
{
LOG_WARNING(default, "Schema:{} not find", name);
return false;
}
if (!GenerateText(*parser, message, &jsongen))
{
LOG_WARNING(default, "Schema:{} Couldn't serialize parsed data to JSON", name);
return false;
}
return true;
}
源文件:
#include "MessageDefine.h"
#include "ConfigLoader.h"
#include "MessageDefineConfig_generated.h"
MessageDefine* MessageDefine::instance()
{
thread_local std::unique_ptr tl_instance;
if (!tl_instance)
{
tl_instance = std::make_unique();
tl_instance->initialize();
}
return tl_instance.get();
}
void MessageDefine::initialize()
{
TConfigLoader cfgMessageDefine;
if (!cfgMessageDefine.parse("common/MessageDefineConfig.fbs", "config/MessageDefineConfig.json"))
{
return;
}
auto cfg = cfgMessageDefine.data;
for (auto item : *cfg->items())
{
auto path = item->path()->string_view();
if (item->names())
{
for (auto name : *item->names())
{
loadSchemaFile(path, name->str(), true);
}
}
if (item->no_strict_names())
{
for (auto name : *item->no_strict_names())
{
loadSchemaFile(path, name->str(), false);
}
}
}
for (auto item : *cfg->request_id_names())
{
m_requestIdNames[item->id()] = item->name()->str();
}
for (auto item : *cfg->reply_id_names())
{
m_replyIdNames[item->id()] = item->name()->str();
}
}
bool MessageDefine::loadSchemaFile(std::string_view path, const std::string& filename, bool bStrict)
{
if (m_parsers.find(filename) != m_parsers.end())
return true;
// load FlatBuffer schema (.fbs)
std::string schemafile;
std::string schemafilename = fmt::format(path, filename);
bool ok = flatbuffers::LoadFile(schemafilename.c_str(), false, &schemafile);
if (!ok)
{
LOG_ERROR(network, "couldn't load schemafilename:{}", filename);
return false;
}
// parse schema first, so we can use it to parse the data after
auto parser = std::make_shared();
const char* include_directories[] = { "../../fbs", nullptr };
ok = parser->Parse(schemafile.c_str(), include_directories);
if (!ok)
{
LOG_ERROR(network, "parse schemafilename:{} failed: {}", filename, parser->error_);
return false;
}
if (bStrict)
{
parser->opts.strict_json = true;
}
m_parsers.emplace(filename, parser);
return true;
}
std::shared_ptr MessageDefine::findSchema(const std::string& name)
{
if (auto it = m_parsers.find(name); it != m_parsers.end())
{
it->second->builder_.Clear();
return it->second;
}
return nullptr;
}
std::shared_ptr MessageDefine::findRequestSchema(MSG_DEFINE id)
{
if (auto it = m_requestIdNames.find(id); it != m_requestIdNames.end())
{
return findSchema(it->second);
}
return nullptr;
}
std::shared_ptr MessageDefine::findReplySchema(MSG_DEFINE id)
{
if (auto it = m_replyIdNames.find(id); it != m_replyIdNames.end())
{
return findSchema(it->second);
}
return nullptr;
}