Bläddra i källkod

esp_http_client: Add support for esp_events

Harshit Malpani 3 år sedan
förälder
incheckning
674fd8feb8

+ 3 - 1
components/esp_http_client/CMakeLists.txt

@@ -1,5 +1,7 @@
 if(NOT ${IDF_TARGET} STREQUAL "linux")
-    set(req lwip)
+    set(req lwip esp_event)
+else()
+    set(req esp_stubs)
 endif()
 
 idf_component_register(SRCS "esp_http_client.c"

+ 33 - 0
components/esp_http_client/esp_http_client.c

@@ -25,6 +25,8 @@
 #include "esp_transport_ssl.h"
 #endif
 
+ESP_EVENT_DEFINE_BASE(ESP_HTTP_CLIENT_EVENT);
+
 static const char *TAG = "HTTP_CLIENT";
 
 /**
@@ -183,6 +185,14 @@ static esp_err_t http_dispatch_event(esp_http_client_t *client, esp_http_client_
     return ESP_OK;
 }
 
+static void http_dispatch_event_to_event_loop(int32_t event_id, const void* event_data, size_t event_data_size)
+{
+    esp_err_t err = esp_event_post(ESP_HTTP_CLIENT_EVENT, event_id, event_data, event_data_size, portMAX_DELAY);
+    if (err != ESP_OK) {
+        ESP_LOGE(TAG, "Failed to post https_ota event: %"PRId32", error: %s", event_id, esp_err_to_name(err));
+    }
+}
+
 static int http_on_message_begin(http_parser *parser)
 {
     esp_http_client_t *client = parser->data;
@@ -211,6 +221,7 @@ static int http_on_header_event(esp_http_client_handle_t client)
         client->event.header_key = client->current_header_key;
         client->event.header_value = client->current_header_value;
         http_dispatch_event(client, HTTP_EVENT_ON_HEADER, NULL, 0);
+        http_dispatch_event_to_event_loop(HTTP_EVENT_ON_HEADER, &client, sizeof(esp_http_client_handle_t));
         free(client->current_header_key);
         free(client->current_header_value);
         client->current_header_key = NULL;
@@ -293,6 +304,10 @@ static int http_on_body(http_parser *parser, const char *at, size_t length)
     client->response->data_process += length;
     client->response->buffer->raw_len += length;
     http_dispatch_event(client, HTTP_EVENT_ON_DATA, (void *)at, length);
+    esp_http_client_on_data_t evt_data = {};
+    evt_data.data_process = client->response->data_process;
+    evt_data.client = client;
+    http_dispatch_event_to_event_loop(HTTP_EVENT_ON_DATA, &evt_data, sizeof(esp_http_client_on_data_t));
     return 0;
 }
 
@@ -891,6 +906,11 @@ static esp_err_t esp_http_check_response(esp_http_client_handle_t client)
                     return ESP_FAIL;
                 };
             }
+            esp_http_client_redirect_event_data_t evt_data = {
+                .status_code = client->response->status_code,
+                .client = client,
+            };
+            http_dispatch_event_to_event_loop(HTTP_EVENT_REDIRECT, &evt_data, sizeof(esp_http_client_redirect_event_data_t));
             break;
         case HttpStatus_Unauthorized:
             esp_http_client_add_auth(client);
@@ -1138,6 +1158,7 @@ int esp_http_client_read(esp_http_client_handle_t client, char *buffer, int len)
 
             if (rlen < 0 && ridx == 0 && !esp_http_client_is_complete_data_received(client)) {
                 http_dispatch_event(client, HTTP_EVENT_ERROR, esp_transport_get_error_handle(client->transport), 0);
+                http_dispatch_event_to_event_loop(HTTP_EVENT_ERROR, &client, sizeof(esp_http_client_handle_t));
                 return ESP_FAIL;
             }
             return ridx;
@@ -1172,6 +1193,7 @@ esp_err_t esp_http_client_perform(esp_http_client_handle_t client)
                         return ESP_ERR_HTTP_EAGAIN;
                     }
                     http_dispatch_event(client, HTTP_EVENT_ERROR, esp_transport_get_error_handle(client->transport), 0);
+                    http_dispatch_event_to_event_loop(HTTP_EVENT_ERROR, &client, sizeof(esp_http_client_handle_t));
                     return err;
                 }
                 /* falls through */
@@ -1181,6 +1203,7 @@ esp_err_t esp_http_client_perform(esp_http_client_handle_t client)
                         return ESP_ERR_HTTP_EAGAIN;
                     }
                     http_dispatch_event(client, HTTP_EVENT_ERROR, esp_transport_get_error_handle(client->transport), 0);
+                    http_dispatch_event_to_event_loop(HTTP_EVENT_ERROR, &client, sizeof(esp_http_client_handle_t));
                     return err;
                 }
                 /* falls through */
@@ -1190,6 +1213,7 @@ esp_err_t esp_http_client_perform(esp_http_client_handle_t client)
                         return ESP_ERR_HTTP_EAGAIN;
                     }
                     http_dispatch_event(client, HTTP_EVENT_ERROR, esp_transport_get_error_handle(client->transport), 0);
+                    http_dispatch_event_to_event_loop(HTTP_EVENT_ERROR, &client, sizeof(esp_http_client_handle_t));
                     return err;
                 }
                 /* falls through */
@@ -1209,9 +1233,11 @@ esp_err_t esp_http_client_perform(esp_http_client_handle_t client)
                         ESP_LOGW(TAG, "Close connection due to FIN received");
                         esp_http_client_close(client);
                         http_dispatch_event(client, HTTP_EVENT_ERROR, esp_transport_get_error_handle(client->transport), 0);
+                        http_dispatch_event_to_event_loop(HTTP_EVENT_ERROR, &client, sizeof(esp_http_client_handle_t));
                         return ESP_ERR_HTTP_CONNECTION_CLOSED;
                     }
                     http_dispatch_event(client, HTTP_EVENT_ERROR, esp_transport_get_error_handle(client->transport), 0);
+                    http_dispatch_event_to_event_loop(HTTP_EVENT_ERROR, &client, sizeof(esp_http_client_handle_t));
                     return ESP_ERR_HTTP_FETCH_HEADER;
                 }
                 /* falls through */
@@ -1222,6 +1248,7 @@ esp_err_t esp_http_client_perform(esp_http_client_handle_t client)
                 if ((err = esp_http_check_response(client)) != ESP_OK) {
                     ESP_LOGE(TAG, "Error response");
                     http_dispatch_event(client, HTTP_EVENT_ERROR, esp_transport_get_error_handle(client->transport), 0);
+                    http_dispatch_event_to_event_loop(HTTP_EVENT_ERROR, &client, sizeof(esp_http_client_handle_t));
                     return err;
                 }
                 while (client->response->is_chunked && !client->is_chunk_complete) {
@@ -1243,6 +1270,7 @@ esp_err_t esp_http_client_perform(esp_http_client_handle_t client)
                     }
                 }
                 http_dispatch_event(client, HTTP_EVENT_ON_FINISH, NULL, 0);
+                http_dispatch_event_to_event_loop(HTTP_EVENT_ON_FINISH, &client, sizeof(esp_http_client_handle_t));
 
                 client->response->buffer->raw_len = 0;
                 if (!http_should_keep_alive(client->parser)) {
@@ -1340,6 +1368,7 @@ static esp_err_t esp_http_client_connect(esp_http_client_handle_t client)
         }
         client->state = HTTP_STATE_CONNECTED;
         http_dispatch_event(client, HTTP_EVENT_ON_CONNECTED, NULL, 0);
+        http_dispatch_event_to_event_loop(HTTP_EVENT_ON_CONNECTED, &client, sizeof(esp_http_client_handle_t));
     }
     return ESP_OK;
 }
@@ -1439,6 +1468,7 @@ static esp_err_t esp_http_client_request_send(esp_http_client_handle_t client, i
     client->data_written_index = 0;
     client->data_write_left = client->post_len;
     http_dispatch_event(client, HTTP_EVENT_HEADERS_SENT, NULL, 0);
+    http_dispatch_event_to_event_loop(HTTP_EVENT_HEADERS_SENT, &client, sizeof(esp_http_client_handle_t));
     client->state = HTTP_STATE_REQ_COMPLETE_HEADER;
     return ESP_OK;
 }
@@ -1477,10 +1507,12 @@ esp_err_t esp_http_client_open(esp_http_client_handle_t client, int write_len)
     esp_err_t err;
     if ((err = esp_http_client_connect(client)) != ESP_OK) {
         http_dispatch_event(client, HTTP_EVENT_ERROR, esp_transport_get_error_handle(client->transport), 0);
+        http_dispatch_event_to_event_loop(HTTP_EVENT_ERROR, &client, sizeof(esp_http_client_handle_t));
         return err;
     }
     if ((err = esp_http_client_request_send(client, write_len)) != ESP_OK) {
         http_dispatch_event(client, HTTP_EVENT_ERROR, esp_transport_get_error_handle(client->transport), 0);
+        http_dispatch_event_to_event_loop(HTTP_EVENT_ERROR, &client, sizeof(esp_http_client_handle_t));
         return err;
     }
     return ESP_OK;
@@ -1510,6 +1542,7 @@ esp_err_t esp_http_client_close(esp_http_client_handle_t client)
 {
     if (client->state >= HTTP_STATE_INIT) {
         http_dispatch_event(client, HTTP_EVENT_DISCONNECTED, esp_transport_get_error_handle(client->transport), 0);
+        http_dispatch_event_to_event_loop(HTTP_EVENT_DISCONNECTED, &client, sizeof(esp_http_client_handle_t));
         client->state = HTTP_STATE_INIT;
         return esp_transport_close(client->transport);
     }

+ 18 - 0
components/esp_http_client/include/esp_http_client.h

@@ -18,6 +18,9 @@ extern "C" {
 
 #define DEFAULT_HTTP_BUF_SIZE (512)
 
+#include "esp_event.h"
+ESP_EVENT_DECLARE_BASE(ESP_HTTP_CLIENT_EVENT);
+
 typedef struct esp_http_client *esp_http_client_handle_t;
 typedef struct esp_http_client_event *esp_http_client_event_handle_t;
 
@@ -50,6 +53,21 @@ typedef struct esp_http_client_event {
     char *header_value;                     /*!< For HTTP_EVENT_ON_HEADER event_id, it's store current http header value */
 } esp_http_client_event_t;
 
+/**
+ * @brief      Argument structure for HTTP_EVENT_ON_DATA event
+ */
+typedef struct esp_http_client_on_data {
+    esp_http_client_handle_t client;    /*!< Client handle */
+    int64_t data_process;               /*!< Total data processed */
+} esp_http_client_on_data_t;
+
+/**
+ * @brief      Argument structure for HTTP_EVENT_REDIRECT event
+ */
+typedef struct esp_http_client_redirect_event_data {
+    esp_http_client_handle_t client;    /*!< Client handle */
+    int status_code;                    /*!< Status Code */
+} esp_http_client_redirect_event_data_t;
 
 /**
  * @brief      HTTP Client transport

+ 27 - 0
docs/en/api-reference/protocols/esp_http_client.rst

@@ -110,6 +110,33 @@ Examples of Authentication Configuration
                 .auth_type = HTTP_AUTH_TYPE_BASIC,
             };
 
+Event Handling
+--------------
+
+ESP HTTP Client supports event handling by triggering an event handler corresponding to the event which took place.
+:cpp:enum:`esp_http_client_event_id_t` contains all the events which could occur while performing an HTTP request using the ESP HTTP Client.
+
+To enable event handling, you just need to set a callback function using the :cpp:member:`esp_http_client_config_t::event_handler` member.
+
+ESP HTTP Client Diagnostic Information
+--------------------------------------
+Diagnostic information could be helpful to gain insights into a problem. In the case of ESP HTTP Client, this diagnostic information can be collected by registering an event handler with :doc:`the Event Loop library <../system/esp_event>`.
+This feature has been added by keeping in mind the `ESP Insights <https://github.com/espressif/esp-insights>`_ framework which collects the diagnostic information. However, this feature can also be used without any dependency on ESP Insights framework for the diagnostic purpose.
+Event handler can be registered to the event loop using the :cpp:func:`esp_event_handler_register` function.
+
+Expected data types for different HTTP Client events in the event loop:
+
+    - HTTP_EVENT_ERROR            :   ``esp_http_client_handle_t``
+    - HTTP_EVENT_ON_CONNECTED     :   ``esp_http_client_handle_t``
+    - HTTP_EVENT_HEADERS_SENT     :   ``esp_http_client_handle_t``
+    - HTTP_EVENT_ON_HEADER        :   ``esp_http_client_handle_t``
+    - HTTP_EVENT_ON_DATA          :   ``esp_http_client_on_data_t``
+    - HTTP_EVENT_ON_FINISH        :   ``esp_http_client_handle_t``
+    - HTTP_EVENT_DISCONNECTED     :   ``esp_http_client_handle_t``
+    - HTTP_EVENT_REDIRECT         :   ``esp_http_client_redirect_event_data_t``
+
+The :cpp:type:`esp_http_client_handle_t` received along with the event data will be valid until :cpp:enumerator:`HTTP_EVENT_DISCONNECTED <esp_http_client_event_id_t::HTTP_EVENT_DISCONNECTED>` is not received. This handle has been sent primarily to differentiate between different client
+connections and must not be used for any other purpose (as it may change based on client connection state).
 
 API Reference
 -------------

+ 7 - 0
examples/protocols/linux_stubs/esp_stubs/esp_stubs.c

@@ -6,6 +6,7 @@
 #include <stdlib.h>
 #include "esp_err.h"
 #include "esp_log.h"
+#include "esp_event.h"
 
 extern void app_main(void);
 
@@ -14,6 +15,12 @@ esp_err_t esp_event_loop_create_default(void)
     return ESP_OK;
 }
 
+esp_err_t esp_event_post(esp_event_base_t event_base, int32_t event_id,
+        const void* event_data, size_t event_data_size, TickType_t ticks_to_wait)
+{
+    return ESP_OK;
+}
+
 esp_err_t esp_netif_init(void)
 {
     return ESP_OK;

+ 9 - 0
examples/protocols/linux_stubs/esp_stubs/include/esp_event.h

@@ -5,4 +5,13 @@
  */
 #include "esp_err.h"
 
+typedef const char*  esp_event_base_t; /**< unique pointer to a subsystem that exposes events */
+typedef unsigned long TickType_t;
+
+#define ESP_EVENT_DECLARE_BASE(id) extern esp_event_base_t id
+#define ESP_EVENT_DEFINE_BASE(id) esp_event_base_t id = #id
+
 esp_err_t esp_event_loop_create_default(void);
+
+esp_err_t esp_event_post(esp_event_base_t event_base, int32_t event_id,
+        const void* event_data, size_t event_data_size, TickType_t ticks_to_wait);