Przeglądaj źródła

Refactor JSON response

jblanked 1 rok temu
rodzic
commit
bddd5baf52
4 zmienionych plików z 148 dodań i 156 usunięć
  1. BIN
      .DS_Store
  2. 37 152
      flip_social_feed.h
  3. 2 2
      flipper_http.h
  4. 109 2
      jsmn.h

BIN
.DS_Store


+ 37 - 152
flip_social_feed.h

@@ -3,7 +3,7 @@
 
 static FlipSocialApp *app_instance = NULL;
 
-#define MAX_TOKENS 128 // Adjust based on expected JSON tokens
+#define MAX_TOKENS 512 // Adjust based on expected JSON tokens
 
 typedef struct
 {
@@ -46,170 +46,55 @@ bool flip_social_get_feed()
     fhttp.state = RECEIVING;
     return true;
 }
-
 bool flip_social_parse_json_feed()
 {
-    // Parse the JSON feed
-    if (fhttp.received_data != NULL)
+    if (fhttp.received_data == NULL)
     {
-        jsmn_parser parser;
-        jsmn_init(&parser);
-
-        // Allocate tokens array on the heap
-        jsmntok_t *tokens = malloc(sizeof(jsmntok_t) * MAX_TOKENS);
-        if (tokens == NULL)
-        {
-            FURI_LOG_E(TAG, "Failed to allocate memory for JSON tokens.");
-            return false;
-        }
+        FURI_LOG_E(TAG, "No data received.");
+        return false;
+    }
 
-        int ret = jsmn_parse(&parser, fhttp.received_data, strlen(fhttp.received_data), tokens, MAX_TOKENS);
+    // Remove newlines
+    char *pos = fhttp.received_data;
+    while ((pos = strchr(pos, '\n')) != NULL)
+    {
+        *pos = ' ';
+    }
 
-        if (ret < 0)
-        {
-            // Handle parsing errors
-            FURI_LOG_E(TAG, "Failed to parse JSON: %d", ret);
-            free(tokens);
-            return false;
-        }
+    // Initialize feed count
+    flip_social_feed.count = 0;
 
-        // Ensure that the root element is an object
-        if (ret < 1 || tokens[0].type != JSMN_OBJECT)
+    // Iterate through the feed array
+    for (int i = 0; i < MAX_FEED_ITEMS; i++)
+    {
+        // Parse each item in the array
+        char *item = get_json_array_value("feed", i, fhttp.received_data, MAX_TOKENS);
+        if (item == NULL)
         {
-            FURI_LOG_E(TAG, "Root element is not an object.");
-            free(tokens);
-            return false;
+            break;
         }
 
-        // Initialize feed count
-        flip_social_feed.count = 0;
+        // Extract individual fields from the JSON object
+        char *username = get_json_value("username", item, MAX_TOKENS);
+        char *message = get_json_value("message", item, MAX_TOKENS);
+        char *flipped = get_json_value("flipped", item, MAX_TOKENS);
+        char *id = get_json_value("id", item, MAX_TOKENS);
 
-        // Loop over all keys in the root object
-        int i = 0;
-        for (i = 1; i < ret; i++)
+        if (username == NULL || message == NULL || flipped == NULL || id == NULL)
         {
-            if (jsoneq(fhttp.received_data, &tokens[i], "feed") == 0)
-            {
-                // Found "feed" key
-                jsmntok_t *feed_array = &tokens[i + 1];
-
-                if (feed_array->type != JSMN_ARRAY)
-                {
-                    FURI_LOG_E(TAG, "'feed' is not an array.");
-                    break;
-                }
-
-                int j, k;
-                int feed_index = 0;
-
-                // Iterate over the feed array
-                for (j = 0; j < feed_array->size; j++)
-                {
-                    int idx = i + 2; // Position of the first feed item
-                    for (k = 0; k < j; k++)
-                    {
-                        // Skip tokens of previous feed items
-                        idx += tokens[idx].size * 2 + 1;
-                    }
-
-                    if (idx >= ret)
-                    {
-                        FURI_LOG_E(TAG, "Index out of bounds while accessing feed items.");
-                        break;
-                    }
-
-                    jsmntok_t *item = &tokens[idx];
-                    if (item->type != JSMN_OBJECT)
-                    {
-                        FURI_LOG_E(TAG, "Feed item is not an object.");
-                        continue;
-                    }
-
-                    // Variables to hold item data
-                    char *username = NULL;
-                    char *message = NULL;
-                    int flipped = 0;
-                    int id = 0;
-
-                    // Iterate over keys in the feed item
-                    int l;
-                    int item_size = item->size;
-                    int item_idx = idx + 1; // Position of the first key in the item
-
-                    for (l = 0; l < item_size; l++)
-                    {
-                        if (item_idx + 1 >= ret)
-                        {
-                            FURI_LOG_E(TAG, "Index out of bounds while accessing item properties.");
-                            break;
-                        }
-
-                        jsmntok_t *key = &tokens[item_idx];
-                        jsmntok_t *val = &tokens[item_idx + 1];
-
-                        if (jsoneq(fhttp.received_data, key, "username") == 0)
-                        {
-                            username = strndup(fhttp.received_data + val->start, val->end - val->start);
-                        }
-                        else if (jsoneq(fhttp.received_data, key, "message") == 0)
-                        {
-                            message = strndup(fhttp.received_data + val->start, val->end - val->start);
-                        }
-                        else if (jsoneq(fhttp.received_data, key, "flipped") == 0)
-                        {
-                            if (val->type == JSMN_PRIMITIVE)
-                            {
-                                if (strncmp(fhttp.received_data + val->start, "true", val->end - val->start) == 0)
-                                    flipped = 1;
-                                else
-                                    flipped = 0;
-                            }
-                        }
-                        else if (jsoneq(fhttp.received_data, key, "id") == 0)
-                        {
-                            if (val->type == JSMN_PRIMITIVE)
-                            {
-                                char id_str[16] = {0};
-                                uint32_t id_len = val->end - val->start;
-                                if (id_len >= sizeof(id_str))
-                                    id_len = sizeof(id_str) - 1;
-                                strncpy(id_str, fhttp.received_data + val->start, id_len);
-                                id = atoi(id_str);
-                            }
-                        }
-
-                        item_idx += 2; // Move to the next key-value pair
-                    }
-
-                    // Store the data in flip_social_feed
-                    if (username && message && feed_index < MAX_FEED_ITEMS)
-                    {
-                        flip_social_feed.usernames[feed_index] = username;
-                        flip_social_feed.messages[feed_index] = message;
-                        flip_social_feed.is_flipped[feed_index] = flipped;
-                        flip_social_feed.ids[feed_index] = id;
-                        feed_index++;
-                        flip_social_feed.count = feed_index;
-                    }
-                    else
-                    {
-                        // Free allocated memory if not stored
-                        if (username)
-                            free(username);
-                        if (message)
-                            free(message);
-                    }
-                }
-                break; // Feed processed
-            }
+            FURI_LOG_E(TAG, "Failed to parse item fields.");
+            free(item);
+            continue;
         }
 
-        free(tokens); // Free the allocated tokens array
-    }
-    else
-    {
-        FURI_LOG_E(TAG, "No data received.");
-        return false;
+        // Store parsed values
+        flip_social_feed.usernames[i] = username;
+        flip_social_feed.messages[i] = message;
+        flip_social_feed.is_flipped[i] = strstr(flipped, "true") != NULL;
+        flip_social_feed.ids[i] = atoi(id);
+        flip_social_feed.count++;
+
+        free(item);
     }
 
     return true;

+ 2 - 2
flipper_http.h

@@ -16,7 +16,7 @@
 #define TIMEOUT_DURATION_TICKS (2 * 1000) // 2 seconds
 #define BAUDRATE (115200)                 // UART baudrate
 #define RX_BUF_SIZE 128                   // UART RX buffer size
-#define RX_LINE_BUFFER_SIZE 2048          // UART RX line buffer size (increase for large responses)
+#define RX_LINE_BUFFER_SIZE 4096          // UART RX line buffer size (increase for large responses)
 
 // Forward declaration for callback
 typedef void (*FlipperHTTP_Callback)(const char *line, void *context);
@@ -724,7 +724,7 @@ void flipper_http_rx_callback(const char *line, void *context)
     }
 
     // Uncomment below line to log the data received over UART
-    // FURI_LOG_I(HTTP_TAG, "Received UART line: %s", line);
+    //(HTTP_TAG, "Received UART line: %s", line);
 
     // Check if we've started receiving data from a GET request
     if (fhttp.started_receiving_get)

+ 109 - 2
jsmn.h

@@ -527,6 +527,8 @@ extern "C"
 
 #endif /* JSMN_H */
 
+#ifndef JB_JSMN_EDIT
+#define JB_JSMN_EDIT
 /* Added in by JBlanked on 2024-10-16 for use in Flipper Zero SDK*/
 
 #include <string.h>
@@ -547,7 +549,6 @@ int jsoneq(const char *json, jsmntok_t *tok, const char *s)
 }
 
 // return the value of the key in the JSON data
-// works for the first level of the JSON data
 char *get_json_value(char *key, char *json_data, uint32_t max_tokens)
 {
   // Parse the JSON feed
@@ -612,4 +613,110 @@ char *get_json_value(char *key, char *json_data, uint32_t max_tokens)
   }
   FURI_LOG_E("JSMM.H", "Failed to find the key in the JSON.");
   return NULL; // Return NULL if something goes wrong
-}
+}
+
+// Revised get_json_array_value function
+char *get_json_array_value(char *key, uint32_t index, char *json_data, uint32_t max_tokens)
+{
+  // Retrieve the array string for the given key
+  char *array_str = get_json_value(key, json_data, max_tokens);
+  if (array_str == NULL)
+  {
+    FURI_LOG_E("JSMM.H", "Failed to get array for key: %s", key);
+    return NULL;
+  }
+
+  // Initialize the JSON parser
+  jsmn_parser parser;
+  jsmn_init(&parser);
+
+  // Allocate memory for JSON tokens
+  jsmntok_t *tokens = malloc(sizeof(jsmntok_t) * max_tokens);
+  if (tokens == NULL)
+  {
+    FURI_LOG_E("JSMM.H", "Failed to allocate memory for JSON tokens.");
+    free(array_str);
+    return NULL;
+  }
+
+  // Parse the JSON array
+  int ret = jsmn_parse(&parser, array_str, strlen(array_str), tokens, max_tokens);
+  if (ret < 0)
+  {
+    FURI_LOG_E("JSMM.H", "Failed to parse JSON array: %d", ret);
+    free(tokens);
+    free(array_str);
+    return NULL;
+  }
+
+  // Ensure the root element is an array
+  if (ret < 1 || tokens[0].type != JSMN_ARRAY)
+  {
+    FURI_LOG_E("JSMM.H", "Value for key '%s' is not an array.", key);
+    free(tokens);
+    free(array_str);
+    return NULL;
+  }
+
+  // Check if the index is within bounds
+  if (index >= (uint32_t)tokens[0].size)
+  {
+    FURI_LOG_E("JSMM.H", "Index %lu out of bounds for array with size %d.", (unsigned long)index, tokens[0].size);
+    free(tokens);
+    free(array_str);
+    return NULL;
+  }
+
+  // Locate the token corresponding to the desired array element
+  int current_token = 1; // Start after the array token
+  for (uint32_t i = 0; i < index; i++)
+  {
+    if (tokens[current_token].type == JSMN_OBJECT)
+    {
+      // For objects, skip all key-value pairs
+      current_token += 1 + 2 * tokens[current_token].size;
+    }
+    else if (tokens[current_token].type == JSMN_ARRAY)
+    {
+      // For nested arrays, skip all elements
+      current_token += 1 + tokens[current_token].size;
+    }
+    else
+    {
+      // For primitive types, simply move to the next token
+      current_token += 1;
+    }
+
+    // Safety check to prevent out-of-bounds
+    if (current_token >= ret)
+    {
+      FURI_LOG_E("JSMM.H", "Unexpected end of tokens while traversing array.");
+      free(tokens);
+      free(array_str);
+      return NULL;
+    }
+  }
+
+  // Extract the array element
+  jsmntok_t element = tokens[current_token];
+  int length = element.end - element.start;
+  char *value = malloc(length + 1);
+  if (value == NULL)
+  {
+    FURI_LOG_E("JSMM.H", "Failed to allocate memory for array element.");
+    free(tokens);
+    free(array_str);
+    return NULL;
+  }
+
+  // Copy the element value to a new string
+  strncpy(value, array_str + element.start, length);
+  value[length] = '\0'; // Null-terminate the string
+
+  // Clean up
+  free(tokens);
+  free(array_str);
+
+  return value;
+}
+#endif /* JB_JSMN_EDIT */