| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365 |
- #include <github/flip_store_github.h>
- #include <flip_storage/flip_store_storage.h>
- // Helper to download a file from Github and save it to the storage
- bool flip_store_download_github_file(
- FlipperHTTP *fhttp,
- const char *filename,
- const char *author,
- const char *repo,
- const char *link)
- {
- if (!fhttp)
- {
- FURI_LOG_E(TAG, "FlipperHTTP is NULL");
- return false;
- }
- // Create the file directory
- char dir[256];
- snprintf(dir, sizeof(dir), STORAGE_EXT_PATH_PREFIX "/apps_data/flip_store/%s/%s/%s", author, repo, filename);
- snprintf(fhttp->file_path, sizeof(fhttp->file_path), "%s", dir);
- Storage *storage = furi_record_open(RECORD_STORAGE);
- storage_common_mkdir(storage, dir);
- furi_record_close(RECORD_STORAGE);
- fhttp->state = IDLE;
- fhttp->save_received_data = false;
- fhttp->is_bytes_request = true;
- return flipper_http_get_request_bytes(fhttp, link, "{\"Content-Type\":\"application/octet-stream\"}");
- }
- bool flip_store_get_github_contents(FlipperHTTP *fhttp, const char *author, const char *repo)
- {
- // Create Initial directory
- Storage *storage = furi_record_open(RECORD_STORAGE);
- char dir[256];
- // create a data directory: /ext/apps_data/flip_store/data
- snprintf(dir, sizeof(dir), STORAGE_EXT_PATH_PREFIX "/apps_data/flip_store/data");
- storage_common_mkdir(storage, dir);
- // create a data directory for the author: /ext/apps_data/flip_store/data/author
- snprintf(dir, sizeof(dir), STORAGE_EXT_PATH_PREFIX "/apps_data/flip_store/data/%s", author);
- storage_common_mkdir(storage, dir);
- // example path: /ext/apps_data/flip_store/data/author/info.json
- snprintf(fhttp->file_path, sizeof(fhttp->file_path), STORAGE_EXT_PATH_PREFIX "/apps_data/flip_store/data/%s/info.json", author);
- // create a data directory for the repo: /ext/apps_data/flip_store/data/author/repo
- snprintf(dir, sizeof(dir), STORAGE_EXT_PATH_PREFIX "/apps_data/flip_store/data/%s/%s", author, repo);
- storage_common_mkdir(storage, dir);
- // example path: /ext/apps_data/flip_store/author
- snprintf(dir, sizeof(dir), STORAGE_EXT_PATH_PREFIX "/apps_data/flip_store/%s", author);
- storage_common_mkdir(storage, dir);
- // example path: /ext/apps_data/flip_store/author/repo
- snprintf(dir, sizeof(dir), STORAGE_EXT_PATH_PREFIX "/apps_data/flip_store/%s/%s", author, repo);
- storage_common_mkdir(storage, dir);
- furi_record_close(RECORD_STORAGE);
- // get the contents of the repo
- char link[256];
- snprintf(link, sizeof(link), "https://api.github.com/repos/%s/%s/contents", author, repo);
- fhttp->save_received_data = true;
- return flipper_http_get_request_with_headers(fhttp, link, "{\"Content-Type\":\"application/json\"}");
- }
- #include <stdio.h>
- #include <string.h>
- #include <stdbool.h>
- // Assuming necessary headers and definitions for FuriString, FURI_LOG, etc., are included.
- bool flip_store_parse_github_contents(char *file_path, const char *author, const char *repo)
- {
- FURI_LOG_I(TAG, "Parsing Github contents from %s - %s.", author, repo);
- if (!file_path || !author || !repo)
- {
- FURI_LOG_E(TAG, "Invalid arguments.");
- return false;
- }
- // Load JSON data from file
- FuriString *git_data = flipper_http_load_from_file(file_path);
- if (git_data == NULL)
- {
- FURI_LOG_E(TAG, "Failed to load received data from file.");
- return false;
- }
- // Allocate a new FuriString to hold the entire JSON structure
- FuriString *git_data_str = furi_string_alloc();
- if (!git_data_str)
- {
- FURI_LOG_E(TAG, "Failed to allocate git_data_str.");
- furi_string_free(git_data);
- return false;
- }
- // Construct the full JSON string
- furi_string_cat_str(git_data_str, "{\"json_data\":");
- furi_string_cat(git_data_str, git_data);
- furi_string_cat_str(git_data_str, "}");
- furi_string_free(git_data); // Free the original git_data as it's now part of git_data_str
- // Check available memory
- const size_t additional_bytes = strlen("{\"json_data\":") + 1; // +1 for the closing "}"
- if (memmgr_get_free_heap() < furi_string_size(git_data_str) + additional_bytes)
- {
- FURI_LOG_E(TAG, "Not enough memory to allocate git_data_str.");
- furi_string_free(git_data_str);
- return false;
- }
- int file_count = 0;
- char dir[512]; // Increased size to accommodate longer paths if necessary
- FURI_LOG_I(TAG, "Looping through Github files.");
- FURI_LOG_I(TAG, "Available memory: %d bytes", memmgr_get_free_heap());
- // Get the C-string and its length for processing
- char *data = (char *)furi_string_get_cstr(git_data_str);
- size_t data_len = furi_string_size(git_data_str);
- size_t pos = 0; // Current position in the data string
- // Locate the start of the JSON array
- char *array_start = strchr(data, '[');
- if (!array_start)
- {
- FURI_LOG_E(TAG, "Invalid JSON format: '[' not found.");
- furi_string_free(git_data_str);
- return false;
- }
- pos = array_start - data; // Update position to the start of the array
- size_t brace_count = 0;
- size_t obj_start = 0;
- bool in_string = false; // To handle braces inside strings
- while (pos < data_len && file_count < MAX_GITHUB_FILES)
- {
- char current = data[pos];
- // Toggle in_string flag if a quote is found (handling escaped quotes)
- if (current == '"' && (pos == 0 || data[pos - 1] != '\\'))
- {
- in_string = !in_string;
- }
- if (!in_string)
- {
- if (current == '{')
- {
- if (brace_count == 0)
- {
- obj_start = pos; // Potential start of a JSON object
- }
- brace_count++;
- }
- else if (current == '}')
- {
- brace_count--;
- if (brace_count == 0)
- {
- size_t obj_end = pos;
- size_t obj_length = obj_end - obj_start + 1;
- // Extract the JSON object substring
- char *obj_str = malloc(obj_length + 1);
- if (!obj_str)
- {
- FURI_LOG_E(TAG, "Memory allocation failed for obj_str.");
- break;
- }
- strncpy(obj_str, data + obj_start, obj_length);
- obj_str[obj_length] = '\0'; // Null-terminate
- FuriString *json_data_array = furi_string_alloc();
- furi_string_set(json_data_array, obj_str); // Set the string to the allocated memory
- free(obj_str); // Free the temporary C-string
- if (!json_data_array)
- {
- FURI_LOG_E(TAG, "Failed to initialize json_data_array.");
- break;
- }
- FURI_LOG_I(TAG, "Loaded json data array value %d. Available memory: %d bytes", file_count, memmgr_get_free_heap());
- // Extract "type" field
- FuriString *type = get_json_value_furi("type", json_data_array);
- if (!type)
- {
- FURI_LOG_E(TAG, "Failed to get type.");
- furi_string_free(json_data_array);
- break;
- }
- // Skip non-file types (e.g., directories)
- if (strcmp(furi_string_get_cstr(type), "file") != 0)
- {
- furi_string_free(type);
- furi_string_free(json_data_array);
- pos = obj_end + 1; // Move past this object
- continue;
- }
- furi_string_free(type);
- // Extract "download_url" and "name"
- FuriString *download_url = get_json_value_furi("download_url", json_data_array);
- if (!download_url)
- {
- FURI_LOG_E(TAG, "Failed to get download_url.");
- furi_string_free(json_data_array);
- break;
- }
- FuriString *name = get_json_value_furi("name", json_data_array);
- if (!name)
- {
- FURI_LOG_E(TAG, "Failed to get name.");
- furi_string_free(json_data_array);
- furi_string_free(download_url);
- break;
- }
- furi_string_free(json_data_array);
- FURI_LOG_I(TAG, "Received name and download_url. Available memory: %d bytes", memmgr_get_free_heap());
- // Create JSON to save
- FuriString *json = furi_string_alloc();
- if (!json)
- {
- FURI_LOG_E(TAG, "Failed to allocate json.");
- furi_string_free(download_url);
- furi_string_free(name);
- break;
- }
- furi_string_cat_str(json, "{\"name\":\"");
- furi_string_cat(json, name);
- furi_string_cat_str(json, "\",\"link\":\"");
- furi_string_cat(json, download_url);
- furi_string_cat_str(json, "\"}");
- FURI_LOG_I(TAG, "Created json. Available memory: %d bytes", memmgr_get_free_heap());
- // Save the JSON to the data folder: /ext/apps_data/flip_store/data/author/repo/fileX.json
- snprintf(dir, sizeof(dir), STORAGE_EXT_PATH_PREFIX "/apps_data/flip_store/data/%s/%s/file%d.json", author, repo, file_count);
- if (!save_char_with_path(dir, furi_string_get_cstr(json)))
- {
- FURI_LOG_E(TAG, "Failed to save json.");
- }
- FURI_LOG_I(TAG, "Saved file %s.", furi_string_get_cstr(name));
- // Free allocated resources
- furi_string_free(name);
- furi_string_free(download_url);
- furi_string_free(json);
- file_count++;
- // This can be expensive for large strings; consider memory constraints
- size_t remaining_length = data_len - (obj_end + 1);
- memmove(data + obj_start, data + obj_end + 1, remaining_length + 1); // +1 to include null terminator
- data_len -= (obj_end + 1 - obj_start);
- pos = obj_start; // Reset position to the start of the modified string
- continue;
- }
- }
- }
- pos++;
- }
- furi_string_free(git_data_str);
- // Save file count
- char file_count_str[16];
- snprintf(file_count_str, sizeof(file_count_str), "%d", file_count);
- char file_count_dir[512]; // Increased size for longer paths
- snprintf(file_count_dir, sizeof(file_count_dir), STORAGE_EXT_PATH_PREFIX "/apps_data/flip_store/data/%s/file_count.txt", author);
- FURI_LOG_I(TAG, "Successfully parsed %d files.", file_count);
- return save_char_with_path(file_count_dir, file_count_str);
- }
- bool flip_store_install_all_github_files(FlipperHTTP *fhttp, const char *author, const char *repo)
- {
- FURI_LOG_I(TAG, "Installing all Github files.");
- if (!fhttp || !author || !repo)
- {
- FURI_LOG_E(TAG, "Invalid arguments.");
- return false;
- }
- // get the file count
- char file_count_dir[256]; // /ext/apps_data/flip_store/data/author/file_count.txt
- snprintf(file_count_dir, sizeof(file_count_dir), STORAGE_EXT_PATH_PREFIX "/apps_data/flip_store/data/%s/file_count.txt", author);
- FuriString *file_count = flipper_http_load_from_file(file_count_dir);
- if (file_count == NULL)
- {
- FURI_LOG_E(TAG, "Failed to load file count.");
- return false;
- }
- int count = atoi(furi_string_get_cstr(file_count));
- furi_string_free(file_count);
- bool parse()
- {
- return true;
- }
- // install all files
- char file_dir[256]; // /ext/apps_data/flip_store/data/author/repo/file.json
- FURI_LOG_I(TAG, "Installing %d files.", count);
- for (int i = 0; i < count; i++)
- {
- snprintf(file_dir, sizeof(file_dir), STORAGE_EXT_PATH_PREFIX "/apps_data/flip_store/data/%s/%s/file%d.json", author, repo, i);
- FURI_LOG_I(TAG, "Loading file %s.", file_dir);
- FuriString *file = flipper_http_load_from_file(file_dir);
- if (file == NULL)
- {
- FURI_LOG_E(TAG, "Failed to load file.");
- return false;
- }
- FURI_LOG_I(TAG, "Loaded file %s.", file_dir);
- FuriString *name = get_json_value_furi("name", file);
- if (!name)
- {
- FURI_LOG_E(TAG, "Failed to get name.");
- furi_string_free(file);
- return false;
- }
- FuriString *link = get_json_value_furi("link", file);
- if (!link)
- {
- FURI_LOG_E(TAG, "Failed to get link.");
- furi_string_free(file);
- furi_string_free(name);
- return false;
- }
- furi_string_free(file);
- bool fetch_file()
- {
- return flip_store_download_github_file(fhttp, furi_string_get_cstr(name), author, repo, furi_string_get_cstr(link));
- }
- // download the file and wait until it is downloaded
- FURI_LOG_I(TAG, "Downloading file %s.", furi_string_get_cstr(name));
- if (!flipper_http_process_response_async(fhttp, fetch_file, parse))
- {
- FURI_LOG_E(TAG, "Failed to download file.");
- furi_string_free(name);
- furi_string_free(link);
- return false;
- }
- FURI_LOG_I(TAG, "Downloaded file %s.", furi_string_get_cstr(name));
- furi_string_free(name);
- furi_string_free(link);
- }
- return true;
- }
|