|
|
|
@ -36,8 +36,9 @@ static void UpdateUIState(struct etcpmon_app* app); |
|
|
|
static void on_connected(void* user_data); |
|
|
|
static void on_connected(void* user_data); |
|
|
|
static void on_disconnected(void* user_data); |
|
|
|
static void on_disconnected(void* user_data); |
|
|
|
static void on_conn_list(struct etcpmon_conn_info* list, uint8_t count, void* user_data); |
|
|
|
static void on_conn_list(struct etcpmon_conn_info* list, uint8_t count, void* user_data); |
|
|
|
static void on_metrics(struct etcpmon_rsp_metrics* metrics,
|
|
|
|
static void on_socket_list(struct etcpmon_socket_info* list, uint8_t count, void* user_data); |
|
|
|
struct etcpmon_link_metrics* links,
|
|
|
|
static void on_metrics(struct etcpmon_rsp_metrics* metrics, |
|
|
|
|
|
|
|
struct etcpmon_link_metrics* links, |
|
|
|
uint8_t links_count, void* user_data); |
|
|
|
uint8_t links_count, void* user_data); |
|
|
|
static void on_error(const char* msg, void* user_data); |
|
|
|
static void on_error(const char* msg, void* user_data); |
|
|
|
|
|
|
|
|
|
|
|
@ -131,9 +132,9 @@ HWND etcpmon_gui_create_window(struct etcpmon_app* app) { |
|
|
|
app->client = (struct etcpmon_client*)malloc(sizeof(struct etcpmon_client)); |
|
|
|
app->client = (struct etcpmon_client*)malloc(sizeof(struct etcpmon_client)); |
|
|
|
if (app->client) { |
|
|
|
if (app->client) { |
|
|
|
etcpmon_client_init(app->client); |
|
|
|
etcpmon_client_init(app->client); |
|
|
|
etcpmon_client_set_callbacks(app->client,
|
|
|
|
etcpmon_client_set_callbacks(app->client, |
|
|
|
on_connected, on_disconnected, |
|
|
|
on_connected, on_disconnected, |
|
|
|
on_conn_list, on_metrics, on_error, |
|
|
|
on_conn_list, on_socket_list, on_metrics, on_error, |
|
|
|
app); |
|
|
|
app); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@ -198,7 +199,16 @@ static void CreateControls(struct etcpmon_app* app) { |
|
|
|
app->hListConnections = CreateWindowExA(WS_EX_CLIENTEDGE, "LISTBOX", "", |
|
|
|
app->hListConnections = CreateWindowExA(WS_EX_CLIENTEDGE, "LISTBOX", "", |
|
|
|
WS_CHILD | WS_VISIBLE | LBS_NOTIFY | WS_VSCROLL | LBS_NOINTEGRALHEIGHT, |
|
|
|
WS_CHILD | WS_VISIBLE | LBS_NOTIFY | WS_VSCROLL | LBS_NOINTEGRALHEIGHT, |
|
|
|
x, y + 20, 300, 120, hWnd, (HMENU)IDC_LIST_CONNECTIONS, hInst, NULL); |
|
|
|
x, y + 20, 300, 120, hWnd, (HMENU)IDC_LIST_CONNECTIONS, hInst, NULL); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Sockets list */ |
|
|
|
|
|
|
|
CreateWindowExA(0, "STATIC", "Sockets:", |
|
|
|
|
|
|
|
WS_CHILD | WS_VISIBLE, |
|
|
|
|
|
|
|
x + 310, y, 100, 20, hWnd, (HMENU)IDC_STATIC, hInst, NULL); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
app->hListSockets = CreateWindowExA(WS_EX_CLIENTEDGE, "LISTBOX", "", |
|
|
|
|
|
|
|
WS_CHILD | WS_VISIBLE | LBS_NOTIFY | WS_VSCROLL | LBS_NOINTEGRALHEIGHT, |
|
|
|
|
|
|
|
x + 310, y + 20, 300, 120, hWnd, (HMENU)IDC_LIST_SOCKETS, hInst, NULL); |
|
|
|
|
|
|
|
|
|
|
|
/* Graph area */ |
|
|
|
/* Graph area */ |
|
|
|
y += 140; |
|
|
|
y += 140; |
|
|
|
app->hGraphWnd = CreateWindowExA( |
|
|
|
app->hGraphWnd = CreateWindowExA( |
|
|
|
@ -790,6 +800,7 @@ static void OnTimer(struct etcpmon_app* app) { |
|
|
|
|
|
|
|
|
|
|
|
if (app->need_initial_request && app->isConnected) { |
|
|
|
if (app->need_initial_request && app->isConnected) { |
|
|
|
etcpmon_client_request_list(app->client); |
|
|
|
etcpmon_client_request_list(app->client); |
|
|
|
|
|
|
|
etcpmon_client_request_socket_list(app->client); |
|
|
|
app->need_initial_request = 0; |
|
|
|
app->need_initial_request = 0; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@ -837,23 +848,28 @@ static void on_disconnected(void* user_data) { |
|
|
|
|
|
|
|
|
|
|
|
static void on_conn_list(struct etcpmon_conn_info* list, uint8_t count, void* user_data) { |
|
|
|
static void on_conn_list(struct etcpmon_conn_info* list, uint8_t count, void* user_data) { |
|
|
|
struct etcpmon_app* app = (struct etcpmon_app*)user_data; |
|
|
|
struct etcpmon_app* app = (struct etcpmon_app*)user_data; |
|
|
|
|
|
|
|
|
|
|
|
etcpmon_gui_update_conn_list(app, list, count); |
|
|
|
etcpmon_gui_update_conn_list(app, list, count); |
|
|
|
|
|
|
|
|
|
|
|
/* Автоматически выбираем первое соединение (только один раз) */ |
|
|
|
/* Автоматически выбираем первое соединение (только один раз) */ |
|
|
|
if (count > 0 && app->last_selected_peer_id == 0) { |
|
|
|
if (count > 0 && app->last_selected_peer_id == 0) { |
|
|
|
uint64_t first_id = list[0].peer_node_id; |
|
|
|
uint64_t first_id = list[0].peer_node_id; |
|
|
|
app->last_selected_peer_id = first_id; |
|
|
|
app->last_selected_peer_id = first_id; |
|
|
|
|
|
|
|
|
|
|
|
etcpmon_client_select_connection(app->client, first_id); |
|
|
|
etcpmon_client_select_connection(app->client, first_id); |
|
|
|
|
|
|
|
|
|
|
|
/* Выделяем первую строку в списке */ |
|
|
|
/* Выделяем первую строку в списке */ |
|
|
|
SendMessage(app->hListConnections, LB_SETCURSEL, 0, 0); |
|
|
|
SendMessage(app->hListConnections, LB_SETCURSEL, 0, 0); |
|
|
|
|
|
|
|
|
|
|
|
etcpmon_gui_set_status(app, "Auto-selected first connection"); |
|
|
|
etcpmon_gui_set_status(app, "Auto-selected first connection"); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void on_socket_list(struct etcpmon_socket_info* list, uint8_t count, void* user_data) { |
|
|
|
|
|
|
|
struct etcpmon_app* app = (struct etcpmon_app*)user_data; |
|
|
|
|
|
|
|
etcpmon_gui_update_socket_list(app, list, count); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static void on_metrics(struct etcpmon_rsp_metrics* metrics,
|
|
|
|
static void on_metrics(struct etcpmon_rsp_metrics* metrics,
|
|
|
|
struct etcpmon_link_metrics* links,
|
|
|
|
struct etcpmon_link_metrics* links,
|
|
|
|
uint8_t links_count, void* user_data) { |
|
|
|
uint8_t links_count, void* user_data) { |
|
|
|
@ -904,26 +920,58 @@ void etcpmon_gui_set_status(struct etcpmon_app* app, const char* text) { |
|
|
|
if (!app || !app->hWndStatus) return; |
|
|
|
if (!app || !app->hWndStatus) return; |
|
|
|
SendMessageA(app->hWndStatus, SB_SETTEXTA, 0, (LPARAM)text); |
|
|
|
SendMessageA(app->hWndStatus, SB_SETTEXTA, 0, (LPARAM)text); |
|
|
|
} |
|
|
|
} |
|
|
|
void etcpmon_gui_update_conn_list(struct etcpmon_app* app,
|
|
|
|
void etcpmon_gui_update_conn_list(struct etcpmon_app* app, |
|
|
|
struct etcpmon_conn_info* list,
|
|
|
|
struct etcpmon_conn_info* list, |
|
|
|
uint8_t count) { |
|
|
|
uint8_t count) { |
|
|
|
if (!app || !app->hListConnections) return; |
|
|
|
if (!app || !app->hListConnections) return; |
|
|
|
|
|
|
|
|
|
|
|
/* Clear existing items */ |
|
|
|
/* Clear existing items */ |
|
|
|
SendMessage(app->hListConnections, LB_RESETCONTENT, 0, 0); |
|
|
|
SendMessage(app->hListConnections, LB_RESETCONTENT, 0, 0); |
|
|
|
|
|
|
|
|
|
|
|
/* Add new items */ |
|
|
|
/* Add new items */ |
|
|
|
for (uint8_t i = 0; i < count; i++) { |
|
|
|
for (uint8_t i = 0; i < count; i++) { |
|
|
|
char display[64]; |
|
|
|
char display[64]; |
|
|
|
snprintf(display, sizeof(display), "%s (%016llX)", |
|
|
|
snprintf(display, sizeof(display), "%s (%016llX)", |
|
|
|
list[i].name, (unsigned long long)list[i].peer_node_id); |
|
|
|
list[i].name, (unsigned long long)list[i].peer_node_id); |
|
|
|
|
|
|
|
|
|
|
|
int idx = (int)SendMessageA(app->hListConnections, LB_ADDSTRING, 0, (LPARAM)display); |
|
|
|
int idx = (int)SendMessageA(app->hListConnections, LB_ADDSTRING, 0, (LPARAM)display); |
|
|
|
if (idx != LB_ERR) { |
|
|
|
if (idx != LB_ERR) { |
|
|
|
SendMessage(app->hListConnections, LB_SETITEMDATA, idx, (LPARAM)list[i].peer_node_id); |
|
|
|
SendMessage(app->hListConnections, LB_SETITEMDATA, idx, (LPARAM)list[i].peer_node_id); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static const char* nat_type_to_string(uint8_t nat_type) { |
|
|
|
|
|
|
|
switch (nat_type) { |
|
|
|
|
|
|
|
case NAT_TYPE_OPEN: return "Open"; |
|
|
|
|
|
|
|
case NAT_TYPE_RESTRICTED: return "Restricted"; |
|
|
|
|
|
|
|
case NAT_VERIFIED_OPEN: return "Verified-Open"; |
|
|
|
|
|
|
|
case NAT_VERIFIED_RESTRICTED: return "Verified-Restricted"; |
|
|
|
|
|
|
|
case NAT_VERIFIED_DIRECT: return "Direct"; |
|
|
|
|
|
|
|
default: return "Unknown"; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void etcpmon_gui_update_socket_list(struct etcpmon_app* app, |
|
|
|
|
|
|
|
struct etcpmon_socket_info* list, |
|
|
|
|
|
|
|
uint8_t count) { |
|
|
|
|
|
|
|
if (!app || !app->hListSockets) return; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
SendMessage(app->hListSockets, LB_RESETCONTENT, 0, 0); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (uint8_t i = 0; i < count; i++) { |
|
|
|
|
|
|
|
char display[128]; |
|
|
|
|
|
|
|
const char* nat_str = nat_type_to_string(list[i].nat_type); |
|
|
|
|
|
|
|
if (list[i].is_ipv6) { |
|
|
|
|
|
|
|
snprintf(display, sizeof(display), "[%s]:%d | NAT: %s", |
|
|
|
|
|
|
|
list[i].ip, list[i].port, nat_str); |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
snprintf(display, sizeof(display), "%s:%d | NAT: %s", |
|
|
|
|
|
|
|
list[i].ip, list[i].port, nat_str); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
SendMessageA(app->hListSockets, LB_ADDSTRING, 0, (LPARAM)display); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
/* Обновляет EDIT только если текст действительно изменился → убирает моргание */ |
|
|
|
/* Обновляет EDIT только если текст действительно изменился → убирает моргание */ |
|
|
|
static BOOL UpdateEditIfChanged(HWND hDlg, int nIDDlgItem, const char* fmt, ...) |
|
|
|
static BOOL UpdateEditIfChanged(HWND hDlg, int nIDDlgItem, const char* fmt, ...) |
|
|
|
{ |
|
|
|
{ |
|
|
|
|