PACS System 0.1.0
PACS DICOM system library
Loading...
Searching...
No Matches
association_endpoints.cpp
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
13// IMPORTANT: Include Crow FIRST before any PACS headers to avoid forward
14// declaration conflicts
15#include "crow.h"
16
17// Workaround for Windows: DELETE is defined as a macro in <winnt.h>
18// which conflicts with crow::HTTPMethod::DELETE
19#ifdef DELETE
20#undef DELETE
21#endif
22
29
30#include <sstream>
31
33
34namespace {
35
39void add_cors_headers(crow::response &res, const rest_server_context &ctx) {
40 if (ctx.config && !ctx.config->cors_allowed_origins.empty()) {
41 res.add_header("Access-Control-Allow-Origin",
42 ctx.config->cors_allowed_origins);
43 }
44}
45
46} // namespace
47
48// Internal implementation function called from rest_server.cpp
50 crow::SimpleApp &app,
51 std::shared_ptr<rest_server_context> ctx) {
52 // GET /api/v1/associations/active - List active DICOM associations
53 CROW_ROUTE(app, "/api/v1/associations/active")
54 .methods(crow::HTTPMethod::GET)([ctx](const crow::request & /*req*/) {
55 crow::response res;
56 res.add_header("Content-Type", "application/json");
57 add_cors_headers(res, *ctx);
58
59 if (!ctx->dicom_server) {
60 res.code = 503;
61 res.body = make_error_json("SERVICE_UNAVAILABLE",
62 "DICOM server not configured");
63 return res;
64 }
65
66 auto stats = ctx->dicom_server->get_statistics();
67 auto active_count = ctx->dicom_server->active_associations();
68 auto uptime_sec = stats.uptime().count();
69
70 std::ostringstream oss;
71 oss << R"({"active_count":)" << active_count
72 << R"(,"total_associations":)" << stats.total_associations
73 << R"(,"rejected_associations":)" << stats.rejected_associations
74 << R"(,"messages_processed":)" << stats.messages_processed
75 << R"(,"bytes_received":)" << stats.bytes_received
76 << R"(,"bytes_sent":)" << stats.bytes_sent
77 << R"(,"uptime_seconds":)" << uptime_sec
78 << R"(,"server_running":)"
79 << (ctx->dicom_server->is_running() ? "true" : "false")
80 << '}';
81
82 res.code = 200;
83 res.body = oss.str();
84 return res;
85 });
86
87 // DELETE /api/v1/associations/:id - Terminate a DICOM association
88 CROW_ROUTE(app, "/api/v1/associations/<string>")
89 .methods(crow::HTTPMethod::DELETE)(
90 [ctx](const crow::request & /*req*/,
91 const std::string &association_id) {
92 crow::response res;
93 res.add_header("Content-Type", "application/json");
94 add_cors_headers(res, *ctx);
95
96 if (association_id.empty()) {
97 res.code = 400;
98 res.body = make_error_json("INVALID_REQUEST",
99 "Association ID is required");
100 return res;
101 }
102
103 if (!ctx->dicom_server) {
104 res.code = 503;
105 res.body = make_error_json("SERVICE_UNAVAILABLE",
106 "DICOM server not configured");
107 return res;
108 }
109
110 // Individual association termination is not supported via the
111 // dicom_server public API. The server manages association
112 // lifecycles internally through idle timeouts and graceful
113 // shutdown.
114 res.code = 501;
115 res.body = make_error_json(
116 "NOT_IMPLEMENTED",
117 "Individual association termination is not supported. "
118 "Associations are managed by the DICOM server via idle "
119 "timeouts and graceful shutdown.");
120 return res;
121 });
122
123 // GET /api/v1/associations/:id - Get specific association details
124 CROW_ROUTE(app, "/api/v1/associations/<string>")
125 .methods(crow::HTTPMethod::GET)(
126 [ctx](const crow::request & /*req*/,
127 const std::string &association_id) {
128 crow::response res;
129 res.add_header("Content-Type", "application/json");
130 add_cors_headers(res, *ctx);
131
132 if (association_id.empty()) {
133 res.code = 400;
134 res.body = make_error_json("INVALID_REQUEST",
135 "Association ID is required");
136 return res;
137 }
138
139 if (!ctx->dicom_server) {
140 res.code = 503;
141 res.body = make_error_json("SERVICE_UNAVAILABLE",
142 "DICOM server not configured");
143 return res;
144 }
145
146 // Individual association lookup is not supported via the
147 // dicom_server public API. Use GET /associations/active for
148 // aggregate statistics.
149 res.code = 501;
150 res.body = make_error_json(
151 "NOT_IMPLEMENTED",
152 "Individual association lookup is not supported. "
153 "Use GET /api/v1/associations/active for aggregate "
154 "statistics.");
155 return res;
156 });
157}
158
159} // namespace kcenon::pacs::web::endpoints
DICOM Association API endpoints for REST server.
Multi-threaded DICOM server for handling multiple associations.
void register_association_endpoints_impl(crow::SimpleApp &app, std::shared_ptr< rest_server_context > ctx)
std::string make_error_json(std::string_view code, std::string_view message)
Create JSON error response body with details.
Definition rest_types.h:79
Configuration for REST API server.
Common types and utilities for REST API.
DICOM Server configuration structures.
System API endpoints for REST server.