Refactor ObjectQueryHandler to use new JSON stream encoder

This commit is contained in:
Johannes Schmidt 2025-06-27 12:46:15 +02:00
parent 749a4b0c89
commit fcad7f77cc

View File

@ -1,6 +1,8 @@
/* Icinga 2 | (c) 2012 Icinga GmbH | GPLv2+ */
#include "remote/objectqueryhandler.hpp"
#include "base/generator.hpp"
#include "base/json.hpp"
#include "remote/httputility.hpp"
#include "remote/filterutility.hpp"
#include "base/serializer.hpp"
@ -9,6 +11,7 @@
#include <boost/algorithm/string/case_conv.hpp>
#include <set>
#include <unordered_map>
#include <memory>
using namespace icinga;
@ -140,6 +143,16 @@ bool ObjectQueryHandler::HandleRequest(
return true;
}
if(umetas){
ObjectLock olock(umetas);
for (String meta : umetas) {
if (!(meta == "used_by" || meta == "location")) {
response.SendJsonError(request.Params(), 400, "Invalid field specified for meta: " + meta);
return true;
}
}
}
bool allJoins = request.GetLastParameter("all_joins");
request.Params()->Set("type", type->GetName());
@ -161,9 +174,6 @@ bool ObjectQueryHandler::HandleRequest(
return true;
}
ArrayData results;
results.reserve(objs.size());
std::set<String> joinAttrs;
std::set<String> userJoinAttrs;
@ -189,14 +199,21 @@ bool ObjectQueryHandler::HandleRequest(
std::unordered_map<Type*, std::pair<bool, std::unique_ptr<Expression>>> typePermissions;
std::unordered_map<Object*, bool> objectAccessAllowed;
for (ConfigObject::Ptr obj : objs) {
auto it = objs.begin();
auto generatorFunc = [&]() -> std::optional<Value> {
if (it == objs.end()) {
return std::nullopt;
}
ConfigObject::Ptr obj = *it;
++it;
DictionaryData result1{
{ "name", obj->GetName() },
{ "type", obj->GetReflectionType()->GetName() }
};
DictionaryData metaAttrs;
if (umetas) {
ObjectLock olock(umetas);
for (String meta : umetas) {
@ -212,9 +229,6 @@ bool ObjectQueryHandler::HandleRequest(
}
} else if (meta == "location") {
metaAttrs.emplace_back("location", obj->GetSourceLocation());
} else {
response.SendJsonError(request.Params(), 400, "Invalid field specified for meta: " + meta);
return true;
}
}
}
@ -224,8 +238,12 @@ bool ObjectQueryHandler::HandleRequest(
try {
result1.emplace_back("attrs", SerializeObjectAttrs(obj, String(), uattrs, false, false));
} catch (const ScriptError& ex) {
response.SendJsonError(request.Params(), 400, ex.what());
return true;
return new Dictionary{
{"type", type->GetName()},
{"name", obj->GetName()},
{"code", 400},
{"status", ex.what()}
};
}
DictionaryData joins;
@ -234,18 +252,8 @@ bool ObjectQueryHandler::HandleRequest(
Object::Ptr joinedObj;
int fid = type->GetFieldId(joinAttr);
if (fid < 0) {
response.SendJsonError(request.Params(), 400, "Invalid field specified for join: " + joinAttr);
return true;
}
Field field = type->GetFieldInfo(fid);
if (!(field.Attributes & FANavigation)) {
response.SendJsonError(request.Params(), 400, "Not a joinable field: " + joinAttr);
return true;
}
joinedObj = obj->NavigateField(fid);
if (!joinedObj)
@ -299,22 +307,30 @@ bool ObjectQueryHandler::HandleRequest(
try {
joins.emplace_back(prefix, SerializeObjectAttrs(joinedObj, prefix, ujoins, true, allJoins));
} catch (const ScriptError& ex) {
response.SendJsonError(request.Params(), 400, ex.what());
return true;
return new Dictionary{
{"type", type->GetName()},
{"name", obj->GetName()},
{"code", 400},
{"status", ex.what()}
};
}
}
result1.emplace_back("joins", new Dictionary(std::move(joins)));
results.push_back(new Dictionary(std::move(result1)));
}
Dictionary::Ptr result = new Dictionary({
{ "results", new Array(std::move(results)) }
});
return new Dictionary{std::move(result1)};
};
response.result(http::status::ok);
response.SendJsonBody(request.Params(), result);
response.set(http::field::content_type, "application/json");
response.StartStreaming();
Dictionary::Ptr results = new Dictionary{{"results", new ValueGenerator{generatorFunc}}};
results->Freeze();
auto adapter = std::make_shared<BeastHttpMessageAdapter<HttpResponse>>(response);
JsonEncoder encoder(adapter, request.IsPretty());
encoder.Encode(results, &yc);
return true;
}