61 using namespace network::dimse;
64 case command_field::n_create_rq:
67 case command_field::n_set_rq:
70 case command_field::n_get_rq:
73 case command_field::n_action_rq:
79 "Unexpected command for UPS Push SCP: " +
85 return "UPS Push SCP";
134 using namespace network::dimse;
140 "No N-CREATE handler configured for UPS Push SCP");
148 "", status_refused_sop_class_not_supported);
153 if (sop_instance_uid.empty()) {
156 "", status_error_missing_attribute);
163 sop_instance_uid, status_error_cannot_understand);
166 const auto& dataset = request.
dataset().value().get();
173 if (!parsed_state.has_value() ||
177 sop_instance_uid, status_error_cannot_understand);
184 workitem.
state =
"SCHEDULED";
202 if (result.is_err()) {
205 sop_instance_uid, status_error_unable_to_process);
212 sop_instance_uid, status_success);
224 using namespace network::dimse;
230 "No N-SET handler configured for UPS Push SCP");
234 auto sop_instance_uid = request.
command_set().get_string(
235 tag_requested_sop_instance_uid);
237 if (sop_instance_uid.empty()) {
241 if (sop_instance_uid.empty()) {
244 "", status_error_missing_attribute);
251 sop_instance_uid, status_error_cannot_understand);
254 const auto& dataset = request.
dataset().value().get();
261 if (parsed_state.has_value() &&
266 sop_instance_uid, status_error_cannot_understand);
272 if (result.is_err()) {
275 sop_instance_uid, status_error_unable_to_process);
282 sop_instance_uid, status_success);
294 using namespace network::dimse;
300 "No N-GET handler configured for UPS Push SCP");
305 if (sop_instance_uid.empty()) {
308 "", status_error_missing_attribute);
313 if (result.is_err()) {
316 sop_instance_uid, status_error_invalid_object_instance);
322 const auto& workitem = result.value();
329 if (!workitem.procedure_step_label.empty()) {
334 if (!workitem.worklist_label.empty()) {
339 if (!workitem.priority.empty()) {
344 if (!workitem.progress_description.empty()) {
348 std::to_string(workitem.progress_percent));
350 if (!workitem.transaction_uid.empty()) {
358 sop_instance_uid, status_success, &response_dataset);
370 using namespace network::dimse;
374 if (!action_type.has_value()) {
377 "Missing Action Type ID in N-ACTION request");
382 if (sop_instance_uid.empty()) {
386 if (sop_instance_uid.empty()) {
389 "", action_type.value(), status_error_missing_attribute);
392 uint16_t action_id = action_type.value();
399 "No Change State handler configured for UPS Push SCP");
405 sop_instance_uid, action_id, status_error_cannot_understand);
408 const auto& dataset = request.
dataset().value().get();
414 sop_instance_uid, action_id, status_error_missing_attribute);
421 if (!parsed_state.has_value()) {
424 sop_instance_uid, action_id, status_error_cannot_understand);
437 sop_instance_uid, action_id, status_error_missing_attribute);
441 if (result.is_err()) {
444 sop_instance_uid, action_id, status_error_unable_to_process);
452 sop_instance_uid, action_id, status_success);
459 "No Request Cancel handler configured for UPS Push SCP");
465 const auto& dataset = request.
dataset().value().get();
472 if (result.is_err()) {
475 sop_instance_uid, action_id, status_error_unable_to_process);
483 sop_instance_uid, action_id, status_success);
489 sop_instance_uid, action_id, status_error_no_such_action_type);
501 const std::string& sop_instance_uid,
504 using namespace network::dimse;
506 dimse_message response{command_field::n_create_rsp, 0};
507 response.set_message_id_responded_to(message_id);
509 response.set_status(status);
511 if (!sop_instance_uid.empty()) {
512 response.set_affected_sop_instance_uid(sop_instance_uid);
515 return assoc.
send_dimse(context_id, response);
522 const std::string& sop_instance_uid,
525 using namespace network::dimse;
527 dimse_message response{command_field::n_set_rsp, 0};
528 response.set_message_id_responded_to(message_id);
530 response.set_status(status);
532 if (!sop_instance_uid.empty()) {
533 response.set_affected_sop_instance_uid(sop_instance_uid);
536 return assoc.
send_dimse(context_id, response);
543 const std::string& sop_instance_uid,
547 using namespace network::dimse;
549 auto response = make_n_get_rsp(
552 if (dataset !=
nullptr) {
553 response.set_dataset(std::move(*dataset));
556 return assoc.
send_dimse(context_id, response);
563 const std::string& sop_instance_uid,
564 uint16_t action_type_id,
567 using namespace network::dimse;
569 auto response = make_n_action_rsp(
571 action_type_id, status);
573 return assoc.
send_dimse(context_id, response);
void set_string(dicom_tag tag, encoding::vr_type vr, std::string_view value)
Set a string value for the given tag.
Result< std::monostate > send_dimse(uint8_t context_id, const dimse::dimse_message &msg)
Send a DIMSE message.
auto message_id() const noexcept -> uint16_t
Get the message ID.
auto affected_sop_class_uid() const -> std::string
Get the Affected SOP Class UID.
auto command_set() noexcept -> core::dicom_dataset &
Get mutable reference to the command set.
auto requested_sop_instance_uid() const -> std::string
Get the Requested SOP Instance UID (for N-SET, N-GET, N-ACTION, N-DELETE)
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 action_type_id() const -> std::optional< uint16_t >
Get the Action Type ID (for N-ACTION)
auto affected_sop_instance_uid() const -> std::string
Get the Affected SOP Instance UID.
auto command() const noexcept -> command_field
Get the command field.
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 > handle_n_set(network::association &assoc, uint8_t context_id, const network::dimse::dimse_message &request)
size_t creates_processed() const noexcept
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 > handle_n_create(network::association &assoc, uint8_t context_id, const network::dimse::dimse_message &request)
std::atomic< size_t > state_changes_
std::atomic< size_t > cancel_requests_
void set_create_handler(ups_create_handler handler)
ups_request_cancel_handler request_cancel_handler_
size_t state_changes() const noexcept
std::vector< std::string > supported_sop_classes() const override
Get the list of SOP Class UIDs supported by this service.
std::string_view service_name() const noexcept override
Get the service name for logging/debugging.
ups_set_handler set_handler_
void reset_statistics() noexcept
void set_request_cancel_handler(ups_request_cancel_handler handler)
size_t gets_processed() const noexcept
size_t cancel_requests() const noexcept
ups_get_handler get_handler_
size_t actions_processed() const noexcept
std::atomic< size_t > actions_processed_
std::atomic< size_t > creates_processed_
void set_get_handler(ups_get_handler handler)
ups_push_scp(std::shared_ptr< di::ILogger > logger=nullptr)
Construct UPS Push SCP with optional logger.
ups_create_handler create_handler_
std::atomic< size_t > gets_processed_
void set_set_handler(ups_set_handler 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)
size_t sets_processed() const noexcept
std::atomic< size_t > sets_processed_
ups_change_state_handler change_state_handler_
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)
void set_change_state_handler(ups_change_state_handler handler)
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 > handle_message(network::association &assoc, uint8_t context_id, const network::dimse::dimse_message &request) override
Handle an incoming DIMSE message.
DIMSE command field enumeration.
Compile-time constants for commonly used DICOM tags.
DIMSE message encoding and decoding.
@ 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 int ups_unexpected_command
constexpr int ups_invalid_action_type
constexpr int ups_handler_not_set
uint16_t status_code
DIMSE status code type alias.
std::function< network::Result< storage::ups_workitem >( const std::string &workitem_uid)> ups_get_handler
N-GET handler function type.
std::function< network::Result< std::monostate >( const std::string &workitem_uid, const core::dicom_dataset &modifications)> ups_set_handler
N-SET handler function type.
std::function< network::Result< std::monostate >( const storage::ups_workitem &workitem)> ups_create_handler
N-CREATE handler function type.
auto to_string(mpps_status status) -> std::string_view
Convert mpps_status to DICOM string representation.
constexpr std::string_view ups_push_sop_class_uid
UPS Push SOP Class UID (PS3.4 Table CC.2-1)
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)
std::function< network::Result< std::monostate >( const std::string &workitem_uid, const std::string &reason)> ups_request_cancel_handler
N-ACTION Type 3 handler: Request Cancellation.
std::function< network::Result< std::monostate >( const std::string &workitem_uid, const std::string &new_state, const std::string &transaction_uid)> ups_change_state_handler
N-ACTION Type 1 handler: Change UPS State.
@ scheduled
Workitem is scheduled (initial state)
@ completed
Workitem completed successfully (final)
@ canceled
Workitem was canceled (final)
@ in_progress
Workitem is being performed.
auto parse_ups_state(std::string_view str) -> std::optional< ups_state >
Parse string to ups_state enum.
VoidResult pacs_void_error(int code, const std::string &message, const std::string &details="")
Create a PACS void error result.
Result<T> type aliases and helpers for PACS system.
UPS workitem record from the database.
std::string workitem_uid
UPS SOP Instance UID - unique identifier for this workitem.
std::string state
Current state of the workitem.
std::string priority
Priority (LOW, MEDIUM, HIGH)
std::string worklist_label
Worklist Label (for grouping workitems)
std::string procedure_step_label
Procedure Step Label (human-readable description)
DICOM UPS (Unified Procedure Step) Push SCP service.