mirror of
https://github.com/esphome/esphome.git
synced 2026-02-11 10:12:38 +00:00
Compare commits
11 Commits
dev
...
api-server
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
419ea723b8 | ||
|
|
a671f6ea85 | ||
|
|
0c62781539 | ||
|
|
e6c743ea67 | ||
|
|
4c006d98af | ||
|
|
c08726036e | ||
|
|
d602a2e5e4 | ||
|
|
dcab12adae | ||
|
|
fb714636e3 | ||
|
|
05a431ea54 | ||
|
|
1a34b4e7d7 |
@@ -117,37 +117,7 @@ void APIServer::setup() {
|
|||||||
void APIServer::loop() {
|
void APIServer::loop() {
|
||||||
// Accept new clients only if the socket exists and has incoming connections
|
// Accept new clients only if the socket exists and has incoming connections
|
||||||
if (this->socket_ && this->socket_->ready()) {
|
if (this->socket_ && this->socket_->ready()) {
|
||||||
while (true) {
|
this->accept_new_connections_();
|
||||||
struct sockaddr_storage source_addr;
|
|
||||||
socklen_t addr_len = sizeof(source_addr);
|
|
||||||
|
|
||||||
auto sock = this->socket_->accept_loop_monitored((struct sockaddr *) &source_addr, &addr_len);
|
|
||||||
if (!sock)
|
|
||||||
break;
|
|
||||||
|
|
||||||
char peername[socket::SOCKADDR_STR_LEN];
|
|
||||||
sock->getpeername_to(peername);
|
|
||||||
|
|
||||||
// Check if we're at the connection limit
|
|
||||||
if (this->clients_.size() >= this->max_connections_) {
|
|
||||||
ESP_LOGW(TAG, "Max connections (%d), rejecting %s", this->max_connections_, peername);
|
|
||||||
// Immediately close - socket destructor will handle cleanup
|
|
||||||
sock.reset();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
ESP_LOGD(TAG, "Accept %s", peername);
|
|
||||||
|
|
||||||
auto *conn = new APIConnection(std::move(sock), this);
|
|
||||||
this->clients_.emplace_back(conn);
|
|
||||||
conn->start();
|
|
||||||
|
|
||||||
// First client connected - clear warning and update timestamp
|
|
||||||
if (this->clients_.size() == 1 && this->reboot_timeout_ != 0) {
|
|
||||||
this->status_clear_warning();
|
|
||||||
this->last_connected_ = App.get_loop_component_start_time();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this->clients_.empty()) {
|
if (this->clients_.empty()) {
|
||||||
@@ -178,46 +148,84 @@ void APIServer::loop() {
|
|||||||
while (client_index < this->clients_.size()) {
|
while (client_index < this->clients_.size()) {
|
||||||
auto &client = this->clients_[client_index];
|
auto &client = this->clients_[client_index];
|
||||||
|
|
||||||
if (!client->flags_.remove) {
|
if (client->flags_.remove) {
|
||||||
|
// Rare case: handle disconnection (don't increment - swapped element needs processing)
|
||||||
|
this->remove_client_(client_index);
|
||||||
|
} else {
|
||||||
// Common case: process active client
|
// Common case: process active client
|
||||||
client->loop();
|
client->loop();
|
||||||
client_index++;
|
client_index++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void APIServer::remove_client_(size_t client_index) {
|
||||||
|
auto &client = this->clients_[client_index];
|
||||||
|
|
||||||
|
#ifdef USE_API_USER_DEFINED_ACTION_RESPONSES
|
||||||
|
this->unregister_active_action_calls_for_connection(client.get());
|
||||||
|
#endif
|
||||||
|
ESP_LOGV(TAG, "Remove connection %s", client->get_name());
|
||||||
|
|
||||||
|
#ifdef USE_API_CLIENT_DISCONNECTED_TRIGGER
|
||||||
|
// Save client info before closing socket and removal for the trigger
|
||||||
|
char peername_buf[socket::SOCKADDR_STR_LEN];
|
||||||
|
std::string client_name(client->get_name());
|
||||||
|
std::string client_peername(client->get_peername_to(peername_buf));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Close socket now (was deferred from on_fatal_error to allow getpeername)
|
||||||
|
client->helper_->close();
|
||||||
|
|
||||||
|
// Swap with the last element and pop (avoids expensive vector shifts)
|
||||||
|
if (client_index < this->clients_.size() - 1) {
|
||||||
|
std::swap(this->clients_[client_index], this->clients_.back());
|
||||||
|
}
|
||||||
|
this->clients_.pop_back();
|
||||||
|
|
||||||
|
// Last client disconnected - set warning and start tracking for reboot timeout
|
||||||
|
if (this->clients_.empty() && this->reboot_timeout_ != 0) {
|
||||||
|
this->status_set_warning();
|
||||||
|
this->last_connected_ = App.get_loop_component_start_time();
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef USE_API_CLIENT_DISCONNECTED_TRIGGER
|
||||||
|
// Fire trigger after client is removed so api.connected reflects the true state
|
||||||
|
this->client_disconnected_trigger_.trigger(client_name, client_peername);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void APIServer::accept_new_connections_() {
|
||||||
|
while (true) {
|
||||||
|
struct sockaddr_storage source_addr;
|
||||||
|
socklen_t addr_len = sizeof(source_addr);
|
||||||
|
|
||||||
|
auto sock = this->socket_->accept_loop_monitored((struct sockaddr *) &source_addr, &addr_len);
|
||||||
|
if (!sock)
|
||||||
|
break;
|
||||||
|
|
||||||
|
char peername[socket::SOCKADDR_STR_LEN];
|
||||||
|
sock->getpeername_to(peername);
|
||||||
|
|
||||||
|
// Check if we're at the connection limit
|
||||||
|
if (this->clients_.size() >= this->max_connections_) {
|
||||||
|
ESP_LOGW(TAG, "Max connections (%d), rejecting %s", this->max_connections_, peername);
|
||||||
|
// Immediately close - socket destructor will handle cleanup
|
||||||
|
sock.reset();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Rare case: handle disconnection
|
ESP_LOGD(TAG, "Accept %s", peername);
|
||||||
#ifdef USE_API_USER_DEFINED_ACTION_RESPONSES
|
|
||||||
this->unregister_active_action_calls_for_connection(client.get());
|
|
||||||
#endif
|
|
||||||
ESP_LOGV(TAG, "Remove connection %s", client->get_name());
|
|
||||||
|
|
||||||
#ifdef USE_API_CLIENT_DISCONNECTED_TRIGGER
|
auto *conn = new APIConnection(std::move(sock), this);
|
||||||
// Save client info before closing socket and removal for the trigger
|
this->clients_.emplace_back(conn);
|
||||||
char peername_buf[socket::SOCKADDR_STR_LEN];
|
conn->start();
|
||||||
std::string client_name(client->get_name());
|
|
||||||
std::string client_peername(client->get_peername_to(peername_buf));
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Close socket now (was deferred from on_fatal_error to allow getpeername)
|
// First client connected - clear warning and update timestamp
|
||||||
client->helper_->close();
|
if (this->clients_.size() == 1 && this->reboot_timeout_ != 0) {
|
||||||
|
this->status_clear_warning();
|
||||||
// Swap with the last element and pop (avoids expensive vector shifts)
|
|
||||||
if (client_index < this->clients_.size() - 1) {
|
|
||||||
std::swap(this->clients_[client_index], this->clients_.back());
|
|
||||||
}
|
|
||||||
this->clients_.pop_back();
|
|
||||||
|
|
||||||
// Last client disconnected - set warning and start tracking for reboot timeout
|
|
||||||
if (this->clients_.empty() && this->reboot_timeout_ != 0) {
|
|
||||||
this->status_set_warning();
|
|
||||||
this->last_connected_ = App.get_loop_component_start_time();
|
this->last_connected_ = App.get_loop_component_start_time();
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef USE_API_CLIENT_DISCONNECTED_TRIGGER
|
|
||||||
// Fire trigger after client is removed so api.connected reflects the true state
|
|
||||||
this->client_disconnected_trigger_.trigger(client_name, client_peername);
|
|
||||||
#endif
|
|
||||||
// Don't increment client_index since we need to process the swapped element
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -234,6 +234,11 @@ class APIServer : public Component,
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
// Accept incoming socket connections. Only called when socket has pending connections.
|
||||||
|
void __attribute__((noinline)) accept_new_connections_();
|
||||||
|
// Remove a disconnected client by index. Swaps with last element and pops.
|
||||||
|
void __attribute__((noinline)) remove_client_(size_t client_index);
|
||||||
|
|
||||||
#ifdef USE_API_NOISE
|
#ifdef USE_API_NOISE
|
||||||
bool update_noise_psk_(const SavedNoisePsk &new_psk, const LogString *save_log_msg, const LogString *fail_log_msg,
|
bool update_noise_psk_(const SavedNoisePsk &new_psk, const LogString *save_log_msg, const LogString *fail_log_msg,
|
||||||
const psk_t &active_psk, bool make_active);
|
const psk_t &active_psk, bool make_active);
|
||||||
|
|||||||
Reference in New Issue
Block a user