Refresh etcpmon connections and preserve selection by peer ID
This commit is contained in:
1 parent
9465ed4939
commit
24906283fe
3 files changed
+91
-34
No files matched your search
@@ -927,6 +927,7 @@ int etcpmon_client_process(struct etcpmon_client* client) {
|
||||
}
|
||||
|
||||
handle_response_with_callback(client, hdr->type, payload, payload_size);
|
||||
if (!client->connected) return -1;
|
||||
processed++;
|
||||
|
||||
/* Удаляем обработанное сообщение */
|
||||
@@ -934,7 +935,6 @@ int etcpmon_client_process(struct etcpmon_client* client) {
|
||||
memmove(client->recv_buffer, client->recv_buffer + total_size,
|
||||
client->recv_len - total_size);
|
||||
}
|
||||
if (!client->connected) return -1;
|
||||
client->recv_len -= total_size;
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,12 @@
|
||||
|
||||
Windows GUI монитор для ETCP соединений uTun в реальном времени (100ms refresh). Подключается по TCP к control_server внутри uTun и отображает метрики соединений, линков, TUN-интерфейса, роутера и дебаг-уровней. Позволяет менять debug levels на лету через GUI.
|
||||
|
||||
Connections и локальные сокеты опрашиваются раз в секунду, даже при пустом списке соединений.
|
||||
Выбор сохраняется по ID узла при изменении порядка и имён. При удалении выбранного соединения
|
||||
выбирается первое доступное; пустой список или отключение очищает метрики и график.
|
||||
Одновременно ожидается не более одного ответа на автоматический запрос метрик. Таймаут ответа
|
||||
на запрос с seq_id — 5 секунд; причина отключения записывается в `etcpmon.log`.
|
||||
|
||||
## 2. Как пользоваться
|
||||
|
||||
### Типовой сценарий
|
||||
|
||||
+84
-33
@@ -22,7 +22,8 @@
|
||||
#define WINDOW_WIDTH 1000
|
||||
#define WINDOW_HEIGHT 1400
|
||||
#define WINDOW_CLIENT_W 1250
|
||||
#define UPDATE_INTERVAL 10 /* 50ms → 20 samples per second */
|
||||
#define UPDATE_INTERVAL 10
|
||||
#define LIST_UPDATE_INTERVAL 1000
|
||||
/* Global app pointer for callbacks */
|
||||
static struct etcpmon_app* g_app = NULL;
|
||||
/* Forward declarations */
|
||||
@@ -1121,8 +1122,8 @@ static void OnConnect(struct etcpmon_app* app) {
|
||||
|
||||
if (etcpmon_client_connect(app->client, addr, port) == 0) {
|
||||
app->isConnected = 1;
|
||||
app->need_initial_request = 1;
|
||||
UpdateUIState(app);
|
||||
etcpmon_gui_set_status(app, "Connected");
|
||||
} else {
|
||||
etcpmon_gui_set_status(app, "Connection failed");
|
||||
}
|
||||
@@ -1131,11 +1132,7 @@ static void OnDisconnect(struct etcpmon_app* app) {
|
||||
if (!app || !app->client) return;
|
||||
|
||||
etcpmon_client_disconnect(app->client);
|
||||
app->isConnected = 0;
|
||||
app->need_initial_request = 1;
|
||||
app->last_selected_peer_id = 0;
|
||||
UpdateUIState(app);
|
||||
etcpmon_gui_set_status(app, "Disconnected");
|
||||
on_disconnected(app);
|
||||
}
|
||||
|
||||
static void OnConnectionSelect(struct etcpmon_app* app) {
|
||||
@@ -1144,14 +1141,19 @@ static void OnConnectionSelect(struct etcpmon_app* app) {
|
||||
int idx = (int)SendMessage(app->hListConnections, LB_GETCURSEL, 0, 0);
|
||||
if (idx == LB_ERR) return;
|
||||
|
||||
uint64_t peer_id = (uint64_t)SendMessage(app->hListConnections, LB_GETITEMDATA, idx, 0);
|
||||
LRESULT list_idx = SendMessage(app->hListConnections, LB_GETITEMDATA, idx, 0);
|
||||
if (list_idx < 0 || list_idx >= app->client->conn_count) return;
|
||||
uint64_t peer_id = app->client->conn_list[list_idx].peer_node_id;
|
||||
if (peer_id == 0) return;
|
||||
|
||||
/* Только если действительно изменилось — иначе спамим сервер */
|
||||
if (peer_id != app->last_selected_peer_id) {
|
||||
if (etcpmon_client_select_connection(app->client, peer_id) != 0) {
|
||||
OnDisconnect(app);
|
||||
etcpmon_gui_set_status(app, "Failed to select connection");
|
||||
return;
|
||||
}
|
||||
app->last_selected_peer_id = peer_id;
|
||||
|
||||
etcpmon_client_select_connection(app->client, peer_id);
|
||||
etcpmon_gui_clear_metrics(app); /* очищаем старые цифры */
|
||||
|
||||
etcpmon_gui_set_status(app, "Connection selected");
|
||||
@@ -1264,9 +1266,7 @@ static void RefreshDebugUI(struct etcpmon_app* app) {
|
||||
|
||||
static void OnTimer(struct etcpmon_app* app) {
|
||||
if (!app || !app->client) return;
|
||||
|
||||
// fprintf(app->client->log_file, "Timer... \n");
|
||||
// fflush(app->client->log_file);
|
||||
if (!app->client->connected) return;
|
||||
|
||||
int processed = etcpmon_client_process(app->client);
|
||||
if (processed < 0) {
|
||||
@@ -1274,10 +1274,17 @@ static void OnTimer(struct etcpmon_app* app) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (app->need_initial_request && app->isConnected) {
|
||||
etcpmon_client_request_list(app->client);
|
||||
etcpmon_client_request_socket_list(app->client);
|
||||
etcpmon_client_request_debug_config(app->client);
|
||||
if (!app->client->fully_connected) return;
|
||||
|
||||
DWORD now = GetTickCount();
|
||||
if (app->need_initial_request || now - app->last_poll_time >= LIST_UPDATE_INTERVAL) {
|
||||
if (etcpmon_client_request_list(app->client) != 0 || etcpmon_client_request_socket_list(app->client) != 0 ||
|
||||
(app->need_initial_request && etcpmon_client_request_debug_config(app->client) != 0)) {
|
||||
OnDisconnect(app);
|
||||
etcpmon_gui_set_status(app, "Failed to request monitor data");
|
||||
return;
|
||||
}
|
||||
app->last_poll_time = now;
|
||||
app->need_initial_request = 0;
|
||||
}
|
||||
|
||||
@@ -1324,6 +1331,12 @@ void etcpmon_gui_update_graph(struct etcpmon_app* app, struct etcpmon_rsp_metric
|
||||
static void on_disconnected(void* user_data) {
|
||||
struct etcpmon_app* app = (struct etcpmon_app*)user_data;
|
||||
app->isConnected = 0;
|
||||
app->need_initial_request = 1;
|
||||
app->last_selected_peer_id = 0;
|
||||
app->last_poll_time = 0;
|
||||
SendMessage(app->hListConnections, LB_RESETCONTENT, 0, 0);
|
||||
SendMessage(app->hListSockets, LB_RESETCONTENT, 0, 0);
|
||||
etcpmon_gui_clear_metrics(app);
|
||||
UpdateUIState(app);
|
||||
etcpmon_gui_set_status(app, "Disconnected");
|
||||
}
|
||||
@@ -1333,17 +1346,16 @@ static void on_conn_list(struct etcpmon_conn_info* list, uint8_t count, void* us
|
||||
|
||||
etcpmon_gui_update_conn_list(app, list, count);
|
||||
|
||||
/* Автоматически выбираем первое соединение (только один раз) */
|
||||
if (count > 0 && app->last_selected_peer_id == 0) {
|
||||
uint64_t first_id = list[0].peer_node_id;
|
||||
app->last_selected_peer_id = first_id;
|
||||
|
||||
etcpmon_client_select_connection(app->client, first_id);
|
||||
|
||||
/* Выделяем первую строку в списке */
|
||||
SendMessage(app->hListConnections, LB_SETCURSEL, 0, 0);
|
||||
|
||||
etcpmon_gui_set_status(app, "Auto-selected first connection");
|
||||
if (count > 0) {
|
||||
OnConnectionSelect(app);
|
||||
} else if (app->last_selected_peer_id != 0) {
|
||||
if (etcpmon_client_select_connection(app->client, 0) != 0) {
|
||||
OnDisconnect(app);
|
||||
return;
|
||||
}
|
||||
app->last_selected_peer_id = 0;
|
||||
etcpmon_gui_clear_metrics(app);
|
||||
etcpmon_gui_set_status(app, "No connections");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1358,7 +1370,6 @@ static void on_metrics(struct etcpmon_rsp_metrics* metrics,
|
||||
struct etcpmon_app* app = (struct etcpmon_app*)user_data;
|
||||
if (app) {
|
||||
etcpmon_gui_update_metrics(app, metrics, links, links_count);
|
||||
etcpmon_client_add_to_history(app->client, metrics);
|
||||
if (!app->graph_cursor_active) {
|
||||
struct metrics_history* h = etcpmon_client_get_history(app->client);
|
||||
if (h && h->count > 0) {
|
||||
@@ -1522,7 +1533,24 @@ void etcpmon_gui_update_conn_list(struct etcpmon_app* app,
|
||||
uint8_t count) {
|
||||
if (!app || !app->hListConnections) return;
|
||||
|
||||
/* Clear existing items */
|
||||
int selected = count ? 0 : -1;
|
||||
int changed = SendMessage(app->hListConnections, LB_GETCOUNT, 0, 0) != count;
|
||||
for (uint8_t i = 0; i < count; i++) {
|
||||
if (list[i].peer_node_id == app->last_selected_peer_id) selected = i;
|
||||
char display[64], previous[64];
|
||||
snprintf(display, sizeof(display), "%s (%016llX)", list[i].name, (unsigned long long)list[i].peer_node_id);
|
||||
if (!changed && (SendMessage(app->hListConnections, LB_GETTEXTLEN, i, 0) >= (LRESULT)sizeof(previous) ||
|
||||
SendMessageA(app->hListConnections, LB_GETTEXT, i, (LPARAM)previous) == LB_ERR || strcmp(display, previous) != 0)) {
|
||||
changed = 1;
|
||||
}
|
||||
}
|
||||
if (!changed) {
|
||||
SendMessage(app->hListConnections, LB_SETCURSEL, selected, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
int top = (int)SendMessage(app->hListConnections, LB_GETTOPINDEX, 0, 0);
|
||||
SendMessage(app->hListConnections, WM_SETREDRAW, FALSE, 0);
|
||||
SendMessage(app->hListConnections, LB_RESETCONTENT, 0, 0);
|
||||
|
||||
/* Add new items */
|
||||
@@ -1532,10 +1560,22 @@ void etcpmon_gui_update_conn_list(struct etcpmon_app* app,
|
||||
list[i].name, (unsigned long long)list[i].peer_node_id);
|
||||
|
||||
int idx = (int)SendMessageA(app->hListConnections, LB_ADDSTRING, 0, (LPARAM)display);
|
||||
if (idx != LB_ERR) {
|
||||
SendMessage(app->hListConnections, LB_SETITEMDATA, idx, (LPARAM)list[i].peer_node_id);
|
||||
if (idx != LB_ERR && idx != LB_ERRSPACE) {
|
||||
/* Индекс сохраняет полный 64-битный ID и в 32-битной Windows. */
|
||||
SendMessage(app->hListConnections, LB_SETITEMDATA, idx, i);
|
||||
} else if (app->client && app->client->log_file) {
|
||||
fprintf(app->client->log_file, "[ERROR] Failed to add connection row: index=%u result=%d\n", i, idx);
|
||||
}
|
||||
}
|
||||
SendMessage(app->hListConnections, LB_SETCURSEL, selected, 0);
|
||||
if (top >= 0 && top < count) SendMessage(app->hListConnections, LB_SETTOPINDEX, top, 0);
|
||||
SendMessage(app->hListConnections, WM_SETREDRAW, TRUE, 0);
|
||||
InvalidateRect(app->hListConnections, NULL, TRUE);
|
||||
if (app->client && app->client->log_file) {
|
||||
fprintf(app->client->log_file, "[LOG] Connections updated: count=%u selected_row=%d previous_peer=%016llX\n",
|
||||
count, selected, (unsigned long long)app->last_selected_peer_id);
|
||||
fflush(app->client->log_file);
|
||||
}
|
||||
}
|
||||
|
||||
static const char* config_type_to_string(uint8_t config_type) {
|
||||
@@ -1565,7 +1605,7 @@ static const char* nat_type_to_string(uint8_t nat_type) {
|
||||
void etcpmon_gui_update_socket_list(struct etcpmon_app* app,
|
||||
struct etcpmon_socket_info* list,
|
||||
uint8_t count) {
|
||||
if (!app || !app->hListSockets || !list || count == 0 || count > 32) return;
|
||||
if (!app || !app->hListSockets) return;
|
||||
|
||||
SendMessage(app->hListSockets, LB_RESETCONTENT, 0, 0);
|
||||
|
||||
@@ -1917,4 +1957,15 @@ void etcpmon_gui_clear_metrics(struct etcpmon_app* app) {
|
||||
if (app->hListLinks) {
|
||||
SendMessage(app->hListLinks, LB_RESETCONTENT, 0, 0);
|
||||
}
|
||||
if (app->client) {
|
||||
memset(&app->client->history, 0, sizeof(app->client->history));
|
||||
free(app->client->last_metrics);
|
||||
app->client->last_metrics = NULL;
|
||||
free(app->client->last_links);
|
||||
app->client->last_links = NULL;
|
||||
app->client->last_links_count = 0;
|
||||
}
|
||||
app->graph_cursor_active = 0;
|
||||
for (int i = 0; i < GRAPH_METRICS_COUNT; i++) SetWindowTextA(app->hChannelValue[i], "");
|
||||
if (app->hGraphWnd) InvalidateRect(app->hGraphWnd, NULL, TRUE);
|
||||
}
|
||||
Reference in new issue
Block a user