diff seobeo/s_sse.c @ 264:04fee26ecce0

add authenticated JRPG conversation platform Add reusable auth/session storage, owned conversation recovery, guest quotas, admin workflows, URL-routed conversation UI, mobile frame support, and parallel browser acceptance. Co-authored-by: Copilot <[email protected]>
author MrJuneJune <me@mrjunejune.com>
date Fri, 07 Aug 2026 07:34:12 -0700
parents 609d3c6aff4e
children
line wrap: on
line diff
--- a/seobeo/s_sse.c	Thu Aug 06 11:31:30 2026 -0700
+++ b/seobeo/s_sse.c	Fri Aug 07 07:34:12 2026 -0700
@@ -407,11 +407,30 @@
   return p_stream;
 }
 
+void Seobeo_SSE_Set_Detach_Callback(
+    Seobeo_SSE_Stream *p_stream,
+    void (*cb)(Seobeo_SSE_Stream *, void *),
+    void *ctx)
+{
+  if (!p_stream)
+    return;
+  pthread_mutex_lock(&g_sse_mutex);
+  p_stream->detach_cb  = cb;
+  p_stream->detach_ctx = ctx;
+  pthread_mutex_unlock(&g_sse_mutex);
+}
+
 void Seobeo_SSE_Server_Detach_Handle(Seobeo_Handle *p_handle)
 {
   if (!p_handle)
     return;
   p_handle->is_sse = FALSE;
+
+  /* Save callback info before releasing the stream reference. */
+  void (*detach_cb)(Seobeo_SSE_Stream *, void *) = NULL;
+  void              *detach_ctx                   = NULL;
+  Seobeo_SSE_Stream *cb_stream                    = NULL;
+
   pthread_mutex_lock(&g_sse_mutex);
   size_t count = Dowa_Array_Length(g_sse_streams);
   for (size_t i = 0; i < count; i++)
@@ -422,11 +441,24 @@
     p_stream->closed = TRUE;
     p_stream->p_handle = NULL;
     sse_clear_pending_unlocked(p_stream);
+    detach_cb  = p_stream->detach_cb;
+    detach_ctx = p_stream->detach_ctx;
+    /* Keep a live reference for the callback; release afterward. */
+    cb_stream = p_stream;
     g_sse_streams[i] = Dowa_Array_Pop(g_sse_streams);
-    sse_release_unlocked(p_stream);
+    /* Do NOT call sse_release_unlocked here; do it after mutex released
+     * so the callback can safely acquire its own locks. */
     break;
   }
   pthread_mutex_unlock(&g_sse_mutex);
+
+  /* Fire callback outside the mutex so callers may acquire other locks. */
+  if (detach_cb && cb_stream)
+    detach_cb(cb_stream, detach_ctx);
+
+  /* Drop the server's reference (the callback may hold its own reference). */
+  if (cb_stream)
+    Seobeo_SSE_Release(cb_stream);
 }
 
 void Seobeo_SSE_Server_Destroy(void)