diff --git a/src/main.c b/src/main.c index 5889ebc..b21852a 100644 --- a/src/main.c +++ b/src/main.c @@ -11,6 +11,7 @@ #define HTTP_PORT "8888" #define STATIC_DIR "./static/" +#define INPUT_BUFFER_SIZE 256 static const char *s_http_addr = "http://0.0.0.0:8888"; static struct mg_mgr mgr; @@ -18,6 +19,9 @@ static struct mg_mgr mgr; struct client_data { struct terminal_session term; bool terminal_ready; + bool closing; // Флаг для закрытия соединения + char input_buffer[INPUT_BUFFER_SIZE]; + size_t input_buffer_len; }; // Функция для логирования запросов @@ -78,6 +82,65 @@ static void restart_terminal_session(struct mg_connection *c, } } +// Функция для проверки команды exit в буфере +static bool check_for_exit_command(struct mg_connection *c, + struct client_data *cd) { + for (size_t i = 0; i < cd->input_buffer_len; i++) { + if (cd->input_buffer[i] == 0x04) { + printf("Ctrl+D pressed\n"); + write_to_terminal(&cd->term, &cd->input_buffer[i], 1); + usleep(100); + mg_ws_send(c, "CLOSE_TAB", 9, WEBSOCKET_OP_TEXT); + cd->closing = true; + cd->input_buffer_len = 0; + return true; + } + } + // Ищем символ новой строки в буфере + for (size_t i = 0; i < cd->input_buffer_len; i++) { + if (cd->input_buffer[i] == '\n' || cd->input_buffer[i] == '\r') { + // Нашли конец строки, проверяем команду + cd->input_buffer[i] = '\0'; // Завершаем строку + printf("Command: %s\n", cd->input_buffer); + if (cd->input_buffer[i - 1] == 'x') { + printf("Ctrl+D pressed\n"); + write_to_terminal(&cd->term, &cd->input_buffer[i], 1); + usleep(100); + mg_ws_send(c, "CLOSE_TAB", 9, WEBSOCKET_OP_TEXT); + cd->closing = true; + cd->input_buffer_len = 0; + return true; + } + // Проверяем, является ли команда "exit" + if (strcmp(cd->input_buffer, "exit") == 0) { + printf("Exit command detected, closing terminal session\n"); + + // Ждем немного чтобы команда выполнилась + usleep(100); + + // Отправляем клиенту сообщение о закрытии вкладки + mg_ws_send(c, "CLOSE_TAB", 9, WEBSOCKET_OP_TEXT); + + // Помечаем соединение для закрытия + cd->closing = true; + + // Сбрасываем буфер + cd->input_buffer_len = 0; + return true; + } + + // Сдвигаем буфер, удаляя обработанную строку + size_t remaining = cd->input_buffer_len - i - 1; + if (remaining > 0) { + memmove(cd->input_buffer, cd->input_buffer + i + 1, remaining); + } + cd->input_buffer_len = remaining; + return false; + } + } + return false; +} + // Обработчик WebSocket сообщений static void handle_websocket_message(struct mg_connection *c, struct mg_ws_message *wm, @@ -104,14 +167,19 @@ static void handle_websocket_message(struct mg_connection *c, cJSON_Delete(json); } - // Проверяем, не команда ли это exit - if (wm->data.len >= 4 && strncmp(wm->data.buf, "exit", 4) == 0) { - printf("Exit command detected, restarting terminal session\n"); - write_to_terminal(&cd->term, wm->data.buf, wm->data.len); - // Даем команде выполниться, затем перезапускаем - usleep(100); - restart_terminal_session(c, cd); - return; + // Добавляем данные в буфер ввода + size_t bytes_to_copy = wm->data.len; + if (cd->input_buffer_len + bytes_to_copy >= INPUT_BUFFER_SIZE) { + // Буфер переполнен, сбрасываем его + cd->input_buffer_len = 0; + } + + memcpy(cd->input_buffer + cd->input_buffer_len, wm->data.buf, bytes_to_copy); + cd->input_buffer_len += bytes_to_copy; + + printf("Input received: %s\n", wm->data.buf); + if (check_for_exit_command(c, cd)) { + return; // Вкладка будет закрыта, выходим } // Обычный ввод от пользователя @@ -157,6 +225,7 @@ static void fn(struct mg_connection *c, int ev, void *ev_data) { } cd->terminal_ready = true; + cd->closing = false; c->fn_data = cd; // Upgrade to WebSocket @@ -198,7 +267,7 @@ static void fn(struct mg_connection *c, int ev, void *ev_data) { printf("WebSocket connection opened\n"); struct client_data *cd = (struct client_data *)c->fn_data; if (cd) { - mg_ws_send(c, "Terminal ready - type 'exit' to restart session\r\n", 49, + mg_ws_send(c, "Terminal ready - type 'exit' to close tab\r\n", 44, WEBSOCKET_OP_TEXT); } } else if (ev == MG_EV_WS_MSG) { @@ -223,7 +292,7 @@ static void fn(struct mg_connection *c, int ev, void *ev_data) { continue; struct client_data *cd = (struct client_data *)conn->fn_data; - if (cd && cd->terminal_ready) { + if (cd && cd->terminal_ready && !cd->closing) { // Проверяем, не завершился ли процесс if (!is_process_alive(cd->term.child_pid)) { printf("Terminal process died, restarting...\n"); diff --git a/static/index.html b/static/index.html index 39585e1..4c7ada2 100644 --- a/static/index.html +++ b/static/index.html @@ -1,194 +1,713 @@ - Web Terminal + Web Terminal with Tabs -

Web Terminal

-
Connecting...
-
+
+

Web Terminal

+
+ Initializing... +
+
+ +
+
+ +
+ +
+ +
+
+

No terminals open

+

Create a new terminal tab to get started

+ +
+ +
+ +
+ No active terminal + Disconnected +