flip_store_github.c 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
  1. #include <github/flip_store_github.h>
  2. #include <flip_storage/flip_store_storage.h>
  3. // Helper to download a file from Github and save it to the storage
  4. bool flip_store_download_github_file(
  5. FlipperHTTP *fhttp,
  6. const char *filename,
  7. const char *author,
  8. const char *repo,
  9. const char *link)
  10. {
  11. if (!fhttp)
  12. {
  13. FURI_LOG_E(TAG, "FlipperHTTP is NULL");
  14. return false;
  15. }
  16. // Create the file directory
  17. char dir[256];
  18. snprintf(dir, sizeof(dir), STORAGE_EXT_PATH_PREFIX "/apps_data/flip_store/%s/%s/%s", author, repo, filename);
  19. snprintf(fhttp->file_path, sizeof(fhttp->file_path), "%s", dir);
  20. Storage *storage = furi_record_open(RECORD_STORAGE);
  21. storage_common_mkdir(storage, dir);
  22. furi_record_close(RECORD_STORAGE);
  23. fhttp->state = IDLE;
  24. fhttp->save_received_data = false;
  25. fhttp->is_bytes_request = true;
  26. return flipper_http_get_request_bytes(fhttp, link, "{\"Content-Type\":\"application/octet-stream\"}");
  27. }
  28. bool flip_store_get_github_contents(FlipperHTTP *fhttp, const char *author, const char *repo)
  29. {
  30. // Create Initial directory
  31. Storage *storage = furi_record_open(RECORD_STORAGE);
  32. char dir[256];
  33. // create a data directory: /ext/apps_data/flip_store/data
  34. snprintf(dir, sizeof(dir), STORAGE_EXT_PATH_PREFIX "/apps_data/flip_store/data");
  35. storage_common_mkdir(storage, dir);
  36. // create a data directory for the author: /ext/apps_data/flip_store/data/author
  37. snprintf(dir, sizeof(dir), STORAGE_EXT_PATH_PREFIX "/apps_data/flip_store/data/%s", author);
  38. storage_common_mkdir(storage, dir);
  39. // example path: /ext/apps_data/flip_store/data/author/info.json
  40. snprintf(fhttp->file_path, sizeof(fhttp->file_path), STORAGE_EXT_PATH_PREFIX "/apps_data/flip_store/data/%s/info.json", author);
  41. // create a data directory for the repo: /ext/apps_data/flip_store/data/author/repo
  42. snprintf(dir, sizeof(dir), STORAGE_EXT_PATH_PREFIX "/apps_data/flip_store/data/%s/%s", author, repo);
  43. storage_common_mkdir(storage, dir);
  44. // example path: /ext/apps_data/flip_store/author
  45. snprintf(dir, sizeof(dir), STORAGE_EXT_PATH_PREFIX "/apps_data/flip_store/%s", author);
  46. storage_common_mkdir(storage, dir);
  47. // example path: /ext/apps_data/flip_store/author/repo
  48. snprintf(dir, sizeof(dir), STORAGE_EXT_PATH_PREFIX "/apps_data/flip_store/%s/%s", author, repo);
  49. storage_common_mkdir(storage, dir);
  50. furi_record_close(RECORD_STORAGE);
  51. // get the contents of the repo
  52. char link[256];
  53. snprintf(link, sizeof(link), "https://api.github.com/repos/%s/%s/contents", author, repo);
  54. fhttp->save_received_data = true;
  55. return flipper_http_get_request_with_headers(fhttp, link, "{\"Content-Type\":\"application/json\"}");
  56. }
  57. bool flip_store_parse_github_contents(char *file_path, const char *author, const char *repo)
  58. {
  59. // Parse list of files and prepare to download
  60. FuriString *git_data = flipper_http_load_from_file(file_path);
  61. if (git_data == NULL)
  62. {
  63. FURI_LOG_E(TAG, "Failed to load received data from file.");
  64. return false;
  65. }
  66. FuriString *git_data_str = furi_string_alloc();
  67. if (!git_data_str)
  68. {
  69. FURI_LOG_E("Game", "Failed to allocate json_data string");
  70. return false;
  71. }
  72. furi_string_cat_str(git_data_str, "{\"json_data\":");
  73. if (memmgr_get_free_heap() < furi_string_size(git_data) + furi_string_size(git_data_str) + 2)
  74. {
  75. FURI_LOG_E(TAG, "Not enough memory to allocate git_data_str.");
  76. furi_string_free(git_data);
  77. furi_string_free(git_data_str);
  78. return false;
  79. }
  80. furi_string_cat(git_data_str, git_data);
  81. furi_string_free(git_data);
  82. furi_string_cat_str(git_data_str, "}");
  83. //
  84. int file_count = 0;
  85. for (int i = 0; i < MAX_GITHUB_FILES; i++)
  86. {
  87. FuriString *json_data_array = get_json_array_value_furi("json_data", i, git_data_str);
  88. if (!json_data_array)
  89. {
  90. break;
  91. }
  92. FuriString *type = get_json_value_furi("type", json_data_array);
  93. if (!type)
  94. {
  95. FURI_LOG_E(TAG, "Failed to get type.");
  96. furi_string_free(json_data_array);
  97. break;
  98. }
  99. // skip directories for now
  100. if (strcmp(furi_string_get_cstr(type), "file") != 0)
  101. {
  102. furi_string_free(type);
  103. furi_string_free(json_data_array);
  104. continue;
  105. }
  106. furi_string_free(type);
  107. FuriString *download_url = get_json_value_furi("download_url", json_data_array);
  108. if (!download_url)
  109. {
  110. FURI_LOG_E(TAG, "Failed to get download_url.");
  111. furi_string_free(json_data_array);
  112. break;
  113. }
  114. FuriString *name = get_json_value_furi("name", json_data_array);
  115. if (!name)
  116. {
  117. FURI_LOG_E(TAG, "Failed to get name.");
  118. furi_string_free(json_data_array);
  119. furi_string_free(download_url);
  120. break;
  121. }
  122. furi_string_free(json_data_array);
  123. // create json to save
  124. FuriString *json = furi_string_alloc();
  125. if (!json)
  126. {
  127. FURI_LOG_E(TAG, "Failed to allocate json.");
  128. furi_string_free(download_url);
  129. furi_string_free(name);
  130. break;
  131. }
  132. furi_string_cat_str(json, "{\"name\":\"");
  133. furi_string_cat(json, name);
  134. furi_string_cat_str(json, "\",\"link\":\"");
  135. furi_string_cat(json, download_url);
  136. furi_string_free(download_url);
  137. furi_string_cat_str(json, "\"}");
  138. // save the json to the data folder: /ext/apps_data/flip_store/data/author/repo
  139. char dir[256];
  140. snprintf(dir, sizeof(dir), STORAGE_EXT_PATH_PREFIX "/apps_data/flip_store/data/%s/%s/file%d.json", author, repo, file_count);
  141. if (!save_char_with_path(dir, furi_string_get_cstr(json)))
  142. {
  143. FURI_LOG_E(TAG, "Failed to save json.");
  144. }
  145. // free the json
  146. furi_string_free(name);
  147. furi_string_free(json);
  148. file_count++;
  149. }
  150. furi_string_free(git_data_str);
  151. // save file count
  152. char file_count_str[16];
  153. snprintf(file_count_str, sizeof(file_count_str), "%d", file_count);
  154. char file_count_dir[256]; // /ext/apps_data/flip_store/data/author/file_count.txt
  155. snprintf(file_count_dir, sizeof(file_count_dir), STORAGE_EXT_PATH_PREFIX "/apps_data/flip_store/data/%s/file_count.txt", author);
  156. return save_char_with_path(file_count_dir, file_count_str);
  157. }
  158. bool flip_store_install_all_github_files(FlipperHTTP *fhttp, const char *author, const char *repo)
  159. {
  160. if (!fhttp)
  161. {
  162. FURI_LOG_E(TAG, "FlipperHTTP is NULL");
  163. return false;
  164. }
  165. // get the file count
  166. char file_count_dir[256]; // /ext/apps_data/flip_store/data/author/file_count.txt
  167. snprintf(file_count_dir, sizeof(file_count_dir), STORAGE_EXT_PATH_PREFIX "/apps_data/flip_store/data/%s/file_count.txt", author);
  168. FuriString *file_count = flipper_http_load_from_file(file_count_dir);
  169. if (file_count == NULL)
  170. {
  171. FURI_LOG_E(TAG, "Failed to load file count.");
  172. return false;
  173. }
  174. int count = atoi(furi_string_get_cstr(file_count));
  175. furi_string_free(file_count);
  176. // install all files
  177. for (int i = 0; i < count; i++)
  178. {
  179. char file_dir[256]; // /ext/apps_data/flip_store/data/author/repo/file.json
  180. snprintf(file_dir, sizeof(file_dir), STORAGE_EXT_PATH_PREFIX "/apps_data/flip_store/data/%s/%s/file%d.json", author, repo, i);
  181. FuriString *file = flipper_http_load_from_file(file_dir);
  182. if (file == NULL)
  183. {
  184. FURI_LOG_E(TAG, "Failed to load file.");
  185. return false;
  186. }
  187. FuriString *name = get_json_value_furi("name", file);
  188. if (!name)
  189. {
  190. FURI_LOG_E(TAG, "Failed to get name.");
  191. furi_string_free(file);
  192. return false;
  193. }
  194. FuriString *link = get_json_value_furi("link", file);
  195. if (!link)
  196. {
  197. FURI_LOG_E(TAG, "Failed to get link.");
  198. furi_string_free(file);
  199. furi_string_free(name);
  200. return false;
  201. }
  202. furi_string_free(file);
  203. // download the file
  204. if (!flip_store_download_github_file(fhttp, furi_string_get_cstr(name), author, repo, furi_string_get_cstr(link)))
  205. {
  206. FURI_LOG_E(TAG, "Failed to download file.");
  207. furi_string_free(name);
  208. furi_string_free(link);
  209. return false;
  210. }
  211. furi_string_free(name);
  212. furi_string_free(link);
  213. }
  214. return true;
  215. }