PACS System 0.1.0
PACS DICOM system library
Loading...
Searching...
No Matches
query_scu.h
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
20#ifndef PACS_SERVICES_QUERY_SCU_HPP
21#define PACS_SERVICES_QUERY_SCU_HPP
22
23#include "query_scp.h"
28
29#include <atomic>
30#include <chrono>
31#include <cstdint>
32#include <functional>
33#include <string>
34#include <vector>
35
36namespace kcenon::pacs::services {
37
38// =============================================================================
39// Query Model Enumeration
40// =============================================================================
41
47enum class query_model {
50};
51
57[[nodiscard]] constexpr std::string_view to_string(query_model model) noexcept {
58 switch (model) {
59 case query_model::patient_root: return "Patient Root";
60 case query_model::study_root: return "Study Root";
61 default: return "Unknown";
62 }
63}
64
70[[nodiscard]] constexpr std::string_view get_find_sop_class_uid(
71 query_model model) noexcept {
72 switch (model) {
77 default:
79 }
80}
81
82// =============================================================================
83// Query Result Structure
84// =============================================================================
85
93 std::vector<core::dicom_dataset> matches;
94
96 uint16_t status{0};
97
99 std::chrono::milliseconds elapsed{0};
100
103 size_t total_pending{0};
104
106 [[nodiscard]] bool is_success() const noexcept {
107 return status == 0x0000;
108 }
109
111 [[nodiscard]] bool is_cancelled() const noexcept {
112 return status == 0xFE00;
113 }
114};
115
116// =============================================================================
117// Typed Query Key Structures
118// =============================================================================
119
124 std::string patient_name;
125 std::string patient_id;
126 std::string birth_date;
127 std::string sex;
128};
129
134 std::string patient_id;
135 std::string study_uid;
136 std::string study_date;
137 std::string accession_number;
138 std::string modality;
139 std::string study_description;
140};
141
146 std::string study_uid;
147 std::string series_uid;
148 std::string modality;
149 std::string series_number;
150};
151
156 std::string series_uid;
157 std::string sop_instance_uid;
158 std::string instance_number;
159};
160
161// =============================================================================
162// Query SCU Configuration
163// =============================================================================
164
171
174
176 std::chrono::milliseconds timeout{30000};
177
179 size_t max_results{0};
180
182 bool cancel_on_max{true};
183};
184
185// =============================================================================
186// Streaming Callback Types
187// =============================================================================
188
197using query_streaming_callback = std::function<bool(const core::dicom_dataset&)>;
198
199// =============================================================================
200// Query SCU Class
201// =============================================================================
202
295public:
296 // =========================================================================
297 // Construction
298 // =========================================================================
299
305 explicit query_scu(std::shared_ptr<di::ILogger> logger = nullptr);
306
313 explicit query_scu(const query_scu_config& config,
314 std::shared_ptr<di::ILogger> logger = nullptr);
315
316 ~query_scu() = default;
317
318 // Non-copyable, non-movable (due to atomic members)
319 query_scu(const query_scu&) = delete;
320 query_scu& operator=(const query_scu&) = delete;
321 query_scu(query_scu&&) = delete;
323
324 // =========================================================================
325 // Generic Query Operations
326 // =========================================================================
327
340 const core::dicom_dataset& query_keys);
341
355 const core::dicom_dataset& query_keys,
356 query_streaming_callback callback);
357
358 // =========================================================================
359 // Typed Convenience Methods
360 // =========================================================================
361
371 const patient_query_keys& keys);
372
382 const study_query_keys& keys);
383
393 const series_query_keys& keys);
394
404 const instance_query_keys& keys);
405
406 // =========================================================================
407 // C-CANCEL Support
408 // =========================================================================
409
419 uint16_t message_id);
420
421 // =========================================================================
422 // Configuration
423 // =========================================================================
424
431
437 [[nodiscard]] const query_scu_config& config() const noexcept;
438
439 // =========================================================================
440 // Statistics
441 // =========================================================================
442
447 [[nodiscard]] size_t queries_performed() const noexcept;
448
453 [[nodiscard]] size_t total_matches() const noexcept;
454
458 void reset_statistics() noexcept;
459
460private:
461 // =========================================================================
462 // Private Implementation
463 // =========================================================================
464
468 [[nodiscard]] network::Result<query_result> find_impl(
469 network::association& assoc,
470 const core::dicom_dataset& query_keys,
471 uint16_t message_id);
472
476 [[nodiscard]] uint16_t next_message_id() noexcept;
477
481 [[nodiscard]] core::dicom_dataset build_query_dataset(
482 const patient_query_keys& keys) const;
483
487 [[nodiscard]] core::dicom_dataset build_query_dataset(
488 const study_query_keys& keys) const;
489
493 [[nodiscard]] core::dicom_dataset build_query_dataset(
494 const series_query_keys& keys) const;
495
499 [[nodiscard]] core::dicom_dataset build_query_dataset(
500 const instance_query_keys& keys) const;
501
505 [[nodiscard]] std::string_view get_sop_class_uid() const noexcept;
506
507 // =========================================================================
508 // Private Members
509 // =========================================================================
510
512 std::shared_ptr<di::ILogger> logger_;
513
516
518 std::atomic<uint16_t> message_id_counter_{1};
519
521 std::atomic<size_t> queries_performed_{0};
522
524 std::atomic<size_t> total_matches_{0};
525};
526
527} // namespace kcenon::pacs::services
528
529#endif // PACS_SERVICES_QUERY_SCU_HPP
DICOM Association management per PS3.8.
std::string_view get_sop_class_uid() const noexcept
Get SOP Class UID based on current configuration.
query_scu_config config_
Configuration.
Definition query_scu.h:515
network::Result< size_t > find_streaming(network::association &assoc, const core::dicom_dataset &query_keys, query_streaming_callback callback)
Perform a streaming C-FIND query for large result sets.
std::shared_ptr< di::ILogger > logger_
Logger instance for service logging.
Definition query_scu.h:512
void set_config(const query_scu_config &config)
Update the SCU configuration.
std::atomic< size_t > queries_performed_
Statistics: number of queries performed.
Definition query_scu.h:521
std::atomic< size_t > total_matches_
Statistics: total number of matches received.
Definition query_scu.h:524
network::Result< query_result > find_patients(network::association &assoc, const patient_query_keys &keys)
Query for patients.
network::Result< query_result > find_instances(network::association &assoc, const instance_query_keys &keys)
Query for instances within a series.
size_t queries_performed() const noexcept
Get the number of queries performed since construction.
network::Result< query_result > find_studies(network::association &assoc, const study_query_keys &keys)
Query for studies.
void reset_statistics() noexcept
Reset statistics counters to zero.
network::Result< std::monostate > cancel(network::association &assoc, uint16_t message_id)
Send a C-CANCEL request to stop an ongoing query.
std::atomic< uint16_t > message_id_counter_
Message ID counter.
Definition query_scu.h:518
uint16_t next_message_id() noexcept
Get the next message ID for DIMSE operations.
const query_scu_config & config() const noexcept
Get the current configuration.
network::Result< query_result > find_impl(network::association &assoc, const core::dicom_dataset &query_keys, uint16_t message_id)
Internal query implementation.
Definition query_scu.cpp:43
query_scu & operator=(query_scu &&)=delete
core::dicom_dataset build_query_dataset(const patient_query_keys &keys) const
Build query dataset from patient keys.
query_scu(query_scu &&)=delete
network::Result< query_result > find_series(network::association &assoc, const series_query_keys &keys)
Query for series within a study.
size_t total_matches() const noexcept
Get the total number of matches received since construction.
query_scu(const query_scu &)=delete
query_scu & operator=(const query_scu &)=delete
network::Result< query_result > find(network::association &assoc, const core::dicom_dataset &query_keys)
Perform a C-FIND query with raw dataset.
Definition query_scu.cpp:36
DICOM Dataset - ordered collection of Data Elements.
DIMSE message encoding and decoding.
Logger interface for dependency injection.
std::function< bool(const core::dicom_dataset &)> query_streaming_callback
Callback type for streaming query results.
Definition query_scu.h:197
constexpr std::string_view study_root_find_sop_class_uid
Study Root Query/Retrieve Information Model - FIND.
Definition query_scp.h:42
constexpr std::string_view get_find_sop_class_uid(query_model model) noexcept
Get the FIND SOP Class UID for a query model.
Definition query_scu.h:70
constexpr std::string_view patient_root_find_sop_class_uid
Patient Root Query/Retrieve Information Model - FIND.
Definition query_scp.h:38
auto to_string(mpps_status status) -> std::string_view
Convert mpps_status to DICOM string representation.
Definition mpps_scp.h:60
query_level
DICOM Query/Retrieve level enumeration.
Definition query_scp.h:63
@ study
Study level - query study information.
query_model
DICOM Query/Retrieve Information Model.
Definition query_scu.h:47
@ study_root
Study Root Query/Retrieve Information Model.
@ patient_root
Patient Root Query/Retrieve Information Model.
DICOM Query SCP service (C-FIND handler)
Query keys for IMAGE (Instance) level queries.
Definition query_scu.h:155
std::string sop_instance_uid
SOP Instance UID (0008,0018)
Definition query_scu.h:157
std::string series_uid
Series Instance UID (0020,000E) - Required.
Definition query_scu.h:156
std::string instance_number
Instance Number (0020,0013)
Definition query_scu.h:158
Query keys for PATIENT level queries.
Definition query_scu.h:123
std::string birth_date
Patient's Birth Date (0010,0030)
Definition query_scu.h:126
std::string sex
Patient's Sex (0010,0040)
Definition query_scu.h:127
std::string patient_id
Patient ID (0010,0020)
Definition query_scu.h:125
std::string patient_name
Patient's Name (0010,0010)
Definition query_scu.h:124
Result of a C-FIND query operation.
Definition query_scu.h:91
bool is_cancelled() const noexcept
Check if the query was cancelled.
Definition query_scu.h:111
std::chrono::milliseconds elapsed
Query execution time.
Definition query_scu.h:99
size_t total_pending
Number of pending responses received (may differ from matches.size() if max_results was enforced)
Definition query_scu.h:103
uint16_t status
Final DIMSE status code (0x0000 = success)
Definition query_scu.h:96
bool is_success() const noexcept
Check if the query was successful.
Definition query_scu.h:106
std::vector< core::dicom_dataset > matches
Matching datasets returned by the SCP.
Definition query_scu.h:93
Configuration for Query SCU service.
Definition query_scu.h:168
std::chrono::milliseconds timeout
Timeout for receiving query responses (milliseconds)
Definition query_scu.h:176
query_model model
Query information model (Patient Root or Study Root)
Definition query_scu.h:170
bool cancel_on_max
Send C-CANCEL when max_results is reached.
Definition query_scu.h:182
size_t max_results
Maximum number of results to return (0 = unlimited)
Definition query_scu.h:179
query_level level
Query level (Patient, Study, Series, or Image)
Definition query_scu.h:173
Query keys for SERIES level queries.
Definition query_scu.h:145
std::string series_number
Series Number (0020,0011)
Definition query_scu.h:149
std::string series_uid
Series Instance UID (0020,000E)
Definition query_scu.h:147
std::string study_uid
Study Instance UID (0020,000D) - Required.
Definition query_scu.h:146
std::string modality
Modality (0008,0060)
Definition query_scu.h:148
Query keys for STUDY level queries.
Definition query_scu.h:133
std::string accession_number
Accession Number (0008,0050)
Definition query_scu.h:137
std::string study_uid
Study Instance UID (0020,000D)
Definition query_scu.h:135
std::string study_description
Study Description (0008,1030)
Definition query_scu.h:139
std::string modality
Modalities in Study (0008,0061)
Definition query_scu.h:138
std::string patient_id
Patient ID (0010,0020) - for filtering.
Definition query_scu.h:134
std::string study_date
Study Date (0008,0020) - YYYYMMDD or range.
Definition query_scu.h:136