Refactor json utility to wxdata, add ReadJsonString function

This commit is contained in:
Dan Paulat 2025-02-01 18:21:41 -06:00
parent 895e760fee
commit 9f33189c18
12 changed files with 245 additions and 228 deletions

View file

@ -245,7 +245,7 @@ size_t RadarSite::ReadConfig(const std::string& path)
bool dataValid = true; bool dataValid = true;
size_t sitesAdded = 0; size_t sitesAdded = 0;
boost::json::value j = util::json::ReadJsonFile(path); boost::json::value j = util::json::ReadJsonQFile(path);
dataValid = j.is_array(); dataValid = j.is_array();

View file

@ -1,10 +1,10 @@
#include <scwx/qt/manager/marker_manager.hpp> #include <scwx/qt/manager/marker_manager.hpp>
#include <scwx/qt/types/marker_types.hpp> #include <scwx/qt/types/marker_types.hpp>
#include <scwx/qt/util/color.hpp> #include <scwx/qt/util/color.hpp>
#include <scwx/qt/util/json.hpp>
#include <scwx/qt/util/texture_atlas.hpp> #include <scwx/qt/util/texture_atlas.hpp>
#include <scwx/qt/main/application.hpp> #include <scwx/qt/main/application.hpp>
#include <scwx/qt/manager/resource_manager.hpp> #include <scwx/qt/manager/resource_manager.hpp>
#include <scwx/util/json.hpp>
#include <scwx/util/logger.hpp> #include <scwx/util/logger.hpp>
#include <filesystem> #include <filesystem>
@ -62,7 +62,7 @@ public:
bool markerFileRead_ {false}; bool markerFileRead_ {false};
void InitalizeIds(); void InitalizeIds();
types::MarkerId NewId(); types::MarkerId NewId();
types::MarkerId lastId_ {0}; types::MarkerId lastId_ {0};
}; };
@ -70,15 +70,9 @@ public:
class MarkerManager::Impl::MarkerRecord class MarkerManager::Impl::MarkerRecord
{ {
public: public:
MarkerRecord(const types::MarkerInfo& info) : MarkerRecord(const types::MarkerInfo& info) : markerInfo_ {info} {}
markerInfo_ {info}
{
}
const types::MarkerInfo& toMarkerInfo() const types::MarkerInfo& toMarkerInfo() { return markerInfo_; }
{
return markerInfo_;
}
types::MarkerInfo markerInfo_; types::MarkerInfo markerInfo_;
@ -175,7 +169,7 @@ void MarkerManager::Impl::ReadMarkerSettings()
// Determine if marker settings exists // Determine if marker settings exists
if (std::filesystem::exists(markerSettingsPath_)) if (std::filesystem::exists(markerSettingsPath_))
{ {
markerJson = util::json::ReadJsonFile(markerSettingsPath_); markerJson = scwx::util::json::ReadJsonFile(markerSettingsPath_);
} }
if (markerJson != nullptr && markerJson.is_array()) if (markerJson != nullptr && markerJson.is_array())
@ -224,8 +218,8 @@ void MarkerManager::Impl::WriteMarkerSettings()
logger_->info("Saving location marker settings"); logger_->info("Saving location marker settings");
const std::shared_lock lock(markerRecordLock_); const std::shared_lock lock(markerRecordLock_);
auto markerJson = boost::json::value_from(markerRecords_); auto markerJson = boost::json::value_from(markerRecords_);
util::json::WriteJsonFile(markerSettingsPath_, markerJson); scwx::util::json::WriteJsonFile(markerSettingsPath_, markerJson);
} }
std::shared_ptr<MarkerManager::Impl::MarkerRecord> std::shared_ptr<MarkerManager::Impl::MarkerRecord>
@ -357,10 +351,11 @@ types::MarkerId MarkerManager::add_marker(const types::MarkerInfo& marker)
types::MarkerId id; types::MarkerId id;
{ {
const std::unique_lock lock(p->markerRecordLock_); const std::unique_lock lock(p->markerRecordLock_);
id = p->NewId(); id = p->NewId();
size_t index = p->markerRecords_.size(); size_t index = p->markerRecords_.size();
p->idToIndex_.emplace(id, index); p->idToIndex_.emplace(id, index);
p->markerRecords_.emplace_back(std::make_shared<Impl::MarkerRecord>(marker)); p->markerRecords_.emplace_back(
std::make_shared<Impl::MarkerRecord>(marker));
p->markerRecords_[index]->markerInfo_.id = id; p->markerRecords_[index]->markerInfo_.id = id;
add_icon(marker.iconName); add_icon(marker.iconName);
@ -499,7 +494,6 @@ void MarkerManager::set_marker_settings_path(const std::string& path)
p->markerSettingsPath_ = path; p->markerSettingsPath_ = path;
} }
std::shared_ptr<MarkerManager> MarkerManager::Instance() std::shared_ptr<MarkerManager> MarkerManager::Instance()
{ {
static std::weak_ptr<MarkerManager> markerManagerReference_ {}; static std::weak_ptr<MarkerManager> markerManagerReference_ {};

View file

@ -2,10 +2,10 @@
#include <scwx/qt/manager/font_manager.hpp> #include <scwx/qt/manager/font_manager.hpp>
#include <scwx/qt/manager/resource_manager.hpp> #include <scwx/qt/manager/resource_manager.hpp>
#include <scwx/qt/main/application.hpp> #include <scwx/qt/main/application.hpp>
#include <scwx/qt/util/json.hpp>
#include <scwx/qt/util/network.hpp> #include <scwx/qt/util/network.hpp>
#include <scwx/gr/placefile.hpp> #include <scwx/gr/placefile.hpp>
#include <scwx/network/cpr.hpp> #include <scwx/network/cpr.hpp>
#include <scwx/util/json.hpp>
#include <scwx/util/logger.hpp> #include <scwx/util/logger.hpp>
#include <shared_mutex> #include <shared_mutex>
@ -385,7 +385,7 @@ void PlacefileManager::Impl::ReadPlacefileSettings()
// Determine if placefile settings exists // Determine if placefile settings exists
if (std::filesystem::exists(placefileSettingsPath_)) if (std::filesystem::exists(placefileSettingsPath_))
{ {
placefileJson = util::json::ReadJsonFile(placefileSettingsPath_); placefileJson = scwx::util::json::ReadJsonFile(placefileSettingsPath_);
} }
// If placefile settings was successfully read // If placefile settings was successfully read
@ -428,7 +428,7 @@ void PlacefileManager::Impl::WritePlacefileSettings()
std::shared_lock lock {placefileRecordLock_}; std::shared_lock lock {placefileRecordLock_};
auto placefileJson = boost::json::value_from(placefileRecords_); auto placefileJson = boost::json::value_from(placefileRecords_);
util::json::WriteJsonFile(placefileSettingsPath_, placefileJson); scwx::util::json::WriteJsonFile(placefileSettingsPath_, placefileJson);
} }
void PlacefileManager::SetRadarSite( void PlacefileManager::SetRadarSite(

View file

@ -9,7 +9,7 @@
#include <scwx/qt/settings/text_settings.hpp> #include <scwx/qt/settings/text_settings.hpp>
#include <scwx/qt/settings/ui_settings.hpp> #include <scwx/qt/settings/ui_settings.hpp>
#include <scwx/qt/settings/unit_settings.hpp> #include <scwx/qt/settings/unit_settings.hpp>
#include <scwx/qt/util/json.hpp> #include <scwx/util/json.hpp>
#include <scwx/util/logger.hpp> #include <scwx/util/logger.hpp>
#include <filesystem> #include <filesystem>

View file

@ -1,4 +1,5 @@
#include <scwx/qt/manager/update_manager.hpp> #include <scwx/qt/manager/update_manager.hpp>
#include <scwx/util/json.hpp>
#include <scwx/util/logger.hpp> #include <scwx/util/logger.hpp>
#include <mutex> #include <mutex>
@ -29,8 +30,7 @@ public:
~Impl() {} ~Impl() {}
static std::string GetVersionString(const std::string& releaseName); static std::string GetVersionString(const std::string& releaseName);
static boost::json::value ParseResponseText(const std::string& s);
size_t PopulateReleases(); size_t PopulateReleases();
size_t AddReleases(const boost::json::value& json); size_t AddReleases(const boost::json::value& json);
@ -70,28 +70,6 @@ UpdateManager::Impl::GetVersionString(const std::string& releaseName)
return versionString; 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) bool UpdateManager::CheckForUpdates(const std::string& currentVersion)
{ {
std::unique_lock lock(p->updateMutex_); std::unique_lock lock(p->updateMutex_);
@ -148,7 +126,7 @@ size_t UpdateManager::Impl::PopulateReleases()
// Successful REST API query // Successful REST API query
if (r.status_code == 200) 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) if (json == nullptr)
{ {
logger_->warn("Response not JSON: {}", r.header["content-type"]); logger_->warn("Response not JSON: {}", r.header["content-type"]);

View file

@ -1,7 +1,7 @@
#include <scwx/qt/model/layer_model.hpp> #include <scwx/qt/model/layer_model.hpp>
#include <scwx/qt/manager/placefile_manager.hpp> #include <scwx/qt/manager/placefile_manager.hpp>
#include <scwx/qt/types/qt_types.hpp> #include <scwx/qt/types/qt_types.hpp>
#include <scwx/qt/util/json.hpp> #include <scwx/util/json.hpp>
#include <scwx/util/logger.hpp> #include <scwx/util/logger.hpp>
#include <filesystem> #include <filesystem>

View file

@ -4,8 +4,8 @@
#include <scwx/qt/types/qt_types.hpp> #include <scwx/qt/types/qt_types.hpp>
#include <scwx/qt/types/unit_types.hpp> #include <scwx/qt/types/unit_types.hpp>
#include <scwx/qt/util/geographic_lib.hpp> #include <scwx/qt/util/geographic_lib.hpp>
#include <scwx/qt/util/json.hpp>
#include <scwx/common/geographic.hpp> #include <scwx/common/geographic.hpp>
#include <scwx/util/json.hpp>
#include <scwx/util/logger.hpp> #include <scwx/util/logger.hpp>
#include <filesystem> #include <filesystem>
@ -117,7 +117,7 @@ void RadarSiteModelImpl::ReadPresets()
// Determine if presets exists // Determine if presets exists
if (std::filesystem::exists(presetsPath_)) if (std::filesystem::exists(presetsPath_))
{ {
presetsJson = util::json::ReadJsonFile(presetsPath_); presetsJson = scwx::util::json::ReadJsonFile(presetsPath_);
} }
// If presets was successfully read // If presets was successfully read
@ -160,7 +160,7 @@ void RadarSiteModelImpl::WritePresets()
logger_->info("Saving presets"); logger_->info("Saving presets");
auto presetsJson = boost::json::value_from(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 int RadarSiteModel::rowCount(const QModelIndex& parent) const

View file

@ -1,41 +1,19 @@
#include <scwx/qt/util/json.hpp> #include <scwx/qt/util/json.hpp>
#include <scwx/util/json.hpp>
#include <scwx/util/logger.hpp> #include <scwx/util/logger.hpp>
#include <fstream>
#include <boost/json.hpp>
#include <fmt/ranges.h>
#include <QFile> #include <QFile>
#include <QTextStream> #include <QTextStream>
namespace scwx namespace scwx::qt::util::json
{
namespace qt
{
namespace util
{
namespace json
{ {
static const std::string logPrefix_ = "scwx::qt::util::json"; static const std::string logPrefix_ = "scwx::qt::util::json";
static const auto logger_ = scwx::util::Logger::Create(logPrefix_); 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 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; boost::json::value json;
@ -46,8 +24,7 @@ boost::json::value ReadJsonFile(const std::string& path)
} }
else else
{ {
std::ifstream ifs {path}; json = ::scwx::util::json::ReadJsonFile(path);
json = ReadJsonStream(ifs);
} }
return json; return json;
@ -65,7 +42,7 @@ static boost::json::value ReadJsonFile(QFile& file)
std::string jsonSource = jsonStream.readAll().toStdString(); std::string jsonSource = jsonStream.readAll().toStdString();
std::istringstream is {jsonSource}; std::istringstream is {jsonSource};
json = ReadJsonStream(is); json = ::scwx::util::json::ReadJsonStream(is);
file.close(); file.close();
} }
@ -78,147 +55,4 @@ static boost::json::value ReadJsonFile(QFile& file)
return json; return json;
} }
static boost::json::value ReadJsonStream(std::istream& is) } // namespace scwx::qt::util::json
{
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

View file

@ -1,7 +1,5 @@
#pragma once #pragma once
#include <optional>
#include <boost/json/value.hpp> #include <boost/json/value.hpp>
namespace scwx namespace scwx
@ -13,10 +11,7 @@ namespace util
namespace json namespace json
{ {
boost::json::value ReadJsonFile(const std::string& path); boost::json::value ReadJsonQFile(const std::string& path);
void WriteJsonFile(const std::string& path,
const boost::json::value& json,
bool prettyPrint = true);
} // namespace json } // namespace json
} // namespace util } // namespace util

View file

@ -0,0 +1,15 @@
#pragma once
#include <boost/json/value.hpp>
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

View file

@ -0,0 +1,199 @@
#include <scwx/util/json.hpp>
#include <scwx/util/logger.hpp>
#include <fstream>
#include <boost/json.hpp>
#include <fmt/ranges.h>
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

View file

@ -78,6 +78,7 @@ set(HDR_UTIL include/scwx/util/digest.hpp
include/scwx/util/float.hpp include/scwx/util/float.hpp
include/scwx/util/hash.hpp include/scwx/util/hash.hpp
include/scwx/util/iterator.hpp include/scwx/util/iterator.hpp
include/scwx/util/json.hpp
include/scwx/util/logger.hpp include/scwx/util/logger.hpp
include/scwx/util/map.hpp include/scwx/util/map.hpp
include/scwx/util/rangebuf.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/environment.cpp
source/scwx/util/float.cpp source/scwx/util/float.cpp
source/scwx/util/hash.cpp source/scwx/util/hash.cpp
source/scwx/util/json.cpp
source/scwx/util/logger.cpp source/scwx/util/logger.cpp
source/scwx/util/rangebuf.cpp source/scwx/util/rangebuf.cpp
source/scwx/util/streams.cpp source/scwx/util/streams.cpp