PACS System 0.1.0
PACS DICOM system library
Loading...
Searching...
No Matches
storage_commitment_scu.cpp
Go to the documentation of this file.
1// BSD 3-Clause License
2// Copyright (c) 2021-2025, 🍀☀🌕🌥 🌊
3// See the LICENSE file in the project root for full license information.
4
11
16
17namespace kcenon::pacs::services {
18
19// =============================================================================
20// Construction
21// =============================================================================
22
24 std::shared_ptr<di::ILogger> logger)
25 : logger_(logger ? std::move(logger) : di::null_logger()) {}
26
27// =============================================================================
28// Callback Configuration
29// =============================================================================
30
34
35// =============================================================================
36// N-ACTION Request
37// =============================================================================
38
41 uint8_t context_id,
42 const std::string& transaction_uid,
43 const std::vector<sop_reference>& references) {
44
45 using namespace network::dimse;
46
47 if (transaction_uid.empty() || references.empty()) {
50 "Transaction UID and references must not be empty");
51 }
52
53 // Build N-ACTION-RQ
54 auto action_rq = make_n_action_rq(
55 1, // message_id
59
60 // Build and attach action dataset
61 auto action_dataset = build_action_dataset(transaction_uid, references);
62 action_rq.set_dataset(std::move(action_dataset));
63
64 // Send N-ACTION-RQ
65 auto send_result = assoc.send_dimse(context_id, action_rq);
66 if (send_result.is_err()) {
67 return send_result;
68 }
69
71 return kcenon::pacs::ok();
72}
73
74// =============================================================================
75// N-EVENT-REPORT Handler
76// =============================================================================
77
79 const network::dimse::dimse_message& event_rq) {
80
81 using namespace network::dimse;
82
83 // Verify command is N-EVENT-REPORT-RQ
84 if (event_rq.command() != command_field::n_event_report_rq) {
87 "Expected N-EVENT-REPORT-RQ, got: " +
88 std::string(to_string(event_rq.command())));
89 }
90
91 // Verify dataset is present
92 if (!event_rq.has_dataset()) {
95 "N-EVENT-REPORT-RQ has no dataset");
96 }
97
98 const auto& dataset = event_rq.dataset().value().get();
99
100 // Parse the event report dataset
101 auto result = parse_event_report_dataset(dataset);
102
104
105 // Invoke callback if registered
106 if (callback_) {
107 callback_(result.transaction_uid, result);
108 }
109
110 return kcenon::pacs::Result<commitment_result>::ok(std::move(result));
111}
112
113// =============================================================================
114// Statistics
115// =============================================================================
116
118 return requests_sent_.load();
119}
120
122 return event_reports_received_.load();
123}
124
129
130// =============================================================================
131// Dataset Builders
132// =============================================================================
133
135 const std::string& transaction_uid,
136 const std::vector<sop_reference>& references) {
137
139
140 // Transaction UID (0008,1195)
142 transaction_uid);
143
144 // Referenced SOP Sequence (0008,1199)
146
147 for (const auto& ref : references) {
150 encoding::vr_type::UI, ref.sop_class_uid);
152 encoding::vr_type::UI, ref.sop_instance_uid);
153 seq.push_back(std::move(item));
154 }
155
156 return ds;
157}
158
160 const core::dicom_dataset& dataset) {
161
162 commitment_result result;
163
164 // Extract Transaction UID (0008,1195)
166 result.timestamp = std::chrono::system_clock::now();
167
168 // Parse Referenced SOP Sequence (0008,1199) — successful instances
169 if (const auto* success_seq =
171 for (const auto& item : *success_seq) {
172 sop_reference ref;
173 ref.sop_class_uid = item.get_string(
175 ref.sop_instance_uid = item.get_string(
177 if (!ref.sop_class_uid.empty() && !ref.sop_instance_uid.empty()) {
178 result.success_references.push_back(std::move(ref));
179 }
180 }
181 }
182
183 // Parse Failed SOP Sequence (0008,1198) — failed instances
184 if (const auto* failed_seq =
186 for (const auto& item : *failed_seq) {
187 sop_reference ref;
188 ref.sop_class_uid = item.get_string(
190 ref.sop_instance_uid = item.get_string(
192
194 auto reason_val = item.get_numeric<uint16_t>(
196 if (reason_val.has_value()) {
197 reason = static_cast<commitment_failure_reason>(
198 reason_val.value());
199 }
200
201 if (!ref.sop_class_uid.empty() && !ref.sop_instance_uid.empty()) {
202 result.failed_references.emplace_back(std::move(ref), reason);
203 }
204 }
205 }
206
207 return result;
208}
209
210} // namespace kcenon::pacs::services
auto get_sequence(dicom_tag tag) const noexcept -> const std::vector< dicom_dataset > *
void set_string(dicom_tag tag, encoding::vr_type vr, std::string_view value)
Set a string value for the given tag.
auto get_or_create_sequence(dicom_tag tag) -> std::vector< dicom_dataset > &
Insert or create a sequence element with the given tag.
auto get_string(dicom_tag tag, std::string_view default_value="") const -> std::string
Get the string value of an element.
Result< std::monostate > send_dimse(uint8_t context_id, const dimse::dimse_message &msg)
Send a DIMSE message.
auto has_dataset() const noexcept -> bool
Check if the message has an associated data set.
auto dataset() -> kcenon::pacs::Result< std::reference_wrapper< core::dicom_dataset > >
Get mutable reference to the data set.
auto command() const noexcept -> command_field
Get the command field.
std::function< void( const std::string &transaction_uid, const commitment_result &result)> commitment_callback
Callback type for commitment results.
storage_commitment_scu(std::shared_ptr< di::ILogger > logger=nullptr)
void set_commitment_callback(commitment_callback cb)
Set callback for commitment result notifications.
network::Result< commitment_result > handle_event_report(const network::dimse::dimse_message &event_rq)
Handle an N-EVENT-REPORT-RQ received from the SCP.
static commitment_result parse_event_report_dataset(const core::dicom_dataset &dataset)
network::Result< std::monostate > request_commitment(network::association &assoc, uint8_t context_id, const std::string &transaction_uid, const std::vector< sop_reference > &references)
Send N-ACTION request to commit stored instances.
static core::dicom_dataset build_action_dataset(const std::string &transaction_uid, const std::vector< sop_reference > &references)
DIMSE command field enumeration.
Compile-time constants for commonly used DICOM tags.
constexpr dicom_tag failed_sop_sequence
Failed SOP Sequence — instances that failed commitment (PS3.4 J.3)
constexpr dicom_tag referenced_sop_sequence
Referenced SOP Sequence — instances in commitment request/success (PS3.4 J.3)
constexpr dicom_tag referenced_sop_class_uid
Referenced SOP Class UID (in Sequence)
constexpr dicom_tag failure_reason
Failure Reason — reason code for commitment failure (PS3.4 Table J.3-2)
constexpr dicom_tag referenced_sop_instance_uid
Referenced SOP Instance UID (in Sequence)
constexpr dicom_tag transaction_uid
Transaction UID — identifies a Storage Commitment transaction (PS3.4 J.3)
@ UI
Unique Identifier (64 chars max)
constexpr int storage_commitment_unexpected_command
Definition result.h:180
constexpr int storage_commitment_missing_transaction_uid
Definition result.h:182
constexpr int storage_commitment_missing_sequence
Definition result.h:183
constexpr std::string_view storage_commitment_push_model_sop_instance_uid
Storage Commitment Push Model SOP Instance UID (Well-Known)
constexpr std::string_view storage_commitment_push_model_sop_class_uid
Storage Commitment Push Model SOP Class UID (PS3.4 Table J.3-1)
commitment_failure_reason
Failure reason codes for Storage Commitment.
@ processing_failure
General processing failure.
constexpr uint16_t storage_commitment_action_type_request
N-ACTION: Request Storage Commitment (Action Type ID = 1)
auto to_string(mpps_status status) -> std::string_view
Convert mpps_status to DICOM string representation.
Definition mpps_scp.h:60
VoidResult pacs_void_error(int code, const std::string &message, const std::string &details="")
Create a PACS void error result.
Definition result.h:249
Result< T > pacs_error(int code, const std::string &message, const std::string &details="")
Create a PACS error result with module context.
Definition result.h:234
Result<T> type aliases and helpers for PACS system.
DIMSE status codes.
DICOM Storage Commitment Push Model SCU service.
Result of a Storage Commitment verification.
std::chrono::system_clock::time_point timestamp
Timestamp when verification was completed.
std::vector< std::pair< sop_reference, commitment_failure_reason > > failed_references
Failed SOP Instance references with failure reasons.
std::vector< sop_reference > success_references
Successfully committed SOP Instance references.
std::string transaction_uid
Transaction UID identifying this commitment request.
Reference to a SOP Instance in a commitment request.
std::string sop_class_uid
Referenced SOP Class UID (0008,1150)
std::string sop_instance_uid
Referenced SOP Instance UID (0008,1155)