PACS System 0.1.0
PACS DICOM system library
Loading...
Searching...
No Matches
query_scp.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
19#ifndef PACS_SERVICES_QUERY_SCP_HPP
20#define PACS_SERVICES_QUERY_SCP_HPP
21
22#include "scp_service.h"
23
24#include <atomic>
25#include <functional>
26#include <memory>
27#include <optional>
28
29namespace kcenon::pacs::security { class atna_service_auditor; }
30
31namespace kcenon::pacs::services {
32
33// =============================================================================
34// SOP Class UIDs
35// =============================================================================
36
38inline constexpr std::string_view patient_root_find_sop_class_uid =
39 "1.2.840.10008.5.1.4.1.2.1.1";
40
42inline constexpr std::string_view study_root_find_sop_class_uid =
43 "1.2.840.10008.5.1.4.1.2.2.1";
44
46inline constexpr std::string_view patient_study_only_find_sop_class_uid =
47 "1.2.840.10008.5.1.4.1.2.3.1";
48
50inline constexpr std::string_view modality_worklist_find_sop_class_uid =
51 "1.2.840.10008.5.1.4.31";
52
53// =============================================================================
54// Query Level
55// =============================================================================
56
63enum class query_level {
64 patient,
65 study,
66 series,
67 image
68};
69
75[[nodiscard]] constexpr std::string_view to_string(query_level level) noexcept {
76 switch (level) {
77 case query_level::patient: return "PATIENT";
78 case query_level::study: return "STUDY";
79 case query_level::series: return "SERIES";
80 case query_level::image: return "IMAGE";
81 default: return "UNKNOWN";
82 }
83}
84
90[[nodiscard]] inline std::optional<query_level> parse_query_level(
91 std::string_view level_str) noexcept {
92 if (level_str == "PATIENT") return query_level::patient;
93 if (level_str == "STUDY") return query_level::study;
94 if (level_str == "SERIES") return query_level::series;
95 if (level_str == "IMAGE") return query_level::image;
96 return std::nullopt;
97}
98
99// =============================================================================
100// Query Handler Types
101// =============================================================================
102
113using query_handler = std::function<std::vector<core::dicom_dataset>(
114 query_level level,
115 const core::dicom_dataset& query_keys,
116 const std::string& calling_ae)>;
117
126using cancel_check = std::function<bool()>;
127
128// =============================================================================
129// Query SCP Class
130// =============================================================================
131
189class query_scp final : public scp_service {
190public:
191 // =========================================================================
192 // Construction
193 // =========================================================================
194
200 explicit query_scp(std::shared_ptr<di::ILogger> logger = nullptr);
201
202 ~query_scp() override = default;
203
204 // =========================================================================
205 // Configuration
206 // =========================================================================
207
216 void set_handler(query_handler handler);
217
223 void set_max_results(size_t max) noexcept;
224
230 [[nodiscard]] size_t max_results() const noexcept;
231
240 void set_cancel_check(cancel_check check);
241
250 std::shared_ptr<kcenon::pacs::security::atna_service_auditor> auditor);
251
252 // =========================================================================
253 // scp_service Interface Implementation
254 // =========================================================================
255
261 [[nodiscard]] std::vector<std::string> supported_sop_classes() const override;
262
274 [[nodiscard]] network::Result<std::monostate> handle_message(
275 network::association& assoc,
276 uint8_t context_id,
277 const network::dimse::dimse_message& request) override;
278
284 [[nodiscard]] std::string_view service_name() const noexcept override;
285
286 // =========================================================================
287 // Statistics
288 // =========================================================================
289
295 [[nodiscard]] size_t queries_processed() const noexcept;
296
300 void reset_statistics() noexcept;
301
302private:
303 // =========================================================================
304 // Private Implementation
305 // =========================================================================
306
313 [[nodiscard]] std::optional<query_level> extract_query_level(
314 const core::dicom_dataset& dataset) const;
315
326 [[nodiscard]] network::Result<std::monostate> send_pending_response(
327 network::association& assoc,
328 uint8_t context_id,
329 uint16_t message_id,
330 std::string_view sop_class_uid,
331 const core::dicom_dataset& result);
332
343 [[nodiscard]] network::Result<std::monostate> send_final_response(
344 network::association& assoc,
345 uint8_t context_id,
346 uint16_t message_id,
347 std::string_view sop_class_uid,
348 network::dimse::status_code status);
349
350 // =========================================================================
351 // Member Variables
352 // =========================================================================
353
356 std::shared_ptr<kcenon::pacs::security::atna_service_auditor> auditor_;
357 size_t max_results_{0}; // 0 = unlimited
358 std::atomic<size_t> queries_processed_{0};
359};
360
361} // namespace kcenon::pacs::services
362
363#endif // PACS_SERVICES_QUERY_SCP_HPP
std::vector< std::string > supported_sop_classes() const override
Get supported SOP Class UIDs.
Definition query_scp.cpp:72
void set_audit_handler(std::shared_ptr< kcenon::pacs::security::atna_service_auditor > auditor)
Set the ATNA audit handler for C-FIND operations.
Definition query_scp.cpp:63
std::optional< query_level > extract_query_level(const core::dicom_dataset &dataset) const
Extract query level from request dataset.
network::Result< std::monostate > send_pending_response(network::association &assoc, uint8_t context_id, uint16_t message_id, std::string_view sop_class_uid, const core::dicom_dataset &result)
Send a pending C-FIND response with matching dataset.
size_t max_results() const noexcept
Get maximum number of results.
Definition query_scp.cpp:55
void set_cancel_check(cancel_check check)
Set the cancel check function.
Definition query_scp.cpp:59
void reset_statistics() noexcept
Reset statistics counters.
std::shared_ptr< kcenon::pacs::security::atna_service_auditor > auditor_
Definition query_scp.h:356
std::atomic< size_t > queries_processed_
Definition query_scp.h:358
void set_handler(query_handler handler)
Set the query handler function.
Definition query_scp.cpp:47
std::string_view service_name() const noexcept override
Get the service name.
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 (C-FIND-RQ)
Definition query_scp.cpp:79
network::Result< std::monostate > send_final_response(network::association &assoc, uint8_t context_id, uint16_t message_id, std::string_view sop_class_uid, network::dimse::status_code status)
Send the final C-FIND response (success or cancel)
void set_max_results(size_t max) noexcept
Set maximum number of results to return.
Definition query_scp.cpp:51
size_t queries_processed() const noexcept
Get total number of queries processed.
query_scp(std::shared_ptr< di::ILogger > logger=nullptr)
Construct Query SCP with optional logger.
Definition query_scp.cpp:40
const std::shared_ptr< di::ILogger > & logger() const noexcept
Get the current logger instance.
Definition scp_service.h:93
constexpr std::string_view modality_worklist_find_sop_class_uid
Modality Worklist Information Model - FIND.
Definition query_scp.h:50
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 patient_root_find_sop_class_uid
Patient Root Query/Retrieve Information Model - FIND.
Definition query_scp.h:38
std::function< std::vector< core::dicom_dataset >( query_level level, const core::dicom_dataset &query_keys, const std::string &calling_ae)> query_handler
Query handler function type.
Definition query_scp.h:113
std::optional< query_level > parse_query_level(std::string_view level_str) noexcept
Parse query level from DICOM string.
Definition query_scp.h:90
auto to_string(mpps_status status) -> std::string_view
Convert mpps_status to DICOM string representation.
Definition mpps_scp.h:60
constexpr std::string_view patient_study_only_find_sop_class_uid
Patient/Study Only Query/Retrieve Information Model - FIND (Retired)
Definition query_scp.h:46
std::function< bool()> cancel_check
Cancel check function type.
Definition query_scp.h:126
query_level
DICOM Query/Retrieve level enumeration.
Definition query_scp.h:63
@ study
Study level - query study information.
@ image
Image (Instance) level - query instance information.
@ patient
Patient level - query patient demographics.
@ series
Series level - query series information.
Base class for DICOM SCP (Service Class Provider) services.