Batch.cpp 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. #define LOG_LOCAL_LEVEL ESP_LOG_VERBOSE
  2. #include "Batch.h"
  3. #include "esp_event.h"
  4. #include "esp_http_client.h"
  5. #include "esp_log.h"
  6. #include "esp_netif.h"
  7. #include "esp_ota_ops.h"
  8. #include "esp_tls.h"
  9. #include "nvs_flash.h"
  10. #if CONFIG_MBEDTLS_CERTIFICATE_BUNDLE
  11. #include "esp_crt_bundle.h"
  12. #endif
  13. #include "esp_system.h"
  14. #include "http_handlers.h"
  15. #include "nvs.h"
  16. #include "nvs_flash.h"
  17. #include "nvs_utilities.h"
  18. #include "tools.h"
  19. #include <algorithm>
  20. #include <iomanip>
  21. #include <sstream>
  22. #include <string>
  23. #include <sys/param.h>
  24. #if CONFIG_WITH_METRICS
  25. static const char* const TAG = "MetricsBatch";
  26. static const char* const feature_evt_name = "$feature_flag_called";
  27. static const char* const feature_flag_name = "$feature_flag";
  28. static const char* const feature_flag_response_name = "$feature_flag_response";
  29. namespace Metrics {
  30. Event& Batch::add_feature_event() { return add_event(feature_evt_name); }
  31. void Batch::add_remove_feature_event(const char* name, bool active) {
  32. if (!active) {
  33. remove_feature_event(name);
  34. } else {
  35. add_event(feature_evt_name).add_property(feature_flag_name, name);
  36. }
  37. }
  38. Event& Batch::add_feature_variant_event(const char* const name, const char* const value) {
  39. return add_event(feature_evt_name)
  40. .add_property(feature_flag_name, name)
  41. .add_property(feature_flag_response_name, value);
  42. }
  43. void Batch::remove_feature_event(const char* name) {
  44. for (Metrics::Event& e : _events) {
  45. if (strcmp(e.get_name(), feature_evt_name) == 0) {
  46. e.remove_property(feature_flag_name, name);
  47. return;
  48. }
  49. }
  50. }
  51. cJSON* Batch::to_json() {
  52. cJSON* batch_json = cJSON_CreateArray();
  53. for (Metrics::Event& e : _events) {
  54. cJSON_AddItemToArray(batch_json, e.to_json(_metrics_uid.c_str()));
  55. }
  56. cJSON* message = cJSON_CreateObject();
  57. cJSON_AddItemToObject(message, "batch", batch_json);
  58. cJSON_AddStringToObject(message, "api_key", _api_key);
  59. return batch_json;
  60. }
  61. char* Batch::to_json_str() {
  62. cJSON* json = to_json();
  63. char* json_str = cJSON_PrintUnformatted(json);
  64. cJSON_Delete(json);
  65. return json_str;
  66. }
  67. void Batch::push() {
  68. int status_code = 0;
  69. if (_metrics_uid.empty() && !_warned) {
  70. ESP_LOGW(TAG, "Metrics disabled; no CID found");
  71. _warned = true;
  72. return;
  73. }
  74. char* json_str = to_json_str();
  75. ESP_LOGV(TAG, "Metrics payload: %s", json_str);
  76. uint32_t start_time = gettime_ms();
  77. status_code = metrics_http_post_request(json_str, _url);
  78. if (status_code == 200 || status_code == 204) {
  79. _events.clear();
  80. }
  81. FREE_AND_NULL(json_str)
  82. ESP_LOGD(TAG, "Total duration for metrics call: %lu. ", gettime_ms() - start_time);
  83. }
  84. void Batch::build_guid() {
  85. uint8_t raw[16];
  86. std::ostringstream oss;
  87. esp_fill_random(raw, 16);
  88. std::for_each(std::begin(raw), std::end(raw), [&oss](const uint8_t& byte) {
  89. oss << std::hex << std::setw(2) << std::setfill('0') << static_cast<int>(byte);
  90. });
  91. _metrics_uid = oss.str();
  92. }
  93. void Batch::assign_id() {
  94. size_t size = 0;
  95. esp_err_t esp_err = ESP_OK;
  96. _metrics_uid = std::string((char*)get_nvs_value_alloc_for_partition(
  97. NVS_DEFAULT_PART_NAME, TAG, NVS_TYPE_BLOB, "cid", &size));
  98. if (_metrics_uid[0] == 'G') {
  99. ESP_LOGW(TAG, "Invalid ID. %s", _metrics_uid.c_str());
  100. _metrics_uid.clear();
  101. }
  102. if (_metrics_uid.empty()) {
  103. build_guid();
  104. if (_metrics_uid.empty()) {
  105. ESP_LOGE(TAG, "ID Failed");
  106. return;
  107. }
  108. ESP_LOGW(TAG, "Metrics ID: %s", _metrics_uid.c_str());
  109. esp_err = store_nvs_value_len_for_partition(NVS_DEFAULT_PART_NAME, TAG, NVS_TYPE_BLOB,
  110. "cid", _metrics_uid.c_str(), _metrics_uid.length() + 1);
  111. if (esp_err != ESP_OK) {
  112. ESP_LOGE(TAG, "Store ID failed: %s", esp_err_to_name(esp_err));
  113. }
  114. }
  115. }
  116. } // namespace Metrics
  117. #endif