diff seobeo/s_web.c @ 175:71ad34a8bc9a hg-web

[HgWeb] Can stream hg response now. Added react page for hg web since we use json anyway.
author MrJuneJune <me@mrjunejune.com>
date Tue, 20 Jan 2026 06:06:47 -0800
parents 827c6ac504cd
children 8cf4ec5e2191
line wrap: on
line diff
--- a/seobeo/s_web.c	Mon Jan 19 18:59:23 2026 -0800
+++ b/seobeo/s_web.c	Tue Jan 20 06:06:47 2026 -0800
@@ -96,13 +96,14 @@
   // Recording IP to see who is ddosing or any web scrappers...
   void *p_real_ip_kv = Dowa_HashMap_Get_Ptr(p_req_map, "X-Real-IP");
   const char *real_ip = p_real_ip_kv ? ((Seobeo_Request_Entry*)p_real_ip_kv)->value : NULL;
+
   // Fallback
   if (!real_ip)
   {
     void *p_forwarded_kv = Dowa_HashMap_Get_Ptr(p_req_map, "X-Forwarded-For");
     real_ip = p_forwarded_kv ? ((Seobeo_Request_Entry*)p_forwarded_kv)->value : NULL;
   }
-  // Fallback
+
   if (!real_ip)
     real_ip = p_cli_handle->host;
 
@@ -137,7 +138,7 @@
 
   // --- Check for WebSocket upgrade request ---
   #ifdef SEOBEO_WEBSOCKET_SERVER
-  Seobeo_Log(SEOBEO_DEBUG, "Web soceket path \n");
+  Seobeo_Log(SEOBEO_DEBUG, "Web socket path \n");
   if (Seobeo_WebSocket_Server_Handle_Upgrade(p_cli_handle, p_req_map, path))
   {
     Seobeo_Log(SEOBEO_INFO, "WebSocket connection established\n");
@@ -149,7 +150,15 @@
   }
   #endif
 
-  // --- Try to match API route first ---
+  // --- Try to match streaming route first ---
+  Seobeo_Stream_Handler stream_handler = Seobeo_Router_Find_Stream_Handler(method, path, &p_req_map, p_request_arena);
+  if (stream_handler != NULL)
+  {
+    stream_handler(p_cli_handle, p_req_map, p_response_arena);
+    goto clean_up;
+  }
+
+  // --- Try to match API route ---
   Seobeo_Route_Handler handler = Seobeo_Router_Find_Handler(method, path, &p_req_map, p_request_arena);
   if (handler != NULL)
   {
@@ -293,7 +302,10 @@
       break;
 
     if (r == 0)
-      return 1;     // EAGAIN, try again later TODO: Add this as part of Handle struct.
+    {
+      Seobeo_Log(SEOBEO_INFO, "Waiting?\n");
+      continue;     // EAGAIN, try again later TODO: Add this as part of Handle struct.
+    }
   }
 
   // "METHOD SP PATH SP VERSION CRLF"
@@ -408,7 +420,6 @@
     char *next = strstr(line, "\r\n");
     if (!next) break;
 
-    // split at colon
     char *colon = memchr(line, ':', next - line);
     if (colon)
     {
@@ -432,7 +443,6 @@
       memcpy(val, val_start, value_len);
       val[value_len] = '\0';
 
-      // Both key and value are arena-allocated, hashmap will use them
       Dowa_HashMap_Push_Arena(*pp_map, key, val, p_arena);
     }
 
@@ -450,7 +460,6 @@
 
     Seobeo_Log(SEOBEO_DEBUG, "Content-Length=%zu, reading body in chunks...\n", body_len);
 
-    // Allocate buffer for entire body
     char *body = Dowa_Arena_Allocate(p_arena, body_len + 1);
     if (!body)
     {
@@ -567,6 +576,7 @@
   char *method; // "GET", "POST", "PUT", "DELETE"
   char *path_pattern; // "/v1/users/:id/posts/:post_id"
   Seobeo_Route_Handler handler;
+  Seobeo_Stream_Handler stream_handler; // For streaming responses
 
   // Pre-parsed path segments for efficient matching
   char **path_segments; // ["v1", "users", ":id", "posts", ":post_id"]
@@ -588,6 +598,25 @@
   route.method = strdup(method);
   route.path_pattern = strdup(path_pattern);
   route.handler = handler;
+  route.stream_handler = NULL;
+  route.path_segments = Dowa_String_Split(path_pattern, "/", strlen(path_pattern), 1, NULL);
+  route.segment_count = Dowa_Array_Length(route.path_segments);
+  route.is_param = (boolean*)malloc(sizeof(boolean) * route.segment_count);
+
+  for (size_t i = 0; i < route.segment_count; i++)
+    route.is_param[i] = (route.path_segments[i][0] == ':');
+
+  Dowa_Array_Push(g_routes, route);
+}
+
+void Seobeo_Router_Register_Stream(const char *method, const char *path_pattern, Seobeo_Stream_Handler handler)
+{
+  Seobeo_Route route = {0};
+
+  route.method = strdup(method);
+  route.path_pattern = strdup(path_pattern);
+  route.handler = NULL;
+  route.stream_handler = handler;
   route.path_segments = Dowa_String_Split(path_pattern, "/", strlen(path_pattern), 1, NULL);
   route.segment_count = Dowa_Array_Length(route.path_segments);
   route.is_param = (boolean*)malloc(sizeof(boolean) * route.segment_count);
@@ -670,6 +699,29 @@
   return NULL;
 }
 
+Seobeo_Stream_Handler Seobeo_Router_Find_Stream_Handler(
+  const char *method,
+  const char *path,
+  Seobeo_Request_Entry **pp_request_map,
+  Dowa_Arena *p_arena)
+{
+  if (g_routes == NULL || method == NULL || path == NULL)
+    return NULL;
+
+  size_t route_count = Dowa_Array_Length(g_routes);
+  for (size_t i = 0; i < route_count; i++)
+  {
+    Seobeo_Route *route = &g_routes[i];
+    if (strcmp(route->method, method) != 0)
+      continue;
+
+    if (route->stream_handler && match_route_and_extract(route, path, pp_request_map, p_arena))
+      return route->stream_handler;
+  }
+
+  return NULL;
+}
+
 void Seobeo_Router_Send_Response(
     Seobeo_Handle *p_handle,
     Seobeo_Request_Entry *p_response_map,
@@ -696,24 +748,23 @@
   const char *body = "";
   void *p_body_kv = Dowa_HashMap_Get_Ptr(p_response_map, "body");
   if (p_body_kv)
-  {
     body = ((Seobeo_Request_Entry*)p_body_kv)->value;
-  }
 
   const char *content_type = "text/html";
   void *p_content_type_kv = Dowa_HashMap_Get_Ptr(p_response_map, "content-type");
   if (p_content_type_kv)
-  {
     content_type = ((Seobeo_Request_Entry*)p_content_type_kv)->value;
-  }
 
-  size_t body_length = strlen(body);
+  // TODO: Update this to be integer
+  size_t body_length;
   void *p_content_length_kv = Dowa_HashMap_Get_Ptr(p_response_map, "content-length");
   if (p_content_length_kv)
   {
     const char *content_length_str = ((Seobeo_Request_Entry*)p_content_length_kv)->value;
     body_length = atoi(content_length_str);
   }
+  else
+    body_length = strlen(body);
 
   char *header = Dowa_Arena_Allocate(p_arena, 4096);
   Seobeo_Web_Header_Generate(header, status, content_type, body_length);
@@ -734,6 +785,8 @@
     free(temp);
   }
 
+  printf("hEADER %s\n", header);
+
   Seobeo_Handle_Queue(p_handle, (uint8_t*)header, strlen(header));
   Seobeo_Handle_Queue(p_handle, (uint8_t*)body, body_length); 
   Seobeo_Handle_Flush(p_handle);