HTTP: websocket mockup

This commit is contained in:
SG 2023-07-23 23:55:10 +04:00
parent a398f19353
commit 1a6d9044c7
2 changed files with 201 additions and 11 deletions

View File

@ -17,6 +17,12 @@
#define WIFI_SCAN_SIZE 20
static httpd_handle_t server = NULL;
typedef struct {
httpd_handle_t hd;
int fd;
} async_resp_arg;
static const char* get_auth_mode(int authmode) {
switch(authmode) {
case WIFI_AUTH_OPEN:
@ -641,6 +647,156 @@ err_fail:
return ESP_FAIL;
}
/*************** UART ***************/
static void ws_async_send(void* arg) {
httpd_ws_frame_t ws_pkt;
async_resp_arg* resp_arg = arg;
httpd_handle_t hd = resp_arg->hd;
memset(&ws_pkt, 0, sizeof(httpd_ws_frame_t));
ws_pkt.payload = (uint8_t*)"Hello!";
ws_pkt.len = strlen((char*)ws_pkt.payload);
ws_pkt.type = HTTPD_WS_TYPE_TEXT;
static size_t max_clients = CONFIG_LWIP_MAX_LISTENING_TCP;
size_t fds = max_clients;
int client_fds[max_clients];
esp_err_t ret = httpd_get_client_list(server, &fds, client_fds);
if(ret != ESP_OK) {
return;
}
for(int i = 0; i < fds; i++) {
int client_info = httpd_ws_get_fd_info(server, client_fds[i]);
if(client_info == HTTPD_WS_CLIENT_WEBSOCKET) {
httpd_ws_send_frame_async(hd, client_fds[i], &ws_pkt);
}
}
free(resp_arg);
}
static esp_err_t trigger_async_send(httpd_handle_t handle, httpd_req_t* req) {
async_resp_arg* resp_arg = malloc(sizeof(async_resp_arg));
resp_arg->hd = req->handle;
resp_arg->fd = httpd_req_to_sockfd(req);
return httpd_queue_work(handle, ws_async_send, resp_arg);
}
#define WS_CLIENTS_MAX 10
#define WS_CLIENT_INVALID -1
static int ws_clients[WS_CLIENTS_MAX] = {0};
static void ws_clients_init() {
for(int i = 0; i < WS_CLIENTS_MAX; i++) {
ws_clients[i] = WS_CLIENT_INVALID;
}
}
static bool ws_client_add(int fd) {
for(int i = 0; i < WS_CLIENTS_MAX; i++) {
if(ws_clients[i] == WS_CLIENT_INVALID) {
ws_clients[i] = fd;
return true;
}
}
return false;
}
static bool ws_client_remove(int fd) {
for(int i = 0; i < WS_CLIENTS_MAX; i++) {
if(ws_clients[i] == fd) {
ws_clients[i] = WS_CLIENT_INVALID;
return true;
}
}
return false;
}
static size_t ws_client_count() {
size_t count = 0;
for(int i = 0; i < WS_CLIENTS_MAX; i++) {
if(ws_clients[i] != WS_CLIENT_INVALID) {
count++;
}
}
return count;
}
static void client_ping_task(void* pvParameters) {
while(true) {
vTaskDelay(1000 / portTICK_PERIOD_MS);
if(ws_client_count() == 0) {
continue;
}
httpd_ws_frame_t ws_pkt;
memset(&ws_pkt, 0, sizeof(httpd_ws_frame_t));
ws_pkt.type = HTTPD_WS_TYPE_TEXT;
ws_pkt.payload = (uint8_t*)"ping";
ws_pkt.len = strlen((char*)ws_pkt.payload);
for(int i = 0; i < WS_CLIENTS_MAX; i++) {
if(ws_clients[i] == WS_CLIENT_INVALID) {
continue;
}
int client_info = httpd_ws_get_fd_info(server, ws_clients[i]);
if(client_info == HTTPD_WS_CLIENT_WEBSOCKET) {
httpd_ws_send_frame_async(server, ws_clients[i], &ws_pkt);
}
}
ESP_LOGI(TAG, "ping sent");
}
}
static esp_err_t uart_websocket_handler(httpd_req_t* req) {
if(req->method == HTTP_GET) {
ESP_LOGI(TAG, "Handshake done, the new connection was opened");
ws_client_add(httpd_req_to_sockfd(req));
return ESP_OK;
}
httpd_ws_frame_t ws_pkt;
uint8_t* buf = NULL;
memset(&ws_pkt, 0, sizeof(httpd_ws_frame_t));
ws_pkt.type = HTTPD_WS_TYPE_TEXT;
esp_err_t ret = httpd_ws_recv_frame(req, &ws_pkt, 0);
if(ret != ESP_OK) {
ESP_LOGE(TAG, "httpd_ws_recv_frame failed to get frame len with %d", ret);
return ret;
}
if(ws_pkt.len) {
buf = calloc(1, ws_pkt.len + 1);
if(buf == NULL) {
ESP_LOGE(TAG, "Failed to calloc memory for buf");
return ESP_ERR_NO_MEM;
}
ws_pkt.payload = buf;
ret = httpd_ws_recv_frame(req, &ws_pkt, ws_pkt.len);
if(ret != ESP_OK) {
ESP_LOGE(TAG, "httpd_ws_recv_frame failed with %d", ret);
free(buf);
return ret;
}
ESP_LOGI(TAG, "Got packet with message: %s", ws_pkt.payload);
}
ESP_LOGI(TAG, "frame len is %d", ws_pkt.len);
if(ws_pkt.type == HTTPD_WS_TYPE_TEXT && strcmp((char*)ws_pkt.payload, "toggle") == 0) {
free(buf);
return trigger_async_send(req->handle, req);
}
return ESP_OK;
}
const httpd_uri_t uri_handlers[] = {
/*************** SYSTEM ***************/
@ -648,59 +804,91 @@ const httpd_uri_t uri_handlers[] = {
{.uri = "/api/v1/system/ping",
.method = HTTP_GET,
.handler = system_ping_handler,
.user_ctx = NULL},
.user_ctx = NULL,
.is_websocket = false},
{.uri = "/api/v1/system/tasks",
.method = HTTP_GET,
.handler = system_tasks_handler,
.user_ctx = NULL},
.user_ctx = NULL,
.is_websocket = false},
{.uri = "/api/v1/system/info",
.method = HTTP_GET,
.handler = system_info_get_handler,
.user_ctx = NULL},
.user_ctx = NULL,
.is_websocket = false},
{.uri = "/api/v1/system/reboot",
.method = HTTP_POST,
.handler = system_reboot,
.user_ctx = NULL},
.user_ctx = NULL,
.is_websocket = false},
/*************** GPIO ***************/
{.uri = "/api/v1/gpio/led",
.method = HTTP_POST,
.handler = gpio_led_set_handler,
.user_ctx = NULL},
.user_ctx = NULL,
.is_websocket = false},
/*************** WIFI ***************/
{.uri = "/api/v1/wifi/list",
.method = HTTP_GET,
.handler = wifi_list_get_handler,
.user_ctx = NULL},
.user_ctx = NULL,
.is_websocket = false},
{.uri = "/api/v1/wifi/set_credentials",
.method = HTTP_POST,
.handler = wifi_set_credentials_handler,
.user_ctx = NULL},
.user_ctx = NULL,
.is_websocket = false},
{.uri = "/api/v1/wifi/get_credentials",
.method = HTTP_GET,
.handler = wifi_get_credentials_handler,
.user_ctx = NULL},
.user_ctx = NULL,
.is_websocket = false},
/*************** UART ***************/
{.uri = "/api/v1/uart/websocket",
.method = HTTP_GET,
.handler = uart_websocket_handler,
.user_ctx = NULL,
.is_websocket = true},
/*************** HTTP ***************/
{.uri = "/*", .method = HTTP_GET, .handler = http_common_get_handler, .user_ctx = NULL},
{.uri = "/*",
.method = HTTP_GET,
.handler = http_common_get_handler,
.user_ctx = NULL,
.is_websocket = false},
};
static esp_err_t httpd_open_fn(httpd_handle_t hd, int sockfd) {
return ESP_OK;
}
static void httpd_close_fn(httpd_handle_t hd, int sockfd) {
ws_client_remove(sockfd);
close(sockfd);
}
void network_http_server_init(void) {
ESP_LOGI(TAG, "init rest server");
httpd_handle_t server = NULL;
ws_clients_init();
httpd_config_t config = HTTPD_DEFAULT_CONFIG();
config.max_uri_handlers = COUNT_OF(uri_handlers);
config.uri_match_fn = httpd_uri_match_wildcard;
config.open_fn = httpd_open_fn;
config.close_fn = httpd_close_fn;
ESP_LOGI(TAG, "starting http server");
if(httpd_start(&server, &config) != ESP_OK) {
@ -713,4 +901,6 @@ void network_http_server_init(void) {
}
ESP_LOGI(TAG, "init rest server done");
xTaskCreate(client_ping_task, "client_ping_task", 4096, NULL, 5, NULL);
}

View File

@ -363,7 +363,7 @@ CONFIG_HTTPD_MAX_URI_LEN=512
CONFIG_HTTPD_ERR_RESP_NO_DELAY=y
CONFIG_HTTPD_PURGE_BUF_LEN=32
# CONFIG_HTTPD_LOG_PURGE_DATA is not set
# CONFIG_HTTPD_WS_SUPPORT is not set
CONFIG_HTTPD_WS_SUPPORT=y
# end of HTTP Server
#