ascii-chat 0.11.33
Video chat in your terminal
Loading...
Searching...
No Matches
ui/mdns.c
Go to the documentation of this file.
1
14#include <ascii-chat/log/log.h>
16#include <ascii-chat/common.h>
18
19#include <stdio.h>
20#include <stdlib.h>
21#include <string.h>
22#ifndef _WIN32
23#include <unistd.h>
24#endif
25
26/* ============================================================================
27 * Log Management
28 * ========================================================================== */
29
30void ui_mdns_log_init(void) {
32 if (buf) {
34 }
35}
36
41
45
46void ui_mdns_log_append(const char *message) {
47 if (message) {
48 log_info("%s", message);
49 }
50}
51
57ui_mdns_server_t *ui_mdns_query(const ui_mdns_config_t *config, int *out_count) {
58 if (!out_count) {
59 SET_ERRNO(ERROR_INVALID_PARAM, "out_count pointer is NULL");
60 return NULL;
61 }
62
63 *out_count = 0;
64
65 // Apply defaults if needed
66 int timeout_ms = (config && config->timeout_ms > 0) ? config->timeout_ms : 2000;
67 int max_servers = (config && config->max_servers > 0) ? config->max_servers : 20;
68 bool quiet = (config && config->quiet);
69
70 // Call the core mDNS discovery function from discovery.c
71 return discovery_mdns_query(timeout_ms, max_servers, quiet, out_count);
72}
73
80
84int ui_mdns_prompt_selection(const ui_mdns_server_t *servers, int count) {
85 if (!servers || count <= 0) {
86 return -1;
87 }
88
89 // Display available servers
90 printf("\nAvailable ascii-chat servers on LAN:\n");
91 for (int i = 0; i < count; i++) {
92 const ui_mdns_server_t *srv = &servers[i];
93 const char *addr = ui_mdns_get_best_address(srv);
94 printf(" %d. %s (%s:%u)\n", i + 1, srv->name, addr, srv->port);
95 }
96
97 // Prompt for selection
98 printf("\nSelect server (1-%d) or press Enter to cancel: ", count);
99 fflush(stdout);
100
101 // Read user input
102 char input[32];
103 if (fgets(input, sizeof(input), stdin) == NULL) {
104 printf("\n");
105 return -1; // EOF or error
106 }
107
108 // Check for empty input (Enter pressed)
109 if (input[0] == '\n' || input[0] == '\r' || input[0] == '\0') {
110 return -1; // User cancelled
111 }
112
113 // Parse input as number
114 char *endptr;
115 long selection = strtol(input, &endptr, 10);
116
117 // Validate input
118 if (selection < 1 || selection > count) {
119 printf("⚠️ Invalid selection. Please enter a number between 1 and %d\n", count);
120 return ui_mdns_prompt_selection(servers, count); // Re-prompt
121 }
122
123 return (int)(selection - 1); // Convert to 0-based index
124}
125
139int ui_mdns_select(const ui_mdns_server_t *servers, int count) {
140 if (!servers || count <= 0) {
141 // No servers found - return special code
142 // Message will be printed at exit in client main
143 return -1;
144 }
145
146 // Lock terminal to prevent concurrent logging from overwriting TUI
147 bool prev_lock_state = log_lock_terminal();
148
149 // Clear terminal
150 log_plain("\033[2J\033[H");
151
152 // Display header
153 log_plain("\n");
154 log_plain("\033[1m╭─ 🔍 ascii-chat Server Discovery ────────────╮\033[0m\n");
155 log_plain("\033[1m│\033[0m\n");
156 char found_buf[64];
157 snprintf(found_buf, sizeof(found_buf), "Found %d server%s on your local network:", count, count == 1 ? "" : "s");
158 log_plain("\033[1m│\033[0m %s\n", colored_string(LOG_COLOR_INFO, found_buf));
159 log_plain("\033[1m│\033[0m\n");
160
161 // Display server list with formatting
162 for (int i = 0; i < count; i++) {
163 const ui_mdns_server_t *srv = &servers[i];
164 const char *addr = ui_mdns_get_best_address(srv);
165
166 char idx_buf[8];
167 snprintf(idx_buf, sizeof(idx_buf), "[%d]", i + 1);
168 char addr_buf[128];
169 snprintf(addr_buf, sizeof(addr_buf), "%s:%u", addr, srv->port);
170
171 log_plain("\033[1m│\033[0m %s %-30s %s\n", colored_string(LOG_COLOR_DEBUG, idx_buf), srv->name,
172 colored_string(LOG_COLOR_WARN, addr_buf));
173 }
174
175 log_plain("\033[1m│\033[0m\n");
176 log_plain("\033[1m╰────────────────────────────────────────────╯\033[0m\n");
177
178 // Prompt for selection
179 log_plain("\n");
180 log_plain("Enter server number (1-%d) or press Enter to cancel: ", count);
181 fflush(stdout);
182
183 // Unlock before waiting for input (user might take time)
184 log_unlock_terminal(prev_lock_state);
185
186 // Read user input
187 char input[32];
188 if (fgets(input, sizeof(input), stdin) == NULL) {
189 return -1;
190 }
191
192 // Check for empty input (Enter pressed)
193 if (input[0] == '\n' || input[0] == '\r' || input[0] == '\0') {
194 return -1;
195 }
196
197 // Parse input as number
198 char *endptr;
199 long selection = strtol(input, &endptr, 10);
200
201 // Validate input
202 if (selection < 1 || selection > count) {
203 char err_buf[64];
204 snprintf(err_buf, sizeof(err_buf), "Please enter a number between 1 and %d", count);
205 printf("%s\n\n", colored_string(LOG_COLOR_WARN, err_buf));
206 return ui_mdns_select(servers, count); // Re-prompt
207 }
208
209 // Lock terminal again for final output
210 prev_lock_state = log_lock_terminal();
211
212 // Clear screen and show connection status
213 log_plain("\033[2J\033[H");
214 log_plain("\n");
215 char connect_buf[128];
216 snprintf(connect_buf, sizeof(connect_buf), "🔗 Connecting to %s...", servers[selection - 1].name);
217 log_plain("%s\n", colored_string(LOG_COLOR_INFO, connect_buf));
218 log_plain("\n");
219 fflush(stdout);
220
221 // Brief delay so user can see the selection before logs overwrite it
223
224 // Unlock terminal now that TUI is complete
225 log_unlock_terminal(prev_lock_state);
226
227 return (int)(selection - 1); // Convert to 0-based index
228}
229
233const char *ui_mdns_get_best_address(const ui_mdns_server_t *server) {
234 if (!server) {
235 return "";
236 }
237
238 // Prefer IPv4 > name > IPv6
239 if (server->ipv4[0] != '\0') {
240 return server->ipv4;
241 }
242 if (server->name[0] != '\0') {
243 return server->name;
244 }
245 if (server->ipv6[0] != '\0') {
246 return server->ipv6;
247 }
248
249 return server->address; // Fallback to address field
250}
Platform abstraction layer umbrella header providing unified cross-platform API.
⚙️ Common definitions, error codes, macros, and types shared throughout the application
void discovery_mdns_destroy(ui_mdns_server_t *servers)
Free memory from mDNS discovery results.
Definition discovery.c:265
ui_mdns_server_t * discovery_mdns_query(int timeout_ms, int max_servers, bool quiet, int *out_count)
Public mDNS query function used by both parallel discovery and TUI wrapper.
Definition discovery.c:179
Buffered terminal frame rendering.
#define SET_ERRNO(code, context_msg,...)
Set error code with custom context message and log it, returning the error code.
@ ERROR_INVALID_PARAM
void log_clear_session_log_buffer(void)
Unregister the session log buffer.
Definition log/log.c:1847
void log_set_session_log_buffer(session_log_buffer_t *buf)
Register a session log buffer with the logger.
Definition log/log.c:1838
bool log_lock_terminal(void)
Lock terminal output for exclusive access by the calling thread.
Definition log/log.c:787
#define log_info(...)
Log an INFO message.
Definition log/log.h:561
#define log_plain(...)
Plain logging - writes to both log file and stderr without timestamps or log levels.
Definition log/log.h:618
void log_unlock_terminal(bool previous_state)
Release terminal lock and flush buffered messages.
Definition log/log.c:796
@ LOG_COLOR_DEBUG
Definition log/log.h:132
@ LOG_COLOR_INFO
Definition log/log.h:133
@ LOG_COLOR_WARN
Definition log/log.h:134
void platform_sleep_ms(unsigned int ms)
Sleep for a specified number of milliseconds.
const char * colored_string(log_color_t color, const char *text)
Build a colored string for terminal output.
Thread-safe circular log buffer for session screens (status, splash)
📝 Logging API with multiple log levels and terminal output control
Internal circular buffer structure.
Configuration for TUI discovery.
Definition ui/mdns.h:69
int max_servers
Maximum servers to collect (default: 20)
Definition ui/mdns.h:71
int timeout_ms
Maximum time to wait for responses (default: 2000)
Definition ui/mdns.h:70
bool quiet
Suppress discovery messages (default: false)
Definition ui/mdns.h:72
Discovered server information from mDNS.
Definition ui/mdns.h:57
char name[256]
Service instance name (e.g., "swift-river-canyon")
Definition ui/mdns.h:58
char ipv4[16]
IPv4 address (if available)
Definition ui/mdns.h:61
char ipv6[46]
IPv6 address (if available)
Definition ui/mdns.h:62
uint16_t port
Server port number.
Definition ui/mdns.h:60
char address[256]
Server address (IPv4, IPv6, or hostname)
Definition ui/mdns.h:59
void terminal_screen_log_destroy(void)
Standard log cleanup for terminal screens.
void terminal_screen_log_clear(void)
Clear buffered logs for terminal screens.
session_log_buffer_t * terminal_screen_log_init(void)
Initialize session log buffer for terminal screens.
Reusable "fixed header + scrolling logs" terminal screen abstraction.
ui_mdns_server_t * ui_mdns_query(const ui_mdns_config_t *config, int *out_count)
TUI wrapper around core mDNS discovery.
Definition ui/mdns.c:57
void ui_mdns_free_results(ui_mdns_server_t *servers)
Free results from mDNS discovery.
Definition ui/mdns.c:77
void ui_mdns_log_append(const char *message)
Append message to mDNS discovery log buffer.
Definition ui/mdns.c:46
const char * ui_mdns_get_best_address(const ui_mdns_server_t *server)
Get best address for a server.
Definition ui/mdns.c:233
void ui_mdns_log_init(void)
Initialize log buffer for mDNS discovery UI.
Definition ui/mdns.c:30
int ui_mdns_select(const ui_mdns_server_t *servers, int count)
TUI-based server selection with formatted display.
Definition ui/mdns.c:139
void ui_mdns_log_clear(void)
Clear mDNS discovery log buffer.
Definition ui/mdns.c:42
void ui_mdns_log_destroy(void)
Destroy mDNS discovery log buffer.
Definition ui/mdns.c:37
int ui_mdns_prompt_selection(const ui_mdns_server_t *servers, int count)
Interactive server selection.
Definition ui/mdns.c:84
mDNS service discovery UI with terminal_screen rendering
🔤 String Manipulation and Shell Escaping Utilities