ascii-chat 0.6.0
Real-time terminal-based video chat with ASCII art conversion
Loading...
Searching...
No Matches
discovery_tui.h File Reference

TUI-based service discovery for ascii-chat client. More...

Go to the source code of this file.

Data Structures

struct  discovery_tui_server_t
 Discovered server information from mDNS. More...
 
struct  discovery_tui_config_t
 Configuration for TUI discovery. More...
 

Functions

discovery_tui_server_tdiscovery_tui_query (const discovery_tui_config_t *config, int *out_count)
 Discover ASCII-Chat servers on the local network via mDNS.
 
void discovery_tui_free_results (discovery_tui_server_t *servers)
 Free results from TUI discovery query.
 
int discovery_tui_prompt_selection (const discovery_tui_server_t *servers, int count)
 Display discovered servers to user and prompt for selection.
 
int discovery_tui_select (const discovery_tui_server_t *servers, int count)
 TUI-based server selection with formatted display.
 
const char * discovery_tui_get_best_address (const discovery_tui_server_t *server)
 Get best address representation for a discovered server.
 

Detailed Description

TUI-based service discovery for ascii-chat client.

Implements interactive mDNS-based discovery of ascii-chat servers on the local network. Provides a terminal UI for browsing and selecting available servers without manual IP entry.

Definition in file discovery_tui.h.

Function Documentation

◆ discovery_tui_free_results()

void discovery_tui_free_results ( discovery_tui_server_t servers)

Free results from TUI discovery query.

Releases memory allocated by discovery_tui_query().

Parameters
serversPointer to server array (safe to pass NULL)
Note
Safe to call multiple times or with NULL pointer

Free results from TUI discovery query.

Definition at line 45 of file discovery_tui.c.

45 {
46 discovery_mdns_free(servers);
47}
void discovery_mdns_free(discovery_tui_server_t *servers)
Free memory from mDNS discovery results.
Definition discovery.c:408

References discovery_mdns_free().

Referenced by client_main().

◆ discovery_tui_get_best_address()

const char * discovery_tui_get_best_address ( const discovery_tui_server_t server)

Get best address representation for a discovered server.

Returns the most suitable address representation (IPv4 > hostname > IPv6) for connecting to a discovered server.

Selection Priority:

  1. IPv4 address (most universal)
  2. Service name (if IPv4 not available)
  3. IPv6 address (last resort)
Parameters
serverDiscovered server
Returns
Pointer to best address string (points to field in server struct)

Get best address representation for a discovered server.

Definition at line 206 of file discovery_tui.c.

206 {
207 if (!server) {
208 return "";
209 }
210
211 // Prefer IPv4 > name > IPv6
212 if (server->ipv4[0] != '\0') {
213 return server->ipv4;
214 }
215 if (server->name[0] != '\0') {
216 return server->name;
217 }
218 if (server->ipv6[0] != '\0') {
219 return server->ipv6;
220 }
221
222 return server->address; // Fallback to address field
223}
char name[256]
Service instance name (e.g., "swift-river-canyon")
char ipv6[46]
IPv6 address (if available)
char ipv4[16]
IPv4 address (if available)
char address[256]
Server address (IPv4, IPv6, or hostname)

References discovery_tui_server_t::address, discovery_tui_server_t::ipv4, discovery_tui_server_t::ipv6, and discovery_tui_server_t::name.

Referenced by client_main(), discovery_tui_prompt_selection(), and discovery_tui_select().

◆ discovery_tui_prompt_selection()

int discovery_tui_prompt_selection ( const discovery_tui_server_t servers,
int  count 
)

Display discovered servers to user and prompt for selection.

Shows a numbered list of discovered servers and prompts user to select one. Handles invalid input with re-prompting.

User Experience:

Available ASCII-Chat servers on LAN:
1. swift-river-canyon (192.168.1.100:27224)
2. quiet-mountain-lake (192.168.1.101:27224)
3. gentle-forest-breeze (192.168.1.102:27224)
Select server (1-3) or press Enter to cancel: _

Behavior:

  • Displays each server with instance name and best-guess address
  • Shows IPv4 address if available, falls back to IPv6 or hostname
  • Handles non-numeric input with error message and re-prompt
  • Returns -1 if user presses Enter/Ctrl+C to cancel
  • Returns 0-based index of selected server
Parameters
serversArray of discovered servers
countNumber of servers in array
Returns
Index of selected server (0 to count-1), or -1 to cancel
Note
This function performs interactive I/O - may not be suitable for automated contexts
For automated selection, use servers[0] directly instead

Display discovered servers to user and prompt for selection.

Definition at line 52 of file discovery_tui.c.

52 {
53 if (!servers || count <= 0) {
54 return -1;
55 }
56
57 // Display available servers
58 printf("\nAvailable ASCII-Chat servers on LAN:\n");
59 for (int i = 0; i < count; i++) {
60 const discovery_tui_server_t *srv = &servers[i];
61 const char *addr = discovery_tui_get_best_address(srv);
62 printf(" %d. %s (%s:%u)\n", i + 1, srv->name, addr, srv->port);
63 }
64
65 // Prompt for selection
66 printf("\nSelect server (1-%d) or press Enter to cancel: ", count);
67 fflush(stdout);
68
69 // Read user input
70 char input[32];
71 if (fgets(input, sizeof(input), stdin) == NULL) {
72 printf("\n");
73 return -1; // EOF or error
74 }
75
76 // Check for empty input (Enter pressed)
77 if (input[0] == '\n' || input[0] == '\r' || input[0] == '\0') {
78 return -1; // User cancelled
79 }
80
81 // Parse input as number
82 char *endptr;
83 long selection = strtol(input, &endptr, 10);
84
85 // Validate input
86 if (selection < 1 || selection > count) {
87 printf("āš ļø Invalid selection. Please enter a number between 1 and %d\n", count);
88 return discovery_tui_prompt_selection(servers, count); // Re-prompt
89 }
90
91 return (int)(selection - 1); // Convert to 0-based index
92}
int discovery_tui_prompt_selection(const discovery_tui_server_t *servers, int count)
Interactive server selection.
const char * discovery_tui_get_best_address(const discovery_tui_server_t *server)
Get best address for a server.
Discovered server information from mDNS.
uint16_t port
Server port number.

References discovery_tui_get_best_address(), discovery_tui_prompt_selection(), discovery_tui_server_t::name, and discovery_tui_server_t::port.

Referenced by discovery_tui_prompt_selection().

◆ discovery_tui_query()

discovery_tui_server_t * discovery_tui_query ( const discovery_tui_config_t config,
int *  out_count 
)

Discover ASCII-Chat servers on the local network via mDNS.

Performs an mDNS query for _ascii-chat._tcp services on the local network. Collects responses and returns discovered servers to the caller.

Behavior:

  • Sends multicast mDNS query for _ascii-chat._tcp.local services
  • Waits for responses for the specified timeout period
  • Collects all discovered servers with their addresses and ports
  • Returns array of discovered servers

Memory Management:

  • Caller is responsible for freeing the returned array with lan_discovery_free_results()
  • Returned servers are valid until lan_discovery_free_results() is called

Error Handling:

  • Returns NULL and sets errno on initialization failure
  • Partial results returned if mDNS init fails but discovery was attempted
  • Network errors logged but don't prevent continuation

Threading:

  • Blocking operation - waits for full timeout period
  • Safe to call from main thread
  • Does not spawn background threads
Parameters
configDiscovery configuration (NULL uses defaults)
out_countOutput parameter: number of discovered servers
Returns
Array of discovered servers, or NULL on error Must be freed with lan_discovery_free_results()
Note
Timeout includes network round-trip time, so 2000ms allows ~1.5s of actual waiting
Returns empty array (non-NULL with count=0) if no servers found, not NULL

Example:

discovery_tui_config_t config = {.timeout_ms = 2000, .max_servers = 20};
int count = 0;
discovery_tui_server_t *servers = discovery_tui_query(&config, &count);
if (servers && count > 0) {
for (int i = 0; i < count; i++) {
printf("%d: %s (%s:%d)\n", i+1, servers[i].name, servers[i].address, servers[i].port);
}
// User selects server...
}
void discovery_tui_free_results(discovery_tui_server_t *servers)
Free results from mDNS discovery.
discovery_tui_server_t * discovery_tui_query(const discovery_tui_config_t *config, int *out_count)
TUI wrapper around core mDNS discovery.
Configuration for TUI discovery.
int timeout_ms
Maximum time to wait for responses (default: 2000)

Discover ASCII-Chat servers on the local network via mDNS.

Calls discovery_mdns_query() from discovery.c with TUI-friendly configuration.

Definition at line 25 of file discovery_tui.c.

25 {
26 if (!out_count) {
27 SET_ERRNO(ERROR_INVALID_PARAM, "out_count pointer is NULL");
28 return NULL;
29 }
30
31 *out_count = 0;
32
33 // Apply defaults if needed
34 int timeout_ms = (config && config->timeout_ms > 0) ? config->timeout_ms : 2000;
35 int max_servers = (config && config->max_servers > 0) ? config->max_servers : 20;
36 bool quiet = (config && config->quiet);
37
38 // Call the core mDNS discovery function from discovery.c
39 return discovery_mdns_query(timeout_ms, max_servers, quiet, out_count);
40}
discovery_tui_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:320
#define SET_ERRNO(code, context_msg,...)
Set error code with custom context message and log it.
@ ERROR_INVALID_PARAM
int max_servers
Maximum servers to collect (default: 20)
bool quiet
Suppress discovery messages (default: false)

References discovery_mdns_query(), ERROR_INVALID_PARAM, discovery_tui_config_t::max_servers, discovery_tui_config_t::quiet, SET_ERRNO, and discovery_tui_config_t::timeout_ms.

Referenced by client_main().

◆ discovery_tui_select()

int discovery_tui_select ( const discovery_tui_server_t servers,
int  count 
)

TUI-based server selection with formatted display.

Displays discovered servers in a formatted terminal UI with:

  • Clear screen and boxed display
  • Server list with numbering and addresses
  • "No results" message if no servers available
  • Interactive numeric selection prompt

Display Example (3 servers):

╭─ šŸ” ASCII-Chat Server Discovery ────────────╮
│
│ Found 3 servers on your local network:
│
│ [1] swift-river-canyon 192.168.1.100:27224
│ [2] quiet-mountain-lake 192.168.1.101:27224
│ [3] gentle-forest-breeze 192.168.1.102:27224
│
╰────────────────────────────────────────────╯
Enter server number (1-3) or press Enter to cancel:

No Results Display:

╭─ šŸ” ASCII-Chat Server Discovery ─╮
│
│ No servers found on local network
│
│ Make sure an ASCII-Chat server is running on your LAN
│ Or provide a server address manually: ascii-chat client <address>
│
╰─────────────────────────────────────────╯
Parameters
serversArray of discovered servers
countNumber of servers (0 for "no results")
Returns
0-based index of selected server, or -1 to cancel

Displays discovered servers in a terminal UI with the following features:

  • Clears terminal and displays formatted server list
  • Shows "No results" message if no servers available
  • Allows numeric input for selection
  • Shows helpful prompts and icons
Parameters
serversArray of discovered servers
countNumber of servers
Returns
0-based index of selected server, or -1 to cancel

Definition at line 120 of file discovery_tui.c.

120 {
121 if (!servers || count <= 0) {
122 // No servers found - return special code
123 // Message will be printed at exit in client main
124 return -1;
125 }
126
127 // Lock terminal to prevent concurrent logging from overwriting TUI
128 bool prev_lock_state = log_lock_terminal();
129
130 // Clear terminal
131 log_plain("%s", ANSI_CLEAR);
132
133 // Display header
134 log_plain("\n");
135 log_plain("%s╭─ šŸ” ASCII-Chat Server Discovery %s────────────╮%s\n", ANSI_BOLD, ANSI_RESET, ANSI_BOLD);
136 log_plain("│%s\n", ANSI_RESET);
137 log_plain("%s│%s Found %d server%s on your local network:%s\n", ANSI_BOLD, ANSI_GREEN, count, count == 1 ? "" : "s",
138 ANSI_RESET);
139 log_plain("%s│%s\n", ANSI_BOLD, ANSI_RESET);
140
141 // Display server list with formatting
142 for (int i = 0; i < count; i++) {
143 const discovery_tui_server_t *srv = &servers[i];
144 const char *addr = discovery_tui_get_best_address(srv);
145
146 log_plain("%s│%s ", ANSI_BOLD, ANSI_RESET);
147 log_plain("%s[%d]%s %-30s %s%s:%u%s", ANSI_CYAN, i + 1, ANSI_RESET, srv->name, ANSI_YELLOW, addr, srv->port,
148 ANSI_RESET);
149 log_plain("\n");
150 }
151
152 log_plain("%s│%s\n", ANSI_BOLD, ANSI_RESET);
153 log_plain("%s╰────────────────────────────────────────────╯%s\n", ANSI_BOLD, ANSI_RESET);
154
155 // Prompt for selection
156 log_plain("\n");
157 log_plain("Enter server number (1-%d) or press Enter to cancel: ", count);
158 fflush(stdout);
159
160 // Unlock before waiting for input (user might take time)
161 log_unlock_terminal(prev_lock_state);
162
163 // Read user input
164 char input[32];
165 if (fgets(input, sizeof(input), stdin) == NULL) {
166 return -1;
167 }
168
169 // Check for empty input (Enter pressed)
170 if (input[0] == '\n' || input[0] == '\r' || input[0] == '\0') {
171 return -1;
172 }
173
174 // Parse input as number
175 char *endptr;
176 long selection = strtol(input, &endptr, 10);
177
178 // Validate input
179 if (selection < 1 || selection > count) {
180 printf("%sError:%s Please enter a number between 1 and %d\n\n", ANSI_YELLOW, ANSI_RESET, count);
181 return discovery_tui_select(servers, count); // Re-prompt
182 }
183
184 // Lock terminal again for final output
185 prev_lock_state = log_lock_terminal();
186
187 // Clear screen and show connection status
188 log_plain("%s", ANSI_CLEAR);
189 log_plain("\n");
190 log_plain("%sšŸ”— Connecting to %s...%s\n", ANSI_GREEN, servers[selection - 1].name, ANSI_RESET);
191 log_plain("\n");
192 fflush(stdout);
193
194 // Brief delay so user can see the selection before logs overwrite it
196
197 // Unlock terminal now that TUI is complete
198 log_unlock_terminal(prev_lock_state);
199
200 return (int)(selection - 1); // Convert to 0-based index
201}
#define ANSI_BOLD
#define ANSI_CLEAR
ANSI escape codes for TUI.
int discovery_tui_select(const discovery_tui_server_t *servers, int count)
TUI-based server selection with formatted display.
#define ANSI_CYAN
#define ANSI_GREEN
#define ANSI_YELLOW
#define ANSI_RESET
bool log_lock_terminal(void)
Lock terminal output for exclusive access by the calling thread.
#define log_plain(...)
Plain logging - writes to both log file and stderr without timestamps or log levels.
void log_unlock_terminal(bool previous_state)
Release terminal lock and flush buffered messages.
void platform_sleep_ms(unsigned int ms)
Sleep for a specified number of milliseconds.

References ANSI_BOLD, ANSI_CLEAR, ANSI_CYAN, ANSI_GREEN, ANSI_RESET, ANSI_YELLOW, discovery_tui_get_best_address(), discovery_tui_select(), log_lock_terminal(), log_plain, log_unlock_terminal(), discovery_tui_server_t::name, platform_sleep_ms(), and discovery_tui_server_t::port.

Referenced by client_main(), and discovery_tui_select().