PACS System 0.1.0
PACS DICOM system library
Loading...
Searching...
No Matches
routing_manager.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
18#pragma once
19
23
24#include <atomic>
25#include <memory>
26#include <shared_mutex>
27#include <string>
28#include <string_view>
29#include <vector>
30
31// Forward declarations
32namespace kcenon::pacs::core {
33class dicom_dataset;
34}
35
36namespace kcenon::pacs::storage {
37class routing_repository;
38}
39
40namespace kcenon::pacs::services {
41class storage_scp;
42}
43
44namespace kcenon::pacs::client {
45
46// Forward declaration
47class job_manager;
48
49// =============================================================================
50// Routing Manager
51// =============================================================================
52
94public:
95 // =========================================================================
96 // Construction / Destruction
97 // =========================================================================
98
106 explicit routing_manager(
107 std::shared_ptr<storage::routing_repository> repo,
108 std::shared_ptr<job_manager> job_manager,
109 std::shared_ptr<di::ILogger> logger = nullptr);
110
119 explicit routing_manager(
121 std::shared_ptr<storage::routing_repository> repo,
122 std::shared_ptr<job_manager> job_manager,
123 std::shared_ptr<di::ILogger> logger = nullptr);
124
129
130 // Non-copyable, non-movable
132 auto operator=(const routing_manager&) -> routing_manager& = delete;
135
136 // =========================================================================
137 // Rule CRUD
138 // =========================================================================
139
146 [[nodiscard]] auto add_rule(const routing_rule& rule) -> kcenon::pacs::VoidResult;
147
154 [[nodiscard]] auto update_rule(const routing_rule& rule) -> kcenon::pacs::VoidResult;
155
162 [[nodiscard]] auto remove_rule(std::string_view rule_id) -> kcenon::pacs::VoidResult;
163
170 [[nodiscard]] auto get_rule(std::string_view rule_id) const
171 -> std::optional<routing_rule>;
172
178 [[nodiscard]] auto list_rules() const -> std::vector<routing_rule>;
179
185 [[nodiscard]] auto list_enabled_rules() const -> std::vector<routing_rule>;
186
187 // =========================================================================
188 // Rule Ordering
189 // =========================================================================
190
198 [[nodiscard]] auto set_rule_priority(std::string_view rule_id, int priority)
199 -> kcenon::pacs::VoidResult;
200
207 [[nodiscard]] auto reorder_rules(const std::vector<std::string>& rule_ids)
208 -> kcenon::pacs::VoidResult;
209
210 // =========================================================================
211 // Rule Evaluation
212 // =========================================================================
213
222 [[nodiscard]] auto evaluate(const core::dicom_dataset& dataset)
223 -> std::vector<routing_action>;
224
231 [[nodiscard]] auto evaluate_with_rule_ids(const core::dicom_dataset& dataset)
232 -> std::vector<std::pair<std::string, std::vector<routing_action>>>;
233
234 // =========================================================================
235 // Routing Execution
236 // =========================================================================
237
245 void route(const core::dicom_dataset& dataset);
246
252 void route(std::string_view sop_instance_uid);
253
254 // =========================================================================
255 // Enable/Disable
256 // =========================================================================
257
261 void enable();
262
266 void disable();
267
273 [[nodiscard]] auto is_enabled() const noexcept -> bool;
274
275 // =========================================================================
276 // Storage SCP Integration
277 // =========================================================================
278
286 void attach_to_storage_scp(services::storage_scp& scp);
287
292
293 // =========================================================================
294 // Event Callbacks
295 // =========================================================================
296
305
306 // =========================================================================
307 // Testing (Dry Run)
308 // =========================================================================
309
316 [[nodiscard]] auto test_rules(const core::dicom_dataset& dataset) const
318
319 // =========================================================================
320 // Statistics
321 // =========================================================================
322
328 [[nodiscard]] auto get_statistics() const -> routing_statistics;
329
336 [[nodiscard]] auto get_rule_statistics(std::string_view rule_id) const
338
342 void reset_statistics();
343
344 // =========================================================================
345 // Configuration
346 // =========================================================================
347
353 [[nodiscard]] auto config() const noexcept -> const routing_manager_config&;
354
355private:
356 // =========================================================================
357 // Private Implementation
358 // =========================================================================
359
363 [[nodiscard]] auto match_condition(const routing_condition& condition,
364 const core::dicom_dataset& dataset) const
365 -> bool;
366
370 [[nodiscard]] auto match_pattern(std::string_view pattern,
371 std::string_view value,
372 bool case_sensitive) const -> bool;
373
377 [[nodiscard]] auto get_field_value(routing_field field,
378 const core::dicom_dataset& dataset) const
379 -> std::string;
380
384 void execute_actions(const std::string& sop_instance_uid,
385 const std::vector<routing_action>& actions);
386
390 void load_rules();
391
392 // =========================================================================
393 // Member Variables
394 // =========================================================================
395
397 std::shared_ptr<storage::routing_repository> repo_;
398 std::shared_ptr<job_manager> job_manager_;
399 std::shared_ptr<di::ILogger> logger_;
400
401 std::vector<routing_rule> rules_;
402 mutable std::shared_mutex rules_mutex_;
403
404 std::atomic<bool> enabled_{true};
406
407 // Statistics
408 std::atomic<size_t> total_evaluated_{0};
409 std::atomic<size_t> total_matched_{0};
410 std::atomic<size_t> total_forwarded_{0};
411 std::atomic<size_t> total_failed_{0};
412
413 // Storage SCP attachment state
415};
416
417} // namespace kcenon::pacs::client
void attach_to_storage_scp(services::storage_scp &scp)
Attach to a Storage SCP for automatic routing.
void set_routing_callback(routing_event_callback callback)
Set callback for routing events.
auto test_rules(const core::dicom_dataset &dataset) const -> routing_test_result
Test rules against a dataset without executing actions.
routing_manager(const routing_manager &)=delete
auto get_field_value(routing_field field, const core::dicom_dataset &dataset) const -> std::string
Get DICOM field value from dataset.
auto get_statistics() const -> routing_statistics
Get overall routing statistics.
auto get_rule(std::string_view rule_id) const -> std::optional< routing_rule >
Get a routing rule by ID.
auto remove_rule(std::string_view rule_id) -> kcenon::pacs::VoidResult
Remove a routing rule.
auto match_pattern(std::string_view pattern, std::string_view value, bool case_sensitive) const -> bool
Match a wildcard pattern against a value.
void enable()
Enable routing globally.
auto get_rule_statistics(std::string_view rule_id) const -> routing_statistics
Get statistics for a specific rule.
routing_manager(std::shared_ptr< storage::routing_repository > repo, std::shared_ptr< job_manager > job_manager, std::shared_ptr< di::ILogger > logger=nullptr)
Construct a routing manager with default configuration.
auto evaluate(const core::dicom_dataset &dataset) -> std::vector< routing_action >
Evaluate rules against a dataset.
auto set_rule_priority(std::string_view rule_id, int priority) -> kcenon::pacs::VoidResult
Set the priority of a rule.
auto config() const noexcept -> const routing_manager_config &
Get current configuration.
void route(const core::dicom_dataset &dataset)
Route a DICOM dataset based on matching rules.
std::shared_ptr< storage::routing_repository > repo_
auto reorder_rules(const std::vector< std::string > &rule_ids) -> kcenon::pacs::VoidResult
Reorder rules by specifying the desired order.
void load_rules()
Load rules from repository into cache.
std::shared_ptr< di::ILogger > logger_
std::shared_ptr< job_manager > job_manager_
void reset_statistics()
Reset all statistics.
auto match_condition(const routing_condition &condition, const core::dicom_dataset &dataset) const -> bool
Check if a condition matches a dataset.
auto is_enabled() const noexcept -> bool
Check if routing is enabled.
void disable()
Disable routing globally.
auto list_rules() const -> std::vector< routing_rule >
List all routing rules.
auto add_rule(const routing_rule &rule) -> kcenon::pacs::VoidResult
Add a new routing rule.
auto operator=(routing_manager &&) -> routing_manager &=delete
void detach_from_storage_scp()
Detach from the currently attached Storage SCP.
auto operator=(const routing_manager &) -> routing_manager &=delete
auto evaluate_with_rule_ids(const core::dicom_dataset &dataset) -> std::vector< std::pair< std::string, std::vector< routing_action > > >
Evaluate rules and return with matched rule IDs.
auto update_rule(const routing_rule &rule) -> kcenon::pacs::VoidResult
Update an existing routing rule.
auto list_enabled_rules() const -> std::vector< routing_rule >
List only enabled routing rules.
std::vector< routing_rule > rules_
routing_manager(routing_manager &&)=delete
void execute_actions(const std::string &sop_instance_uid, const std::vector< routing_action > &actions)
Execute routing actions.
Logger interface for dependency injection.
routing_field
DICOM field to match in routing conditions.
std::function< void( const std::string &rule_id, const std::string &instance_uid, const std::vector< routing_action > &triggered_actions)> routing_event_callback
Callback type for routing events.
Result<T> type aliases and helpers for PACS system.
Routing types and structures for auto-forwarding DICOM images.
Action to perform when a routing rule matches.
A single condition for routing rule evaluation.
Configuration for the routing manager.
A complete routing rule with conditions and actions.
Statistics for routing operations.
Result of testing rules against a dataset (dry run)