PACS System 0.1.0
PACS DICOM system library
Loading...
Searching...
No Matches
kcenon::pacs::services::ups_push_scp Class Referencefinal

#include <ups_push_scp.h>

Inheritance diagram for kcenon::pacs::services::ups_push_scp:
Inheritance graph
Collaboration diagram for kcenon::pacs::services::ups_push_scp:
Collaboration graph

Public Member Functions

 ups_push_scp (std::shared_ptr< di::ILogger > logger=nullptr)
 Construct UPS Push SCP with optional logger.
 
 ~ups_push_scp () override=default
 
void set_create_handler (ups_create_handler handler)
 
void set_set_handler (ups_set_handler handler)
 
void set_get_handler (ups_get_handler handler)
 
void set_change_state_handler (ups_change_state_handler handler)
 
void set_request_cancel_handler (ups_request_cancel_handler handler)
 
std::vector< std::string > supported_sop_classes () const override
 Get the list of SOP Class UIDs supported by this service.
 
network::Result< std::monostate > handle_message (network::association &assoc, uint8_t context_id, const network::dimse::dimse_message &request) override
 Handle an incoming DIMSE message.
 
std::string_view service_name () const noexcept override
 Get the service name for logging/debugging.
 
size_t creates_processed () const noexcept
 
size_t sets_processed () const noexcept
 
size_t gets_processed () const noexcept
 
size_t actions_processed () const noexcept
 
size_t state_changes () const noexcept
 
size_t cancel_requests () const noexcept
 
void reset_statistics () noexcept
 
- Public Member Functions inherited from kcenon::pacs::services::scp_service
 scp_service (std::shared_ptr< di::ILogger > logger=nullptr)
 Construct SCP service with optional logger.
 
virtual ~scp_service ()=default
 
 scp_service (const scp_service &)=delete
 
scp_serviceoperator= (const scp_service &)=delete
 
 scp_service (scp_service &&)=default
 
scp_serviceoperator= (scp_service &&)=default
 
void set_logger (std::shared_ptr< di::ILogger > logger)
 Set the logger instance.
 
const std::shared_ptr< di::ILogger > & logger () const noexcept
 Get the current logger instance.
 
bool supports_sop_class (std::string_view sop_class_uid) const
 Check if this service supports a specific SOP Class.
 

Private Member Functions

network::Result< std::monostate > handle_n_create (network::association &assoc, uint8_t context_id, const network::dimse::dimse_message &request)
 
network::Result< std::monostate > handle_n_set (network::association &assoc, uint8_t context_id, const network::dimse::dimse_message &request)
 
network::Result< std::monostate > handle_n_get (network::association &assoc, uint8_t context_id, const network::dimse::dimse_message &request)
 
network::Result< std::monostate > handle_n_action (network::association &assoc, uint8_t context_id, const network::dimse::dimse_message &request)
 
network::Result< std::monostate > send_n_create_response (network::association &assoc, uint8_t context_id, uint16_t message_id, const std::string &sop_instance_uid, network::dimse::status_code status)
 
network::Result< std::monostate > send_n_set_response (network::association &assoc, uint8_t context_id, uint16_t message_id, const std::string &sop_instance_uid, network::dimse::status_code status)
 
network::Result< std::monostate > send_n_get_response (network::association &assoc, uint8_t context_id, uint16_t message_id, const std::string &sop_instance_uid, network::dimse::status_code status, core::dicom_dataset *dataset=nullptr)
 
network::Result< std::monostate > send_n_action_response (network::association &assoc, uint8_t context_id, uint16_t message_id, const std::string &sop_instance_uid, uint16_t action_type_id, network::dimse::status_code status)
 

Private Attributes

ups_create_handler create_handler_
 
ups_set_handler set_handler_
 
ups_get_handler get_handler_
 
ups_change_state_handler change_state_handler_
 
ups_request_cancel_handler request_cancel_handler_
 
std::atomic< size_t > creates_processed_ {0}
 
std::atomic< size_t > sets_processed_ {0}
 
std::atomic< size_t > gets_processed_ {0}
 
std::atomic< size_t > actions_processed_ {0}
 
std::atomic< size_t > state_changes_ {0}
 
std::atomic< size_t > cancel_requests_ {0}
 

Additional Inherited Members

- Protected Attributes inherited from kcenon::pacs::services::scp_service
std::shared_ptr< di::ILoggerlogger_
 Logger instance for service logging.
 

Detailed Description

Definition at line 171 of file ups_push_scp.h.

Constructor & Destructor Documentation

◆ ups_push_scp()

kcenon::pacs::services::ups_push_scp::ups_push_scp ( std::shared_ptr< di::ILogger > logger = nullptr)
explicit

Construct UPS Push SCP with optional logger.

Parameters
loggerLogger instance for service logging (nullptr uses null_logger)

Definition at line 21 of file ups_push_scp.cpp.

22 : scp_service(std::move(logger)) {}
const std::shared_ptr< di::ILogger > & logger() const noexcept
Get the current logger instance.
Definition scp_service.h:93
scp_service(std::shared_ptr< di::ILogger > logger=nullptr)
Construct SCP service with optional logger.
Definition scp_service.h:64

◆ ~ups_push_scp()

kcenon::pacs::services::ups_push_scp::~ups_push_scp ( )
overridedefault

Member Function Documentation

◆ actions_processed()

size_t kcenon::pacs::services::ups_push_scp::actions_processed ( ) const
nodiscardnoexcept

Definition at line 104 of file ups_push_scp.cpp.

104 {
105 return actions_processed_.load();
106}
std::atomic< size_t > actions_processed_

References actions_processed_.

◆ cancel_requests()

size_t kcenon::pacs::services::ups_push_scp::cancel_requests ( ) const
nodiscardnoexcept

Definition at line 112 of file ups_push_scp.cpp.

112 {
113 return cancel_requests_.load();
114}
std::atomic< size_t > cancel_requests_

References cancel_requests_.

◆ creates_processed()

size_t kcenon::pacs::services::ups_push_scp::creates_processed ( ) const
nodiscardnoexcept

Definition at line 92 of file ups_push_scp.cpp.

92 {
93 return creates_processed_.load();
94}
std::atomic< size_t > creates_processed_

References creates_processed_.

◆ gets_processed()

size_t kcenon::pacs::services::ups_push_scp::gets_processed ( ) const
nodiscardnoexcept

Definition at line 100 of file ups_push_scp.cpp.

100 {
101 return gets_processed_.load();
102}
std::atomic< size_t > gets_processed_

References gets_processed_.

◆ handle_message()

network::Result< std::monostate > kcenon::pacs::services::ups_push_scp::handle_message ( network::association & assoc,
uint8_t context_id,
const network::dimse::dimse_message & request )
nodiscardoverridevirtual

Handle an incoming DIMSE message.

Processes the request and sends appropriate response(s) via the association.

Parameters
assocThe association on which the message was received
context_idThe presentation context ID for the message
requestThe incoming DIMSE request message
Returns
Success or error result

Implements kcenon::pacs::services::scp_service.

Definition at line 56 of file ups_push_scp.cpp.

59 {
60
61 using namespace network::dimse;
62
63 switch (request.command()) {
64 case command_field::n_create_rq:
65 return handle_n_create(assoc, context_id, request);
66
67 case command_field::n_set_rq:
68 return handle_n_set(assoc, context_id, request);
69
70 case command_field::n_get_rq:
71 return handle_n_get(assoc, context_id, request);
72
73 case command_field::n_action_rq:
74 return handle_n_action(assoc, context_id, request);
75
76 default:
79 "Unexpected command for UPS Push SCP: " +
80 std::string(to_string(request.command())));
81 }
82}
network::Result< std::monostate > handle_n_set(network::association &assoc, uint8_t context_id, const network::dimse::dimse_message &request)
network::Result< std::monostate > handle_n_create(network::association &assoc, uint8_t context_id, const network::dimse::dimse_message &request)
network::Result< std::monostate > handle_n_action(network::association &assoc, uint8_t context_id, const network::dimse::dimse_message &request)
network::Result< std::monostate > handle_n_get(network::association &assoc, uint8_t context_id, const network::dimse::dimse_message &request)
constexpr int ups_unexpected_command
Definition result.h:210
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

References kcenon::pacs::network::dimse::dimse_message::command(), handle_n_action(), handle_n_create(), handle_n_get(), handle_n_set(), kcenon::pacs::pacs_void_error(), kcenon::pacs::services::to_string(), and kcenon::pacs::error_codes::ups_unexpected_command.

Here is the call graph for this function:

◆ handle_n_action()

network::Result< std::monostate > kcenon::pacs::services::ups_push_scp::handle_n_action ( network::association & assoc,
uint8_t context_id,
const network::dimse::dimse_message & request )
nodiscardprivate

Definition at line 365 of file ups_push_scp.cpp.

368 {
369
370 using namespace network::dimse;
371
372 // Get Action Type ID
373 auto action_type = request.action_type_id();
374 if (!action_type.has_value()) {
377 "Missing Action Type ID in N-ACTION request");
378 }
379
380 // Get SOP Instance UID
381 auto sop_instance_uid = request.requested_sop_instance_uid();
382 if (sop_instance_uid.empty()) {
383 sop_instance_uid = request.affected_sop_instance_uid();
384 }
385
386 if (sop_instance_uid.empty()) {
388 assoc, context_id, request.message_id(),
389 "", action_type.value(), status_error_missing_attribute);
390 }
391
392 uint16_t action_id = action_type.value();
393
394 if (action_id == ups_action_change_state) {
395 // N-ACTION Type 1: Change UPS State
399 "No Change State handler configured for UPS Push SCP");
400 }
401
402 if (!request.has_dataset()) {
404 assoc, context_id, request.message_id(),
405 sop_instance_uid, action_id, status_error_cannot_understand);
406 }
407
408 const auto& dataset = request.dataset().value().get();
409
410 // Extract new state
411 if (!dataset.contains(ups_tags::procedure_step_state)) {
413 assoc, context_id, request.message_id(),
414 sop_instance_uid, action_id, status_error_missing_attribute);
415 }
416
417 auto new_state = dataset.get_string(ups_tags::procedure_step_state);
418
419 // Validate the state value
420 auto parsed_state = storage::parse_ups_state(new_state);
421 if (!parsed_state.has_value()) {
423 assoc, context_id, request.message_id(),
424 sop_instance_uid, action_id, status_error_cannot_understand);
425 }
426
427 // Extract Transaction UID (required when transitioning to IN PROGRESS)
428 std::string txn_uid;
429 if (dataset.contains(ups_tags::transaction_uid)) {
430 txn_uid = dataset.get_string(ups_tags::transaction_uid);
431 }
432
433 if (parsed_state.value() == storage::ups_state::in_progress &&
434 txn_uid.empty()) {
436 assoc, context_id, request.message_id(),
437 sop_instance_uid, action_id, status_error_missing_attribute);
438 }
439
440 auto result = change_state_handler_(sop_instance_uid, new_state, txn_uid);
441 if (result.is_err()) {
443 assoc, context_id, request.message_id(),
444 sop_instance_uid, action_id, status_error_unable_to_process);
445 }
446
449
451 assoc, context_id, request.message_id(),
452 sop_instance_uid, action_id, status_success);
453
454 } else if (action_id == ups_action_request_cancel) {
455 // N-ACTION Type 3: Request Cancellation
459 "No Request Cancel handler configured for UPS Push SCP");
460 }
461
462 // Extract cancellation reason (optional)
463 std::string reason;
464 if (request.has_dataset()) {
465 const auto& dataset = request.dataset().value().get();
466 if (dataset.contains(ups_tags::reason_for_cancellation)) {
467 reason = dataset.get_string(ups_tags::reason_for_cancellation);
468 }
469 }
470
471 auto result = request_cancel_handler_(sop_instance_uid, reason);
472 if (result.is_err()) {
474 assoc, context_id, request.message_id(),
475 sop_instance_uid, action_id, status_error_unable_to_process);
476 }
477
480
482 assoc, context_id, request.message_id(),
483 sop_instance_uid, action_id, status_success);
484
485 } else {
486 // Unknown action type
488 assoc, context_id, request.message_id(),
489 sop_instance_uid, action_id, status_error_no_such_action_type);
490 }
491}
std::atomic< size_t > state_changes_
ups_request_cancel_handler request_cancel_handler_
network::Result< std::monostate > send_n_action_response(network::association &assoc, uint8_t context_id, uint16_t message_id, const std::string &sop_instance_uid, uint16_t action_type_id, network::dimse::status_code status)
ups_change_state_handler change_state_handler_
constexpr dicom_tag sop_instance_uid
SOP Instance UID.
constexpr int ups_invalid_action_type
Definition result.h:214
constexpr int ups_handler_not_set
Definition result.h:209
constexpr core::dicom_tag transaction_uid
Transaction UID (0008,1195)
constexpr core::dicom_tag procedure_step_state
Procedure Step State (0074,1000)
constexpr core::dicom_tag reason_for_cancellation
Reason for Cancellation (0074,1238)
constexpr uint16_t ups_action_change_state
N-ACTION Type 1: Change UPS State (PS3.4 CC.2.4)
constexpr uint16_t ups_action_request_cancel
N-ACTION Type 3: Request Cancellation (PS3.4 CC.2.5)
@ in_progress
Workitem is being performed.
auto parse_ups_state(std::string_view str) -> std::optional< ups_state >
Parse string to ups_state enum.

References kcenon::pacs::network::dimse::dimse_message::action_type_id(), actions_processed_, kcenon::pacs::network::dimse::dimse_message::affected_sop_instance_uid(), cancel_requests_, change_state_handler_, kcenon::pacs::network::dimse::dimse_message::dataset(), kcenon::pacs::network::dimse::dimse_message::has_dataset(), kcenon::pacs::storage::in_progress, kcenon::pacs::network::dimse::dimse_message::message_id(), kcenon::pacs::pacs_void_error(), kcenon::pacs::storage::parse_ups_state(), kcenon::pacs::services::ups_tags::procedure_step_state, kcenon::pacs::services::ups_tags::reason_for_cancellation, request_cancel_handler_, kcenon::pacs::network::dimse::dimse_message::requested_sop_instance_uid(), send_n_action_response(), state_changes_, kcenon::pacs::services::ups_tags::transaction_uid, kcenon::pacs::services::ups_action_change_state, kcenon::pacs::services::ups_action_request_cancel, kcenon::pacs::error_codes::ups_handler_not_set, and kcenon::pacs::error_codes::ups_invalid_action_type.

Referenced by handle_message().

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

◆ handle_n_create()

network::Result< std::monostate > kcenon::pacs::services::ups_push_scp::handle_n_create ( network::association & assoc,
uint8_t context_id,
const network::dimse::dimse_message & request )
nodiscardprivate

Definition at line 129 of file ups_push_scp.cpp.

132 {
133
134 using namespace network::dimse;
135
136 // Verify we have a handler configured
137 if (!create_handler_) {
140 "No N-CREATE handler configured for UPS Push SCP");
141 }
142
143 // Verify the SOP Class is UPS Push
144 auto sop_class_uid = request.affected_sop_class_uid();
145 if (sop_class_uid != ups_push_sop_class_uid) {
147 assoc, context_id, request.message_id(),
148 "", status_refused_sop_class_not_supported);
149 }
150
151 // Get the SOP Instance UID (workitem UID)
152 auto sop_instance_uid = request.affected_sop_instance_uid();
153 if (sop_instance_uid.empty()) {
155 assoc, context_id, request.message_id(),
156 "", status_error_missing_attribute);
157 }
158
159 // Verify we have a dataset
160 if (!request.has_dataset()) {
162 assoc, context_id, request.message_id(),
163 sop_instance_uid, status_error_cannot_understand);
164 }
165
166 const auto& dataset = request.dataset().value().get();
167
168 // Validate initial state is SCHEDULED (if present in dataset)
169 if (dataset.contains(ups_tags::procedure_step_state)) {
170 auto state_str = dataset.get_string(ups_tags::procedure_step_state);
171 auto parsed_state = storage::parse_ups_state(state_str);
172
173 if (!parsed_state.has_value() ||
174 parsed_state.value() != storage::ups_state::scheduled) {
176 assoc, context_id, request.message_id(),
177 sop_instance_uid, status_error_cannot_understand);
178 }
179 }
180
181 // Build UPS workitem from request data
182 storage::ups_workitem workitem;
183 workitem.workitem_uid = sop_instance_uid;
184 workitem.state = "SCHEDULED";
185
186 // Extract optional fields from dataset
187 if (dataset.contains(ups_tags::procedure_step_label)) {
188 workitem.procedure_step_label =
189 dataset.get_string(ups_tags::procedure_step_label);
190 }
191 if (dataset.contains(ups_tags::worklist_label)) {
192 workitem.worklist_label =
193 dataset.get_string(ups_tags::worklist_label);
194 }
195 if (dataset.contains(ups_tags::scheduled_procedure_step_priority)) {
196 workitem.priority =
198 }
199
200 // Call the handler to create the workitem
201 auto result = create_handler_(workitem);
202 if (result.is_err()) {
204 assoc, context_id, request.message_id(),
205 sop_instance_uid, status_error_unable_to_process);
206 }
207
209
211 assoc, context_id, request.message_id(),
212 sop_instance_uid, status_success);
213}
network::Result< std::monostate > send_n_create_response(network::association &assoc, uint8_t context_id, uint16_t message_id, const std::string &sop_instance_uid, network::dimse::status_code status)
constexpr dicom_tag sop_class_uid
SOP Class UID.
constexpr core::dicom_tag procedure_step_label
Procedure Step Label (0074,1204)
constexpr core::dicom_tag worklist_label
Worklist Label (0074,1202)
constexpr core::dicom_tag scheduled_procedure_step_priority
Scheduled Procedure Step Priority (0074,1200)
constexpr std::string_view ups_push_sop_class_uid
UPS Push SOP Class UID (PS3.4 Table CC.2-1)
@ scheduled
Workitem is scheduled (initial state)

References kcenon::pacs::network::dimse::dimse_message::affected_sop_class_uid(), kcenon::pacs::network::dimse::dimse_message::affected_sop_instance_uid(), create_handler_, creates_processed_, kcenon::pacs::network::dimse::dimse_message::dataset(), kcenon::pacs::network::dimse::dimse_message::has_dataset(), kcenon::pacs::network::dimse::dimse_message::message_id(), kcenon::pacs::pacs_void_error(), kcenon::pacs::storage::parse_ups_state(), kcenon::pacs::storage::ups_workitem::priority, kcenon::pacs::services::ups_tags::procedure_step_label, kcenon::pacs::storage::ups_workitem::procedure_step_label, kcenon::pacs::services::ups_tags::procedure_step_state, kcenon::pacs::storage::scheduled, kcenon::pacs::services::ups_tags::scheduled_procedure_step_priority, send_n_create_response(), kcenon::pacs::storage::ups_workitem::state, kcenon::pacs::error_codes::ups_handler_not_set, kcenon::pacs::services::ups_push_sop_class_uid, kcenon::pacs::storage::ups_workitem::workitem_uid, kcenon::pacs::services::ups_tags::worklist_label, and kcenon::pacs::storage::ups_workitem::worklist_label.

Referenced by handle_message().

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

◆ handle_n_get()

network::Result< std::monostate > kcenon::pacs::services::ups_push_scp::handle_n_get ( network::association & assoc,
uint8_t context_id,
const network::dimse::dimse_message & request )
nodiscardprivate

Definition at line 289 of file ups_push_scp.cpp.

292 {
293
294 using namespace network::dimse;
295
296 // Verify we have a handler configured
297 if (!get_handler_) {
300 "No N-GET handler configured for UPS Push SCP");
301 }
302
303 // Extract Requested SOP Instance UID
304 auto sop_instance_uid = request.requested_sop_instance_uid();
305 if (sop_instance_uid.empty()) {
306 return send_n_get_response(
307 assoc, context_id, request.message_id(),
308 "", status_error_missing_attribute);
309 }
310
311 // Call the handler to retrieve the workitem
312 auto result = get_handler_(sop_instance_uid);
313 if (result.is_err()) {
314 return send_n_get_response(
315 assoc, context_id, request.message_id(),
316 sop_instance_uid, status_error_invalid_object_instance);
317 }
318
320
321 // Build response dataset from workitem
322 const auto& workitem = result.value();
323 core::dicom_dataset response_dataset;
324
325 response_dataset.set_string(
327 encoding::vr_type::CS, workitem.state);
328
329 if (!workitem.procedure_step_label.empty()) {
330 response_dataset.set_string(
332 encoding::vr_type::LO, workitem.procedure_step_label);
333 }
334 if (!workitem.worklist_label.empty()) {
335 response_dataset.set_string(
337 encoding::vr_type::LO, workitem.worklist_label);
338 }
339 if (!workitem.priority.empty()) {
340 response_dataset.set_string(
342 encoding::vr_type::CS, workitem.priority);
343 }
344 if (!workitem.progress_description.empty()) {
345 response_dataset.set_string(
348 std::to_string(workitem.progress_percent));
349 }
350 if (!workitem.transaction_uid.empty()) {
351 response_dataset.set_string(
353 encoding::vr_type::UI, workitem.transaction_uid);
354 }
355
356 return send_n_get_response(
357 assoc, context_id, request.message_id(),
358 sop_instance_uid, status_success, &response_dataset);
359}
network::Result< std::monostate > send_n_get_response(network::association &assoc, uint8_t context_id, uint16_t message_id, const std::string &sop_instance_uid, network::dimse::status_code status, core::dicom_dataset *dataset=nullptr)
@ LO
Long String (64 chars max)
@ DS
Decimal String (16 chars max)
@ UI
Unique Identifier (64 chars max)
@ CS
Code String (16 chars max, uppercase + digits + space + underscore)
constexpr core::dicom_tag procedure_step_progress
Procedure Step Progress (0074,1004)

References kcenon::pacs::encoding::CS, kcenon::pacs::encoding::DS, get_handler_, gets_processed_, kcenon::pacs::encoding::LO, kcenon::pacs::network::dimse::dimse_message::message_id(), kcenon::pacs::pacs_void_error(), kcenon::pacs::services::ups_tags::procedure_step_label, kcenon::pacs::services::ups_tags::procedure_step_progress, kcenon::pacs::services::ups_tags::procedure_step_state, kcenon::pacs::network::dimse::dimse_message::requested_sop_instance_uid(), kcenon::pacs::services::ups_tags::scheduled_procedure_step_priority, send_n_get_response(), kcenon::pacs::core::dicom_dataset::set_string(), kcenon::pacs::services::ups_tags::transaction_uid, kcenon::pacs::encoding::UI, kcenon::pacs::error_codes::ups_handler_not_set, and kcenon::pacs::services::ups_tags::worklist_label.

Referenced by handle_message().

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

◆ handle_n_set()

network::Result< std::monostate > kcenon::pacs::services::ups_push_scp::handle_n_set ( network::association & assoc,
uint8_t context_id,
const network::dimse::dimse_message & request )
nodiscardprivate

Definition at line 219 of file ups_push_scp.cpp.

222 {
223
224 using namespace network::dimse;
225
226 // Verify we have a handler configured
227 if (!set_handler_) {
230 "No N-SET handler configured for UPS Push SCP");
231 }
232
233 // Get SOP Instance UID (from Requested SOP Instance UID for N-SET)
234 auto sop_instance_uid = request.command_set().get_string(
235 tag_requested_sop_instance_uid);
236
237 if (sop_instance_uid.empty()) {
238 sop_instance_uid = request.affected_sop_instance_uid();
239 }
240
241 if (sop_instance_uid.empty()) {
242 return send_n_set_response(
243 assoc, context_id, request.message_id(),
244 "", status_error_missing_attribute);
245 }
246
247 // Verify we have a dataset with modifications
248 if (!request.has_dataset()) {
249 return send_n_set_response(
250 assoc, context_id, request.message_id(),
251 sop_instance_uid, status_error_cannot_understand);
252 }
253
254 const auto& dataset = request.dataset().value().get();
255
256 // Reject if dataset tries to set a final state directly via N-SET
257 // (state changes must go through N-ACTION)
258 if (dataset.contains(ups_tags::procedure_step_state)) {
259 auto state_str = dataset.get_string(ups_tags::procedure_step_state);
260 auto parsed_state = storage::parse_ups_state(state_str);
261 if (parsed_state.has_value() &&
262 (parsed_state.value() == storage::ups_state::completed ||
263 parsed_state.value() == storage::ups_state::canceled)) {
264 return send_n_set_response(
265 assoc, context_id, request.message_id(),
266 sop_instance_uid, status_error_cannot_understand);
267 }
268 }
269
270 // Call the handler to update the workitem
271 auto result = set_handler_(sop_instance_uid, dataset);
272 if (result.is_err()) {
273 return send_n_set_response(
274 assoc, context_id, request.message_id(),
275 sop_instance_uid, status_error_unable_to_process);
276 }
277
279
280 return send_n_set_response(
281 assoc, context_id, request.message_id(),
282 sop_instance_uid, status_success);
283}
network::Result< std::monostate > send_n_set_response(network::association &assoc, uint8_t context_id, uint16_t message_id, const std::string &sop_instance_uid, network::dimse::status_code status)
std::atomic< size_t > sets_processed_
@ completed
Workitem completed successfully (final)
@ canceled
Workitem was canceled (final)

References kcenon::pacs::network::dimse::dimse_message::affected_sop_instance_uid(), kcenon::pacs::storage::canceled, kcenon::pacs::network::dimse::dimse_message::command_set(), kcenon::pacs::storage::completed, kcenon::pacs::network::dimse::dimse_message::dataset(), kcenon::pacs::network::dimse::dimse_message::has_dataset(), kcenon::pacs::network::dimse::dimse_message::message_id(), kcenon::pacs::pacs_void_error(), kcenon::pacs::storage::parse_ups_state(), kcenon::pacs::services::ups_tags::procedure_step_state, send_n_set_response(), set_handler_, sets_processed_, and kcenon::pacs::error_codes::ups_handler_not_set.

Referenced by handle_message().

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

◆ reset_statistics()

void kcenon::pacs::services::ups_push_scp::reset_statistics ( )
noexcept

◆ send_n_action_response()

network::Result< std::monostate > kcenon::pacs::services::ups_push_scp::send_n_action_response ( network::association & assoc,
uint8_t context_id,
uint16_t message_id,
const std::string & sop_instance_uid,
uint16_t action_type_id,
network::dimse::status_code status )
nodiscardprivate

Definition at line 559 of file ups_push_scp.cpp.

565 {
566
567 using namespace network::dimse;
568
569 auto response = make_n_action_rsp(
570 message_id, ups_push_sop_class_uid, sop_instance_uid,
571 action_type_id, status);
572
573 return assoc.send_dimse(context_id, response);
574}

References kcenon::pacs::network::association::send_dimse(), and kcenon::pacs::services::ups_push_sop_class_uid.

Referenced by handle_n_action().

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

◆ send_n_create_response()

network::Result< std::monostate > kcenon::pacs::services::ups_push_scp::send_n_create_response ( network::association & assoc,
uint8_t context_id,
uint16_t message_id,
const std::string & sop_instance_uid,
network::dimse::status_code status )
nodiscardprivate

Definition at line 497 of file ups_push_scp.cpp.

502 {
503
504 using namespace network::dimse;
505
506 dimse_message response{command_field::n_create_rsp, 0};
507 response.set_message_id_responded_to(message_id);
508 response.set_affected_sop_class_uid(ups_push_sop_class_uid);
509 response.set_status(status);
510
511 if (!sop_instance_uid.empty()) {
512 response.set_affected_sop_instance_uid(sop_instance_uid);
513 }
514
515 return assoc.send_dimse(context_id, response);
516}

References kcenon::pacs::network::association::send_dimse(), and kcenon::pacs::services::ups_push_sop_class_uid.

Referenced by handle_n_create().

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

◆ send_n_get_response()

network::Result< std::monostate > kcenon::pacs::services::ups_push_scp::send_n_get_response ( network::association & assoc,
uint8_t context_id,
uint16_t message_id,
const std::string & sop_instance_uid,
network::dimse::status_code status,
core::dicom_dataset * dataset = nullptr )
nodiscardprivate

Definition at line 539 of file ups_push_scp.cpp.

545 {
546
547 using namespace network::dimse;
548
549 auto response = make_n_get_rsp(
550 message_id, ups_push_sop_class_uid, sop_instance_uid, status);
551
552 if (dataset != nullptr) {
553 response.set_dataset(std::move(*dataset));
554 }
555
556 return assoc.send_dimse(context_id, response);
557}

References kcenon::pacs::network::association::send_dimse(), and kcenon::pacs::services::ups_push_sop_class_uid.

Referenced by handle_n_get().

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

◆ send_n_set_response()

network::Result< std::monostate > kcenon::pacs::services::ups_push_scp::send_n_set_response ( network::association & assoc,
uint8_t context_id,
uint16_t message_id,
const std::string & sop_instance_uid,
network::dimse::status_code status )
nodiscardprivate

Definition at line 518 of file ups_push_scp.cpp.

523 {
524
525 using namespace network::dimse;
526
527 dimse_message response{command_field::n_set_rsp, 0};
528 response.set_message_id_responded_to(message_id);
529 response.set_affected_sop_class_uid(ups_push_sop_class_uid);
530 response.set_status(status);
531
532 if (!sop_instance_uid.empty()) {
533 response.set_affected_sop_instance_uid(sop_instance_uid);
534 }
535
536 return assoc.send_dimse(context_id, response);
537}

References kcenon::pacs::network::association::send_dimse(), and kcenon::pacs::services::ups_push_sop_class_uid.

Referenced by handle_n_set().

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

◆ service_name()

std::string_view kcenon::pacs::services::ups_push_scp::service_name ( ) const
nodiscardoverridevirtualnoexcept

Get the service name for logging/debugging.

Returns
Human-readable service name

Implements kcenon::pacs::services::scp_service.

Definition at line 84 of file ups_push_scp.cpp.

84 {
85 return "UPS Push SCP";
86}

◆ set_change_state_handler()

void kcenon::pacs::services::ups_push_scp::set_change_state_handler ( ups_change_state_handler handler)

Definition at line 40 of file ups_push_scp.cpp.

40 {
41 change_state_handler_ = std::move(handler);
42}

References change_state_handler_.

◆ set_create_handler()

void kcenon::pacs::services::ups_push_scp::set_create_handler ( ups_create_handler handler)

Definition at line 28 of file ups_push_scp.cpp.

28 {
29 create_handler_ = std::move(handler);
30}

References create_handler_.

◆ set_get_handler()

void kcenon::pacs::services::ups_push_scp::set_get_handler ( ups_get_handler handler)

Definition at line 36 of file ups_push_scp.cpp.

36 {
37 get_handler_ = std::move(handler);
38}

References get_handler_.

◆ set_request_cancel_handler()

void kcenon::pacs::services::ups_push_scp::set_request_cancel_handler ( ups_request_cancel_handler handler)

Definition at line 44 of file ups_push_scp.cpp.

44 {
45 request_cancel_handler_ = std::move(handler);
46}

References request_cancel_handler_.

◆ set_set_handler()

void kcenon::pacs::services::ups_push_scp::set_set_handler ( ups_set_handler handler)

Definition at line 32 of file ups_push_scp.cpp.

32 {
33 set_handler_ = std::move(handler);
34}

References set_handler_.

◆ sets_processed()

size_t kcenon::pacs::services::ups_push_scp::sets_processed ( ) const
nodiscardnoexcept

Definition at line 96 of file ups_push_scp.cpp.

96 {
97 return sets_processed_.load();
98}

References sets_processed_.

◆ state_changes()

size_t kcenon::pacs::services::ups_push_scp::state_changes ( ) const
nodiscardnoexcept

Definition at line 108 of file ups_push_scp.cpp.

108 {
109 return state_changes_.load();
110}

References state_changes_.

◆ supported_sop_classes()

std::vector< std::string > kcenon::pacs::services::ups_push_scp::supported_sop_classes ( ) const
nodiscardoverridevirtual

Get the list of SOP Class UIDs supported by this service.

Returns
Vector of SOP Class UIDs that this service can handle

Implements kcenon::pacs::services::scp_service.

Definition at line 52 of file ups_push_scp.cpp.

52 {
53 return {std::string(ups_push_sop_class_uid)};
54}

References kcenon::pacs::services::ups_push_sop_class_uid.

Member Data Documentation

◆ actions_processed_

std::atomic<size_t> kcenon::pacs::services::ups_push_scp::actions_processed_ {0}
private

Definition at line 290 of file ups_push_scp.h.

290{0};

Referenced by actions_processed(), handle_n_action(), and reset_statistics().

◆ cancel_requests_

std::atomic<size_t> kcenon::pacs::services::ups_push_scp::cancel_requests_ {0}
private

Definition at line 292 of file ups_push_scp.h.

292{0};

Referenced by cancel_requests(), handle_n_action(), and reset_statistics().

◆ change_state_handler_

ups_change_state_handler kcenon::pacs::services::ups_push_scp::change_state_handler_
private

Definition at line 284 of file ups_push_scp.h.

Referenced by handle_n_action(), and set_change_state_handler().

◆ create_handler_

ups_create_handler kcenon::pacs::services::ups_push_scp::create_handler_
private

Definition at line 281 of file ups_push_scp.h.

Referenced by handle_n_create(), and set_create_handler().

◆ creates_processed_

std::atomic<size_t> kcenon::pacs::services::ups_push_scp::creates_processed_ {0}
private

Definition at line 287 of file ups_push_scp.h.

287{0};

Referenced by creates_processed(), handle_n_create(), and reset_statistics().

◆ get_handler_

ups_get_handler kcenon::pacs::services::ups_push_scp::get_handler_
private

Definition at line 283 of file ups_push_scp.h.

Referenced by handle_n_get(), and set_get_handler().

◆ gets_processed_

std::atomic<size_t> kcenon::pacs::services::ups_push_scp::gets_processed_ {0}
private

Definition at line 289 of file ups_push_scp.h.

289{0};

Referenced by gets_processed(), handle_n_get(), and reset_statistics().

◆ request_cancel_handler_

ups_request_cancel_handler kcenon::pacs::services::ups_push_scp::request_cancel_handler_
private

Definition at line 285 of file ups_push_scp.h.

Referenced by handle_n_action(), and set_request_cancel_handler().

◆ set_handler_

ups_set_handler kcenon::pacs::services::ups_push_scp::set_handler_
private

Definition at line 282 of file ups_push_scp.h.

Referenced by handle_n_set(), and set_set_handler().

◆ sets_processed_

std::atomic<size_t> kcenon::pacs::services::ups_push_scp::sets_processed_ {0}
private

Definition at line 288 of file ups_push_scp.h.

288{0};

Referenced by handle_n_set(), reset_statistics(), and sets_processed().

◆ state_changes_

std::atomic<size_t> kcenon::pacs::services::ups_push_scp::state_changes_ {0}
private

Definition at line 291 of file ups_push_scp.h.

291{0};

Referenced by handle_n_action(), reset_statistics(), and state_changes().


The documentation for this class was generated from the following files: