gstreamer
Loading...
Searching...
No Matches
publishDigitized.cc
Go to the documentation of this file.
1// gstreamer
4
5// c++
6#include <sstream>
7
8bool GstreamerJsonFactory::publishEventDigitizedDataImpl(const std::string& detectorName,
9 const std::vector<const GDigitizedData*>& digitizedData) {
10 if (!is_building_event) {
11 log->error(
12 ERR_PUBLISH_ERROR, "publishEventDigitizedDataImpl called without an active event in GstreamerJsonFactory");
13 return false;
14 }
15
16 // IMPORTANT:
17 // The current JSON assembly approach writes one detector block per call to true-info publishing,
18 // and leaves "digitized": [] as default.
19 //
20 // In the current gstreamer core flow, digitized publishing happens immediately after true-info
21 // for the same detector. We therefore append an additional compact "digitized_data" object at
22 // the event level to avoid fragile in-place string editing.
23 //
24 // This keeps output valid and preserves all digitized information while avoiding string surgery.
25
26 if (digitizedData.empty()) return true;
27
28 // If this is the first digitized block added at event level, create the container.
29 // We detect this by searching whether we've already inserted the key; simple state is best.
30 // Use a conservative heuristic: add only once by tracking a marker in the stream state.
31 static const char* marker = "\"digitized_by_detector\": {";
32 const std::string assembled = current_event.str();
33
34 const bool has_digitized_container = (assembled.find(marker) != std::string::npos);
35
36 if (!has_digitized_container) {
37 // Insert after detectors (which may or may not exist).
38 // If detectors exist, we are still inside the event object assembly and detectors are not closed yet.
39 // Our detector blocks close themselves, and we keep detectors object open until endEventImpl.
40 // Therefore we can safely append inside the detectors object by adding a reserved key.
41 //
42 // The reserved key lives inside "detectors" so the schema stays naturally grouped.
43 if (!current_event_has_any_detector) {
44 current_event << ", \"detectors\": {";
45 current_event_has_any_detector = true;
46 }
47 else {
48 current_event << ", ";
49 }
50
51 current_event << "\"digitized_by_detector\": {";
52 }
53
54 // Append detector digitized array inside digitized_by_detector.
55 // If this is not the first detector in digitized_by_detector, add comma.
56 const std::string updated = current_event.str();
57 const bool digitized_has_any_detector =
58 (updated.find("\"digitized_by_detector\": {") != std::string::npos) &&
59 (updated.find("\"digitized_by_detector\": {") < updated.size() - 1) &&
60 (updated.find("\"digitized_by_detector\": {") != std::string::npos);
61
62 // We cannot robustly determine "first" by parsing; instead, we append with a comma if the last
63 // character before we append is not '{'.
64 // This works because we only ever append within the object and we never add trailing spaces/newlines.
65 if (!updated.empty()) {
66 char last = updated.back();
67 if (last != '{') current_event << ", ";
68 }
69
70 current_event << "\"" << jsonEscape(detectorName) << "\": [";
71
72 bool wrote_first_hit = false;
73 for (const auto* hit : digitizedData) {
74 if (!hit) continue;
75
76 if (wrote_first_hit) current_event << ", ";
77 wrote_first_hit = true;
78
79 current_event << "{";
80
81 const std::string addr = hit->getIdentityString();
82 current_event << "\"address\": \"" << jsonEscape(addr) << "\"";
83
84 current_event << ", \"vars\": {";
85
86 bool wrote_first_var = false;
87
88 // int observables (argument: 0 = do not include sro variables)
89 for (const auto& [name, value] : hit->getIntObservablesMap(0)) {
90 if (wrote_first_var) current_event << ", ";
91 wrote_first_var = true;
92 current_event << "\"" << jsonEscape(name) << "\": " << value;
93 }
94
95 // double observables
96 for (const auto& [name, value] : hit->getDblObservablesMap(0)) {
97 if (wrote_first_var) current_event << ", ";
98 wrote_first_var = true;
99 current_event << "\"" << jsonEscape(name) << "\": " << value;
100 }
101
102 current_event << "}"; // vars
103 current_event << "}"; // hit
104 }
105
106 current_event << "]"; // detector array
107
108 // If we opened the digitized_by_detector container earlier, it remains open until endEventImpl.
109 // endEventImpl closes the detectors object implicitly only by terminating the event; therefore we need
110 // to ensure the reserved container is properly closed before the detectors object closes.
111 //
112 // We close the reserved container immediately after each insertion *only if it was newly opened*,
113 // otherwise we'd break subsequent inserts. Since we do not track that state robustly in this minimal
114 // implementation, we keep the container open and close it in endEventImpl by emitting a closing brace
115 // when present. That requires endEventImpl to be aware of it; we avoid that by leaving the container
116 // as a standard detector-like entry:
117 //
118 // "detectors": {
119 // "ctof": {...},
120 // "digitized_by_detector": { "ctof":[...], ... }
121 // }
122 //
123 // This is valid as long as the digitized_by_detector object is closed before "detectors" closes.
124 // To guarantee that without rewriting endEventImpl, we close digitized_by_detector here by appending "}"
125 // and then re-open it on the next call if needed (safe, simple).
126 current_event << "}"; // close digitized_by_detector object
127
128 return true;
129}
std::shared_ptr< GLogger > log
void error(int exit_code, Args &&... args) const
Shared constants and error codes for the gstreamer module.
#define ERR_PUBLISH_ERROR
Generic publish-time error (null pointers, invalid state).