Radix Relay
Hybrid mesh communications with Signal Protocol encryption
Loading...
Searching...
No Matches
command_handler.hpp
Go to the documentation of this file.
1#pragma once
2
6#include <core/events.hpp>
7#include <fmt/core.h>
8#include <memory>
10
11#include "internal_use_only/config.hpp"
12
14
23template<concepts::signal_bridge Bridge> struct command_handler
24{
25 // Type traits for standard_processor
27
29 {
30 std::shared_ptr<async::async_queue<events::display_filter_input_t>> display;
31 std::shared_ptr<async::async_queue<events::transport::in_t>> transport;
32 std::shared_ptr<async::async_queue<events::session_orchestrator::in_t>> session;
33 std::shared_ptr<async::async_queue<events::connection_monitor::in_t>> connection_monitor;
34 };
35
42 explicit command_handler(const std::shared_ptr<Bridge> &bridge, const out_queues_t &queues)
43 : bridge_(bridge), display_out_queue_(queues.display), transport_out_queue_(queues.transport),
44 session_out_queue_(queues.session), connection_monitor_out_queue_(queues.connection_monitor)
45 {}
46
53 template<events::Command T> auto handle(const T &command) const -> void { handle_impl(command); }
54
60 [[nodiscard]] auto get_bridge() -> std::shared_ptr<Bridge> { return bridge_; }
61
62private:
63 template<typename... Args> auto emit(fmt::format_string<Args...> format_string, Args &&...args) const -> void
64 {
65 display_out_queue_->push(
66 events::display_message{ .message = fmt::format(format_string, std::forward<Args>(args)...),
67 .contact_rdx = std::nullopt,
68 .timestamp = platform::current_timestamp_ms(),
70 }
71
72 auto handle_impl(const events::help & /*command*/) const -> void
73 {
74 std::ignore = initialized_;
75 emit(
76 "Interactive Commands:\n"
77 " /broadcast <message> Send to all local peers\n"
78 " /chat <contact> Enter chat mode with contact\n"
79 " /connect <relay> Add Nostr relay\n"
80 " /disconnect Disconnect from Nostr relay\n"
81 " /identities List discovered identities\n"
82 " /leave Exit chat mode\n"
83 " /mode <internet|mesh|hybrid> Switch transport mode\n"
84 " /peers List discovered peers\n"
85 " /publish Publish identity to network\n"
86 " /scan Force peer discovery\n"
87 " /send <peer> <message> Send encrypted message to peer\n"
88 " /sessions Show encrypted sessions\n"
89 " /status Show network status\n"
90 " /trust <peer> [alias] Establish session with peer\n"
91 " /verify <peer> Show safety numbers\n"
92 " /version Show version information\n"
93 " /quit Exit interactive mode\n");
94 }
95
96 auto handle_impl(const events::peers & /*command*/) const -> void
97 {
98 std::ignore = initialized_;
99 emit(
100 "Connected Peers: (transport layer not implemented)\n"
101 " No peers discovered yet\n");
102 }
103
104 auto handle_impl(const events::status & /*command*/) const -> void
105 {
106 std::ignore = initialized_;
107
108 connection_monitor_out_queue_->push(events::connection_monitor::query_status{});
109
110 std::string node_fingerprint = bridge_->get_node_fingerprint();
111 emit("\nCrypto Status:\n Node Fingerprint: {}\n", node_fingerprint);
112 }
113
114 auto handle_impl(const events::sessions & /*command*/) const -> void
115 {
116 std::ignore = initialized_;
117 auto contacts = bridge_->list_contacts();
118
119 if (contacts.empty()) {
120 emit("No active sessions\n");
121 return;
122 }
123
124 emit("Active Sessions ({}):\n", contacts.size());
125 for (const auto &contact : contacts) {
126 if (contact.user_alias.empty()) {
127 emit(" {}\n", contact.rdx_fingerprint);
128 } else {
129 emit(" {} ({})\n", contact.user_alias, contact.rdx_fingerprint);
130 }
131 }
132 }
133
134 auto handle_impl(const events::identities & /*command*/) const -> void
135 {
136 std::ignore = initialized_;
137 session_out_queue_->push(events::list_identities{});
138 }
139
140 auto handle_impl(const events::publish_identity & /*command*/) const -> void
141 {
142 std::ignore = initialized_;
143 session_out_queue_->push(events::publish_identity{});
144 emit("Publishing identity to network...\n");
145 }
146
147 auto handle_impl(const events::unpublish_identity & /*command*/) const -> void
148 {
149 std::ignore = initialized_;
150 session_out_queue_->push(events::unpublish_identity{});
151 emit("Unpublishing identity from network...\n");
152 }
153
154 auto handle_impl(const events::scan & /*command*/) const -> void
155 {
156 std::ignore = initialized_;
157 emit(
158 "Scanning for BLE peers... (BLE transport not implemented)\n"
159 " No peers found\n");
160 }
161
162 auto handle_impl(const events::version & /*command*/) const -> void
163 {
164 std::ignore = initialized_;
165 emit("Radix Relay v{}\n", radix_relay::cmake::project_version);
166 }
167
168 auto handle_impl(const events::mode &command) const -> void
169 {
170 std::ignore = initialized_;
171 if (command.new_mode == "internet" or command.new_mode == "mesh" or command.new_mode == "hybrid") {
172 emit("Switched to {} mode\n", command.new_mode);
173 } else {
174 emit("Invalid mode. Use: internet, mesh, or hybrid\n");
175 }
176 }
177
178 auto handle_impl(const events::send &command) const -> void
179 {
180 std::ignore = initialized_;
181 if (not command.peer.empty() and not command.message.empty()) {
182 session_out_queue_->push(command);
183 emit("Sending '{}' to '{}'...\n", command.message, command.peer);
184 } else {
185 emit("Usage: send <peer> <message>\n");
186 }
187 }
188
189 auto handle_impl(const events::broadcast &command) const -> void
190 {
191 std::ignore = initialized_;
192 if (not command.message.empty()) {
193 emit("Broadcasting '{}' to all local peers (not implemented)\n", command.message);
194 } else {
195 emit("Usage: broadcast <message>\n");
196 }
197 }
198
199 auto handle_impl(const events::connect &command) const -> void
200 {
201 std::ignore = initialized_;
202 if (not command.relay.empty()) {
203 session_out_queue_->push(command);
204 emit("Connecting to Nostr relay {}\n", command.relay);
205 } else {
206 emit("Usage: connect <relay>\n");
207 }
208 }
209
210 auto handle_impl(const events::disconnect & /*command*/) const -> void
211 {
212 std::ignore = initialized_;
213 transport_out_queue_->push(events::transport::disconnect{});
214 emit("Disconnecting from Nostr relay\n");
215 }
216
217 auto handle_impl(const events::trust &command) const -> void
218 {
219 std::ignore = initialized_;
220 if (not command.peer.empty()) {
221 session_out_queue_->push(command);
222 emit("Establishing session with {}...\n", command.peer);
223 } else {
224 emit("Usage: trust <peer> [alias]\n");
225 }
226 }
227
228 auto handle_impl(const events::verify &command) const -> void
229 {
230 std::ignore = initialized_;
231 if (not command.peer.empty()) {
232 emit("Safety numbers for {} (Signal Protocol not implemented)\n", command.peer);
233 } else {
234 emit("Usage: verify <peer>\n");
235 }
236 }
237
238 auto handle_impl(const events::chat &command) const -> void
239 {
240 std::ignore = initialized_;
241 if (command.contact.empty()) {
242 emit("Usage: /chat <contact>\n");
243 return;
244 }
245
246 try {
247 const auto contact = bridge_->lookup_contact(command.contact);
248 display_out_queue_->push(events::enter_chat_mode{ .rdx_fingerprint = contact.rdx_fingerprint });
249 const auto display_name = contact.user_alias.empty() ? contact.rdx_fingerprint : contact.user_alias;
250 emit("Entering chat with {} ({})\n", display_name, contact.rdx_fingerprint);
251 } catch (const std::exception & /*e*/) {
252 emit("Contact not found: {}\n", command.contact);
253 }
254 }
255
256 auto handle_impl(const events::leave & /*command*/) const -> void
257 {
258 std::ignore = initialized_;
259 display_out_queue_->push(events::exit_chat_mode{});
260 emit("Exiting chat mode\n");
261 }
262
263 std::shared_ptr<Bridge> bridge_;
264 std::shared_ptr<async::async_queue<events::display_filter_input_t>> display_out_queue_;
265 std::shared_ptr<async::async_queue<events::transport::in_t>> transport_out_queue_;
266 std::shared_ptr<async::async_queue<events::session_orchestrator::in_t>> session_out_queue_;
267 std::shared_ptr<async::async_queue<events::connection_monitor::in_t>> connection_monitor_out_queue_;
268 bool initialized_ = true;
269};
270
271}// namespace radix_relay::core
Thread-safe asynchronous queue for message passing between coroutines.
auto current_timestamp_ms() -> std::uint64_t
Gets current timestamp in milliseconds since Unix epoch.
std::shared_ptr< async::async_queue< events::display_filter_input_t > > display
std::shared_ptr< async::async_queue< events::connection_monitor::in_t > > connection_monitor
std::shared_ptr< async::async_queue< events::transport::in_t > > transport
std::shared_ptr< async::async_queue< events::session_orchestrator::in_t > > session
Handles typed command events and coordinates with subsystems.
command_handler(const std::shared_ptr< Bridge > &bridge, const out_queues_t &queues)
Constructs a command handler with required subsystem queues.
auto get_bridge() -> std::shared_ptr< Bridge >
Returns the Signal Protocol bridge.
auto handle(const T &command) const -> void
Handles a typed command event.
Request to display a message to the user.
Definition events.hpp:375
std::string message
Message content to display.
Definition events.hpp:385