ORE Studio 0.0.4
Loading...
Searching...
No Matches
instrument_ref_handler.hpp
1/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 *
3 * Copyright (C) 2026 Marco Craveiro <marco.craveiro@gmail.com>
4 *
5 * This program is free software; you can redistribute it and/or modify it under
6 * the terms of the GNU General Public License as published by the Free Software
7 * Foundation; either version 3 of the License, or (at your option) any later
8 * version.
9 *
10 * This program is distributed in the hope that it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
12 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
13 * details.
14 *
15 * You should have received a copy of the GNU General Public License along with
16 * this program; if not, write to the Free Software Foundation, Inc., 51
17 * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 *
19 */
20#ifndef ORES_TRADING_MESSAGING_INSTRUMENT_REF_HANDLER_HPP
21#define ORES_TRADING_MESSAGING_INSTRUMENT_REF_HANDLER_HPP
22
23#include <optional>
24#include "ores.logging/make_logger.hpp"
25#include "ores.nats/domain/message.hpp"
26#include "ores.nats/service/client.hpp"
27#include "ores.database/domain/context.hpp"
28#include "ores.security/jwt/jwt_authenticator.hpp"
29#include "ores.service/messaging/handler_helpers.hpp"
30#include "ores.service/service/request_context.hpp"
31#include "ores.trading.api/messaging/day_count_fraction_type_protocol.hpp"
32#include "ores.trading.api/messaging/business_day_convention_type_protocol.hpp"
33#include "ores.trading.api/messaging/floating_index_type_protocol.hpp"
34#include "ores.trading.api/messaging/payment_frequency_type_protocol.hpp"
35#include "ores.trading.api/messaging/leg_type_protocol.hpp"
36#include "ores.trading.core/service/day_count_fraction_type_service.hpp"
37#include "ores.trading.core/service/business_day_convention_type_service.hpp"
38#include "ores.trading.core/service/floating_index_type_service.hpp"
39#include "ores.trading.core/service/payment_frequency_type_service.hpp"
40#include "ores.trading.core/service/leg_type_service.hpp"
41#include "ores.utility/uuid/tenant_id.hpp"
42
43namespace ores::trading::messaging {
44
45namespace {
46inline auto& instrument_ref_handler_lg() {
47 static auto instance = ores::logging::make_logger(
48 "ores.trading.messaging.instrument_ref_handler");
49 return instance;
50}
51} // namespace
52
53using ores::service::messaging::reply;
54using ores::service::messaging::decode;
55using ores::service::messaging::error_reply;
56using ores::service::messaging::has_permission;
57using namespace ores::logging;
58
59class instrument_ref_handler {
60public:
61 instrument_ref_handler(ores::nats::service::client& nats,
63 std::optional<ores::security::jwt::jwt_authenticator> verifier)
64 : nats_(nats), ctx_(std::move(ctx)), verifier_(std::move(verifier)) {}
65
66private:
67 template<typename Svc, typename Req, typename Resp>
68 void list_impl(ores::nats::message msg) {
69 BOOST_LOG_SEV(instrument_ref_handler_lg(), debug) << "Handling " << msg.subject;
70 auto req_ctx_expected = ores::service::service::make_request_context(
71 ctx_, msg, verifier_);
72 if (!req_ctx_expected) {
73 error_reply(nats_, msg, req_ctx_expected.error());
74 return;
75 }
76 const auto& req_ctx = *req_ctx_expected;
77 const auto sys_ctx = req_ctx.with_tenant(
79 Svc svc(sys_ctx);
80 Resp resp;
81 try {
82 resp.types = svc.list_types();
83 resp.total_available_count = static_cast<int>(resp.types.size());
84 } catch (...) {}
85 BOOST_LOG_SEV(instrument_ref_handler_lg(), debug) << "Completed " << msg.subject;
86 reply(nats_, msg, resp);
87 }
88
89 template<typename Svc, typename Req, typename Resp>
90 void save_impl(ores::nats::message msg) {
91 BOOST_LOG_SEV(instrument_ref_handler_lg(), debug) << "Handling " << msg.subject;
92 auto req_ctx_expected = ores::service::service::make_request_context(
93 ctx_, msg, verifier_);
94 if (!req_ctx_expected) {
95 error_reply(nats_, msg, req_ctx_expected.error());
96 return;
97 }
98 const auto& req_ctx = *req_ctx_expected;
99 if (!has_permission(req_ctx, "trading::instruments:write")) {
100 error_reply(nats_, msg, ores::service::error_code::forbidden);
101 return;
102 }
103 Svc svc(req_ctx);
104 if (auto req = decode<Req>(msg)) {
105 try {
106 svc.save_type(req->data);
107 BOOST_LOG_SEV(instrument_ref_handler_lg(), debug)
108 << "Completed " << msg.subject;
109 reply(nats_, msg, Resp{.success = true});
110 } catch (const std::exception& e) {
111 BOOST_LOG_SEV(instrument_ref_handler_lg(), error)
112 << msg.subject << " failed: " << e.what();
113 reply(nats_, msg, Resp{.success = false, .message = e.what()});
114 }
115 } else {
116 BOOST_LOG_SEV(instrument_ref_handler_lg(), warn)
117 << "Failed to decode: " << msg.subject;
118 }
119 }
120
121 template<typename Svc, typename Req, typename Resp>
122 void delete_impl(ores::nats::message msg) {
123 BOOST_LOG_SEV(instrument_ref_handler_lg(), debug) << "Handling " << msg.subject;
124 auto req_ctx_expected = ores::service::service::make_request_context(
125 ctx_, msg, verifier_);
126 if (!req_ctx_expected) {
127 error_reply(nats_, msg, req_ctx_expected.error());
128 return;
129 }
130 const auto& req_ctx = *req_ctx_expected;
131 if (!has_permission(req_ctx, "trading::instruments:delete")) {
132 error_reply(nats_, msg, ores::service::error_code::forbidden);
133 return;
134 }
135 Svc svc(req_ctx);
136 if (auto req = decode<Req>(msg)) {
137 try {
138 svc.remove_types(req->codes);
139 BOOST_LOG_SEV(instrument_ref_handler_lg(), debug)
140 << "Completed " << msg.subject;
141 reply(nats_, msg, Resp{.success = true});
142 } catch (const std::exception& e) {
143 BOOST_LOG_SEV(instrument_ref_handler_lg(), error)
144 << msg.subject << " failed: " << e.what();
145 reply(nats_, msg, Resp{.success = false, .message = e.what()});
146 }
147 } else {
148 BOOST_LOG_SEV(instrument_ref_handler_lg(), warn)
149 << "Failed to decode: " << msg.subject;
150 }
151 }
152
153 template<typename Svc, typename Req, typename Resp>
154 void history_impl(ores::nats::message msg) {
155 BOOST_LOG_SEV(instrument_ref_handler_lg(), debug) << "Handling " << msg.subject;
156 auto req_ctx_expected = ores::service::service::make_request_context(
157 ctx_, msg, verifier_);
158 if (!req_ctx_expected) {
159 error_reply(nats_, msg, req_ctx_expected.error());
160 return;
161 }
162 const auto& req_ctx = *req_ctx_expected;
163 const auto sys_ctx = req_ctx.with_tenant(
164 ores::utility::uuid::tenant_id::system(), req_ctx.actor());
165 Svc svc(sys_ctx);
166 if (auto req = decode<Req>(msg)) {
167 try {
168 auto hist = svc.get_type_history(req->code);
169 BOOST_LOG_SEV(instrument_ref_handler_lg(), debug)
170 << "Completed " << msg.subject;
171 reply(nats_, msg, Resp{.success = true, .history = std::move(hist)});
172 } catch (const std::exception& e) {
173 BOOST_LOG_SEV(instrument_ref_handler_lg(), error)
174 << msg.subject << " failed: " << e.what();
175 reply(nats_, msg, Resp{.success = false, .message = e.what()});
176 }
177 } else {
178 BOOST_LOG_SEV(instrument_ref_handler_lg(), warn)
179 << "Failed to decode: " << msg.subject;
180 }
181 }
182
183public:
184 // Day count fraction type
185 void list_day_count_fraction_types(ores::nats::message msg) {
186 list_impl<service::day_count_fraction_type_service,
187 get_day_count_fraction_types_request,
188 get_day_count_fraction_types_response>(std::move(msg));
189 }
190 void save_day_count_fraction_type(ores::nats::message msg) {
191 save_impl<service::day_count_fraction_type_service,
192 save_day_count_fraction_type_request,
193 save_day_count_fraction_type_response>(std::move(msg));
194 }
195 void delete_day_count_fraction_type(ores::nats::message msg) {
196 delete_impl<service::day_count_fraction_type_service,
197 delete_day_count_fraction_type_request,
198 delete_day_count_fraction_type_response>(std::move(msg));
199 }
200 void history_day_count_fraction_type(ores::nats::message msg) {
201 history_impl<service::day_count_fraction_type_service,
202 get_day_count_fraction_type_history_request,
203 get_day_count_fraction_type_history_response>(std::move(msg));
204 }
205
206 // Business day convention type
207 void list_business_day_convention_types(ores::nats::message msg) {
208 list_impl<service::business_day_convention_type_service,
209 get_business_day_convention_types_request,
210 get_business_day_convention_types_response>(std::move(msg));
211 }
212 void save_business_day_convention_type(ores::nats::message msg) {
213 save_impl<service::business_day_convention_type_service,
214 save_business_day_convention_type_request,
215 save_business_day_convention_type_response>(std::move(msg));
216 }
217 void delete_business_day_convention_type(ores::nats::message msg) {
218 delete_impl<service::business_day_convention_type_service,
219 delete_business_day_convention_type_request,
220 delete_business_day_convention_type_response>(std::move(msg));
221 }
222 void history_business_day_convention_type(ores::nats::message msg) {
223 history_impl<service::business_day_convention_type_service,
224 get_business_day_convention_type_history_request,
225 get_business_day_convention_type_history_response>(std::move(msg));
226 }
227
228 // Floating index type
229 void list_floating_index_types(ores::nats::message msg) {
230 list_impl<service::floating_index_type_service,
231 get_floating_index_types_request,
232 get_floating_index_types_response>(std::move(msg));
233 }
234 void save_floating_index_type(ores::nats::message msg) {
235 save_impl<service::floating_index_type_service,
236 save_floating_index_type_request,
237 save_floating_index_type_response>(std::move(msg));
238 }
239 void delete_floating_index_type(ores::nats::message msg) {
240 delete_impl<service::floating_index_type_service,
241 delete_floating_index_type_request,
242 delete_floating_index_type_response>(std::move(msg));
243 }
244 void history_floating_index_type(ores::nats::message msg) {
245 history_impl<service::floating_index_type_service,
246 get_floating_index_type_history_request,
247 get_floating_index_type_history_response>(std::move(msg));
248 }
249
250 // Payment frequency type
251 void list_payment_frequency_types(ores::nats::message msg) {
252 list_impl<service::payment_frequency_type_service,
253 get_payment_frequency_types_request,
254 get_payment_frequency_types_response>(std::move(msg));
255 }
256 void save_payment_frequency_type(ores::nats::message msg) {
257 save_impl<service::payment_frequency_type_service,
258 save_payment_frequency_type_request,
259 save_payment_frequency_type_response>(std::move(msg));
260 }
261 void delete_payment_frequency_type(ores::nats::message msg) {
262 delete_impl<service::payment_frequency_type_service,
263 delete_payment_frequency_type_request,
264 delete_payment_frequency_type_response>(std::move(msg));
265 }
266 void history_payment_frequency_type(ores::nats::message msg) {
267 history_impl<service::payment_frequency_type_service,
268 get_payment_frequency_type_history_request,
269 get_payment_frequency_type_history_response>(std::move(msg));
270 }
271
272 // Leg type
273 void list_leg_types(ores::nats::message msg) {
274 list_impl<service::leg_type_service,
275 get_leg_types_request,
276 get_leg_types_response>(std::move(msg));
277 }
278 void save_leg_type(ores::nats::message msg) {
279 save_impl<service::leg_type_service,
280 save_leg_type_request,
281 save_leg_type_response>(std::move(msg));
282 }
283 void delete_leg_type(ores::nats::message msg) {
284 delete_impl<service::leg_type_service,
285 delete_leg_type_request,
286 delete_leg_type_response>(std::move(msg));
287 }
288 void history_leg_type(ores::nats::message msg) {
289 history_impl<service::leg_type_service,
290 get_leg_type_history_request,
291 get_leg_type_history_response>(std::move(msg));
292 }
293
294private:
297 std::optional<ores::security::jwt::jwt_authenticator> verifier_;
298};
299
300} // namespace ores::trading::messaging
301
302#endif
STL namespace.
Implements logging infrastructure for ORE Studio.
Definition boost_severity.hpp:28
@ forbidden
The caller is authenticated but lacks the required permission.
Context for the operations on a postgres database.
Definition context.hpp:47
A received NATS message.
Definition message.hpp:40
std::string subject
The subject the message was published to.
Definition message.hpp:44
NATS client: connection, pub/sub, request/reply, and JetStream.
Definition client.hpp:73
static tenant_id system()
Creates a tenant_id representing the system tenant.
Definition tenant_id.cpp:41