|
34 | 34 |
|
35 | 35 | #include "shared-bindings/wifi/Radio.h"
|
36 | 36 | #include "shared-module/storage/__init__.h"
|
| 37 | +#include "shared/timeutils/timeutils.h" |
37 | 38 | #include "supervisor/shared/translate/translate.h"
|
38 | 39 | #include "supervisor/shared/web_workflow/web_workflow.h"
|
39 | 40 | #include "supervisor/usb.h"
|
@@ -77,6 +78,7 @@ typedef struct {
|
77 | 78 | bool done;
|
78 | 79 | bool authenticated;
|
79 | 80 | bool expect;
|
| 81 | + bool json; |
80 | 82 | } _request;
|
81 | 83 |
|
82 | 84 | static wifi_radio_error_t wifi_status = WIFI_RADIO_ERROR_NONE;
|
@@ -381,6 +383,59 @@ static void _reply_redirect(socketpool_socket_obj_t *socket, const char *path) {
|
381 | 383 | _send_str(socket, "\r\n\r\n");
|
382 | 384 | }
|
383 | 385 |
|
| 386 | +static void _reply_directory_json(socketpool_socket_obj_t *socket, FF_DIR *dir, const char *request_path, const char *path) { |
| 387 | + const char *ok_response = "HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\n" |
| 388 | + "Content-Type: application/json\r\n\r\n"; |
| 389 | + socketpool_socket_send(socket, (const uint8_t *)ok_response, strlen(ok_response)); |
| 390 | + _send_chunk(socket, "["); |
| 391 | + bool first = true; |
| 392 | + |
| 393 | + FILINFO file_info; |
| 394 | + char *fn = file_info.fname; |
| 395 | + FRESULT res = f_readdir(dir, &file_info); |
| 396 | + while (res == FR_OK && fn[0] != 0) { |
| 397 | + if (!first) { |
| 398 | + _send_chunk(socket, ","); |
| 399 | + } |
| 400 | + _send_chunk(socket, "{\"name\": \""); |
| 401 | + _send_chunk(socket, file_info.fname); |
| 402 | + _send_chunk(socket, "\", \"directory\": "); |
| 403 | + if ((file_info.fattrib & AM_DIR) != 0) { |
| 404 | + _send_chunk(socket, "true"); |
| 405 | + } else { |
| 406 | + _send_chunk(socket, "false"); |
| 407 | + } |
| 408 | + // We use nanoseconds past Jan 1, 1970 for consistency with BLE API and |
| 409 | + // LittleFS. |
| 410 | + _send_chunk(socket, ", \"modified_ns\": "); |
| 411 | + |
| 412 | + uint64_t truncated_time = timeutils_mktime(1980 + (file_info.fdate >> 9), |
| 413 | + (file_info.fdate >> 5) & 0xf, |
| 414 | + file_info.fdate & 0x1f, |
| 415 | + file_info.ftime >> 11, |
| 416 | + (file_info.ftime >> 5) & 0x1f, |
| 417 | + (file_info.ftime & 0x1f) * 2) * 1000000000ULL; |
| 418 | + |
| 419 | + char encoded_number[32]; |
| 420 | + snprintf(encoded_number, sizeof(encoded_number), "%lld", truncated_time); |
| 421 | + _send_chunk(socket, encoded_number); |
| 422 | + |
| 423 | + _send_chunk(socket, ", \"file_size\": "); |
| 424 | + size_t file_size = 0; |
| 425 | + if ((file_info.fattrib & AM_DIR) == 0) { |
| 426 | + file_size = file_info.fsize; |
| 427 | + } |
| 428 | + snprintf(encoded_number, sizeof(encoded_number), "%d", file_size); |
| 429 | + _send_chunk(socket, encoded_number); |
| 430 | + |
| 431 | + _send_chunk(socket, "}"); |
| 432 | + first = false; |
| 433 | + res = f_readdir(dir, &file_info); |
| 434 | + } |
| 435 | + _send_chunk(socket, "]"); |
| 436 | + _send_chunk(socket, ""); |
| 437 | +} |
| 438 | + |
384 | 439 | static void _reply_directory_html(socketpool_socket_obj_t *socket, FF_DIR *dir, const char *request_path, const char *path) {
|
385 | 440 | const char *ok_response = "HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\n"
|
386 | 441 | "Content-Type: text/html\r\n\r\n";
|
@@ -737,7 +792,12 @@ static void _reply(socketpool_socket_obj_t *socket, _request *request) {
|
737 | 792 | _reply_missing(socket);
|
738 | 793 | return;
|
739 | 794 | }
|
740 |
| - _reply_directory_html(socket, &dir, request->path, path); |
| 795 | + if (request->json) { |
| 796 | + _reply_directory_json(socket, &dir, request->path, path); |
| 797 | + } else { |
| 798 | + _reply_directory_html(socket, &dir, request->path, path); |
| 799 | + } |
| 800 | + |
741 | 801 | f_closedir(&dir);
|
742 | 802 | } else if (strcmp(request->method, "PUT") == 0) {
|
743 | 803 | if (_usb_active()) {
|
@@ -884,6 +944,8 @@ static void _process_request(socketpool_socket_obj_t *socket, _request *request)
|
884 | 944 | request->content_length = strtoul(request->header_value, NULL, 10);
|
885 | 945 | } else if (strcmp(request->header_key, "Expect") == 0) {
|
886 | 946 | request->expect = strcmp(request->header_value, "100-continue") == 0;
|
| 947 | + } else if (strcmp(request->header_key, "Accept") == 0) { |
| 948 | + request->json = strcmp(request->header_value, "application/json") == 0; |
887 | 949 | }
|
888 | 950 | ESP_LOGW(TAG, "Header %s %s", request->header_key, request->header_value);
|
889 | 951 | } else if (request->offset > sizeof(request->header_value) - 1) {
|
|
0 commit comments