ascii-chat 0.11.33
Video chat in your terminal
Loading...
Searching...
No Matches
wasm.c
Go to the documentation of this file.
1
7#include <emscripten.h>
8#include <string.h>
11#include <stdint.h>
12#include <stddef.h>
13
14// EM_JS bridge: route to appropriate console method based on log level
15// level: 0=DEV, 1=DEBUG, 2=INFO, 3=WARN, 4=ERROR, 5=FATAL
16// Message contains the COMPLETE formatted log line with timestamp, level, thread, file:line, etc.
17// clang-format off
18EM_JS(void, js_console_log, (int level, const char *message), {
19 const msg = UTF8ToString(message);
20 const levelNames = [ 'DEV', 'DEBUG', 'INFO', 'WARN', 'ERROR', 'FATAL' ];
21 const levelName = (level >= 0 && level <= 5) ? levelNames[level] : '?????';
22
23 // Debug: show message length to verify content is being passed
24 const msgLen = msg.length;
25 const hasTimestamp =
26 msg.startsWith('[') && msg.includes(':') && msg.includes('.') && msg[msg.indexOf(']') + 1] === ' ';
27 const debugInfo = `[WASM_MSG_LEN = ${msgLen}, HAS_TS = ${hasTimestamp}]`;
28
29 // Route to appropriate console method
30 switch (level) {
31 case 0: // LOG_DEV
32 case 1: // LOG_DEBUG
33 case 2: // LOG_INFO
34 console.log(debugInfo, msg);
35 break;
36 case 3: // LOG_WARN
37 console.warn(debugInfo, msg);
38 break;
39 case 4: // LOG_ERROR
40 case 5: // LOG_FATAL
41 console.error(debugInfo, msg);
42 break;
43 default:
44 console.log(debugInfo, msg);
45 }
46});
47// clang-format on
48
49// Platform hook called by logging system
50// This is called after each log message is formatted, before printing to stderr/stdout
51// The message parameter contains the COMPLETE formatted log line with ANSI codes:
52// [HH:MM:SS.microseconds] [LEVEL] [thread/name] file:line@function(): message
53// We strip the ANSI codes before sending to browser console for clean output
54void platform_log_hook(log_level_t level, const char *message) {
55 if (message) {
56 // Strip ANSI codes for clean browser console output
57 static char clean_message[4096];
58 strip_ansi_codes(message, clean_message, sizeof(clean_message));
59 js_console_log((int)level, clean_message);
60 }
61}
62
63// Parse log level from formatted message: "[LEVEL] message..."
64// Returns the log_level_t enum value, or -1 if not found
65int wasm_parse_log_level(const uint8_t *buf, size_t count) {
66 if (!buf || count < 5) {
67 return -1; // Too short to contain [LEVEL]
68 }
69
70 // Check if message starts with [
71 if (buf[0] != '[') {
72 return -1;
73 }
74
75 // Look for closing ]
76 int bracket_end = -1;
77 for (size_t i = 1; i < count && i < 10; i++) {
78 if (buf[i] == ']') {
79 bracket_end = (int)i;
80 break;
81 }
82 }
83
84 if (bracket_end < 3) {
85 return -1; // Too short, minimum is [XX]
86 }
87
88 // Extract level string
89 int level_len = bracket_end - 1;
90 const char *level_start = (const char *)&buf[1];
91
92 // Match against known level strings (from logging.c)
93 if (level_len == 3 && strncmp(level_start, "DEV", 3) == 0) {
94 return LOG_DEV;
95 }
96 if (level_len == 5 && strncmp(level_start, "DEBUG", 5) == 0) {
97 return LOG_DEBUG;
98 }
99 if (level_len == 4 && strncmp(level_start, "INFO", 4) == 0) {
100 return LOG_INFO;
101 }
102 if (level_len == 4 && strncmp(level_start, "WARN", 4) == 0) {
103 return LOG_WARN;
104 }
105 if (level_len == 5 && strncmp(level_start, "ERROR", 5) == 0) {
106 return LOG_ERROR;
107 }
108 if (level_len == 5 && strncmp(level_start, "FATAL", 5) == 0) {
109 return LOG_FATAL;
110 }
111
112 return -1; // Level not recognized
113}
114
115// Public API for logging to console
116void wasm_log_to_console(int fd, const uint8_t *buf, size_t count) {
117 // For WASM, route stdout/stderr to browser console
118 if ((fd == 1 || fd == 2) && buf && count > 0) {
119 // Parse log level from formatted message
120 int level = wasm_parse_log_level(buf, count);
121 if (level >= 0) {
122 // Create null-terminated string for console output
123 // Copy buffer to local array and null-terminate
124 static char msg_buffer[4096];
125 size_t copy_len = (count < sizeof(msg_buffer) - 1) ? count : (sizeof(msg_buffer) - 1);
126 memcpy(msg_buffer, buf, copy_len);
127 msg_buffer[copy_len] = '\0';
128
129 // Remove trailing newline if present (console adds it automatically)
130 if (copy_len > 0 && msg_buffer[copy_len - 1] == '\n') {
131 msg_buffer[copy_len - 1] = '\0';
132 }
133
134 // Route to console
135 js_console_log(level, msg_buffer);
136 }
137 }
138}
unsigned char uint8_t
Definition common.h:56
log_level_t
Logging levels enumeration.
Definition types.h:29
void strip_ansi_codes(const char *input, char *output, size_t output_size)
Strip ANSI escape codes from a string.
📝 Logging API with multiple log levels and terminal output control
#define LOG_DEV
Definition types.h:38
#define LOG_DEBUG
Definition types.h:39
#define LOG_FATAL
Definition types.h:43
#define LOG_ERROR
Definition types.h:42
#define LOG_WARN
Definition types.h:41
#define LOG_INFO
Definition types.h:40
🔤 String Manipulation and Shell Escaping Utilities
EM_JS(void, js_console_log,(int level, const char *message), { const msg=UTF8ToString(message);const levelNames=[ 'DEV', 'DEBUG', 'INFO', 'WARN', 'ERROR', 'FATAL'];const levelName=(level >=0 &&level<=5) ? levelNames[level] :'???^;const msgLen=msg.length;const hasTimestamp=msg.startsWith('[') &&msg.includes(':') &&msg.includes('.') &&msg[msg.indexOf(']')+1]===' ';const debugInfo=`[WASM_MSG_LEN=${msgLen}, HAS_TS=${hasTimestamp}]`;switch(level) { case 0:case 1:case 2:console.log(debugInfo, msg);break;case 3:console.warn(debugInfo, msg);break;case 4:case 5:console.error(debugInfo, msg);break;default:console.log(debugInfo, msg);} })
int wasm_parse_log_level(const uint8_t *buf, size_t count)
Parse log level from formatted message.
Definition wasm.c:65
void platform_log_hook(log_level_t level, const char *message)
Definition wasm.c:54
void wasm_log_to_console(int fd, const uint8_t *buf, size_t count)
Route output to browser console based on log level.
Definition wasm.c:116