FastLED 3.9.15
Loading...
Searching...
No Matches
native_client.cpp.hpp
Go to the documentation of this file.
1#pragma once
2
3// This file requires native socket APIs (Windows or POSIX).
4// On embedded platforms (STM32, AVR, etc.) this file compiles to nothing.
5#ifdef FASTLED_HAS_NETWORKING
6
7// Platform-specific socket includes (provides normalized POSIX API)
8#ifdef FL_IS_WIN
9 #include "platforms/win/socket_win.h" // ok platform headers // IWYU pragma: keep
10#else
11 #include "platforms/posix/socket_posix.h" // ok platform headers // IWYU pragma: keep
12#endif
13
14// Now include FastLED headers
16#include "fl/stl/noexcept.h"
17
18namespace fl {
19
20NativeHttpClient::NativeHttpClient(const asio::ip::tcp::endpoint& ep, const ConnectionConfig& config)
21 : mEndpoint(ep)
22 , mConnection(config)
23{
24}
25
26NativeHttpClient::NativeHttpClient(const string& host, u16 port, const ConnectionConfig& config)
27 : mEndpoint(host, port)
28 , mConnection(config)
29{
30}
31
32NativeHttpClient::~NativeHttpClient() FL_NOEXCEPT {
33 disconnect();
34}
35
36bool NativeHttpClient::connect() {
37 if (mConnection.getState() == ConnectionState::CLOSED) {
38 return false; // Permanently closed
39 }
40
41 // If already connected, return true
42 if (isConnected()) {
43 return true;
44 }
45
46 // Notify connection state machine
47 mConnection.connect();
48
49 // Attempt platform-specific connection
50 if (platformConnect()) {
51 mConnection.onConnected(0); // TODO: pass actual currentTimeMs
52 return true;
53 }
54
55 // Connection failed
56 mConnection.onDisconnected();
57 return false;
58}
59
60void NativeHttpClient::disconnect() {
61 if (mSocket.is_open()) {
62 platformDisconnect();
63 mConnection.disconnect();
64 }
65}
66
67void NativeHttpClient::close() {
68 disconnect();
69 mConnection.close();
70}
71
72bool NativeHttpClient::isConnected() const {
73 return mConnection.isConnected() && isSocketConnected();
74}
75
76ConnectionState NativeHttpClient::getState() const {
77 return mConnection.getState();
78}
79
80int NativeHttpClient::send(fl::span<const u8> data) {
81 if (!isConnected() || !mSocket.is_open()) {
82 return -1;
83 }
84
85 asio::error_code ec;
86 size_t n = mSocket.write_some(data, ec);
87
88 if (ec) {
89 if (ec.code == asio::errc::would_block) {
90 return 0;
91 }
92 mConnection.onDisconnected();
93 return -1;
94 }
95
96 return static_cast<int>(n);
97}
98
99int NativeHttpClient::recv(fl::span<u8> buffer) {
100 if (!isConnected() || !mSocket.is_open()) {
101 return -1;
102 }
103
104 asio::error_code ec;
105 size_t n = mSocket.read_some(buffer, ec);
106
107 if (ec) {
108 if (ec.code == asio::errc::would_block) {
109 return 0; // Non-blocking socket, no data available
110 }
111 // Connection error or EOF
112 mConnection.onDisconnected();
113 return -1;
114 }
115
116 // Data received, update heartbeat tracking
117 mConnection.onHeartbeatReceived();
118
119 return static_cast<int>(n);
120}
121
122void NativeHttpClient::update(u32 currentTimeMs) {
123 // Update connection state machine
124 mConnection.update(currentTimeMs);
125
126 // Check if we should reconnect
127 if (mConnection.shouldReconnect()) {
128 // Attempt reconnection
129 connect();
130 }
131
132 // Check if connection was lost
133 if (!isConnected() && mSocket.is_open()) {
134 disconnect();
135 }
136}
137
138bool NativeHttpClient::shouldSendHeartbeat(u32 currentTimeMs) const {
139 return mConnection.shouldSendHeartbeat(currentTimeMs);
140}
141
142void NativeHttpClient::onHeartbeatSent() {
143 mConnection.onHeartbeatSent();
144}
145
146void NativeHttpClient::onHeartbeatReceived() {
147 mConnection.onHeartbeatReceived();
148}
149
150u32 NativeHttpClient::getReconnectDelayMs() const {
151 return mConnection.getReconnectDelayMs();
152}
153
154u32 NativeHttpClient::getReconnectAttempts() const {
155 return mConnection.getReconnectAttempts();
156}
157
158bool NativeHttpClient::platformConnect() {
159 // Delegate to tcp::socket::connect using the endpoint
160 if (mSocket.is_open()) {
161 platformDisconnect();
162 }
163
164 asio::error_code ec = mSocket.connect(mEndpoint);
165 return ec.ok();
166}
167
168void NativeHttpClient::platformDisconnect() {
169 mSocket.close();
170}
171
172bool NativeHttpClient::isSocketConnected() const {
173 if (!mSocket.is_open()) {
174 return false;
175 }
176
177 // Check socket status using getsockopt
178 int error = 0;
179 socklen_t len = sizeof(error);
180 int ret = getsockopt(mSocket.native_handle(), SOL_SOCKET, SO_ERROR, (char*)&error, &len);
181
182 if (ret != 0 || error != 0) {
183 return false;
184 }
185
186 return true;
187}
188
189} // namespace fl
190
191#endif // FASTLED_HAS_NETWORKING
ConnectionState
Definition connection.h:9
Base definition for an LED controller.
Definition crgb.hpp:179
#define FL_NOEXCEPT
Asio-compatible endpoint type: bundles host address + port.
Definition tcp.h:21