diff --git a/cmd/protoc-gen-cpp-tableau-loader/embed/load.pc.cc b/cmd/protoc-gen-cpp-tableau-loader/embed/load.pc.cc index 0cf2d6c3..2f5b68f6 100644 --- a/cmd/protoc-gen-cpp-tableau-loader/embed/load.pc.cc +++ b/cmd/protoc-gen-cpp-tableau-loader/embed/load.pc.cc @@ -64,8 +64,8 @@ std::shared_ptr ParseMessagerOptions(std::shared_ptr options /* = nullptr*/) { +bool LoadMessagerWithPatch(google::protobuf::Message& msg, const std::filesystem::path& path, Format fmt, + tableau::Patch patch, std::shared_ptr options /* = nullptr*/) { if (options == nullptr) { return LoadMessager(msg, path, fmt, nullptr); } @@ -73,21 +73,21 @@ bool LoadMessagerWithPatch(google::protobuf::Message& msg, const std::string& pa // ignore patch files when LoadMode::kModeOnlyMain specified return options->load_func(msg, path, fmt, nullptr); } - std::string name = util::GetProtoName(msg); - std::vector patch_paths; + const std::string& name = msg.GetDescriptor()->name(); + std::vector patch_paths; if (!options->patch_paths.empty()) { // patch path specified in PatchPaths, then use it instead of PatchDirs. patch_paths = options->patch_paths; } else { - std::string filename = name + util::Format2Ext(fmt); + std::filesystem::path filename = name + util::Format2Ext(fmt); for (auto&& patch_dir : options->patch_dirs) { - patch_paths.emplace_back((std::filesystem::path(patch_dir) / filename).make_preferred().string()); + patch_paths.emplace_back(patch_dir / filename); } } - std::vector existed_patch_paths; + std::vector existed_patch_paths; for (auto&& patch_path : patch_paths) { - if (util::ExistsFile(patch_path)) { + if (std::filesystem::exists(patch_path)) { existed_patch_paths.emplace_back(patch_path); } } @@ -103,8 +103,8 @@ bool LoadMessagerWithPatch(google::protobuf::Message& msg, const std::string& pa switch (patch) { case tableau::PATCH_REPLACE: { // just use the last "patch" file - std::string& patch_path = existed_patch_paths.back(); - if (!options->load_func(msg, patch_path, util::Ext2Format(util::GetExt(patch_path)), options)) { + std::filesystem::path& patch_path = existed_patch_paths.back(); + if (!options->load_func(msg, patch_path, util::GetFormat(patch_path), options)) { return false; } break; @@ -121,7 +121,7 @@ bool LoadMessagerWithPatch(google::protobuf::Message& msg, const std::string& pa std::unique_ptr _auto_release(msg.New()); // load patch_msg from each "patch" file for (auto&& patch_path : existed_patch_paths) { - if (!options->load_func(*patch_msg_ptr, patch_path, util::Ext2Format(util::GetExt(patch_path)), options)) { + if (!options->load_func(*patch_msg_ptr, patch_path, util::GetFormat(patch_path), options)) { return false; } if (!PatchMessage(msg, *patch_msg_ptr)) { @@ -131,16 +131,16 @@ bool LoadMessagerWithPatch(google::protobuf::Message& msg, const std::string& pa break; } default: { - SetErrMsg("unknown patch type: " + util::GetPatchName(patch)); + SetErrMsg("unknown patch type: " + tableau::Patch_Name(patch)); return false; } } - ATOM_DEBUG("patched(%s) %s by %s: %s", util::GetPatchName(patch).c_str(), name.c_str(), + ATOM_DEBUG("patched(%s) %s by %s: %s", tableau::Patch_Name(patch).c_str(), name.c_str(), ATOM_VECTOR_STR(existed_patch_paths).c_str(), msg.ShortDebugString().c_str()); return true; } -bool LoadMessager(google::protobuf::Message& msg, const std::string& path, Format fmt, +bool LoadMessager(google::protobuf::Message& msg, const std::filesystem::path& path, Format fmt, std::shared_ptr options /* = nullptr*/) { std::string content; ReadFunc read_func = util::ReadFile; @@ -168,27 +168,23 @@ bool LoadMessager(google::protobuf::Message& msg, const std::string& path, Forma } } -bool LoadMessagerInDir(google::protobuf::Message& msg, const std::string& dir, Format fmt, +bool LoadMessagerInDir(google::protobuf::Message& msg, const std::filesystem::path& dir, Format fmt, std::shared_ptr options /* = nullptr*/) { - std::string name = util::GetProtoName(msg); - std::string path; + const std::string& name = msg.GetDescriptor()->name(); + std::filesystem::path path; if (options && !options->path.empty()) { // path specified in Paths, then use it instead of dir. path = options->path; - fmt = util::Ext2Format(util::GetExt(path)); + fmt = util::GetFormat(path); } if (path.empty()) { - std::string filename = name + util::Format2Ext(fmt); - path = (std::filesystem::path(dir) / filename).make_preferred().string(); + std::filesystem::path filename = name + util::Format2Ext(fmt); + path = dir / filename; } const google::protobuf::Descriptor* descriptor = msg.GetDescriptor(); - if (!descriptor) { - SetErrMsg("failed to get descriptor of message: " + name); - return false; - } // access the extension directly using the generated identifier - const tableau::WorksheetOptions worksheet_options = descriptor->options().GetExtension(tableau::worksheet); + const tableau::WorksheetOptions& worksheet_options = descriptor->options().GetExtension(tableau::worksheet); if (worksheet_options.patch() != tableau::PATCH_NONE) { return LoadMessagerWithPatch(msg, path, fmt, worksheet_options.patch(), options); } diff --git a/cmd/protoc-gen-cpp-tableau-loader/embed/load.pc.h b/cmd/protoc-gen-cpp-tableau-loader/embed/load.pc.h index b37f05a8..e8ba9118 100644 --- a/cmd/protoc-gen-cpp-tableau-loader/embed/load.pc.h +++ b/cmd/protoc-gen-cpp-tableau-loader/embed/load.pc.h @@ -2,6 +2,7 @@ #include #include +#include #include #include #include @@ -20,10 +21,10 @@ struct MessagerOptions; class Hub; // ReadFunc reads the config file and returns its content. -using ReadFunc = std::function; +using ReadFunc = std::function; // LoadFunc defines a func which can load message's content based on the given // path, format, and options. -using LoadFunc = std::function options)>; // BaseOptions is the common struct for both global-level and messager-level @@ -34,7 +35,7 @@ struct BaseOptions { // Refer https://protobuf.dev/reference/cpp/api-docs/google.protobuf.util.json_util/#JsonParseOptions. std::optional ignore_unknown_fields; // Specify the directory paths for config patching. - std::vector patch_dirs; + std::vector patch_dirs; // Specify the loading mode for config patching. // - For LoadOptions, default is LoadMode::kModeAll. // - For MessagerOptions, inherit from LoadOptions if not set. @@ -63,10 +64,10 @@ struct MessagerOptions : public BaseOptions { // Path maps each messager name to a corresponding config file path. // If specified, then the main messager will be parsed from the file // directly, other than the specified load dir. - std::string path; + std::filesystem::path path; // Patch paths maps each messager name to one or multiple corresponding patch file paths. // If specified, then main messager will be patched. - std::vector patch_paths; + std::vector patch_paths; }; class Messager { @@ -77,10 +78,14 @@ class Messager { public: virtual ~Messager() = default; - static const std::string& Name() { return kEmpty; } + static const std::string& Name() { + static const std::string kEmpty = ""; + return kEmpty; + } const Stats& GetStats() { return stats_; } // Load fills message from file in the specified directory and format. - virtual bool Load(const std::string& dir, Format fmt, std::shared_ptr options = nullptr) = 0; + virtual bool Load(const std::filesystem::path& dir, Format fmt, + std::shared_ptr options = nullptr) = 0; // Message returns the inner message data. virtual const google::protobuf::Message* Message() const { return nullptr; } // callback after all messagers loaded. @@ -98,8 +103,8 @@ std::shared_ptr ParseLoadOptions(std::shared_ptr ParseMessagerOptions(std::shared_ptr opts, const std::string& name); -bool LoadMessager(google::protobuf::Message& msg, const std::string& path, Format fmt = Format::kJSON, +bool LoadMessager(google::protobuf::Message& msg, const std::filesystem::path& path, Format fmt = Format::kJSON, std::shared_ptr options = nullptr); -bool LoadMessagerInDir(google::protobuf::Message& msg, const std::string& dir, Format fmt = Format::kJSON, +bool LoadMessagerInDir(google::protobuf::Message& msg, const std::filesystem::path& dir, Format fmt = Format::kJSON, std::shared_ptr options = nullptr); } // namespace tableau \ No newline at end of file diff --git a/cmd/protoc-gen-cpp-tableau-loader/embed/logger.pc.cc b/cmd/protoc-gen-cpp-tableau-loader/embed/logger.pc.cc index 893b63a6..8f2e199c 100644 --- a/cmd/protoc-gen-cpp-tableau-loader/embed/logger.pc.cc +++ b/cmd/protoc-gen-cpp-tableau-loader/embed/logger.pc.cc @@ -12,6 +12,7 @@ #include #endif +#include #include #include @@ -53,14 +54,12 @@ void SetDefaultLogger(Logger* logger) { g_default_logger = logger; } -int Logger::Init(const std::string& path, Level level) { - std::string dir = util::GetDir(path); - if (!dir.empty()) { - // prepare the specified directory - int status = util::Mkdir(dir); - if (status == -1) { - return status; - } +int Logger::Init(const std::filesystem::path& path, Level level) { + std::error_code ec; + std::filesystem::create_directories(path.parent_path(), ec); + if (ec) { + SetErrMsg("failed to create log directory: " + ec.message()); + return ec.value(); } ofs_.open(path, std::ofstream::out | std::ofstream::app); os_ = &ofs_; // use file stream as output stream diff --git a/cmd/protoc-gen-cpp-tableau-loader/embed/logger.pc.h b/cmd/protoc-gen-cpp-tableau-loader/embed/logger.pc.h index 8c26f011..ca212403 100644 --- a/cmd/protoc-gen-cpp-tableau-loader/embed/logger.pc.h +++ b/cmd/protoc-gen-cpp-tableau-loader/embed/logger.pc.h @@ -1,4 +1,5 @@ #pragma once +#include #include #include #include @@ -49,7 +50,7 @@ class Logger { ~Logger() { ofs_.close(); } // Init the logger with the specified path. // NOTE: no guarantee of thread-safety. - int Init(const std::string& path, Level level); + int Init(const std::filesystem::path& path, Level level); // Set the writer for writing log. void SetWriter(Writer writer) { writer_ = writer; } // Log with guarantee of thread-safety. diff --git a/cmd/protoc-gen-cpp-tableau-loader/embed/util.pc.cc b/cmd/protoc-gen-cpp-tableau-loader/embed/util.pc.cc index 67dc773e..11236ea3 100644 --- a/cmd/protoc-gen-cpp-tableau-loader/embed/util.pc.cc +++ b/cmd/protoc-gen-cpp-tableau-loader/embed/util.pc.cc @@ -22,42 +22,18 @@ const std::string kTextExt = ".txt"; const std::string kBinExt = ".bin"; namespace util { -int Mkdir(const std::string& path) { - std::error_code ec; - if (!std::filesystem::create_directories(path, ec)) { - if (ec) { - std::cerr << "system error: " << ec.message() << std::endl; - return -1; - } - } - return 0; -} - -std::string GetDir(const std::string& path) { return std::filesystem::path(path).parent_path().string(); } - -bool ExistsFile(const std::string& filename) { return std::filesystem::exists(filename); } - -bool ReadFile(const std::string& filename, std::string& content) { +bool ReadFile(const std::filesystem::path& filename, std::string& content) { std::ifstream file(filename); if (!file.is_open()) { - SetErrMsg("failed to open " + filename + ": " + strerror(errno)); + SetErrMsg("failed to open " + filename.string() + ": " + strerror(errno)); return false; } - std::stringstream ss; - ss << file.rdbuf(); - content = ss.str(); + content.assign(std::istreambuf_iterator(file), {}); return true; } -std::string GetExt(const std::string& path) { - std::size_t pos = path.find_last_of("."); - if (pos != std::string::npos) { - return path.substr(pos); - } - return kEmpty; -} - -Format Ext2Format(const std::string& ext) { +Format GetFormat(const std::filesystem::path& path) { + auto ext = path.extension(); if (ext == kJSONExt) { return Format::kJSON; } else if (ext == kTextExt) { @@ -93,7 +69,7 @@ bool JSON2Message(const std::string& json, google::protobuf::Message& msg, status = google::protobuf::util::JsonStringToMessage(json, &msg); } if (!status.ok()) { - SetErrMsg("failed to parse " + GetProtoName(msg) + kJSONExt + ": " + status.ToString()); + SetErrMsg("failed to parse " + msg.GetDescriptor()->name() + kJSONExt + ": " + status.ToString()); return false; } return true; @@ -101,35 +77,20 @@ bool JSON2Message(const std::string& json, google::protobuf::Message& msg, bool Text2Message(const std::string& text, google::protobuf::Message& msg) { if (!google::protobuf::TextFormat::ParseFromString(text, &msg)) { - SetErrMsg("failed to parse " + GetProtoName(msg) + kTextExt); + SetErrMsg("failed to parse " + msg.GetDescriptor()->name() + kTextExt); return false; } return true; } + bool Bin2Message(const std::string& bin, google::protobuf::Message& msg) { if (!msg.ParseFromString(bin)) { - SetErrMsg("failed to parse " + GetProtoName(msg) + kBinExt); + SetErrMsg("failed to parse " + msg.GetDescriptor()->name() + kBinExt); return false; } return true; } -const std::string& GetProtoName(const google::protobuf::Message& msg) { - const auto* md = msg.GetDescriptor(); - return md != nullptr ? md->name() : kEmpty; -} - -std::string GetPatchName(tableau::Patch patch) { - auto* descriptor = tableau::Patch_descriptor(); - if (descriptor) { - auto* value = descriptor->FindValueByNumber(patch); - if (value) { - return value->name(); - } - } - return std::to_string(static_cast(patch)); -} - // refer: https://github.com/protocolbuffers/protobuf/blob/main/src/google/protobuf/stubs/logging.h void ProtobufLogHandler(google::protobuf::LogLevel level, const char* filename, int line, const std::string& msg) { static const std::unordered_map kLevelMap = {{google::protobuf::LOGLEVEL_INFO, log::kInfo}, diff --git a/cmd/protoc-gen-cpp-tableau-loader/embed/util.pc.h b/cmd/protoc-gen-cpp-tableau-loader/embed/util.pc.h index f2ed38c0..72350710 100644 --- a/cmd/protoc-gen-cpp-tableau-loader/embed/util.pc.h +++ b/cmd/protoc-gen-cpp-tableau-loader/embed/util.pc.h @@ -2,6 +2,7 @@ #include #include +#include #include #include @@ -18,7 +19,6 @@ enum class Format { kBin, }; -static const std::string kEmpty = ""; extern const std::string kUnknownExt; extern const std::string kJSONExt; extern const std::string kTextExt; @@ -48,27 +48,11 @@ inline std::size_t SugaredHashCombine(const T& v, O... others) { return seed; } -// Mkdir makes dir recursively. -int Mkdir(const std::string& path); -// GetDir returns all but the last element of path, typically the path's -// directory. -std::string GetDir(const std::string& path); -// ExistsFile checks if a file exists. -bool ExistsFile(const std::string& filename); // ReadFile reads the file named by filename and returns the contents. -bool ReadFile(const std::string& filename, std::string& content); +bool ReadFile(const std::filesystem::path& filename, std::string& content); -// GetExt returns the file name extension used by path. -// The extension is the suffix beginning at the final dot -// in the final element of path; it is empty if there is -// no dot. -std::string GetExt(const std::string& path); -// Convert file extension to Format type. -// NOTE: ext includes dot ".", such as: -// - kJSONExt: ".json" -// - kTextExt: ".txt" -// - kBinExt: ".bin" -Format Ext2Format(const std::string& ext); +// GetFormat returns the Format type used by path. +Format GetFormat(const std::filesystem::path& path); // Empty string will be returned if an unsupported enum value has been passed, // and the error message can be obtained by GetErrMsg(). const std::string& Format2Ext(Format fmt); @@ -78,9 +62,6 @@ bool JSON2Message(const std::string& json, google::protobuf::Message& msg, bool Text2Message(const std::string& text, google::protobuf::Message& msg); bool Bin2Message(const std::string& bin, google::protobuf::Message& msg); -const std::string& GetProtoName(const google::protobuf::Message& msg); -std::string GetPatchName(tableau::Patch patch); - void ProtobufLogHandler(google::protobuf::LogLevel level, const char* filename, int line, const std::string& msg); class TimeProfiler { diff --git a/cmd/protoc-gen-cpp-tableau-loader/hub.go b/cmd/protoc-gen-cpp-tableau-loader/hub.go index 63453bed..dee3a2cf 100644 --- a/cmd/protoc-gen-cpp-tableau-loader/hub.go +++ b/cmd/protoc-gen-cpp-tableau-loader/hub.go @@ -125,7 +125,7 @@ func generateHubCppTplSpec(g *protogen.GeneratedFile, protofiles []string, fileM func generateHubCppMsgContainerCtor(g *protogen.GeneratedFile, protofiles []string, fileMessagers map[string][]string) { for _, proto := range protofiles { for _, messager := range fileMessagers[proto] { - g.P(helper.Indent(1), strcase.ToSnake(messager), "_ = std::dynamic_pointer_cast<", messager, `>(GetMessager("`, messager, `"));`) + g.P(helper.Indent(1), strcase.ToSnake(messager), "_ = std::dynamic_pointer_cast<", messager, `>(GetMessager(`, messager, `::Name()));`) } } } @@ -179,12 +179,13 @@ class Hub { /***** Synchronous Loading *****/ // Load fills messages (in MessagerContainer) from files in the specified directory and format. - bool Load(const std::string& dir, Format fmt = Format::kJSON, std::shared_ptr options = nullptr); + bool Load(const std::filesystem::path& dir, Format fmt = Format::kJSON, + std::shared_ptr options = nullptr); /***** Asynchronous Loading *****/ // Load configs into temp MessagerContainer, and you should call LoopOnce() in you app's main loop, // in order to take the temp MessagerContainer into effect. - bool AsyncLoad(const std::string& dir, Format fmt = Format::kJSON, + bool AsyncLoad(const std::filesystem::path& dir, Format fmt = Format::kJSON, std::shared_ptr options = nullptr); int LoopOnce(); // You'd better initialize the scheduler in the main thread. @@ -212,7 +213,7 @@ class Hub { inline std::time_t GetLastLoadedTime() const; private: - std::shared_ptr InternalLoad(const std::string& dir, Format fmt = Format::kJSON, + std::shared_ptr InternalLoad(const std::filesystem::path& dir, Format fmt = Format::kJSON, std::shared_ptr options = nullptr) const; std::shared_ptr NewMessagerMap() const; std::shared_ptr GetMessagerContainerWithProvider() const; @@ -308,7 +309,7 @@ void Hub::InitOnce(std::shared_ptr options) { std::call_once(init_once_, [&]() { options_ = options; }); } -bool Hub::Load(const std::string& dir, Format fmt /* = Format::kJSON */, +bool Hub::Load(const std::filesystem::path& dir, Format fmt /* = Format::kJSON */, std::shared_ptr options /* = nullptr */) { auto msger_map = InternalLoad(dir, fmt, options); if (!msger_map) { @@ -322,7 +323,7 @@ bool Hub::Load(const std::string& dir, Format fmt /* = Format::kJSON */, return true; } -bool Hub::AsyncLoad(const std::string& dir, Format fmt /* = Format::kJSON */, +bool Hub::AsyncLoad(const std::filesystem::path& dir, Format fmt /* = Format::kJSON */, std::shared_ptr options /* = nullptr */) { auto msger_map = InternalLoad(dir, fmt, options); if (!msger_map) { @@ -343,7 +344,7 @@ void Hub::InitScheduler() { sched_->Current(); } -std::shared_ptr Hub::InternalLoad(const std::string& dir, Format fmt /* = Format::kJSON */, +std::shared_ptr Hub::InternalLoad(const std::filesystem::path& dir, Format fmt /* = Format::kJSON */, std::shared_ptr options /* = nullptr */) const { // intercept protobuf error logs auto old_handler = google::protobuf::SetLogHandler(util::ProtobufLogHandler); diff --git a/cmd/protoc-gen-cpp-tableau-loader/messager.go b/cmd/protoc-gen-cpp-tableau-loader/messager.go index 19f2e3a5..8734d486 100644 --- a/cmd/protoc-gen-cpp-tableau-loader/messager.go +++ b/cmd/protoc-gen-cpp-tableau-loader/messager.go @@ -43,6 +43,7 @@ func generateCppFile(gen *protogen.Plugin, file *protogen.File) *protogen.Genera // generateHppFileContent generates type definitions. func generateHppFileContent(file *protogen.File, g *protogen.GeneratedFile) { g.P("#pragma once") + g.P("#include ") g.P("#include ") g.P() g.P(`#include "`, "load.", pcExt, `.h"`) @@ -56,7 +57,7 @@ func generateHppFileContent(file *protogen.File, g *protogen.GeneratedFile) { opts := message.Desc.Options().(*descriptorpb.MessageOptions) worksheet := proto.GetExtension(opts, tableaupb.E_Worksheet).(*tableaupb.WorksheetOptions) if worksheet != nil { - genHppMessage(file, g, message) + genHppMessage(g, message) messagerName := string(message.Desc.Name()) fileMessagers = append(fileMessagers, messagerName) } @@ -76,16 +77,15 @@ func generateHppFileContent(file *protogen.File, g *protogen.GeneratedFile) { } // genHppMessage generates a message definition. -func genHppMessage(file *protogen.File, g *protogen.GeneratedFile, message *protogen.Message) { - pkg := string(file.Desc.Package()) - cppFullName := strings.ReplaceAll(pkg, ".", "::") + "::" + string(message.Desc.Name()) +func genHppMessage(g *protogen.GeneratedFile, message *protogen.Message) { + cppFullName := helper.ParseCppClassType(message.Desc) messagerFullName := string(message.Desc.FullName()) indexDescriptor := index.ParseIndexDescriptor(message.Desc) g.P("class ", message.Desc.Name(), " : public Messager {") g.P(" public:") g.P(helper.Indent(1), "static const std::string& Name() { return kProtoName; }") - g.P(helper.Indent(1), "virtual bool Load(const std::string& dir, Format fmt, std::shared_ptr options = nullptr) override;") + g.P(helper.Indent(1), "virtual bool Load(const std::filesystem::path& dir, Format fmt, std::shared_ptr options = nullptr) override;") g.P(helper.Indent(1), "const ", cppFullName, "& Data() const { return data_; }") g.P(helper.Indent(1), "const google::protobuf::Message* Message() const override { return &data_; }") g.P() @@ -154,11 +154,12 @@ func generateCppFileContent(file *protogen.File, g *protogen.GeneratedFile) { func genCppMessage(g *protogen.GeneratedFile, message *protogen.Message) { messagerName := string(message.Desc.Name()) messagerFullName := string(message.Desc.FullName()) + cppFullName := helper.ParseCppClassType(message.Desc) indexDescriptor := index.ParseIndexDescriptor(message.Desc) - g.P("const std::string ", messagerName, "::kProtoName = ", `"`, messagerName, `";`) + g.P("const std::string ", messagerName, "::kProtoName = ", cppFullName, `::GetDescriptor()->name();`) g.P() - g.P("bool ", messagerName, "::Load(const std::string& dir, Format fmt, std::shared_ptr options /* = nullptr */) {") + g.P("bool ", messagerName, "::Load(const std::filesystem::path& dir, Format fmt, std::shared_ptr options /* = nullptr */) {") g.P(helper.Indent(1), "tableau::util::TimeProfiler profiler;") g.P(helper.Indent(1), "bool loaded = LoadMessagerInDir(data_, dir, fmt, options);") g.P(helper.Indent(1), "bool ok = loaded ? ProcessAfterLoad() : false;") diff --git a/cmd/protoc-gen-cpp-tableau-loader/shard.go b/cmd/protoc-gen-cpp-tableau-loader/shard.go index b1e0aeb7..3737e659 100644 --- a/cmd/protoc-gen-cpp-tableau-loader/shard.go +++ b/cmd/protoc-gen-cpp-tableau-loader/shard.go @@ -109,7 +109,7 @@ func generateShardedHubCppFileContent(g *protogen.GeneratedFile, shardIndex int, g.P("void MessagerContainer::InitShard", shardIndex, "() {") for _, proto := range protofiles { for _, messager := range fileMessagers[proto] { - g.P(helper.Indent(1), strcase.ToSnake(messager), "_ = std::dynamic_pointer_cast<", messager, `>(GetMessager("`, messager, `"));`) + g.P(helper.Indent(1), strcase.ToSnake(messager), "_ = std::dynamic_pointer_cast<", messager, `>(GetMessager(`, messager, `::Name()));`) } } g.P("}") diff --git a/cmd/protoc-gen-go-tableau-loader/hub.go b/cmd/protoc-gen-go-tableau-loader/hub.go index 38df4dd2..1db4316d 100644 --- a/cmd/protoc-gen-go-tableau-loader/hub.go +++ b/cmd/protoc-gen-go-tableau-loader/hub.go @@ -36,7 +36,7 @@ func generateHub(gen *protogen.Plugin) { g.P("loadedTime: time.Now(),") g.P("}") for _, messager := range messagers { - g.P("messagerContainer.", strcase.ToLowerCamel(messager), `, _ = messagerMap["`, messager, `"].(*`, messager, ")") + g.P("messagerContainer.", strcase.ToLowerCamel(messager), `, _ = messagerMap[(&`, messager, `{}).Name()].(*`, messager, ")") } g.P("return messagerContainer") g.P("}") diff --git a/test/cpp-tableau-loader/src/hub/custom/item/custom_item_conf.h b/test/cpp-tableau-loader/src/hub/custom/item/custom_item_conf.h index 76835861..637d9e41 100644 --- a/test/cpp-tableau-loader/src/hub/custom/item/custom_item_conf.h +++ b/test/cpp-tableau-loader/src/hub/custom/item/custom_item_conf.h @@ -4,7 +4,7 @@ class CustomItemConf : public tableau::Messager { public: static const std::string& Name() { return kCustomName; }; - virtual bool Load(const std::string&, tableau::Format, + virtual bool Load(const std::filesystem::path&, tableau::Format, std::shared_ptr options = nullptr) override { return true; } diff --git a/test/cpp-tableau-loader/src/main.cpp b/test/cpp-tableau-loader/src/main.cpp index d298ff2e..f3a310ab 100644 --- a/test/cpp-tableau-loader/src/main.cpp +++ b/test/cpp-tableau-loader/src/main.cpp @@ -17,15 +17,13 @@ bool LoadWithPatch(std::shared_ptr options) { return Hub::Instance().Load("../../testdata/conf/", tableau::Format::kJSON, options); } -bool CustomReadFile(const std::string& filename, std::string& content) { +bool CustomReadFile(const std::filesystem::path& filename, std::string& content) { std::ifstream file(filename); if (!file.is_open()) { return false; } - std::stringstream ss; - ss << file.rdbuf(); - content = ss.str(); - ATOM_DEBUG("custom read %s sussess", filename.c_str()); + content.assign(std::istreambuf_iterator(file), {}); + ATOM_DEBUG("custom read %s success", filename.c_str()); return true; } diff --git a/test/cpp-tableau-loader/src/protoconf/hero_conf.pc.cc b/test/cpp-tableau-loader/src/protoconf/hero_conf.pc.cc index d0182838..b5433ffa 100644 --- a/test/cpp-tableau-loader/src/protoconf/hero_conf.pc.cc +++ b/test/cpp-tableau-loader/src/protoconf/hero_conf.pc.cc @@ -10,9 +10,9 @@ #include "util.pc.h" namespace tableau { -const std::string HeroConf::kProtoName = "HeroConf"; +const std::string HeroConf::kProtoName = protoconf::HeroConf::GetDescriptor()->name(); -bool HeroConf::Load(const std::string& dir, Format fmt, std::shared_ptr options /* = nullptr */) { +bool HeroConf::Load(const std::filesystem::path& dir, Format fmt, std::shared_ptr options /* = nullptr */) { tableau::util::TimeProfiler profiler; bool loaded = LoadMessagerInDir(data_, dir, fmt, options); bool ok = loaded ? ProcessAfterLoad() : false; @@ -69,9 +69,9 @@ const HeroConf::Hero_Attr_OrderedMap* HeroConf::GetOrderedMap(const std::string& return &iter->second.first; } -const std::string HeroBaseConf::kProtoName = "HeroBaseConf"; +const std::string HeroBaseConf::kProtoName = protoconf::HeroBaseConf::GetDescriptor()->name(); -bool HeroBaseConf::Load(const std::string& dir, Format fmt, std::shared_ptr options /* = nullptr */) { +bool HeroBaseConf::Load(const std::filesystem::path& dir, Format fmt, std::shared_ptr options /* = nullptr */) { tableau::util::TimeProfiler profiler; bool loaded = LoadMessagerInDir(data_, dir, fmt, options); bool ok = loaded ? ProcessAfterLoad() : false; diff --git a/test/cpp-tableau-loader/src/protoconf/hero_conf.pc.h b/test/cpp-tableau-loader/src/protoconf/hero_conf.pc.h index e07b07c4..006f646b 100644 --- a/test/cpp-tableau-loader/src/protoconf/hero_conf.pc.h +++ b/test/cpp-tableau-loader/src/protoconf/hero_conf.pc.h @@ -5,6 +5,7 @@ // source: hero_conf.proto #pragma once +#include #include #include "load.pc.h" @@ -15,7 +16,7 @@ namespace tableau { class HeroConf : public Messager { public: static const std::string& Name() { return kProtoName; } - virtual bool Load(const std::string& dir, Format fmt, std::shared_ptr options = nullptr) override; + virtual bool Load(const std::filesystem::path& dir, Format fmt, std::shared_ptr options = nullptr) override; const protoconf::HeroConf& Data() const { return data_; } const google::protobuf::Message* Message() const override { return &data_; } @@ -46,7 +47,7 @@ class HeroConf : public Messager { class HeroBaseConf : public Messager { public: static const std::string& Name() { return kProtoName; } - virtual bool Load(const std::string& dir, Format fmt, std::shared_ptr options = nullptr) override; + virtual bool Load(const std::filesystem::path& dir, Format fmt, std::shared_ptr options = nullptr) override; const protoconf::HeroBaseConf& Data() const { return data_; } const google::protobuf::Message* Message() const override { return &data_; } diff --git a/test/cpp-tableau-loader/src/protoconf/hub.pc.cc b/test/cpp-tableau-loader/src/protoconf/hub.pc.cc index 4953d5e1..a89a9fe2 100644 --- a/test/cpp-tableau-loader/src/protoconf/hub.pc.cc +++ b/test/cpp-tableau-loader/src/protoconf/hub.pc.cc @@ -19,7 +19,7 @@ void Hub::InitOnce(std::shared_ptr options) { std::call_once(init_once_, [&]() { options_ = options; }); } -bool Hub::Load(const std::string& dir, Format fmt /* = Format::kJSON */, +bool Hub::Load(const std::filesystem::path& dir, Format fmt /* = Format::kJSON */, std::shared_ptr options /* = nullptr */) { auto msger_map = InternalLoad(dir, fmt, options); if (!msger_map) { @@ -33,7 +33,7 @@ bool Hub::Load(const std::string& dir, Format fmt /* = Format::kJSON */, return true; } -bool Hub::AsyncLoad(const std::string& dir, Format fmt /* = Format::kJSON */, +bool Hub::AsyncLoad(const std::filesystem::path& dir, Format fmt /* = Format::kJSON */, std::shared_ptr options /* = nullptr */) { auto msger_map = InternalLoad(dir, fmt, options); if (!msger_map) { @@ -54,7 +54,7 @@ void Hub::InitScheduler() { sched_->Current(); } -std::shared_ptr Hub::InternalLoad(const std::string& dir, Format fmt /* = Format::kJSON */, +std::shared_ptr Hub::InternalLoad(const std::filesystem::path& dir, Format fmt /* = Format::kJSON */, std::shared_ptr options /* = nullptr */) const { // intercept protobuf error logs auto old_handler = google::protobuf::SetLogHandler(util::ProtobufLogHandler); diff --git a/test/cpp-tableau-loader/src/protoconf/hub.pc.h b/test/cpp-tableau-loader/src/protoconf/hub.pc.h index e80c9710..35faa163 100644 --- a/test/cpp-tableau-loader/src/protoconf/hub.pc.h +++ b/test/cpp-tableau-loader/src/protoconf/hub.pc.h @@ -44,12 +44,13 @@ class Hub { /***** Synchronous Loading *****/ // Load fills messages (in MessagerContainer) from files in the specified directory and format. - bool Load(const std::string& dir, Format fmt = Format::kJSON, std::shared_ptr options = nullptr); + bool Load(const std::filesystem::path& dir, Format fmt = Format::kJSON, + std::shared_ptr options = nullptr); /***** Asynchronous Loading *****/ // Load configs into temp MessagerContainer, and you should call LoopOnce() in you app's main loop, // in order to take the temp MessagerContainer into effect. - bool AsyncLoad(const std::string& dir, Format fmt = Format::kJSON, + bool AsyncLoad(const std::filesystem::path& dir, Format fmt = Format::kJSON, std::shared_ptr options = nullptr); int LoopOnce(); // You'd better initialize the scheduler in the main thread. @@ -77,7 +78,7 @@ class Hub { inline std::time_t GetLastLoadedTime() const; private: - std::shared_ptr InternalLoad(const std::string& dir, Format fmt = Format::kJSON, + std::shared_ptr InternalLoad(const std::filesystem::path& dir, Format fmt = Format::kJSON, std::shared_ptr options = nullptr) const; std::shared_ptr NewMessagerMap() const; std::shared_ptr GetMessagerContainerWithProvider() const; diff --git a/test/cpp-tableau-loader/src/protoconf/hub_shard0.pc.cc b/test/cpp-tableau-loader/src/protoconf/hub_shard0.pc.cc index d7fbeb61..a48b3804 100644 --- a/test/cpp-tableau-loader/src/protoconf/hub_shard0.pc.cc +++ b/test/cpp-tableau-loader/src/protoconf/hub_shard0.pc.cc @@ -25,9 +25,9 @@ const std::shared_ptr Hub::Get() const { } void MessagerContainer::InitShard0() { - hero_base_conf_ = std::dynamic_pointer_cast(GetMessager("HeroBaseConf")); - hero_conf_ = std::dynamic_pointer_cast(GetMessager("HeroConf")); - item_conf_ = std::dynamic_pointer_cast(GetMessager("ItemConf")); + hero_base_conf_ = std::dynamic_pointer_cast(GetMessager(HeroBaseConf::Name())); + hero_conf_ = std::dynamic_pointer_cast(GetMessager(HeroConf::Name())); + item_conf_ = std::dynamic_pointer_cast(GetMessager(ItemConf::Name())); } void Registry::InitShard0() { diff --git a/test/cpp-tableau-loader/src/protoconf/hub_shard1.pc.cc b/test/cpp-tableau-loader/src/protoconf/hub_shard1.pc.cc index e063eeeb..370d348e 100644 --- a/test/cpp-tableau-loader/src/protoconf/hub_shard1.pc.cc +++ b/test/cpp-tableau-loader/src/protoconf/hub_shard1.pc.cc @@ -45,13 +45,13 @@ const std::shared_ptr Hub::Get() const { } void MessagerContainer::InitShard1() { - patch_merge_conf_ = std::dynamic_pointer_cast(GetMessager("PatchMergeConf")); - patch_replace_conf_ = std::dynamic_pointer_cast(GetMessager("PatchReplaceConf")); - recursive_patch_conf_ = std::dynamic_pointer_cast(GetMessager("RecursivePatchConf")); - activity_conf_ = std::dynamic_pointer_cast(GetMessager("ActivityConf")); - chapter_conf_ = std::dynamic_pointer_cast(GetMessager("ChapterConf")); - task_conf_ = std::dynamic_pointer_cast(GetMessager("TaskConf")); - theme_conf_ = std::dynamic_pointer_cast(GetMessager("ThemeConf")); + patch_merge_conf_ = std::dynamic_pointer_cast(GetMessager(PatchMergeConf::Name())); + patch_replace_conf_ = std::dynamic_pointer_cast(GetMessager(PatchReplaceConf::Name())); + recursive_patch_conf_ = std::dynamic_pointer_cast(GetMessager(RecursivePatchConf::Name())); + activity_conf_ = std::dynamic_pointer_cast(GetMessager(ActivityConf::Name())); + chapter_conf_ = std::dynamic_pointer_cast(GetMessager(ChapterConf::Name())); + task_conf_ = std::dynamic_pointer_cast(GetMessager(TaskConf::Name())); + theme_conf_ = std::dynamic_pointer_cast(GetMessager(ThemeConf::Name())); } void Registry::InitShard1() { diff --git a/test/cpp-tableau-loader/src/protoconf/item_conf.pc.cc b/test/cpp-tableau-loader/src/protoconf/item_conf.pc.cc index a1460ba4..98963d31 100644 --- a/test/cpp-tableau-loader/src/protoconf/item_conf.pc.cc +++ b/test/cpp-tableau-loader/src/protoconf/item_conf.pc.cc @@ -10,9 +10,9 @@ #include "util.pc.h" namespace tableau { -const std::string ItemConf::kProtoName = "ItemConf"; +const std::string ItemConf::kProtoName = protoconf::ItemConf::GetDescriptor()->name(); -bool ItemConf::Load(const std::string& dir, Format fmt, std::shared_ptr options /* = nullptr */) { +bool ItemConf::Load(const std::filesystem::path& dir, Format fmt, std::shared_ptr options /* = nullptr */) { tableau::util::TimeProfiler profiler; bool loaded = LoadMessagerInDir(data_, dir, fmt, options); bool ok = loaded ? ProcessAfterLoad() : false; diff --git a/test/cpp-tableau-loader/src/protoconf/item_conf.pc.h b/test/cpp-tableau-loader/src/protoconf/item_conf.pc.h index 308b99e1..f5e1b9c9 100644 --- a/test/cpp-tableau-loader/src/protoconf/item_conf.pc.h +++ b/test/cpp-tableau-loader/src/protoconf/item_conf.pc.h @@ -5,6 +5,7 @@ // source: item_conf.proto #pragma once +#include #include #include "load.pc.h" @@ -15,7 +16,7 @@ namespace tableau { class ItemConf : public Messager { public: static const std::string& Name() { return kProtoName; } - virtual bool Load(const std::string& dir, Format fmt, std::shared_ptr options = nullptr) override; + virtual bool Load(const std::filesystem::path& dir, Format fmt, std::shared_ptr options = nullptr) override; const protoconf::ItemConf& Data() const { return data_; } const google::protobuf::Message* Message() const override { return &data_; } diff --git a/test/cpp-tableau-loader/src/protoconf/load.pc.cc b/test/cpp-tableau-loader/src/protoconf/load.pc.cc index d08d3f93..62c0145f 100644 --- a/test/cpp-tableau-loader/src/protoconf/load.pc.cc +++ b/test/cpp-tableau-loader/src/protoconf/load.pc.cc @@ -69,8 +69,8 @@ std::shared_ptr ParseMessagerOptions(std::shared_ptr options /* = nullptr*/) { +bool LoadMessagerWithPatch(google::protobuf::Message& msg, const std::filesystem::path& path, Format fmt, + tableau::Patch patch, std::shared_ptr options /* = nullptr*/) { if (options == nullptr) { return LoadMessager(msg, path, fmt, nullptr); } @@ -78,21 +78,21 @@ bool LoadMessagerWithPatch(google::protobuf::Message& msg, const std::string& pa // ignore patch files when LoadMode::kModeOnlyMain specified return options->load_func(msg, path, fmt, nullptr); } - std::string name = util::GetProtoName(msg); - std::vector patch_paths; + const std::string& name = msg.GetDescriptor()->name(); + std::vector patch_paths; if (!options->patch_paths.empty()) { // patch path specified in PatchPaths, then use it instead of PatchDirs. patch_paths = options->patch_paths; } else { - std::string filename = name + util::Format2Ext(fmt); + std::filesystem::path filename = name + util::Format2Ext(fmt); for (auto&& patch_dir : options->patch_dirs) { - patch_paths.emplace_back((std::filesystem::path(patch_dir) / filename).make_preferred().string()); + patch_paths.emplace_back(patch_dir / filename); } } - std::vector existed_patch_paths; + std::vector existed_patch_paths; for (auto&& patch_path : patch_paths) { - if (util::ExistsFile(patch_path)) { + if (std::filesystem::exists(patch_path)) { existed_patch_paths.emplace_back(patch_path); } } @@ -108,8 +108,8 @@ bool LoadMessagerWithPatch(google::protobuf::Message& msg, const std::string& pa switch (patch) { case tableau::PATCH_REPLACE: { // just use the last "patch" file - std::string& patch_path = existed_patch_paths.back(); - if (!options->load_func(msg, patch_path, util::Ext2Format(util::GetExt(patch_path)), options)) { + std::filesystem::path& patch_path = existed_patch_paths.back(); + if (!options->load_func(msg, patch_path, util::GetFormat(patch_path), options)) { return false; } break; @@ -126,7 +126,7 @@ bool LoadMessagerWithPatch(google::protobuf::Message& msg, const std::string& pa std::unique_ptr _auto_release(msg.New()); // load patch_msg from each "patch" file for (auto&& patch_path : existed_patch_paths) { - if (!options->load_func(*patch_msg_ptr, patch_path, util::Ext2Format(util::GetExt(patch_path)), options)) { + if (!options->load_func(*patch_msg_ptr, patch_path, util::GetFormat(patch_path), options)) { return false; } if (!PatchMessage(msg, *patch_msg_ptr)) { @@ -136,16 +136,16 @@ bool LoadMessagerWithPatch(google::protobuf::Message& msg, const std::string& pa break; } default: { - SetErrMsg("unknown patch type: " + util::GetPatchName(patch)); + SetErrMsg("unknown patch type: " + tableau::Patch_Name(patch)); return false; } } - ATOM_DEBUG("patched(%s) %s by %s: %s", util::GetPatchName(patch).c_str(), name.c_str(), + ATOM_DEBUG("patched(%s) %s by %s: %s", tableau::Patch_Name(patch).c_str(), name.c_str(), ATOM_VECTOR_STR(existed_patch_paths).c_str(), msg.ShortDebugString().c_str()); return true; } -bool LoadMessager(google::protobuf::Message& msg, const std::string& path, Format fmt, +bool LoadMessager(google::protobuf::Message& msg, const std::filesystem::path& path, Format fmt, std::shared_ptr options /* = nullptr*/) { std::string content; ReadFunc read_func = util::ReadFile; @@ -173,27 +173,23 @@ bool LoadMessager(google::protobuf::Message& msg, const std::string& path, Forma } } -bool LoadMessagerInDir(google::protobuf::Message& msg, const std::string& dir, Format fmt, +bool LoadMessagerInDir(google::protobuf::Message& msg, const std::filesystem::path& dir, Format fmt, std::shared_ptr options /* = nullptr*/) { - std::string name = util::GetProtoName(msg); - std::string path; + const std::string& name = msg.GetDescriptor()->name(); + std::filesystem::path path; if (options && !options->path.empty()) { // path specified in Paths, then use it instead of dir. path = options->path; - fmt = util::Ext2Format(util::GetExt(path)); + fmt = util::GetFormat(path); } if (path.empty()) { - std::string filename = name + util::Format2Ext(fmt); - path = (std::filesystem::path(dir) / filename).make_preferred().string(); + std::filesystem::path filename = name + util::Format2Ext(fmt); + path = dir / filename; } const google::protobuf::Descriptor* descriptor = msg.GetDescriptor(); - if (!descriptor) { - SetErrMsg("failed to get descriptor of message: " + name); - return false; - } // access the extension directly using the generated identifier - const tableau::WorksheetOptions worksheet_options = descriptor->options().GetExtension(tableau::worksheet); + const tableau::WorksheetOptions& worksheet_options = descriptor->options().GetExtension(tableau::worksheet); if (worksheet_options.patch() != tableau::PATCH_NONE) { return LoadMessagerWithPatch(msg, path, fmt, worksheet_options.patch(), options); } diff --git a/test/cpp-tableau-loader/src/protoconf/load.pc.h b/test/cpp-tableau-loader/src/protoconf/load.pc.h index b9088234..87564d57 100644 --- a/test/cpp-tableau-loader/src/protoconf/load.pc.h +++ b/test/cpp-tableau-loader/src/protoconf/load.pc.h @@ -7,6 +7,7 @@ #include #include +#include #include #include #include @@ -25,10 +26,10 @@ struct MessagerOptions; class Hub; // ReadFunc reads the config file and returns its content. -using ReadFunc = std::function; +using ReadFunc = std::function; // LoadFunc defines a func which can load message's content based on the given // path, format, and options. -using LoadFunc = std::function options)>; // BaseOptions is the common struct for both global-level and messager-level @@ -39,7 +40,7 @@ struct BaseOptions { // Refer https://protobuf.dev/reference/cpp/api-docs/google.protobuf.util.json_util/#JsonParseOptions. std::optional ignore_unknown_fields; // Specify the directory paths for config patching. - std::vector patch_dirs; + std::vector patch_dirs; // Specify the loading mode for config patching. // - For LoadOptions, default is LoadMode::kModeAll. // - For MessagerOptions, inherit from LoadOptions if not set. @@ -68,10 +69,10 @@ struct MessagerOptions : public BaseOptions { // Path maps each messager name to a corresponding config file path. // If specified, then the main messager will be parsed from the file // directly, other than the specified load dir. - std::string path; + std::filesystem::path path; // Patch paths maps each messager name to one or multiple corresponding patch file paths. // If specified, then main messager will be patched. - std::vector patch_paths; + std::vector patch_paths; }; class Messager { @@ -82,10 +83,14 @@ class Messager { public: virtual ~Messager() = default; - static const std::string& Name() { return kEmpty; } + static const std::string& Name() { + static const std::string kEmpty = ""; + return kEmpty; + } const Stats& GetStats() { return stats_; } // Load fills message from file in the specified directory and format. - virtual bool Load(const std::string& dir, Format fmt, std::shared_ptr options = nullptr) = 0; + virtual bool Load(const std::filesystem::path& dir, Format fmt, + std::shared_ptr options = nullptr) = 0; // Message returns the inner message data. virtual const google::protobuf::Message* Message() const { return nullptr; } // callback after all messagers loaded. @@ -103,8 +108,8 @@ std::shared_ptr ParseLoadOptions(std::shared_ptr ParseMessagerOptions(std::shared_ptr opts, const std::string& name); -bool LoadMessager(google::protobuf::Message& msg, const std::string& path, Format fmt = Format::kJSON, +bool LoadMessager(google::protobuf::Message& msg, const std::filesystem::path& path, Format fmt = Format::kJSON, std::shared_ptr options = nullptr); -bool LoadMessagerInDir(google::protobuf::Message& msg, const std::string& dir, Format fmt = Format::kJSON, +bool LoadMessagerInDir(google::protobuf::Message& msg, const std::filesystem::path& dir, Format fmt = Format::kJSON, std::shared_ptr options = nullptr); } // namespace tableau diff --git a/test/cpp-tableau-loader/src/protoconf/logger.pc.cc b/test/cpp-tableau-loader/src/protoconf/logger.pc.cc index 99e62c6d..a98045f3 100644 --- a/test/cpp-tableau-loader/src/protoconf/logger.pc.cc +++ b/test/cpp-tableau-loader/src/protoconf/logger.pc.cc @@ -17,6 +17,7 @@ #include #endif +#include #include #include @@ -58,14 +59,12 @@ void SetDefaultLogger(Logger* logger) { g_default_logger = logger; } -int Logger::Init(const std::string& path, Level level) { - std::string dir = util::GetDir(path); - if (!dir.empty()) { - // prepare the specified directory - int status = util::Mkdir(dir); - if (status == -1) { - return status; - } +int Logger::Init(const std::filesystem::path& path, Level level) { + std::error_code ec; + std::filesystem::create_directories(path.parent_path(), ec); + if (ec) { + SetErrMsg("failed to create log directory: " + ec.message()); + return ec.value(); } ofs_.open(path, std::ofstream::out | std::ofstream::app); os_ = &ofs_; // use file stream as output stream diff --git a/test/cpp-tableau-loader/src/protoconf/logger.pc.h b/test/cpp-tableau-loader/src/protoconf/logger.pc.h index 90090cc9..7248c61d 100644 --- a/test/cpp-tableau-loader/src/protoconf/logger.pc.h +++ b/test/cpp-tableau-loader/src/protoconf/logger.pc.h @@ -4,6 +4,7 @@ // - protoc v3.19.3 #pragma once +#include #include #include #include @@ -54,7 +55,7 @@ class Logger { ~Logger() { ofs_.close(); } // Init the logger with the specified path. // NOTE: no guarantee of thread-safety. - int Init(const std::string& path, Level level); + int Init(const std::filesystem::path& path, Level level); // Set the writer for writing log. void SetWriter(Writer writer) { writer_ = writer; } // Log with guarantee of thread-safety. diff --git a/test/cpp-tableau-loader/src/protoconf/patch_conf.pc.cc b/test/cpp-tableau-loader/src/protoconf/patch_conf.pc.cc index 66a14069..f197abca 100644 --- a/test/cpp-tableau-loader/src/protoconf/patch_conf.pc.cc +++ b/test/cpp-tableau-loader/src/protoconf/patch_conf.pc.cc @@ -10,9 +10,9 @@ #include "util.pc.h" namespace tableau { -const std::string PatchReplaceConf::kProtoName = "PatchReplaceConf"; +const std::string PatchReplaceConf::kProtoName = protoconf::PatchReplaceConf::GetDescriptor()->name(); -bool PatchReplaceConf::Load(const std::string& dir, Format fmt, std::shared_ptr options /* = nullptr */) { +bool PatchReplaceConf::Load(const std::filesystem::path& dir, Format fmt, std::shared_ptr options /* = nullptr */) { tableau::util::TimeProfiler profiler; bool loaded = LoadMessagerInDir(data_, dir, fmt, options); bool ok = loaded ? ProcessAfterLoad() : false; @@ -20,9 +20,9 @@ bool PatchReplaceConf::Load(const std::string& dir, Format fmt, std::shared_ptr< return ok; } -const std::string PatchMergeConf::kProtoName = "PatchMergeConf"; +const std::string PatchMergeConf::kProtoName = protoconf::PatchMergeConf::GetDescriptor()->name(); -bool PatchMergeConf::Load(const std::string& dir, Format fmt, std::shared_ptr options /* = nullptr */) { +bool PatchMergeConf::Load(const std::filesystem::path& dir, Format fmt, std::shared_ptr options /* = nullptr */) { tableau::util::TimeProfiler profiler; bool loaded = LoadMessagerInDir(data_, dir, fmt, options); bool ok = loaded ? ProcessAfterLoad() : false; @@ -38,9 +38,9 @@ const protoconf::Item* PatchMergeConf::Get(uint32_t id) const { return &iter->second; } -const std::string RecursivePatchConf::kProtoName = "RecursivePatchConf"; +const std::string RecursivePatchConf::kProtoName = protoconf::RecursivePatchConf::GetDescriptor()->name(); -bool RecursivePatchConf::Load(const std::string& dir, Format fmt, std::shared_ptr options /* = nullptr */) { +bool RecursivePatchConf::Load(const std::filesystem::path& dir, Format fmt, std::shared_ptr options /* = nullptr */) { tableau::util::TimeProfiler profiler; bool loaded = LoadMessagerInDir(data_, dir, fmt, options); bool ok = loaded ? ProcessAfterLoad() : false; diff --git a/test/cpp-tableau-loader/src/protoconf/patch_conf.pc.h b/test/cpp-tableau-loader/src/protoconf/patch_conf.pc.h index 191fd685..d92a8c38 100644 --- a/test/cpp-tableau-loader/src/protoconf/patch_conf.pc.h +++ b/test/cpp-tableau-loader/src/protoconf/patch_conf.pc.h @@ -5,6 +5,7 @@ // source: patch_conf.proto #pragma once +#include #include #include "load.pc.h" @@ -15,7 +16,7 @@ namespace tableau { class PatchReplaceConf : public Messager { public: static const std::string& Name() { return kProtoName; } - virtual bool Load(const std::string& dir, Format fmt, std::shared_ptr options = nullptr) override; + virtual bool Load(const std::filesystem::path& dir, Format fmt, std::shared_ptr options = nullptr) override; const protoconf::PatchReplaceConf& Data() const { return data_; } const google::protobuf::Message* Message() const override { return &data_; } @@ -28,7 +29,7 @@ class PatchReplaceConf : public Messager { class PatchMergeConf : public Messager { public: static const std::string& Name() { return kProtoName; } - virtual bool Load(const std::string& dir, Format fmt, std::shared_ptr options = nullptr) override; + virtual bool Load(const std::filesystem::path& dir, Format fmt, std::shared_ptr options = nullptr) override; const protoconf::PatchMergeConf& Data() const { return data_; } const google::protobuf::Message* Message() const override { return &data_; } @@ -43,7 +44,7 @@ class PatchMergeConf : public Messager { class RecursivePatchConf : public Messager { public: static const std::string& Name() { return kProtoName; } - virtual bool Load(const std::string& dir, Format fmt, std::shared_ptr options = nullptr) override; + virtual bool Load(const std::filesystem::path& dir, Format fmt, std::shared_ptr options = nullptr) override; const protoconf::RecursivePatchConf& Data() const { return data_; } const google::protobuf::Message* Message() const override { return &data_; } diff --git a/test/cpp-tableau-loader/src/protoconf/test_conf.pc.cc b/test/cpp-tableau-loader/src/protoconf/test_conf.pc.cc index c178d100..4d9dc39d 100644 --- a/test/cpp-tableau-loader/src/protoconf/test_conf.pc.cc +++ b/test/cpp-tableau-loader/src/protoconf/test_conf.pc.cc @@ -10,9 +10,9 @@ #include "util.pc.h" namespace tableau { -const std::string ActivityConf::kProtoName = "ActivityConf"; +const std::string ActivityConf::kProtoName = protoconf::ActivityConf::GetDescriptor()->name(); -bool ActivityConf::Load(const std::string& dir, Format fmt, std::shared_ptr options /* = nullptr */) { +bool ActivityConf::Load(const std::filesystem::path& dir, Format fmt, std::shared_ptr options /* = nullptr */) { tableau::util::TimeProfiler profiler; bool loaded = LoadMessagerInDir(data_, dir, fmt, options); bool ok = loaded ? ProcessAfterLoad() : false; @@ -238,9 +238,9 @@ const protoconf::Section::SectionItem* ActivityConf::FindFirstAward(uint32_t id) } -const std::string ChapterConf::kProtoName = "ChapterConf"; +const std::string ChapterConf::kProtoName = protoconf::ChapterConf::GetDescriptor()->name(); -bool ChapterConf::Load(const std::string& dir, Format fmt, std::shared_ptr options /* = nullptr */) { +bool ChapterConf::Load(const std::filesystem::path& dir, Format fmt, std::shared_ptr options /* = nullptr */) { tableau::util::TimeProfiler profiler; bool loaded = LoadMessagerInDir(data_, dir, fmt, options); bool ok = loaded ? ProcessAfterLoad() : false; @@ -256,9 +256,9 @@ const protoconf::ChapterConf::Chapter* ChapterConf::Get(uint64_t id) const { return &iter->second; } -const std::string ThemeConf::kProtoName = "ThemeConf"; +const std::string ThemeConf::kProtoName = protoconf::ThemeConf::GetDescriptor()->name(); -bool ThemeConf::Load(const std::string& dir, Format fmt, std::shared_ptr options /* = nullptr */) { +bool ThemeConf::Load(const std::filesystem::path& dir, Format fmt, std::shared_ptr options /* = nullptr */) { tableau::util::TimeProfiler profiler; bool loaded = LoadMessagerInDir(data_, dir, fmt, options); bool ok = loaded ? ProcessAfterLoad() : false; @@ -286,9 +286,9 @@ const std::string* ThemeConf::Get(const std::string& name, const std::string& pa return &iter->second; } -const std::string TaskConf::kProtoName = "TaskConf"; +const std::string TaskConf::kProtoName = protoconf::TaskConf::GetDescriptor()->name(); -bool TaskConf::Load(const std::string& dir, Format fmt, std::shared_ptr options /* = nullptr */) { +bool TaskConf::Load(const std::filesystem::path& dir, Format fmt, std::shared_ptr options /* = nullptr */) { tableau::util::TimeProfiler profiler; bool loaded = LoadMessagerInDir(data_, dir, fmt, options); bool ok = loaded ? ProcessAfterLoad() : false; diff --git a/test/cpp-tableau-loader/src/protoconf/test_conf.pc.h b/test/cpp-tableau-loader/src/protoconf/test_conf.pc.h index 2b12c0e0..bec18ae3 100644 --- a/test/cpp-tableau-loader/src/protoconf/test_conf.pc.h +++ b/test/cpp-tableau-loader/src/protoconf/test_conf.pc.h @@ -5,6 +5,7 @@ // source: test_conf.proto #pragma once +#include #include #include "load.pc.h" @@ -15,7 +16,7 @@ namespace tableau { class ActivityConf : public Messager { public: static const std::string& Name() { return kProtoName; } - virtual bool Load(const std::string& dir, Format fmt, std::shared_ptr options = nullptr) override; + virtual bool Load(const std::filesystem::path& dir, Format fmt, std::shared_ptr options = nullptr) override; const protoconf::ActivityConf& Data() const { return data_; } const google::protobuf::Message* Message() const override { return &data_; } @@ -102,7 +103,7 @@ class ActivityConf : public Messager { class ChapterConf : public Messager { public: static const std::string& Name() { return kProtoName; } - virtual bool Load(const std::string& dir, Format fmt, std::shared_ptr options = nullptr) override; + virtual bool Load(const std::filesystem::path& dir, Format fmt, std::shared_ptr options = nullptr) override; const protoconf::ChapterConf& Data() const { return data_; } const google::protobuf::Message* Message() const override { return &data_; } @@ -117,7 +118,7 @@ class ChapterConf : public Messager { class ThemeConf : public Messager { public: static const std::string& Name() { return kProtoName; } - virtual bool Load(const std::string& dir, Format fmt, std::shared_ptr options = nullptr) override; + virtual bool Load(const std::filesystem::path& dir, Format fmt, std::shared_ptr options = nullptr) override; const protoconf::ThemeConf& Data() const { return data_; } const google::protobuf::Message* Message() const override { return &data_; } @@ -133,7 +134,7 @@ class ThemeConf : public Messager { class TaskConf : public Messager { public: static const std::string& Name() { return kProtoName; } - virtual bool Load(const std::string& dir, Format fmt, std::shared_ptr options = nullptr) override; + virtual bool Load(const std::filesystem::path& dir, Format fmt, std::shared_ptr options = nullptr) override; const protoconf::TaskConf& Data() const { return data_; } const google::protobuf::Message* Message() const override { return &data_; } diff --git a/test/cpp-tableau-loader/src/protoconf/util.pc.cc b/test/cpp-tableau-loader/src/protoconf/util.pc.cc index 98ee62de..b404aee2 100644 --- a/test/cpp-tableau-loader/src/protoconf/util.pc.cc +++ b/test/cpp-tableau-loader/src/protoconf/util.pc.cc @@ -27,42 +27,18 @@ const std::string kTextExt = ".txt"; const std::string kBinExt = ".bin"; namespace util { -int Mkdir(const std::string& path) { - std::error_code ec; - if (!std::filesystem::create_directories(path, ec)) { - if (ec) { - std::cerr << "system error: " << ec.message() << std::endl; - return -1; - } - } - return 0; -} - -std::string GetDir(const std::string& path) { return std::filesystem::path(path).parent_path().string(); } - -bool ExistsFile(const std::string& filename) { return std::filesystem::exists(filename); } - -bool ReadFile(const std::string& filename, std::string& content) { +bool ReadFile(const std::filesystem::path& filename, std::string& content) { std::ifstream file(filename); if (!file.is_open()) { - SetErrMsg("failed to open " + filename + ": " + strerror(errno)); + SetErrMsg("failed to open " + filename.string() + ": " + strerror(errno)); return false; } - std::stringstream ss; - ss << file.rdbuf(); - content = ss.str(); + content.assign(std::istreambuf_iterator(file), {}); return true; } -std::string GetExt(const std::string& path) { - std::size_t pos = path.find_last_of("."); - if (pos != std::string::npos) { - return path.substr(pos); - } - return kEmpty; -} - -Format Ext2Format(const std::string& ext) { +Format GetFormat(const std::filesystem::path& path) { + auto ext = path.extension(); if (ext == kJSONExt) { return Format::kJSON; } else if (ext == kTextExt) { @@ -98,7 +74,7 @@ bool JSON2Message(const std::string& json, google::protobuf::Message& msg, status = google::protobuf::util::JsonStringToMessage(json, &msg); } if (!status.ok()) { - SetErrMsg("failed to parse " + GetProtoName(msg) + kJSONExt + ": " + status.ToString()); + SetErrMsg("failed to parse " + msg.GetDescriptor()->name() + kJSONExt + ": " + status.ToString()); return false; } return true; @@ -106,35 +82,20 @@ bool JSON2Message(const std::string& json, google::protobuf::Message& msg, bool Text2Message(const std::string& text, google::protobuf::Message& msg) { if (!google::protobuf::TextFormat::ParseFromString(text, &msg)) { - SetErrMsg("failed to parse " + GetProtoName(msg) + kTextExt); + SetErrMsg("failed to parse " + msg.GetDescriptor()->name() + kTextExt); return false; } return true; } + bool Bin2Message(const std::string& bin, google::protobuf::Message& msg) { if (!msg.ParseFromString(bin)) { - SetErrMsg("failed to parse " + GetProtoName(msg) + kBinExt); + SetErrMsg("failed to parse " + msg.GetDescriptor()->name() + kBinExt); return false; } return true; } -const std::string& GetProtoName(const google::protobuf::Message& msg) { - const auto* md = msg.GetDescriptor(); - return md != nullptr ? md->name() : kEmpty; -} - -std::string GetPatchName(tableau::Patch patch) { - auto* descriptor = tableau::Patch_descriptor(); - if (descriptor) { - auto* value = descriptor->FindValueByNumber(patch); - if (value) { - return value->name(); - } - } - return std::to_string(static_cast(patch)); -} - // refer: https://github.com/protocolbuffers/protobuf/blob/main/src/google/protobuf/stubs/logging.h void ProtobufLogHandler(google::protobuf::LogLevel level, const char* filename, int line, const std::string& msg) { static const std::unordered_map kLevelMap = {{google::protobuf::LOGLEVEL_INFO, log::kInfo}, diff --git a/test/cpp-tableau-loader/src/protoconf/util.pc.h b/test/cpp-tableau-loader/src/protoconf/util.pc.h index 6d5a94fc..3d917ef9 100644 --- a/test/cpp-tableau-loader/src/protoconf/util.pc.h +++ b/test/cpp-tableau-loader/src/protoconf/util.pc.h @@ -7,6 +7,7 @@ #include #include +#include #include #include @@ -23,7 +24,6 @@ enum class Format { kBin, }; -static const std::string kEmpty = ""; extern const std::string kUnknownExt; extern const std::string kJSONExt; extern const std::string kTextExt; @@ -53,27 +53,11 @@ inline std::size_t SugaredHashCombine(const T& v, O... others) { return seed; } -// Mkdir makes dir recursively. -int Mkdir(const std::string& path); -// GetDir returns all but the last element of path, typically the path's -// directory. -std::string GetDir(const std::string& path); -// ExistsFile checks if a file exists. -bool ExistsFile(const std::string& filename); // ReadFile reads the file named by filename and returns the contents. -bool ReadFile(const std::string& filename, std::string& content); - -// GetExt returns the file name extension used by path. -// The extension is the suffix beginning at the final dot -// in the final element of path; it is empty if there is -// no dot. -std::string GetExt(const std::string& path); -// Convert file extension to Format type. -// NOTE: ext includes dot ".", such as: -// - kJSONExt: ".json" -// - kTextExt: ".txt" -// - kBinExt: ".bin" -Format Ext2Format(const std::string& ext); +bool ReadFile(const std::filesystem::path& filename, std::string& content); + +// GetFormat returns the Format type used by path. +Format GetFormat(const std::filesystem::path& path); // Empty string will be returned if an unsupported enum value has been passed, // and the error message can be obtained by GetErrMsg(). const std::string& Format2Ext(Format fmt); @@ -83,9 +67,6 @@ bool JSON2Message(const std::string& json, google::protobuf::Message& msg, bool Text2Message(const std::string& text, google::protobuf::Message& msg); bool Bin2Message(const std::string& bin, google::protobuf::Message& msg); -const std::string& GetProtoName(const google::protobuf::Message& msg); -std::string GetPatchName(tableau::Patch patch); - void ProtobufLogHandler(google::protobuf::LogLevel level, const char* filename, int line, const std::string& msg); class TimeProfiler { diff --git a/test/go-tableau-loader/protoconf/loader/hub.pc.go b/test/go-tableau-loader/protoconf/loader/hub.pc.go index a80fb21a..c81082f7 100644 --- a/test/go-tableau-loader/protoconf/loader/hub.pc.go +++ b/test/go-tableau-loader/protoconf/loader/hub.pc.go @@ -339,16 +339,16 @@ func newMessagerContainer(messagerMap MessagerMap) *messagerContainer { messagerMap: messagerMap, loadedTime: time.Now(), } - messagerContainer.heroConf, _ = messagerMap["HeroConf"].(*HeroConf) - messagerContainer.heroBaseConf, _ = messagerMap["HeroBaseConf"].(*HeroBaseConf) - messagerContainer.itemConf, _ = messagerMap["ItemConf"].(*ItemConf) - messagerContainer.patchReplaceConf, _ = messagerMap["PatchReplaceConf"].(*PatchReplaceConf) - messagerContainer.patchMergeConf, _ = messagerMap["PatchMergeConf"].(*PatchMergeConf) - messagerContainer.recursivePatchConf, _ = messagerMap["RecursivePatchConf"].(*RecursivePatchConf) - messagerContainer.activityConf, _ = messagerMap["ActivityConf"].(*ActivityConf) - messagerContainer.chapterConf, _ = messagerMap["ChapterConf"].(*ChapterConf) - messagerContainer.themeConf, _ = messagerMap["ThemeConf"].(*ThemeConf) - messagerContainer.taskConf, _ = messagerMap["TaskConf"].(*TaskConf) + messagerContainer.heroConf, _ = messagerMap[(&HeroConf{}).Name()].(*HeroConf) + messagerContainer.heroBaseConf, _ = messagerMap[(&HeroBaseConf{}).Name()].(*HeroBaseConf) + messagerContainer.itemConf, _ = messagerMap[(&ItemConf{}).Name()].(*ItemConf) + messagerContainer.patchReplaceConf, _ = messagerMap[(&PatchReplaceConf{}).Name()].(*PatchReplaceConf) + messagerContainer.patchMergeConf, _ = messagerMap[(&PatchMergeConf{}).Name()].(*PatchMergeConf) + messagerContainer.recursivePatchConf, _ = messagerMap[(&RecursivePatchConf{}).Name()].(*RecursivePatchConf) + messagerContainer.activityConf, _ = messagerMap[(&ActivityConf{}).Name()].(*ActivityConf) + messagerContainer.chapterConf, _ = messagerMap[(&ChapterConf{}).Name()].(*ChapterConf) + messagerContainer.themeConf, _ = messagerMap[(&ThemeConf{}).Name()].(*ThemeConf) + messagerContainer.taskConf, _ = messagerMap[(&TaskConf{}).Name()].(*TaskConf) return messagerContainer }