mirror of
https://github.com/esphome/esphome.git
synced 2026-02-08 00:31:58 +00:00
[api] Fire on_client_disconnected trigger after removing client from list (#13088)
This commit is contained in:
@@ -186,14 +186,17 @@ void APIServer::loop() {
|
||||
}
|
||||
|
||||
// Rare case: handle disconnection
|
||||
#ifdef USE_API_CLIENT_DISCONNECTED_TRIGGER
|
||||
this->client_disconnected_trigger_->trigger(std::string(client->get_name()), std::string(client->get_peername()));
|
||||
#endif
|
||||
#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 removal for the trigger
|
||||
std::string client_name(client->get_name());
|
||||
std::string client_peername(client->get_peername());
|
||||
#endif
|
||||
|
||||
// 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());
|
||||
@@ -205,6 +208,11 @@ void APIServer::loop() {
|
||||
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
|
||||
// Don't increment client_index since we need to process the swapped element
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,6 +24,14 @@ api:
|
||||
- logger.log:
|
||||
format: "Client %s disconnected from %s"
|
||||
args: [client_info.c_str(), client_address.c_str()]
|
||||
# Verify fix for issue #11131: api.connected should reflect true state in trigger
|
||||
- if:
|
||||
condition:
|
||||
api.connected:
|
||||
then:
|
||||
- logger.log: "Other clients still connected"
|
||||
else:
|
||||
- logger.log: "No clients remaining"
|
||||
|
||||
logger:
|
||||
level: DEBUG
|
||||
|
||||
@@ -23,12 +23,14 @@ async def test_api_conditional_memory(
|
||||
# Track log messages
|
||||
connected_future = loop.create_future()
|
||||
disconnected_future = loop.create_future()
|
||||
no_clients_future = loop.create_future()
|
||||
service_simple_future = loop.create_future()
|
||||
service_args_future = loop.create_future()
|
||||
|
||||
# Patterns to match in logs
|
||||
connected_pattern = re.compile(r"Client .* connected from")
|
||||
disconnected_pattern = re.compile(r"Client .* disconnected from")
|
||||
no_clients_pattern = re.compile(r"No clients remaining")
|
||||
service_simple_pattern = re.compile(r"Simple service called")
|
||||
service_args_pattern = re.compile(
|
||||
r"Service called with: test_string, 123, 1, 42\.50"
|
||||
@@ -40,6 +42,8 @@ async def test_api_conditional_memory(
|
||||
connected_future.set_result(True)
|
||||
elif not disconnected_future.done() and disconnected_pattern.search(line):
|
||||
disconnected_future.set_result(True)
|
||||
elif not no_clients_future.done() and no_clients_pattern.search(line):
|
||||
no_clients_future.set_result(True)
|
||||
elif not service_simple_future.done() and service_simple_pattern.search(line):
|
||||
service_simple_future.set_result(True)
|
||||
elif not service_args_future.done() and service_args_pattern.search(line):
|
||||
@@ -109,3 +113,7 @@ async def test_api_conditional_memory(
|
||||
|
||||
# Client disconnected here, wait for disconnect log
|
||||
await asyncio.wait_for(disconnected_future, timeout=5.0)
|
||||
|
||||
# Verify fix for issue #11131: api.connected should be false in trigger
|
||||
# when the last client disconnects
|
||||
await asyncio.wait_for(no_clients_future, timeout=5.0)
|
||||
|
||||
Reference in New Issue
Block a user