Compare commits

...

1 Commits

Author SHA1 Message Date
J. Nick Koston
b22a8b00bf [api] Guarantee SSO for action call timeout keys 2026-01-12 16:14:13 -10:00

View File

@@ -639,6 +639,14 @@ bool APIServer::teardown() {
#define USE_API_ACTION_CALL_TIMEOUT_MS 30000 // NOLINT
#endif
// SSO-friendly action call key - hex format guarantees max 11 chars ("ac_ffffffff")
// which fits in any std::string SSO buffer (typically 12-15 bytes)
static inline std::string make_action_call_key(uint32_t id) {
char buf[12];
size_t len = snprintf(buf, sizeof(buf), "ac_%x", id);
return std::string(buf, len);
}
uint32_t APIServer::register_active_action_call(uint32_t client_call_id, APIConnection *conn) {
uint32_t action_call_id = this->next_action_call_id_++;
// Handle wraparound (skip 0 as it means "no call")
@@ -648,18 +656,17 @@ uint32_t APIServer::register_active_action_call(uint32_t client_call_id, APIConn
this->active_action_calls_.push_back({action_call_id, client_call_id, conn});
// Schedule automatic cleanup after timeout (client will have given up by then)
this->set_timeout(str_sprintf("action_call_%u", action_call_id), USE_API_ACTION_CALL_TIMEOUT_MS,
[this, action_call_id]() {
ESP_LOGD(TAG, "Action call %u timed out", action_call_id);
this->unregister_active_action_call(action_call_id);
});
this->set_timeout(make_action_call_key(action_call_id), USE_API_ACTION_CALL_TIMEOUT_MS, [this, action_call_id]() {
ESP_LOGD(TAG, "Action call %u timed out", action_call_id);
this->unregister_active_action_call(action_call_id);
});
return action_call_id;
}
void APIServer::unregister_active_action_call(uint32_t action_call_id) {
// Cancel the timeout for this action call
this->cancel_timeout(str_sprintf("action_call_%u", action_call_id));
this->cancel_timeout(make_action_call_key(action_call_id));
// Swap-and-pop is more efficient than remove_if for unordered vectors
for (size_t i = 0; i < this->active_action_calls_.size(); i++) {
@@ -676,7 +683,7 @@ void APIServer::unregister_active_action_calls_for_connection(APIConnection *con
for (size_t i = 0; i < this->active_action_calls_.size();) {
if (this->active_action_calls_[i].connection == conn) {
// Cancel the timeout for this action call
this->cancel_timeout(str_sprintf("action_call_%u", this->active_action_calls_[i].action_call_id));
this->cancel_timeout(make_action_call_key(this->active_action_calls_[i].action_call_id));
std::swap(this->active_action_calls_[i], this->active_action_calls_.back());
this->active_action_calls_.pop_back();