flip_social_feed.c 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277
  1. #include "flip_social_feed.h"
  2. bool flip_social_get_feed(bool alloc_http)
  3. {
  4. if (!app_instance)
  5. {
  6. FURI_LOG_E(TAG, "FlipSocialApp is NULL");
  7. return false;
  8. }
  9. if (alloc_http && !flipper_http_init(flipper_http_rx_callback, app_instance))
  10. {
  11. FURI_LOG_E(TAG, "Failed to initialize FlipperHTTP");
  12. return false;
  13. }
  14. // Get the feed from the server
  15. if (app_instance->login_username_logged_out == NULL)
  16. {
  17. FURI_LOG_E(TAG, "Username is NULL");
  18. return false;
  19. }
  20. snprintf(
  21. fhttp.file_path,
  22. sizeof(fhttp.file_path),
  23. STORAGE_EXT_PATH_PREFIX "/apps_data/flip_social/feed.json");
  24. fhttp.save_received_data = true;
  25. auth_headers_alloc();
  26. char command[96];
  27. snprintf(command, 96, "https://www.flipsocial.net/api/feed/50/%s/extended/", app_instance->login_username_logged_out);
  28. if (!flipper_http_get_request_with_headers(command, auth_headers))
  29. {
  30. FURI_LOG_E(TAG, "Failed to send HTTP request for feed");
  31. fhttp.state = ISSUE;
  32. return false;
  33. }
  34. fhttp.state = RECEIVING;
  35. return true;
  36. }
  37. FlipSocialFeedMini *flip_social_parse_json_feed()
  38. {
  39. // load the received data from the saved file
  40. FuriString *feed_data = flipper_http_load_from_file(fhttp.file_path);
  41. if (feed_data == NULL)
  42. {
  43. FURI_LOG_E(TAG, "Failed to load received data from file.");
  44. return NULL;
  45. }
  46. flipper_http_deinit();
  47. char *data_cstr = (char *)furi_string_get_cstr(feed_data);
  48. if (data_cstr == NULL)
  49. {
  50. FURI_LOG_E(TAG, "Failed to get C-string from FuriString.");
  51. furi_string_free(feed_data);
  52. return NULL;
  53. }
  54. FlipSocialFeedMini *feed_info = (FlipSocialFeedMini *)malloc(sizeof(FlipSocialFeedMini));
  55. if (!feed_info)
  56. {
  57. FURI_LOG_E(TAG, "Failed to allocate memory for feed_info");
  58. return NULL;
  59. }
  60. // Remove newlines
  61. char *pos = data_cstr;
  62. while ((pos = strchr(pos, '\n')) != NULL)
  63. {
  64. *pos = ' ';
  65. }
  66. int feed_count = 0;
  67. // Iterate through the feed array
  68. for (int i = 0; i < MAX_FEED_ITEMS; i++)
  69. {
  70. // Parse each item in the array
  71. char *item = get_json_array_value("feed", i, data_cstr, MAX_TOKENS);
  72. if (item == NULL)
  73. {
  74. break;
  75. }
  76. // Extract individual fields from the JSON object
  77. char *username = get_json_value("username", item, 40);
  78. char *message = get_json_value("message", item, 40);
  79. char *flipped = get_json_value("flipped", item, 40);
  80. char *flips = get_json_value("flip_count", item, 40);
  81. char *id = get_json_value("id", item, 40);
  82. if (username == NULL || message == NULL || flipped == NULL || id == NULL)
  83. {
  84. FURI_LOG_E(TAG, "Failed to parse item fields.");
  85. free(item);
  86. free(username);
  87. free(message);
  88. free(flipped);
  89. free(flips);
  90. free(id);
  91. continue;
  92. }
  93. if (!flip_social_save_post(id, item))
  94. {
  95. FURI_LOG_E(TAG, "Failed to save post.");
  96. free(item);
  97. free(username);
  98. free(message);
  99. free(flipped);
  100. free(flips);
  101. free(id);
  102. continue;
  103. }
  104. feed_count++;
  105. feed_info->ids[i] = atoi(id);
  106. // Free allocated memory
  107. free(item);
  108. free(username);
  109. free(message);
  110. free(flipped);
  111. free(flips);
  112. free(id);
  113. }
  114. // Store the number of feed items
  115. feed_info->count = feed_count;
  116. feed_info->index = 0;
  117. furi_string_free(feed_data);
  118. free(data_cstr);
  119. return feed_info;
  120. }
  121. bool flip_social_load_feed_post(int post_id)
  122. {
  123. char file_path[128];
  124. snprintf(file_path, sizeof(file_path), STORAGE_EXT_PATH_PREFIX "/apps_data/flip_social/feed_post_%d.json", post_id);
  125. // load the received data from the saved file
  126. FuriString *feed_data = flipper_http_load_from_file(file_path);
  127. if (feed_data == NULL)
  128. {
  129. FURI_LOG_E(TAG, "Failed to load received data from file.");
  130. return false;
  131. }
  132. char *data_cstr = (char *)furi_string_get_cstr(feed_data);
  133. if (data_cstr == NULL)
  134. {
  135. FURI_LOG_E(TAG, "Failed to get C-string from FuriString.");
  136. furi_string_free(feed_data);
  137. return false;
  138. }
  139. // Parse the feed post
  140. if (!flip_feed_item)
  141. {
  142. flip_feed_item = (FlipSocialFeedItem *)malloc(sizeof(FlipSocialFeedItem));
  143. if (flip_feed_item == NULL)
  144. {
  145. FURI_LOG_E(TAG, "Failed to allocate memory for feed post.");
  146. furi_string_free(feed_data);
  147. free(data_cstr);
  148. return false;
  149. }
  150. }
  151. // Extract individual fields from the JSON object
  152. char *username = get_json_value("username", data_cstr, 16);
  153. char *message = get_json_value("message", data_cstr, 16);
  154. char *flipped = get_json_value("flipped", data_cstr, 16);
  155. char *flips = get_json_value("flip_count", data_cstr, 16);
  156. char *id = get_json_value("id", data_cstr, 16);
  157. if (username == NULL || message == NULL || flipped == NULL || id == NULL)
  158. {
  159. FURI_LOG_E(TAG, "Failed to parse item fields.");
  160. free(username);
  161. free(message);
  162. free(flipped);
  163. free(flips);
  164. free(id);
  165. free(data_cstr);
  166. furi_string_free(feed_data);
  167. return false;
  168. }
  169. // Safely copy strings with bounds checking
  170. snprintf(flip_feed_item->username, MAX_USER_LENGTH, "%s", username);
  171. snprintf(flip_feed_item->message, MAX_MESSAGE_LENGTH, "%s", message);
  172. // Store boolean and integer values
  173. flip_feed_item->is_flipped = strstr(flipped, "true") != NULL;
  174. flip_feed_item->id = atoi(id);
  175. flip_feed_item->flips = atoi(flips);
  176. // Free allocated memory
  177. free(username);
  178. free(message);
  179. free(flipped);
  180. free(flips);
  181. free(id);
  182. furi_string_free(feed_data);
  183. free(data_cstr);
  184. return true;
  185. }
  186. bool flip_social_load_initial_feed(bool alloc_http)
  187. {
  188. if (fhttp.state == INACTIVE)
  189. {
  190. FURI_LOG_E(TAG, "HTTP state is INACTIVE");
  191. return false;
  192. }
  193. if (!easy_flipper_set_loading(&app_instance->loading, FlipSocialViewLoading, flip_social_callback_to_submenu_logged_in, &app_instance->view_dispatcher))
  194. {
  195. FURI_LOG_E(TAG, "Failed to set loading screen");
  196. return false;
  197. }
  198. view_dispatcher_switch_to_view(app_instance->view_dispatcher, FlipSocialViewLoading);
  199. if (flip_social_get_feed(alloc_http)) // start the async request
  200. {
  201. furi_timer_start(fhttp.get_timeout_timer, TIMEOUT_DURATION_TICKS);
  202. fhttp.state = RECEIVING;
  203. }
  204. else
  205. {
  206. FURI_LOG_E(HTTP_TAG, "Failed to send request");
  207. fhttp.state = ISSUE;
  208. view_dispatcher_switch_to_view(app_instance->view_dispatcher, FlipSocialViewLoggedInSubmenu);
  209. view_dispatcher_remove_view(app_instance->view_dispatcher, FlipSocialViewLoading);
  210. loading_free(app_instance->loading);
  211. return false;
  212. }
  213. while (fhttp.state == RECEIVING && furi_timer_is_running(fhttp.get_timeout_timer) > 0)
  214. {
  215. // Wait for the request to be received
  216. furi_delay_ms(100);
  217. }
  218. furi_timer_stop(fhttp.get_timeout_timer);
  219. // load feed info
  220. flip_feed_info = flip_social_parse_json_feed();
  221. if (!flip_feed_info || flip_feed_info->count < 1)
  222. {
  223. FURI_LOG_E(TAG, "Failed to parse JSON feed");
  224. view_dispatcher_switch_to_view(app_instance->view_dispatcher, FlipSocialViewLoggedInSubmenu);
  225. view_dispatcher_remove_view(app_instance->view_dispatcher, FlipSocialViewLoading);
  226. loading_free(app_instance->loading);
  227. return false;
  228. }
  229. // load the current feed post
  230. if (!flip_social_load_feed_post(flip_feed_info->ids[flip_feed_info->index]))
  231. {
  232. FURI_LOG_E(TAG, "Failed to load feed post");
  233. view_dispatcher_switch_to_view(app_instance->view_dispatcher, FlipSocialViewLoggedInSubmenu);
  234. view_dispatcher_remove_view(app_instance->view_dispatcher, FlipSocialViewLoading);
  235. loading_free(app_instance->loading);
  236. return false;
  237. }
  238. if (!feed_dialog_alloc())
  239. {
  240. FURI_LOG_E(TAG, "Failed to allocate feed dialog");
  241. view_dispatcher_switch_to_view(app_instance->view_dispatcher, FlipSocialViewLoggedInSubmenu);
  242. view_dispatcher_remove_view(app_instance->view_dispatcher, FlipSocialViewLoading);
  243. loading_free(app_instance->loading);
  244. return false;
  245. }
  246. view_dispatcher_switch_to_view(app_instance->view_dispatcher, FlipSocialViewFeedDialog);
  247. view_dispatcher_remove_view(app_instance->view_dispatcher, FlipSocialViewLoading);
  248. loading_free(app_instance->loading);
  249. return true;
  250. }