MayaFlux 1.0.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches
NetworkSubsystem.hpp
Go to the documentation of this file.
1#pragma once
2
3#include "Subsystem.hpp"
4
6
7#if defined(_WIN32) || defined(_WIN64)
8#include <windows.h>
9#endif
10
11#include <asio/executor_work_guard.hpp>
12#include <asio/io_context.hpp>
13
14#if defined(_WIN32) || defined(_WIN64)
15#ifdef ERROR
16#undef ERROR
17#endif
18#endif
19
21struct NetworkService;
22}
23
24namespace MayaFlux::Core {
25
26/**
27 * @class NetworkSubsystem
28 * @brief General-purpose network transport subsystem
29 *
30 * Owns multiple INetworkBackend instances (UDP, TCP, SharedMemory) and
31 * registers a NetworkService into BackendRegistry for decoupled access
32 * by any engine component.
33 *
34 * Structural parallel to InputSubsystem:
35 * - InputSubsystem owns IInputBackend instances (HID, MIDI).
36 * - NetworkSubsystem owns INetworkBackend instances (UDP, TCP, SHM).
37 * - InputSubsystem registers InputService.
38 * - NetworkSubsystem registers NetworkService.
39 *
40 * Key difference: InputSubsystem is receive-only (InputCallback delivers
41 * events to InputManager). NetworkSubsystem is bidirectional. It provides
42 * send and receive through NetworkService, and manages persistent
43 * endpoints rather than device handles.
44 *
45 * Relationship to InputSubsystem's OSC/Serial stubs:
46 * InputSubsystem::initialize_osc_backend() will create an OSCBackend
47 * (IInputBackend) that internally obtains a UDP endpoint through
48 * NetworkService. The OSCBackend handles OSC address parsing and
49 * produces InputValue events. The actual socket is managed here.
50 * Same pattern for Serial if it ever rides over TCP or SHM.
51 *
52 * Endpoint IDs are globally unique across all backends. The subsystem
53 * maintains a transport-to-backend routing map so callers never need
54 * to know which backend handles their endpoint.
55 *
56 * Tokens:
57 * Buffer = NETWORK_BACKEND (new ProcessingToken)
58 * Node = EVENT_RATE (shared with InputSubsystem, async arrival)
59 * Task = EVENT_DRIVEN (shared with InputSubsystem)
60 *
61 * @code
62 * GlobalNetworkConfig config;
63 * config.udp.enabled = true;
64 * config.tcp.enabled = true;
65 *
66 * auto subsystem = std::make_unique<NetworkSubsystem>(config);
67 * subsystem_manager->add_subsystem(SubsystemType::NETWORK, subsystem);
68 * @endcode
69 */
70class MAYAFLUX_API NetworkSubsystem : public ISubsystem {
71public:
72 explicit NetworkSubsystem(const GlobalNetworkConfig& config);
73 ~NetworkSubsystem() override;
74
79
80 // ─────────────────────────────────────────────────────────────────────────
81 // ISubsystem implementation
82 // ─────────────────────────────────────────────────────────────────────────
83
84 void register_callbacks() override;
85 void initialize(SubsystemProcessingHandle& handle) override;
86 void start() override;
87 void pause() override;
88 void resume() override;
89 void stop() override;
90 void shutdown() override;
91 void wait_until_running() override;
92
93 [[nodiscard]] SubsystemTokens get_tokens() const override { return m_tokens; }
94 [[nodiscard]] bool is_ready() const override { return m_ready.load(); }
95 [[nodiscard]] bool is_running() const override { return m_running.load(); }
96 [[nodiscard]] SubsystemType get_type() const override { return SubsystemType::NETWORK; }
98
99 // ─────────────────────────────────────────────────────────────────────────
100 // Backend management (mirrors InputSubsystem::add_backend pattern)
101 // ─────────────────────────────────────────────────────────────────────────
102
103 /**
104 * @brief Add a network backend
105 * @param backend Backend instance (takes ownership)
106 * @return true if added successfully
107 *
108 * Only one backend per NetworkTransport type is permitted.
109 */
110 bool add_backend(std::unique_ptr<INetworkBackend> backend);
111
112 /**
113 * @brief Get a backend by transport type
114 */
115 [[nodiscard]] INetworkBackend* get_backend(NetworkTransport transport) const;
116
117 /**
118 * @brief Get all active backends
119 */
120 [[nodiscard]] std::vector<INetworkBackend*> get_backends() const;
121
122 // ─────────────────────────────────────────────────────────────────────────
123 // Endpoint management (routed through to correct backend)
124 // ─────────────────────────────────────────────────────────────────────────
125
126 /**
127 * @brief Open an endpoint on the backend matching info.transport
128 * @param info Endpoint configuration.
129 * @return Globally unique endpoint id, or 0 on failure.
130 */
131 uint64_t open_endpoint(const EndpointInfo& info);
132
133 /**
134 * @brief Close an endpoint
135 */
136 void close_endpoint(uint64_t endpoint_id);
137
138 /**
139 * @brief Send data through an endpoint
140 */
141 bool send(uint64_t endpoint_id, const uint8_t* data, size_t size);
142
143 /**
144 * @brief Send data to a specific address
145 */
146 bool send_to(uint64_t endpoint_id, const uint8_t* data, size_t size,
147 const std::string& address, uint16_t port);
148
149 /**
150 * @brief Query endpoint state
151 */
152 [[nodiscard]] EndpointState get_endpoint_state(uint64_t endpoint_id) const;
153
154 /**
155 * @brief Register a per-endpoint receive callback
156 *
157 * Stored locally and invoked from the backend's receive callback
158 * after endpoint routing.
159 */
160 void set_endpoint_receive_callback(uint64_t endpoint_id,
162
163 /**
164 * @brief List all open endpoints across all backends
165 */
166 [[nodiscard]] std::vector<EndpointInfo> get_all_endpoints() const;
167
168private:
170 SubsystemProcessingHandle* m_handle { nullptr };
172
173 std::atomic<bool> m_ready { false };
174 std::atomic<bool> m_running { false };
175
176 // ─── Asio event loop ────────────────────────────────────────────────────
177 //
178 // Single io_context shared by all backends. One jthread runs
179 // io_context::run(). All async operations (send, receive, accept,
180 // connect, reconnect timers) complete on this thread. No per-socket
181 // threads, no per-connection threads, no mutexes on the data path.
182 //
183 // work_guard prevents io_context::run() from returning when there
184 // are no pending operations (idle between endpoint opens).
185 // ────────────────────────────────────────────────────────────────────────
186
187 std::unique_ptr<asio::io_context> m_io_context;
188 std::unique_ptr<asio::executor_work_guard<asio::io_context::executor_type>> m_work_guard;
189
190 std::jthread m_io_thread;
191
192 mutable std::shared_mutex m_backends_mutex;
193 std::unordered_map<NetworkTransport, std::unique_ptr<INetworkBackend>> m_backends;
194
195 std::shared_ptr<Registry::Service::NetworkService> m_network_service;
196
197 /**
198 * @brief Maps endpoint_id -> transport for routing send/close/query
199 * to the correct backend without scanning all backends.
200 */
201 mutable std::shared_mutex m_routing_mutex;
202 std::unordered_map<uint64_t, NetworkTransport> m_endpoint_routing;
203
204 /**
205 * @brief Per-endpoint receive callbacks set by consumers via
206 * set_endpoint_receive_callback(). Backend-level receive
207 * callbacks route here.
208 */
209 mutable std::shared_mutex m_callbacks_mutex;
210 std::unordered_map<uint64_t, NetworkReceiveCallback> m_endpoint_callbacks;
211
212 /**
213 * @brief Global endpoint id counter shared across all backends.
214 * Backends do not assign their own ids. The subsystem assigns
215 * and maps them.
216 */
217 std::atomic<uint64_t> m_next_endpoint_id { 1 };
218
219 void initialize_udp_backend();
220 void initialize_tcp_backend();
221 void initialize_shm_backend();
222
223 void register_backend_service();
224
225 /**
226 * @brief Wired as the receive callback on each backend. Routes
227 * to per-endpoint callbacks in m_endpoint_callbacks.
228 */
229 void on_backend_receive(uint64_t endpoint_id, const uint8_t* data,
230 size_t size, std::string_view sender_addr);
231
232 /**
233 * @brief Wired as the state callback on each backend. Forwards
234 * to any registered state observers.
235 */
236 void on_backend_state_change(const EndpointInfo& info,
238
239 /**
240 * @brief Resolve endpoint_id to its owning backend. Returns nullptr
241 * if the id is unknown.
242 */
243 INetworkBackend* resolve_backend(uint64_t endpoint_id) const;
244};
245
246} // namespace MayaFlux::Core
bool size
glm::vec2 current
PickCallback callback
Definition Picker.cpp:22
Abstract interface for network transport backends.
Base interface for all subsystems in the MayaFlux processing architecture.
Definition Subsystem.hpp:26
std::unique_ptr< asio::io_context > m_io_context
std::shared_mutex m_routing_mutex
Maps endpoint_id -> transport for routing send/close/query to the correct backend without scanning al...
bool is_running() const override
Check if subsystem is currently processing.
std::unique_ptr< asio::executor_work_guard< asio::io_context::executor_type > > m_work_guard
NetworkSubsystem & operator=(const NetworkSubsystem &)=delete
SubsystemProcessingHandle * get_processing_context_handle() override
Get the processing context handle for this subsystem.
std::unordered_map< uint64_t, NetworkTransport > m_endpoint_routing
SubsystemTokens get_tokens() const override
Get the processing token configuration this subsystem manages.
NetworkSubsystem(const NetworkSubsystem &)=delete
std::unordered_map< uint64_t, NetworkReceiveCallback > m_endpoint_callbacks
std::shared_mutex m_callbacks_mutex
Per-endpoint receive callbacks set by consumers via set_endpoint_receive_callback().
NetworkSubsystem & operator=(NetworkSubsystem &&)=delete
bool is_ready() const override
Check if subsystem is ready for operation.
SubsystemType get_type() const override
Get the type of this subsystem.
NetworkSubsystem(NetworkSubsystem &&)=delete
std::unordered_map< NetworkTransport, std::unique_ptr< INetworkBackend > > m_backends
std::shared_ptr< Registry::Service::NetworkService > m_network_service
General-purpose network transport subsystem.
Unified interface combining buffer and node processing for subsystems.
void initialize()
Definition main.cpp:10
EndpointState
Observable connection state for an endpoint.
NetworkTransport
Identifies the transport protocol a backend implements.
std::function< void(uint64_t endpoint_id, const uint8_t *data, size_t size, std::string_view sender_addr)> NetworkReceiveCallback
Callback signature for inbound data on an endpoint.
Describes one logical send/receive endpoint managed by a backend.
Configuration for the NetworkSubsystem.
Processing token configuration for subsystem operation.