Skip to content

Commit bb75d73

Browse files
Refactor ObjectQueryHandler to use new JSON stream encoder
1 parent 62b2dad commit bb75d73

File tree

1 file changed

+68
-52
lines changed

1 file changed

+68
-52
lines changed

lib/remote/objectqueryhandler.cpp

Lines changed: 68 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
/* Icinga 2 | (c) 2012 Icinga GmbH | GPLv2+ */
22

33
#include "remote/objectqueryhandler.hpp"
4+
#include "base/generator.hpp"
5+
#include "base/json.hpp"
46
#include "remote/httputility.hpp"
57
#include "remote/filterutility.hpp"
68
#include "base/serializer.hpp"
@@ -9,6 +11,7 @@
911
#include <boost/algorithm/string/case_conv.hpp>
1012
#include <set>
1113
#include <unordered_map>
14+
#include <memory>
1215

1316
using namespace icinga;
1417

@@ -144,6 +147,22 @@ bool ObjectQueryHandler::HandleRequest(
144147
return true;
145148
}
146149

150+
bool includeUsedBy = false;
151+
bool includeLocation = false;
152+
if (umetas) {
153+
ObjectLock olock(umetas);
154+
for (String meta : umetas) {
155+
if (meta == "used_by") {
156+
includeUsedBy = true;
157+
} else if (meta == "location") {
158+
includeLocation = true;
159+
} else {
160+
HttpUtility::SendJsonError(response, params, 400, "Invalid field specified for meta: " + meta);
161+
return true;
162+
}
163+
}
164+
}
165+
147166
bool allJoins = HttpUtility::GetLastParameter(params, "all_joins");
148167

149168
params->Set("type", type->GetName());
@@ -165,10 +184,7 @@ bool ObjectQueryHandler::HandleRequest(
165184
return true;
166185
}
167186

168-
ArrayData results;
169-
results.reserve(objs.size());
170-
171-
std::set<String> joinAttrs;
187+
std::set<int> joinAttrs;
172188
std::set<String> userJoinAttrs;
173189

174190
if (ujoins) {
@@ -187,70 +203,63 @@ bool ObjectQueryHandler::HandleRequest(
187203
if (!allJoins && userJoinAttrs.find(field.NavigationName) == userJoinAttrs.end())
188204
continue;
189205

190-
joinAttrs.insert(field.Name);
206+
joinAttrs.insert(fid);
191207
}
192208

193209
std::unordered_map<Type*, std::pair<bool, std::unique_ptr<Expression>>> typePermissions;
194210
std::unordered_map<Object*, bool> objectAccessAllowed;
195211

196-
for (ConfigObject::Ptr obj : objs) {
212+
auto it = objs.begin();
213+
auto generatorFunc = [&]() -> std::optional<Value> {
214+
if (it == objs.end()) {
215+
return std::nullopt;
216+
}
217+
218+
ConfigObject::Ptr obj = *it;
219+
++it;
220+
197221
DictionaryData result1{
198222
{ "name", obj->GetName() },
199223
{ "type", obj->GetReflectionType()->GetName() }
200224
};
201225

202226
DictionaryData metaAttrs;
203-
204-
if (umetas) {
205-
ObjectLock olock(umetas);
206-
for (String meta : umetas) {
207-
if (meta == "used_by") {
208-
Array::Ptr used_by = new Array();
209-
metaAttrs.emplace_back("used_by", used_by);
210-
211-
for (auto& configObj : DependencyGraph::GetChildren(obj)) {
212-
used_by->Add(new Dictionary({
213-
{ "type", configObj->GetReflectionType()->GetName() },
214-
{ "name", configObj->GetName() }
215-
}));
216-
}
217-
} else if (meta == "location") {
218-
metaAttrs.emplace_back("location", obj->GetSourceLocation());
219-
} else {
220-
HttpUtility::SendJsonError(response, params, 400, "Invalid field specified for meta: " + meta);
221-
return true;
222-
}
227+
if (includeUsedBy) {
228+
Array::Ptr used_by = new Array();
229+
metaAttrs.emplace_back("used_by", used_by);
230+
231+
for (auto& configObj : DependencyGraph::GetChildren(obj)) {
232+
used_by->Add(new Dictionary({
233+
{"type", configObj->GetReflectionType()->GetName()},
234+
{"name", configObj->GetName()}
235+
}));
223236
}
224237
}
225238

239+
if (includeLocation) {
240+
metaAttrs.emplace_back("location", obj->GetSourceLocation());
241+
}
242+
226243
result1.emplace_back("meta", new Dictionary(std::move(metaAttrs)));
227244

228245
try {
229246
result1.emplace_back("attrs", SerializeObjectAttrs(obj, String(), uattrs, false, false));
230247
} catch (const ScriptError& ex) {
231-
HttpUtility::SendJsonError(response, params, 400, ex.what());
232-
return true;
248+
return new Dictionary{
249+
{"type", type->GetName()},
250+
{"name", obj->GetName()},
251+
{"code", 400},
252+
{"status", ex.what()}
253+
};
233254
}
234255

235256
DictionaryData joins;
236257

237-
for (const String& joinAttr : joinAttrs) {
258+
for (auto joinAttr : joinAttrs) {
238259
Object::Ptr joinedObj;
239-
int fid = type->GetFieldId(joinAttr);
240-
241-
if (fid < 0) {
242-
HttpUtility::SendJsonError(response, params, 400, "Invalid field specified for join: " + joinAttr);
243-
return true;
244-
}
260+
Field field = type->GetFieldInfo(joinAttr);
245261

246-
Field field = type->GetFieldInfo(fid);
247-
248-
if (!(field.Attributes & FANavigation)) {
249-
HttpUtility::SendJsonError(response, params, 400, "Not a joinable field: " + joinAttr);
250-
return true;
251-
}
252-
253-
joinedObj = obj->NavigateField(fid);
262+
joinedObj = obj->NavigateField(joinAttr);
254263

255264
if (!joinedObj)
256265
continue;
@@ -303,22 +312,29 @@ bool ObjectQueryHandler::HandleRequest(
303312
try {
304313
joins.emplace_back(prefix, SerializeObjectAttrs(joinedObj, prefix, ujoins, true, allJoins));
305314
} catch (const ScriptError& ex) {
306-
HttpUtility::SendJsonError(response, params, 400, ex.what());
307-
return true;
315+
return new Dictionary{
316+
{"type", type->GetName()},
317+
{"name", obj->GetName()},
318+
{"code", 400},
319+
{"status", ex.what()}
320+
};
308321
}
309322
}
310323

311324
result1.emplace_back("joins", new Dictionary(std::move(joins)));
312325

313-
results.push_back(new Dictionary(std::move(result1)));
314-
}
315-
316-
Dictionary::Ptr result = new Dictionary({
317-
{ "results", new Array(std::move(results)) }
318-
});
326+
return new Dictionary{std::move(result1)};
327+
};
319328

320329
response.result(http::status::ok);
321-
HttpUtility::SendJsonBody(response, params, result);
330+
response.set(http::field::content_type, "application/json");
331+
response.StartStreaming();
332+
333+
Dictionary::Ptr results = new Dictionary{{"results", new ValueGenerator{generatorFunc}}};
334+
results->Freeze();
335+
336+
bool pretty = HttpUtility::GetLastParameter(params, "pretty");
337+
response.GetJsonEncoder(pretty).Encode(results, &yc);
322338

323339
return true;
324340
}

0 commit comments

Comments
 (0)