feat(websocket): add ability to reconnect after close

Needed to support protocols like Socket.IO, where some
websocket closes issued by the server are reconnectable.
This commit is contained in:
Richard Allen
2025-01-30 12:06:11 -06:00
parent 85a8dac42d
commit 19891d8c3c
2 changed files with 21 additions and 6 deletions

View File

@ -1,5 +1,5 @@
/* /*
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD * SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
@ -80,6 +80,7 @@ typedef struct {
char *auth; char *auth;
int port; int port;
bool auto_reconnect; bool auto_reconnect;
bool close_reconnect;
void *user_context; void *user_context;
int network_timeout_ms; int network_timeout_ms;
char *subprotocol; char *subprotocol;
@ -376,6 +377,7 @@ static esp_err_t esp_websocket_client_set_config(esp_websocket_client_handle_t c
if (config->disable_auto_reconnect) { if (config->disable_auto_reconnect) {
cfg->auto_reconnect = false; cfg->auto_reconnect = false;
} }
cfg->close_reconnect = config->enable_close_reconnect;
if (config->disable_pingpong_discon) { if (config->disable_pingpong_discon) {
cfg->pingpong_timeout_sec = 0; cfg->pingpong_timeout_sec = 0;
@ -1127,12 +1129,23 @@ static void esp_websocket_client_task(void *pv)
} else if (ret < 0) { } else if (ret < 0) {
ESP_LOGW(TAG, "Connection terminated while waiting for clean TCP close"); ESP_LOGW(TAG, "Connection terminated while waiting for clean TCP close");
} }
if (client->config->close_reconnect && xSemaphoreTakeRecursive(client->lock, lock_timeout) == pdPASS) {
client->state = WEBSOCKET_STATE_WAIT_TIMEOUT;
client->error_handle.error_type = WEBSOCKET_ERROR_TYPE_SERVER_CLOSE;
esp_transport_close(client->transport);
esp_websocket_client_dispatch_event(client, WEBSOCKET_EVENT_CLOSED, NULL, 0);
client->reconnect_tick_ms = _tick_get_ms();
ESP_LOGI(TAG, "Reconnect after %d ms", client->wait_timeout_ms);
xEventGroupClearBits(client->status_bits, STOPPED_BIT | CLOSE_FRAME_SENT_BIT);
xSemaphoreGiveRecursive(client->lock);
} else {
client->run = false; client->run = false;
client->state = WEBSOCKET_STATE_UNKNOW; client->state = WEBSOCKET_STATE_UNKNOW;
esp_websocket_client_dispatch_event(client, WEBSOCKET_EVENT_CLOSED, NULL, 0); esp_websocket_client_dispatch_event(client, WEBSOCKET_EVENT_CLOSED, NULL, 0);
break; break;
} }
} }
}
esp_websocket_client_dispatch_event(client, WEBSOCKET_EVENT_FINISH, NULL, 0); esp_websocket_client_dispatch_event(client, WEBSOCKET_EVENT_FINISH, NULL, 0);
esp_transport_close(client->transport); esp_transport_close(client->transport);

View File

@ -48,7 +48,8 @@ typedef enum {
WEBSOCKET_ERROR_TYPE_NONE = 0, WEBSOCKET_ERROR_TYPE_NONE = 0,
WEBSOCKET_ERROR_TYPE_TCP_TRANSPORT, WEBSOCKET_ERROR_TYPE_TCP_TRANSPORT,
WEBSOCKET_ERROR_TYPE_PONG_TIMEOUT, WEBSOCKET_ERROR_TYPE_PONG_TIMEOUT,
WEBSOCKET_ERROR_TYPE_HANDSHAKE WEBSOCKET_ERROR_TYPE_HANDSHAKE,
WEBSOCKET_ERROR_TYPE_SERVER_CLOSE
} esp_websocket_error_type_t; } esp_websocket_error_type_t;
/** /**
@ -101,6 +102,7 @@ typedef struct {
const char *password; /*!< Using for Http authentication */ const char *password; /*!< Using for Http authentication */
const char *path; /*!< HTTP Path, if not set, default is `/` */ const char *path; /*!< HTTP Path, if not set, default is `/` */
bool disable_auto_reconnect; /*!< Disable the automatic reconnect function when disconnected */ bool disable_auto_reconnect; /*!< Disable the automatic reconnect function when disconnected */
bool enable_close_reconnect; /*!< Enable reconnect after server close */
void *user_context; /*!< HTTP user data context */ void *user_context; /*!< HTTP user data context */
int task_prio; /*!< Websocket task priority */ int task_prio; /*!< Websocket task priority */
const char *task_name; /*!< Websocket task name */ const char *task_name; /*!< Websocket task name */