From 9f33189c18f5b277f752b0ca75dd85e52fe6c24c Mon Sep 17 00:00:00 2001 From: Dan Paulat Date: Sat, 1 Feb 2025 18:21:41 -0600 Subject: [PATCH] Refactor json utility to wxdata, add ReadJsonString function --- scwx-qt/source/scwx/qt/config/radar_site.cpp | 2 +- .../source/scwx/qt/manager/marker_manager.cpp | 26 +-- .../scwx/qt/manager/placefile_manager.cpp | 6 +- .../scwx/qt/manager/settings_manager.cpp | 2 +- .../source/scwx/qt/manager/update_manager.cpp | 28 +-- scwx-qt/source/scwx/qt/model/layer_model.cpp | 2 +- .../source/scwx/qt/model/radar_site_model.cpp | 6 +- scwx-qt/source/scwx/qt/util/json.cpp | 178 +--------------- scwx-qt/source/scwx/qt/util/json.hpp | 7 +- wxdata/include/scwx/util/json.hpp | 15 ++ wxdata/source/scwx/util/json.cpp | 199 ++++++++++++++++++ wxdata/wxdata.cmake | 2 + 12 files changed, 245 insertions(+), 228 deletions(-) create mode 100644 wxdata/include/scwx/util/json.hpp create mode 100644 wxdata/source/scwx/util/json.cpp diff --git a/scwx-qt/source/scwx/qt/config/radar_site.cpp b/scwx-qt/source/scwx/qt/config/radar_site.cpp index 5c1dba2e..69815636 100644 --- a/scwx-qt/source/scwx/qt/config/radar_site.cpp +++ b/scwx-qt/source/scwx/qt/config/radar_site.cpp @@ -245,7 +245,7 @@ size_t RadarSite::ReadConfig(const std::string& path) bool dataValid = true; size_t sitesAdded = 0; - boost::json::value j = util::json::ReadJsonFile(path); + boost::json::value j = util::json::ReadJsonQFile(path); dataValid = j.is_array(); diff --git a/scwx-qt/source/scwx/qt/manager/marker_manager.cpp b/scwx-qt/source/scwx/qt/manager/marker_manager.cpp index 952dea44..ea21b211 100644 --- a/scwx-qt/source/scwx/qt/manager/marker_manager.cpp +++ b/scwx-qt/source/scwx/qt/manager/marker_manager.cpp @@ -1,10 +1,10 @@ #include #include #include -#include #include #include #include +#include #include #include @@ -62,7 +62,7 @@ public: bool markerFileRead_ {false}; - void InitalizeIds(); + void InitalizeIds(); types::MarkerId NewId(); types::MarkerId lastId_ {0}; }; @@ -70,15 +70,9 @@ public: class MarkerManager::Impl::MarkerRecord { public: - MarkerRecord(const types::MarkerInfo& info) : - markerInfo_ {info} - { - } + MarkerRecord(const types::MarkerInfo& info) : markerInfo_ {info} {} - const types::MarkerInfo& toMarkerInfo() - { - return markerInfo_; - } + const types::MarkerInfo& toMarkerInfo() { return markerInfo_; } types::MarkerInfo markerInfo_; @@ -175,7 +169,7 @@ void MarkerManager::Impl::ReadMarkerSettings() // Determine if marker settings exists if (std::filesystem::exists(markerSettingsPath_)) { - markerJson = util::json::ReadJsonFile(markerSettingsPath_); + markerJson = scwx::util::json::ReadJsonFile(markerSettingsPath_); } if (markerJson != nullptr && markerJson.is_array()) @@ -224,8 +218,8 @@ void MarkerManager::Impl::WriteMarkerSettings() logger_->info("Saving location marker settings"); const std::shared_lock lock(markerRecordLock_); - auto markerJson = boost::json::value_from(markerRecords_); - util::json::WriteJsonFile(markerSettingsPath_, markerJson); + auto markerJson = boost::json::value_from(markerRecords_); + scwx::util::json::WriteJsonFile(markerSettingsPath_, markerJson); } std::shared_ptr @@ -357,10 +351,11 @@ types::MarkerId MarkerManager::add_marker(const types::MarkerInfo& marker) types::MarkerId id; { const std::unique_lock lock(p->markerRecordLock_); - id = p->NewId(); + id = p->NewId(); size_t index = p->markerRecords_.size(); p->idToIndex_.emplace(id, index); - p->markerRecords_.emplace_back(std::make_shared(marker)); + p->markerRecords_.emplace_back( + std::make_shared(marker)); p->markerRecords_[index]->markerInfo_.id = id; add_icon(marker.iconName); @@ -499,7 +494,6 @@ void MarkerManager::set_marker_settings_path(const std::string& path) p->markerSettingsPath_ = path; } - std::shared_ptr MarkerManager::Instance() { static std::weak_ptr markerManagerReference_ {}; diff --git a/scwx-qt/source/scwx/qt/manager/placefile_manager.cpp b/scwx-qt/source/scwx/qt/manager/placefile_manager.cpp index a6158773..d85f9e40 100644 --- a/scwx-qt/source/scwx/qt/manager/placefile_manager.cpp +++ b/scwx-qt/source/scwx/qt/manager/placefile_manager.cpp @@ -2,10 +2,10 @@ #include #include #include -#include #include #include #include +#include #include #include @@ -385,7 +385,7 @@ void PlacefileManager::Impl::ReadPlacefileSettings() // Determine if placefile settings exists if (std::filesystem::exists(placefileSettingsPath_)) { - placefileJson = util::json::ReadJsonFile(placefileSettingsPath_); + placefileJson = scwx::util::json::ReadJsonFile(placefileSettingsPath_); } // If placefile settings was successfully read @@ -428,7 +428,7 @@ void PlacefileManager::Impl::WritePlacefileSettings() std::shared_lock lock {placefileRecordLock_}; auto placefileJson = boost::json::value_from(placefileRecords_); - util::json::WriteJsonFile(placefileSettingsPath_, placefileJson); + scwx::util::json::WriteJsonFile(placefileSettingsPath_, placefileJson); } void PlacefileManager::SetRadarSite( diff --git a/scwx-qt/source/scwx/qt/manager/settings_manager.cpp b/scwx-qt/source/scwx/qt/manager/settings_manager.cpp index 5b2e9cbb..a47428bb 100644 --- a/scwx-qt/source/scwx/qt/manager/settings_manager.cpp +++ b/scwx-qt/source/scwx/qt/manager/settings_manager.cpp @@ -9,7 +9,7 @@ #include #include #include -#include +#include #include #include diff --git a/scwx-qt/source/scwx/qt/manager/update_manager.cpp b/scwx-qt/source/scwx/qt/manager/update_manager.cpp index d21068cb..5910fcaf 100644 --- a/scwx-qt/source/scwx/qt/manager/update_manager.cpp +++ b/scwx-qt/source/scwx/qt/manager/update_manager.cpp @@ -1,4 +1,5 @@ #include +#include #include #include @@ -29,8 +30,7 @@ public: ~Impl() {} - static std::string GetVersionString(const std::string& releaseName); - static boost::json::value ParseResponseText(const std::string& s); + static std::string GetVersionString(const std::string& releaseName); size_t PopulateReleases(); size_t AddReleases(const boost::json::value& json); @@ -70,28 +70,6 @@ UpdateManager::Impl::GetVersionString(const std::string& releaseName) return versionString; } -boost::json::value UpdateManager::Impl::ParseResponseText(const std::string& s) -{ - boost::json::stream_parser p; - boost::system::error_code ec; - - p.write(s, ec); - if (ec) - { - logger_->warn("{}", ec.message()); - return nullptr; - } - - p.finish(ec); - if (ec) - { - logger_->warn("{}", ec.message()); - return nullptr; - } - - return p.release(); -} - bool UpdateManager::CheckForUpdates(const std::string& currentVersion) { std::unique_lock lock(p->updateMutex_); @@ -148,7 +126,7 @@ size_t UpdateManager::Impl::PopulateReleases() // Successful REST API query if (r.status_code == 200) { - boost::json::value json = Impl::ParseResponseText(r.text); + boost::json::value json = util::json::ReadJsonString(r.text); if (json == nullptr) { logger_->warn("Response not JSON: {}", r.header["content-type"]); diff --git a/scwx-qt/source/scwx/qt/model/layer_model.cpp b/scwx-qt/source/scwx/qt/model/layer_model.cpp index 2f1b8a9d..6be8eb9d 100644 --- a/scwx-qt/source/scwx/qt/model/layer_model.cpp +++ b/scwx-qt/source/scwx/qt/model/layer_model.cpp @@ -1,7 +1,7 @@ #include #include #include -#include +#include #include #include diff --git a/scwx-qt/source/scwx/qt/model/radar_site_model.cpp b/scwx-qt/source/scwx/qt/model/radar_site_model.cpp index e1a593d7..f131a1cd 100644 --- a/scwx-qt/source/scwx/qt/model/radar_site_model.cpp +++ b/scwx-qt/source/scwx/qt/model/radar_site_model.cpp @@ -4,8 +4,8 @@ #include #include #include -#include #include +#include #include #include @@ -117,7 +117,7 @@ void RadarSiteModelImpl::ReadPresets() // Determine if presets exists if (std::filesystem::exists(presetsPath_)) { - presetsJson = util::json::ReadJsonFile(presetsPath_); + presetsJson = scwx::util::json::ReadJsonFile(presetsPath_); } // If presets was successfully read @@ -160,7 +160,7 @@ void RadarSiteModelImpl::WritePresets() logger_->info("Saving presets"); auto presetsJson = boost::json::value_from(presets_); - util::json::WriteJsonFile(presetsPath_, presetsJson); + scwx::util::json::WriteJsonFile(presetsPath_, presetsJson); } int RadarSiteModel::rowCount(const QModelIndex& parent) const diff --git a/scwx-qt/source/scwx/qt/util/json.cpp b/scwx-qt/source/scwx/qt/util/json.cpp index 7bf0d23a..d508a224 100644 --- a/scwx-qt/source/scwx/qt/util/json.cpp +++ b/scwx-qt/source/scwx/qt/util/json.cpp @@ -1,41 +1,19 @@ #include +#include #include -#include - -#include -#include #include #include -namespace scwx -{ -namespace qt -{ -namespace util -{ -namespace json +namespace scwx::qt::util::json { static const std::string logPrefix_ = "scwx::qt::util::json"; static const auto logger_ = scwx::util::Logger::Create(logPrefix_); -/* Adapted from: - * https://www.boost.org/doc/libs/1_77_0/libs/json/doc/html/json/examples.html#json.examples.pretty - * - * Copyright (c) 2019, 2020 Vinnie Falco - * Copyright (c) 2020 Krystian Stasiowski - * Distributed under the Boost Software License, Version 1.0. (See - * http://www.boost.org/LICENSE_1_0.txt) - */ -static void PrettyPrintJson(std::ostream& os, - boost::json::value const& jv, - std::string* indent = nullptr); - static boost::json::value ReadJsonFile(QFile& file); -static boost::json::value ReadJsonStream(std::istream& is); -boost::json::value ReadJsonFile(const std::string& path) +boost::json::value ReadJsonQFile(const std::string& path) { boost::json::value json; @@ -46,8 +24,7 @@ boost::json::value ReadJsonFile(const std::string& path) } else { - std::ifstream ifs {path}; - json = ReadJsonStream(ifs); + json = ::scwx::util::json::ReadJsonFile(path); } return json; @@ -65,7 +42,7 @@ static boost::json::value ReadJsonFile(QFile& file) std::string jsonSource = jsonStream.readAll().toStdString(); std::istringstream is {jsonSource}; - json = ReadJsonStream(is); + json = ::scwx::util::json::ReadJsonStream(is); file.close(); } @@ -78,147 +55,4 @@ static boost::json::value ReadJsonFile(QFile& file) return json; } -static boost::json::value ReadJsonStream(std::istream& is) -{ - std::string line; - - boost::json::stream_parser p; - boost::system::error_code ec; - - while (std::getline(is, line)) - { - p.write(line, ec); - if (ec) - { - logger_->warn("{}", ec.message()); - return nullptr; - } - } - - p.finish(ec); - if (ec) - { - logger_->warn("{}", ec.message()); - return nullptr; - } - - return p.release(); -} - -void WriteJsonFile(const std::string& path, - const boost::json::value& json, - bool prettyPrint) -{ - std::ofstream ofs {path}; - - if (!ofs.is_open()) - { - logger_->warn("Cannot write JSON file: \"{}\"", path); - } - else - { - if (prettyPrint) - { - PrettyPrintJson(ofs, json); - } - else - { - ofs << json; - } - ofs.close(); - } -} - -static void PrettyPrintJson(std::ostream& os, - boost::json::value const& jv, - std::string* indent) -{ - std::string indent_; - if (!indent) - indent = &indent_; - switch (jv.kind()) - { - case boost::json::kind::object: - { - os << "{\n"; - indent->append(4, ' '); - auto const& obj = jv.get_object(); - if (!obj.empty()) - { - auto it = obj.begin(); - for (;;) - { - os << *indent << boost::json::serialize(it->key()) << " : "; - PrettyPrintJson(os, it->value(), indent); - if (++it == obj.end()) - break; - os << ",\n"; - } - } - os << "\n"; - indent->resize(indent->size() - 4); - os << *indent << "}"; - break; - } - - case boost::json::kind::array: - { - os << "[\n"; - indent->append(4, ' '); - auto const& arr = jv.get_array(); - if (!arr.empty()) - { - auto it = arr.begin(); - for (;;) - { - os << *indent; - PrettyPrintJson(os, *it, indent); - if (++it == arr.end()) - break; - os << ",\n"; - } - } - os << "\n"; - indent->resize(indent->size() - 4); - os << *indent << "]"; - break; - } - - case boost::json::kind::string: - { - os << boost::json::serialize(jv.get_string()); - break; - } - - case boost::json::kind::uint64: - os << jv.get_uint64(); - break; - - case boost::json::kind::int64: - os << jv.get_int64(); - break; - - case boost::json::kind::double_: - os << jv.get_double(); - break; - - case boost::json::kind::bool_: - if (jv.get_bool()) - os << "true"; - else - os << "false"; - break; - - case boost::json::kind::null: - os << "null"; - break; - } - - if (indent->empty()) - os << "\n"; -} - -} // namespace json -} // namespace util -} // namespace qt -} // namespace scwx +} // namespace scwx::qt::util::json diff --git a/scwx-qt/source/scwx/qt/util/json.hpp b/scwx-qt/source/scwx/qt/util/json.hpp index bbf497f4..9dd09810 100644 --- a/scwx-qt/source/scwx/qt/util/json.hpp +++ b/scwx-qt/source/scwx/qt/util/json.hpp @@ -1,7 +1,5 @@ #pragma once -#include - #include namespace scwx @@ -13,10 +11,7 @@ namespace util namespace json { -boost::json::value ReadJsonFile(const std::string& path); -void WriteJsonFile(const std::string& path, - const boost::json::value& json, - bool prettyPrint = true); +boost::json::value ReadJsonQFile(const std::string& path); } // namespace json } // namespace util diff --git a/wxdata/include/scwx/util/json.hpp b/wxdata/include/scwx/util/json.hpp new file mode 100644 index 00000000..ab836edc --- /dev/null +++ b/wxdata/include/scwx/util/json.hpp @@ -0,0 +1,15 @@ +#pragma once + +#include + +namespace scwx::util::json +{ + +boost::json::value ReadJsonFile(const std::string& path); +boost::json::value ReadJsonStream(std::istream& is); +boost::json::value ReadJsonString(std::string_view sv); +void WriteJsonFile(const std::string& path, + const boost::json::value& json, + bool prettyPrint = true); + +} // namespace scwx::util::json diff --git a/wxdata/source/scwx/util/json.cpp b/wxdata/source/scwx/util/json.cpp new file mode 100644 index 00000000..b8f51507 --- /dev/null +++ b/wxdata/source/scwx/util/json.cpp @@ -0,0 +1,199 @@ +#include +#include + +#include + +#include +#include + +namespace scwx::util::json +{ + +static const std::string logPrefix_ = "scwx::util::json"; +static const auto logger_ = scwx::util::Logger::Create(logPrefix_); + +/* Adapted from: + * https://www.boost.org/doc/libs/1_77_0/libs/json/doc/html/json/examples.html#json.examples.pretty + * + * Copyright (c) 2019, 2020 Vinnie Falco + * Copyright (c) 2020 Krystian Stasiowski + * Distributed under the Boost Software License, Version 1.0. (See + * http://www.boost.org/LICENSE_1_0.txt) + */ +static void PrettyPrintJson(std::ostream& os, + boost::json::value const& jv, + std::string* indent = nullptr); + +boost::json::value ReadJsonFile(const std::string& path) +{ + boost::json::value json; + + std::ifstream ifs {path}; + json = ReadJsonStream(ifs); + + return json; +} + +boost::json::value ReadJsonStream(std::istream& is) +{ + std::string line; + + boost::json::stream_parser p; + boost::system::error_code ec; + + while (std::getline(is, line)) + { + p.write(line, ec); + if (ec) + { + logger_->warn("{}", ec.message()); + return nullptr; + } + } + + p.finish(ec); + if (ec) + { + logger_->warn("{}", ec.message()); + return nullptr; + } + + return p.release(); +} + +boost::json::value ReadJsonString(std::string_view sv) +{ + boost::json::stream_parser p; + boost::system::error_code ec; + + p.write(sv, ec); + if (ec) + { + logger_->warn("{}", ec.message()); + return nullptr; + } + + p.finish(ec); + if (ec) + { + logger_->warn("{}", ec.message()); + return nullptr; + } + + return p.release(); +} + +void WriteJsonFile(const std::string& path, + const boost::json::value& json, + bool prettyPrint) +{ + std::ofstream ofs {path}; + + if (!ofs.is_open()) + { + logger_->warn("Cannot write JSON file: \"{}\"", path); + } + else + { + if (prettyPrint) + { + PrettyPrintJson(ofs, json); + } + else + { + ofs << json; + } + ofs.close(); + } +} + +static void PrettyPrintJson(std::ostream& os, + boost::json::value const& jv, + std::string* indent) +{ + std::string indent_; + if (!indent) + indent = &indent_; + switch (jv.kind()) + { + case boost::json::kind::object: + { + os << "{\n"; + indent->append(4, ' '); + auto const& obj = jv.get_object(); + if (!obj.empty()) + { + auto it = obj.begin(); + for (;;) + { + os << *indent << boost::json::serialize(it->key()) << " : "; + PrettyPrintJson(os, it->value(), indent); + if (++it == obj.end()) + break; + os << ",\n"; + } + } + os << "\n"; + indent->resize(indent->size() - 4); + os << *indent << "}"; + break; + } + + case boost::json::kind::array: + { + os << "[\n"; + indent->append(4, ' '); + auto const& arr = jv.get_array(); + if (!arr.empty()) + { + auto it = arr.begin(); + for (;;) + { + os << *indent; + PrettyPrintJson(os, *it, indent); + if (++it == arr.end()) + break; + os << ",\n"; + } + } + os << "\n"; + indent->resize(indent->size() - 4); + os << *indent << "]"; + break; + } + + case boost::json::kind::string: + { + os << boost::json::serialize(jv.get_string()); + break; + } + + case boost::json::kind::uint64: + os << jv.get_uint64(); + break; + + case boost::json::kind::int64: + os << jv.get_int64(); + break; + + case boost::json::kind::double_: + os << jv.get_double(); + break; + + case boost::json::kind::bool_: + if (jv.get_bool()) + os << "true"; + else + os << "false"; + break; + + case boost::json::kind::null: + os << "null"; + break; + } + + if (indent->empty()) + os << "\n"; +} + +} // namespace scwx::util::json diff --git a/wxdata/wxdata.cmake b/wxdata/wxdata.cmake index 77e65c58..4b08ad19 100644 --- a/wxdata/wxdata.cmake +++ b/wxdata/wxdata.cmake @@ -78,6 +78,7 @@ set(HDR_UTIL include/scwx/util/digest.hpp include/scwx/util/float.hpp include/scwx/util/hash.hpp include/scwx/util/iterator.hpp + include/scwx/util/json.hpp include/scwx/util/logger.hpp include/scwx/util/map.hpp include/scwx/util/rangebuf.hpp @@ -90,6 +91,7 @@ set(SRC_UTIL source/scwx/util/digest.cpp source/scwx/util/environment.cpp source/scwx/util/float.cpp source/scwx/util/hash.cpp + source/scwx/util/json.cpp source/scwx/util/logger.cpp source/scwx/util/rangebuf.cpp source/scwx/util/streams.cpp