PACS System 0.1.0
PACS DICOM system library
Loading...
Searching...
No Matches
kcenon::pacs::web::storage_commitment Namespace Reference

Classes

struct  commitment_transaction
 A storage commitment transaction record. More...
 
struct  parse_result
 Parse a commitment request from JSON body. More...
 
class  transaction_store
 In-memory store for commitment transactions. More...
 

Enumerations

enum class  transaction_state { pending , success , partial , failure }
 Transaction state for DICOMweb Storage Commitment. More...
 

Functions

std::string_view to_string (transaction_state state) noexcept
 Convert transaction state to string.
 
std::optional< transaction_stateparse_state (std::string_view str) noexcept
 Parse transaction state from string.
 
std::string transaction_to_json (const commitment_transaction &txn)
 Serialize a commitment transaction to DICOM JSON.
 
std::string transactions_to_json (const std::vector< commitment_transaction > &transactions)
 Serialize a list of transactions to DICOM JSON array.
 
parse_result parse_commitment_request (std::string_view json_body, std::string_view study_uid="")
 

Enumeration Type Documentation

◆ transaction_state

Transaction state for DICOMweb Storage Commitment.

Enumerator
pending 

Commitment request received, verification in progress.

success 

All referenced instances verified present and intact.

partial 

Some instances verified, others failed.

failure 

Commitment verification failed.

Definition at line 40 of file storage_commitment_endpoints.h.

40 {
41 pending,
42 success,
43 partial,
44 failure
45};

Function Documentation

◆ parse_commitment_request()

parse_result kcenon::pacs::web::storage_commitment::parse_commitment_request ( std::string_view json_body,
std::string_view study_uid = "" )
nodiscard

Definition at line 222 of file storage_commitment_endpoints.cpp.

224 {
225
226 parse_result result;
227
228 if (json_body.empty()) {
229 result.error_message = "Request body is empty";
230 return result;
231 }
232
233 // Look for referencedSOPSequence array
234 auto seq_pos = json_body.find("\"referencedSOPSequence\"");
235 if (seq_pos == std::string_view::npos) {
236 result.error_message = "Missing referencedSOPSequence in request body";
237 return result;
238 }
239
240 // Find the array start
241 auto arr_start = json_body.find('[', seq_pos);
242 if (arr_start == std::string_view::npos) {
243 result.error_message = "Invalid referencedSOPSequence format";
244 return result;
245 }
246
247 // Find matching array end
248 size_t depth = 0;
249 size_t arr_end = std::string_view::npos;
250 for (size_t i = arr_start; i < json_body.size(); ++i) {
251 if (json_body[i] == '[') ++depth;
252 else if (json_body[i] == ']') {
253 --depth;
254 if (depth == 0) {
255 arr_end = i;
256 break;
257 }
258 }
259 }
260
261 if (arr_end == std::string_view::npos) {
262 result.error_message = "Unterminated referencedSOPSequence array";
263 return result;
264 }
265
266 // Parse individual items in the array
267 auto array_content = json_body.substr(arr_start + 1, arr_end - arr_start - 1);
268
269 // Find each object in the array
270 size_t pos = 0;
271 while (pos < array_content.size()) {
272 auto obj_start = array_content.find('{', pos);
273 if (obj_start == std::string_view::npos) break;
274
275 size_t obj_depth = 0;
276 size_t obj_end = std::string_view::npos;
277 for (size_t i = obj_start; i < array_content.size(); ++i) {
278 if (array_content[i] == '{') ++obj_depth;
279 else if (array_content[i] == '}') {
280 --obj_depth;
281 if (obj_depth == 0) {
282 obj_end = i;
283 break;
284 }
285 }
286 }
287
288 if (obj_end == std::string_view::npos) break;
289
290 auto obj = array_content.substr(obj_start, obj_end - obj_start + 1);
291 auto sop_class = extract_json_string(obj, "sopClassUID");
292 auto sop_instance = extract_json_string(obj, "sopInstanceUID");
293
294 if (sop_instance.empty()) {
295 result.error_message = "Missing sopInstanceUID in reference";
296 return result;
297 }
298
299 result.references.push_back({std::move(sop_class), std::move(sop_instance)});
300 pos = obj_end + 1;
301 }
302
303 if (result.references.empty()) {
304 result.error_message = "No valid SOP references found in request";
305 return result;
306 }
307
308 // Ignore study_uid parameter (used for context only)
309 (void)study_uid;
310
311 result.valid = true;
312 return result;
313}

References kcenon::pacs::web::storage_commitment::parse_result::error_message, kcenon::pacs::web::storage_commitment::parse_result::references, and kcenon::pacs::web::storage_commitment::parse_result::valid.

Referenced by kcenon::pacs::web::endpoints::register_storage_commitment_endpoints_impl().

Here is the caller graph for this function:

◆ parse_state()

std::optional< transaction_state > kcenon::pacs::web::storage_commitment::parse_state ( std::string_view str)
nodiscardnoexcept

Parse transaction state from string.

Definition at line 53 of file storage_commitment_endpoints.cpp.

53 {
54 if (str == "PENDING") return transaction_state::pending;
55 if (str == "SUCCESS") return transaction_state::success;
56 if (str == "PARTIAL") return transaction_state::partial;
57 if (str == "FAILURE") return transaction_state::failure;
58 return std::nullopt;
59}

References failure, partial, pending, and success.

◆ to_string()

std::string_view kcenon::pacs::web::storage_commitment::to_string ( transaction_state state)
nodiscardnoexcept

Convert transaction state to string.

Definition at line 43 of file storage_commitment_endpoints.cpp.

43 {
44 switch (state) {
45 case transaction_state::pending: return "PENDING";
46 case transaction_state::success: return "SUCCESS";
47 case transaction_state::partial: return "PARTIAL";
48 case transaction_state::failure: return "FAILURE";
49 }
50 return "UNKNOWN";
51}

References failure, partial, pending, and success.

Referenced by transaction_to_json().

Here is the caller graph for this function:

◆ transaction_to_json()

std::string kcenon::pacs::web::storage_commitment::transaction_to_json ( const commitment_transaction & txn)
nodiscard

Serialize a commitment transaction to DICOM JSON.

Parameters
txnThe transaction to serialize
Returns
JSON string

Definition at line 144 of file storage_commitment_endpoints.cpp.

144 {
145 std::ostringstream ss;
146 ss << R"({"transactionUID":")" << json_escape(txn.transaction_uid) << R"(",)";
147 ss << R"("state":")" << to_string(txn.state) << R"(",)";
148
149 if (!txn.study_instance_uid.empty()) {
150 ss << R"("studyInstanceUID":")" << json_escape(txn.study_instance_uid) << R"(",)";
151 }
152
153 ss << R"("createdAt":")" << format_timestamp(txn.created_at) << R"(",)";
154
155 if (txn.completed_at.has_value()) {
156 ss << R"("completedAt":")" << format_timestamp(*txn.completed_at) << R"(",)";
157 }
158
159 // Requested references
160 ss << R"("requestedReferences":[)";
161 for (size_t i = 0; i < txn.requested_references.size(); ++i) {
162 if (i > 0) ss << ",";
163 ss << sop_reference_to_json(txn.requested_references[i]);
164 }
165 ss << "],";
166
167 // Success references
168 ss << R"("successReferences":[)";
169 for (size_t i = 0; i < txn.success_references.size(); ++i) {
170 if (i > 0) ss << ",";
171 ss << sop_reference_to_json(txn.success_references[i]);
172 }
173 ss << "],";
174
175 // Failed references
176 ss << R"("failedReferences":[)";
177 for (size_t i = 0; i < txn.failed_references.size(); ++i) {
178 if (i > 0) ss << ",";
179 ss << failed_reference_to_json(txn.failed_references[i]);
180 }
181 ss << "]}";
182
183 return ss.str();
184}
std::vector< std::pair< services::sop_reference, services::commitment_failure_reason > > failed_references
Failed references with reasons (populated when verified)
std::string transaction_uid
Unique transaction identifier (DICOM UID format)
std::vector< services::sop_reference > success_references
Successfully committed references (populated when verified)
std::optional< std::chrono::system_clock::time_point > completed_at
Timestamp when verification completed.
std::string study_instance_uid
Study Instance UID (optional, for study-level commitment)
std::vector< services::sop_reference > requested_references
SOP Instance references requested for commitment.
std::chrono::system_clock::time_point created_at
Timestamp when the commitment was requested.

References kcenon::pacs::web::storage_commitment::commitment_transaction::completed_at, kcenon::pacs::web::storage_commitment::commitment_transaction::created_at, kcenon::pacs::web::storage_commitment::commitment_transaction::failed_references, kcenon::pacs::web::json_escape(), kcenon::pacs::web::storage_commitment::commitment_transaction::requested_references, kcenon::pacs::web::storage_commitment::commitment_transaction::state, kcenon::pacs::web::storage_commitment::commitment_transaction::study_instance_uid, kcenon::pacs::web::storage_commitment::commitment_transaction::success_references, to_string(), and kcenon::pacs::web::storage_commitment::commitment_transaction::transaction_uid.

Referenced by kcenon::pacs::web::endpoints::register_storage_commitment_endpoints_impl(), and transactions_to_json().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ transactions_to_json()

std::string kcenon::pacs::web::storage_commitment::transactions_to_json ( const std::vector< commitment_transaction > & transactions)
nodiscard

Serialize a list of transactions to DICOM JSON array.

Parameters
transactionsThe transactions to serialize
Returns
JSON array string

Definition at line 186 of file storage_commitment_endpoints.cpp.

187 {
188 std::ostringstream ss;
189 ss << "[";
190 for (size_t i = 0; i < transactions.size(); ++i) {
191 if (i > 0) ss << ",";
192 ss << transaction_to_json(transactions[i]);
193 }
194 ss << "]";
195 return ss.str();
196}
std::string transaction_to_json(const commitment_transaction &txn)
Serialize a commitment transaction to DICOM JSON.

References transaction_to_json().

Referenced by kcenon::pacs::web::endpoints::register_storage_commitment_endpoints_impl().

Here is the call graph for this function:
Here is the caller graph for this function: