Skip to content

Commit

Permalink
broker: better valitdation of jsondata
Browse files Browse the repository at this point in the history
  • Loading branch information
bcsanches committed Jul 20, 2024
1 parent 3749ba4 commit fbeb0a1
Show file tree
Hide file tree
Showing 16 changed files with 303 additions and 90 deletions.
47 changes: 23 additions & 24 deletions data/MyRailroad/broker.config.json
Original file line number Diff line number Diff line change
@@ -1,26 +1,25 @@
{
"name": "MyRailroad",
"services": [
{
"class": "DccLite",
"name": "Dcc0",
"port": 8989,
"devices": [
{
"name": "TestDevice",
"class": "ArduinoMega"
}
]
},
{
"class": "Terminal",
"name": "terminal",
"port": 4190
},
{
"class": "DccppService",
"name": "dccpp",
"system":"Dcc0"
}
]
"name": "MyRailroad",
"services": [
{
"class": "DccLiteService",
"name": "dcc0",
"devices": [
{
"name": "TestDevice",
"class": "ArduinoMega"
}
]
},
{
"class": "Terminal",
"name": "terminal",
"port": 4190
},
{
"class": "DccppService",
"name": "dccpp",
"requires":"DccLiteService"
}
]
}
2 changes: 2 additions & 0 deletions release_notes.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
## Broker

- Support to unnamed devices (auto generate a name with IP)
- Better validation of json data
- fixed sample "MyRailroad"

## SharpTerminal

Expand Down
4 changes: 3 additions & 1 deletion src/Broker/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@

add_executable(Broker main.cpp)
add_executable(Broker
main.cpp
)

target_include_directories(Broker
PRIVATE ${DCCLite_SOURCE_DIR}/src/BrokerLib
Expand Down
23 changes: 7 additions & 16 deletions src/BrokerLib/dcc/DccLiteService.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include <exception>
#include <Log.h>

#include <JsonUtils.h>
#include <FmtUtils.h>
#include <GuidUtils.h>
#include <Packet.h>
Expand Down Expand Up @@ -116,14 +117,8 @@ namespace dcclite::broker

m_pLocations = static_cast<LocationManager *>(this->AddChild(std::make_unique<LocationManager>(RName{ "locations" }, params)));

uint16_t port = dcclite::DEFAULT_DCCLITE_SERVER_PORT;
uint16_t port = json::TryGetDefaultInt(params, "port", dcclite::DEFAULT_DCCLITE_SERVER_PORT);

{
auto portData = params.FindMember("port");
if (portData != params.MemberEnd())
port = portData->value.GetInt();
}

[[unlikely]]
if (!m_clSocket.Open(port, dcclite::Socket::Type::DATAGRAM, dcclite::Socket::FLAG_BLOCKING_MODE))
{
Expand All @@ -132,18 +127,14 @@ namespace dcclite::broker

dcclite::Log::Info("[DccLiteService::{}] Listening on port {}", this->GetName(), port);

const rapidjson::Value &devicesData = params["devices"];

[[unlikely]]
if (!devicesData.IsArray())
throw std::runtime_error(fmt::format("[DccLiteService::{}] error: invalid config, expected devices array inside DccLiteService", name));

const auto devicesArray = json::GetArray(params, "devices", "DccLiteService");

try
{
for (auto &device : devicesData.GetArray())
for (auto &device : devicesArray)
{
RName nodeName{ device["name"].GetString() };
auto className = device["class"].GetString();
RName nodeName{ json::GetString(device, "name", "device data for DccLiteService")};
auto className = json::GetString(device, "class", "device data for DccLiteService");

if (strcmp(className, "Virtual"))
m_pDevices->AddChild(std::make_unique<NetworkDevice>(nodeName, *static_cast<IDccLite_DeviceServices *>(this), device, project));
Expand Down
13 changes: 4 additions & 9 deletions src/BrokerLib/dcc/DccppService.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

#include "Decoder.h"
#include "DccLiteService.h"
#include "JsonUtils.h"
#include "NetMessenger.h"
#include "NmraUtil.h"
#include "SignalDecoder.h"
Expand Down Expand Up @@ -718,16 +719,10 @@ namespace dcclite::broker

DccppServiceImpl::DccppServiceImpl(RName name, Broker &broker, const rapidjson::Value& params, const Project& project):
DccppService(name, broker, params, project),
m_rclDccService{ static_cast<DccLiteService &>(m_rclBroker.ResolveRequirement(params["requires"].GetString())) }
{


m_rclDccService{ static_cast<DccLiteService &>(m_rclBroker.ResolveRequirement(dcclite::json::GetString(params, "requires", name.GetData().data()))) }
{
//standard port used by DCC++
int port = 2560;

auto it = params.FindMember("port");
if (it != params.MemberEnd())
port = it->value.GetInt();
const auto port = dcclite::json::TryGetDefaultInt(params, "port", 2560);

if (!m_clSocket.Open(port, dcclite::Socket::Type::STREAM, dcclite::Socket::Flags::FLAG_BLOCKING_MODE))
{
Expand Down
7 changes: 4 additions & 3 deletions src/BrokerLib/dcc/Device.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include "Decoder.h"
#include "FmtUtils.h"
#include "IDccLiteService.h"
#include "JsonUtils.h"
#include "Log.h"

namespace dcclite::broker
Expand Down Expand Up @@ -171,14 +172,14 @@ namespace dcclite::broker
{
for (auto &element : decodersData.GetArray())
{
auto className = element["class"].GetString();
auto className = json::GetString(element, "class", "Device");

//Just used for annotations on JSON file...as the parser does not support comments
if (strcmp(className, "IgnoreMe") == 0)
continue;

auto decoderName = RName{ element["name"].GetString() };
DccAddress address{ element["address"] };
auto decoderName = RName{ json::GetString(element, "name", "Device") };
DccAddress address{ json::GetValue(element, "address", "Device") };

auto &decoder = m_clDccService.Device_CreateDecoder(*this, className, address, decoderName, element);

Expand Down
12 changes: 7 additions & 5 deletions src/BrokerLib/dcc/LocationManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
#include "LocationManager.h"

#include <FmtUtils.h>

#include <JsonUtil.h>
#include <Log.h>

#include "Decoder.h"
Expand Down Expand Up @@ -126,16 +128,16 @@ namespace dcclite::broker
const rapidjson::Value &sectorsData = it->value;

if(!sectorsData.IsArray())
throw new std::runtime_error(fmt::format("[{}] LocationManagerService no sectors data array", this->GetName()));
throw new std::runtime_error(fmt::format("[{}] LocationManagerService sectors data must be an array", this->GetName()));

m_vecIndex.reserve(sectorsData.GetArray().Size());

for(auto &sectorData : sectorsData.GetArray())
{
RName dname{ sectorData["name"].GetString()};
RName prefix{ sectorData["prefix"].GetString() };
auto beginAddress = DccAddress{static_cast<uint16_t>(sectorData["begin"].GetInt())};
auto endAddress = DccAddress{ static_cast<uint16_t>(sectorData["end"].GetInt())};
RName dname{ json::GetString(sectorData, "name", "LocationManager::Sector")};
RName prefix{ json::GetString(sectorData, "prefix", "LocationManager::Sector") };
auto beginAddress = DccAddress{static_cast<uint16_t>(json::GetInt(sectorData, "begin", "LocationManager::Sector"))};
auto endAddress = DccAddress{ static_cast<uint16_t>(json::GetInt(sectorData, "end", "LocationManager::Sector"))};

m_vecIndex.emplace_back(dname, prefix, beginAddress, endAddress, *this);

Expand Down
17 changes: 7 additions & 10 deletions src/BrokerLib/dcc/QuadInverter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

#include "QuadInverter.h"

#include <JsonUtils.h>
#include <Packet.h>

#include "IDevice.h"
Expand All @@ -26,8 +27,8 @@ namespace dcclite::broker
) :
OutputDecoder(address, name, owner, dev, params)
{
const auto &trackAPins = params["trackPowerAPins"].GetArray();
const auto &trackBPins = params["trackPowerBPins"].GetArray();
const auto trackAPins = json::GetArray(params, "trackPowerAPins", "QuadInverter");
const auto trackBPins = json::GetArray(params, "trackPowerBPins", "QuadInverter");

m_arTrackAPins[0] = dcclite::BasicPin{ static_cast<PinType_t>(trackAPins[0].GetInt()) };
m_arTrackAPins[1] = dcclite::BasicPin{ static_cast<PinType_t>(trackAPins[1].GetInt()) };
Expand All @@ -42,15 +43,11 @@ namespace dcclite::broker

networkDevice->Decoder_RegisterPin(*this, m_arTrackBPins[0], "trackB0");
networkDevice->Decoder_RegisterPin(*this, m_arTrackBPins[1], "trackB1");

m_fIgnoreSavedState = json::TryGetDefaultBool(params, "ignoreSavedState", false);
m_fActivateOnPowerUp = json::TryGetDefaultBool(params, "activateOnPowerUp", false);

auto ignoreSavedState = params.FindMember("ignoreSavedState");
m_fIgnoreSavedState = ignoreSavedState != params.MemberEnd() ? ignoreSavedState->value.GetBool() : false;

auto activateOnPowerUp = params.FindMember("activateOnPowerUp");
m_fActivateOnPowerUp = activateOnPowerUp != params.MemberEnd() ? activateOnPowerUp->value.GetBool() : false;

auto flipIntervalData = params.FindMember("flipInterval");
m_u8FlipInterval = flipIntervalData != params.MemberEnd() ? flipIntervalData->value.GetInt() : m_u8FlipInterval;
m_u8FlipInterval = json::TryGetDefaultInt(params, "flipInterval", m_u8FlipInterval);

this->SyncRemoteState(m_fIgnoreSavedState && m_fActivateOnPowerUp ? dcclite::DecoderStates::ACTIVE : dcclite::DecoderStates::INACTIVE);
}
Expand Down
48 changes: 26 additions & 22 deletions src/BrokerLib/sys/Broker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,11 @@
#include <string>

#include <fmt/format.h>

#include <rapidjson/document.h>
#include <rapidjson/istreamwrapper.h>
#include <rapidjson/schema.h>

#include <spdlog/logger.h>

#include <Log.h>
Expand All @@ -38,6 +41,7 @@

#include "BonjourService.h"

#include "JsonUtils.h"
#include "Thinker.h"
#include "ScriptSystem.h"
#include "SpecialFolders.h"
Expand All @@ -48,16 +52,15 @@

namespace dcclite::broker
{
static bool CheckIfServiceIsIgnorable(const rapidjson::Value &data)
static inline bool CheckIfServiceIsIgnorable(const rapidjson::Value &data) noexcept
{
auto ignoreServiceFlag = data.FindMember("ignoreOnLoadFailure");
return ((ignoreServiceFlag != data.MemberEnd()) && (ignoreServiceFlag->value.GetBool()));
return dcclite::json::TryGetDefaultBool(data, "ignoreOnLoadFailure", false);
}

static std::unique_ptr<Service> CreateBrokerService(Broker &broker, const rapidjson::Value &data, const Project &project)
{
const char *className = data["class"].GetString();
RName name{ data["name"].GetString() };
const char *className = dcclite::json::GetString(data, "class", "service block");
RName name{ dcclite::json::GetString(data, "name", "service block") };

dcclite::Log::Info("[Broker] [CreateBrokerService] Creating DccLite Service: {}", name);

Expand Down Expand Up @@ -137,44 +140,45 @@ namespace dcclite::broker
ScriptSystem::Stop();

ZeroConfSystem::Stop();
}
}

void Broker::LoadConfig()
{
{
const auto configFileName = m_clProject.GetFilePath("broker.config.json");
const auto configFileNameStr = configFileName.string();

dcclite::Log::Info("[Broker] [LoadConfig] Trying to open {}", configFileNameStr);

std::ifstream configFile(configFileName);

if (!configFile)
{
throw std::runtime_error(fmt::format("[Broker] [LoadConfig] error: cannot open config file {}", configFileName.string()));
throw std::runtime_error(fmt::format("[Broker] [LoadConfig] error: cannot open config file {}", configFileNameStr));
}

dcclite::Log::Debug("[Broker] [LoadConfig] Loaded config {}", configFileName.string());
dcclite::Log::Info("[Broker] [LoadConfig] Opened {}, starting parser", configFileNameStr);

rapidjson::IStreamWrapper isw(configFile);
rapidjson::Document data;
data.ParseStream(isw);
if (data.ParseStream(isw).HasParseError())
{
throw std::runtime_error(fmt::format("[Broker] [LoadConfig] {} is not a valid json", configFileNameStr));
}

m_clProject.SetName(data["name"].GetString());
m_clProject.SetName(dcclite::json::GetString(data, "name", "broker"));

const auto &services = data["services"];
const auto &services = dcclite::json::GetArray(data, "services", "broker");

if (!services.IsArray())
{
throw std::runtime_error("[Broker] [LoadConfig] error: invalid config, expected services array");
}
dcclite::Log::Info("[Broker] [LoadConfig] Loaded config {}", configFileNameStr);

auto bonjourSetting = data.FindMember("bonjourService");
if ((bonjourSetting != data.MemberEnd()) && (bonjourSetting->value.GetBool()))
if(dcclite::json::TryGetDefaultBool(data, "bonjourService", false))
m_pServices->AddChild(BonjourService::Create(RName{ BONJOUR_SERVICE_NAME }, *this, m_clProject));

dcclite::Log::Debug("[Broker] [LoadConfig] Processing config services array entries: {}", services.Size());

auto servicesDataArray = services.GetArray();
dcclite::Log::Debug("[Broker] [LoadConfig] Processing config services array entries: {}", services.Size());

std::vector<const rapidjson::Value *> pendingServices;

for (auto &serviceData : servicesDataArray)
for (auto &serviceData : services)
{
auto requiresData = serviceData.FindMember("requires");
if (requiresData == serviceData.MemberEnd())
Expand Down
2 changes: 2 additions & 0 deletions src/Common/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ add_library(
GuidUtils.h
IFolderObject.cpp
IFolderObject.h
JsonUtils.cpp
JsonUtils.h
Log.h
LogUtils.cpp
LogUtils.h
Expand Down
Loading

0 comments on commit fbeb0a1

Please sign in to comment.