changeset 132:7a63e41a21fb

[Seobeo] Added debug targets.
author June Park <parkjune1995@gmail.com>
date Fri, 09 Jan 2026 08:23:54 -0800
parents b230a743a01e
children 902e29c38d66
files mrjunejune/BUILD mrjunejune/main.c mrjunejune/src/blog/websocket-demystified/index.md seobeo/BUILD seobeo/s_web.c seobeo/seobeo_internal.h
diffstat 6 files changed, 181 insertions(+), 13 deletions(-) [+]
line wrap: on
line diff
--- a/mrjunejune/BUILD	Fri Jan 09 07:42:04 2026 -0800
+++ b/mrjunejune/BUILD	Fri Jan 09 08:23:54 2026 -0800
@@ -41,7 +41,15 @@
   data = [":src_files"],
 )
 
-# Rlease bundle
+# Debug build with verbose logging
+cc_binary(
+  name = "mrjunejune_server_debug",
+  srcs = ["main.c"],
+  deps = ["//seobeo:seobeo_tcp_server_ws_debug"],
+  data = [":src_files"],
+)
+
+# Release bundle
 bundle(
   name = "mrjunejune_server_bundle",
   binary = ":mrjunejune_server",
--- a/mrjunejune/main.c	Fri Jan 09 07:42:04 2026 -0800
+++ b/mrjunejune/main.c	Fri Jan 09 08:23:54 2026 -0800
@@ -1,4 +1,4 @@
-#define SEOBEO_ENABLE_DEBUG
+// Debug mode is now controlled by build target: use //seobeo:seobeo_tcp_server_ws_debug
 #include "seobeo/seobeo.h"
 #include <time.h>
 
--- a/mrjunejune/src/blog/websocket-demystified/index.md	Fri Jan 09 07:42:04 2026 -0800
+++ b/mrjunejune/src/blog/websocket-demystified/index.md	Fri Jan 09 08:23:54 2026 -0800
@@ -4,14 +4,20 @@
 
 Today, it’s the standard for everything from chat apps to LLM interfaces, where the model streams bytes back to you one token at a time as it predicts the next word.
 
-Most developers just grab a library like [ws](https://github.com/websockets/ws) for Node.js or [websockets](https://websockets.readthedocs.io/) for Python and call it a day. But many don’t realize the underlying mechanism is actually pretty simple to implement yourself in a day or so. Let's look at how to build it from scratch.
+Most developers just grab a library like [ws](https://github.com/websockets/ws) for Node.js or [websockets](https://websockets.readthedocs.io/) for Python and call it a day. But many don’t realize the underlying mechanism is actually pretty simple to implement yourself in a day or so. Also they misunderstand what websocket actually do. Let's look at how to build it from scratch and debunk myths.
+
+### The "65,535" Myth 
+
+Before we write a single line of code, Let's talk about common myth. You’ll often hear developers say, *"A server can only handle 65,535 WebSocket connections because there are only 65,535 ports."*
+
+If this were true, Discord or Slack would need millions of separate IP addresses just to function. The confusion comes from the 16-bit size of the TCP port field, but a connection isn't defined by a port alone. You will see in this blog.
 
 ---
 
 ## Requirements
 
 * Ability to type
-* Half a brain
+* Half a brain to real mechanics, not the surface-level myths.
 * A computer
 
 ---
@@ -31,7 +37,8 @@
 
 To start the upgrade from HTTP to WebSocket, the client sends a standard GET request but with some very specific headers.
 
-<div class="center"> <img src="/public/white-noise-grass.png" /> </div>
+<div class="center"> <img src="/public/web-socket-header.webp" /> </div>
+
 
 I’m assuming you know how HTTP works. If not, you can open a developer tool by right clicking on your browser and seeing into network tab and refershign the page. The only interesting values here is the `Sec-WebSocket-Key`. This key is usually a 16-byte random value encoded in **Base64**.
 
@@ -124,13 +131,25 @@
 Seobeo_WebSocket_Server_Connection *p_conn = malloc(sizeof(Seobeo_WebSocket_Server_Connection));
 memset(p_conn, 0, sizeof(Seobeo_WebSocket_Server_Connection));
 
-p_conn->p_handle = p_handle;
+p_conn->p_handle = p_handle; // file descriptor
 p_conn->is_active = TRUE;
 p_conn->fragment_capacity = 4096;
 p_conn->fragment_buffer = malloc(p_conn->fragment_capacity);
 
 ```
 
+### Wait, what is the p_handle or file descriptor here??
+
+The File Descriptor (FD) is the internal ID badge your server assigns to a connection. The OS identifies a unique connection via a 4-tuple; Source IP, Source Port, Destination IP, Destination Port. You can think of the OS as a giant hashmap that links these 4-tuples to an integer (the FD).
+
+So the limits are from the number of FD and RAM capactiy. You can check your system's FD limit with:
+
+```bash
+ulimit -n
+```
+
+Now, we have debunked this myth. Let's see how the protocol actually works.
+
 ---
 
 ## Frame-Based Protocols
--- a/seobeo/BUILD	Fri Jan 09 07:42:04 2026 -0800
+++ b/seobeo/BUILD	Fri Jan 09 08:23:54 2026 -0800
@@ -341,7 +341,7 @@
   visibility = ["//visibility:public"],
 )
 
-# Names I often use 
+# Names I often use
 alias(
   name = "seobeo_server",
   actual = ":seobeo_tcp_server",
@@ -353,6 +353,130 @@
   actual = ":seobeo",
   visibility = ["//visibility:public"],
 )
+
+# ============================================================================
+# Debug Builds (with SEOBEO_ENABLE_DEBUG defined)
+# ============================================================================
+
+# TCP Server with HTTP + WebSocket (DEBUG)
+alias(
+  name = "seobeo_tcp_server_ws_debug",
+  actual = select({
+    "//config:macos":  ":seobeo_tcp_server_ws_debug_macos",
+    "//config:linux":  ":seobeo_tcp_server_ws_debug_linux",
+    "//conditions:default": ":seobeo_tcp_server_ws_debug_linux",
+  }),
+  visibility = ["//visibility:public"],
+)
+
+cc_library(
+  name = "seobeo_tcp_server_ws_debug_macos",
+  srcs = [
+    "s_network.c",
+    "s_web.c",
+    "s_logging.c",
+    "s_ssl.c",
+    "s_websocket_common.c",
+    "s_websocket_server.c",
+    "os/s_macos_edge.c",
+  ],
+  hdrs = [":seobeo_hdrs"],
+  deps = [
+    "//dowa:dowa",
+    "@openssl//:ssl",
+  ],
+  defines = ["SEOBEO_WEBSOCKET_SERVER", "SEOBEO_ENABLE_DEBUG"],
+  target_compatible_with = [
+    "@platforms//os:osx",
+  ],
+  visibility = ["//visibility:public"],
+)
+
+cc_library(
+  name = "seobeo_tcp_server_ws_debug_linux",
+  srcs = [
+    "s_network.c",
+    "s_web.c",
+    "s_logging.c",
+    "s_ssl.c",
+    "s_websocket_common.c",
+    "s_websocket_server.c",
+    "os/s_linux_edge.c",
+  ],
+  hdrs = [":seobeo_hdrs"],
+  deps = [
+    "//dowa:dowa",
+    "@openssl//:ssl",
+  ],
+  defines = ["SEOBEO_WEBSOCKET_SERVER", "SEOBEO_ENABLE_DEBUG"],
+  target_compatible_with = [
+    "@platforms//os:linux",
+  ],
+  visibility = ["//visibility:public"],
+)
+
+# All combined (DEBUG)
+alias(
+  name = "seobeo_debug",
+  actual = select({
+    "//config:macos":  ":seobeo_debug_macos",
+    "//config:linux":  ":seobeo_debug_linux",
+    "//conditions:default": ":seobeo_debug_linux",
+  }),
+  visibility = ["//visibility:public"],
+)
+
+cc_library(
+  name = "seobeo_debug_macos",
+  srcs = [
+    "s_network.c",
+    "s_web.c",
+    "s_logging.c",
+    "s_ssl.c",
+    "s_http_client.c",
+    "s_websocket_common.c",
+    "s_websocket.c",
+    "s_websocket_server.c",
+    "snapshot_creator.c",
+    "os/s_macos_edge.c",
+  ],
+  hdrs = [":seobeo_hdrs"],
+  deps = [
+    "//dowa:dowa",
+    "@openssl//:ssl",
+  ],
+  defines = ["SEOBEO_WEBSOCKET_SERVER", "SEOBEO_ENABLE_DEBUG"],
+  target_compatible_with = [
+    "@platforms//os:osx",
+  ],
+  visibility = ["//visibility:public"],
+)
+
+cc_library(
+  name = "seobeo_debug_linux",
+  srcs = [
+    "s_network.c",
+    "s_web.c",
+    "s_logging.c",
+    "s_ssl.c",
+    "s_http_client.c",
+    "s_websocket_common.c",
+    "s_websocket.c",
+    "s_websocket_server.c",
+    "snapshot_creator.c",
+    "os/s_linux_edge.c",
+  ],
+  hdrs = [":seobeo_hdrs"],
+  deps = [
+    "//dowa:dowa",
+    "@openssl//:ssl",
+  ],
+  defines = ["SEOBEO_WEBSOCKET_SERVER", "SEOBEO_ENABLE_DEBUG"],
+  target_compatible_with = [
+    "@platforms//os:linux",
+  ],
+  visibility = ["//visibility:public"],
+)
 # ============================================================================
 # Testing Utilities
 # ============================================================================
--- a/seobeo/s_web.c	Fri Jan 09 07:42:04 2026 -0800
+++ b/seobeo/s_web.c	Fri Jan 09 08:23:54 2026 -0800
@@ -189,15 +189,21 @@
 
     if (p_file_kv)
     {
-      // File is cached
-      file_content = ((Seobeo_Cache_Entry*)p_file_kv)->value;
-      body_size = strlen(file_content);
+      // File is cached - use stored size for binary file support
+      Seobeo_Cached_File *cached = ((Seobeo_Cache_Entry*)p_file_kv)->value;
+      file_content = cached->content;
+      body_size = cached->size;
     }
     else
     {
       file_content = Seobeo_Web_LoadFile(file_path, &body_size);
       if (file_content)
-        Dowa_HashMap_Push(p_html_cache, file_path, file_content);
+      {
+        Seobeo_Cached_File *cached = malloc(sizeof(Seobeo_Cached_File));
+        cached->content = (char*)file_content;
+        cached->size = body_size;
+        Dowa_HashMap_Push(p_html_cache, file_path, cached);
+      }
     }
 
     if (!file_content)
@@ -219,11 +225,16 @@
     else if (strstr(file_path, ".js")) mime = "application/javascript";
     else if (strstr(file_path, ".png")) mime = "image/png";
     else if (strstr(file_path, ".jpg") || strstr(file_path, ".jpeg")) mime = "image/jpeg";
+    else if (strstr(file_path, ".webp")) mime = "image/webp";
     else if (strstr(file_path, ".gif")) mime = "image/gif";
     else if (strstr(file_path, ".svg")) mime = "image/svg+xml";
     else if (strstr(file_path, ".ico")) mime = "image/x-icon";
     else if (strstr(file_path, ".json")) mime = "application/json";
     else if (strstr(file_path, ".wasm")) mime = "application/wasm";
+    else if (strstr(file_path, ".mp4")) mime = "video/mp4";
+    else if (strstr(file_path, ".webm")) mime = "video/webm";
+    else if (strstr(file_path, ".glb")) mime = "model/gltf-binary";
+    else if (strstr(file_path, ".gltf")) mime = "model/gltf+json";
 
     Seobeo_Log(SEOBEO_DEBUG, "File path: %s\nBody Size: %zu\n", file_path, body_size);
 
--- a/seobeo/seobeo_internal.h	Fri Jan 09 07:42:04 2026 -0800
+++ b/seobeo/seobeo_internal.h	Fri Jan 09 08:23:54 2026 -0800
@@ -50,8 +50,14 @@
   atomic_bool destroyed;
 } Seobeo_Handle;
 
-// HTML cache type: maps file paths (char*) to file contents (char*)
-typedef Dowa_KV(char*, char*) Seobeo_Cache_Entry;
+// Cached file entry with content and size (for binary file support)
+typedef struct {
+  char  *content;
+  size_t size;
+} Seobeo_Cached_File;
+
+// HTML cache type: maps file paths (char*) to cached file entries (Seobeo_Cached_File*)
+typedef Dowa_KV(char*, Seobeo_Cached_File*) Seobeo_Cache_Entry;
 
 typedef struct {
   Seobeo_Handle       *srv;