Mercurial
comparison 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 |
comparison
equal
deleted
inserted
replaced
| 263:ee04e4e69fed | 264:04fee26ecce0 |
|---|---|
| 405 Dowa_Array_Push(g_sse_streams, p_stream); | 405 Dowa_Array_Push(g_sse_streams, p_stream); |
| 406 pthread_mutex_unlock(&g_sse_mutex); | 406 pthread_mutex_unlock(&g_sse_mutex); |
| 407 return p_stream; | 407 return p_stream; |
| 408 } | 408 } |
| 409 | 409 |
| 410 void Seobeo_SSE_Set_Detach_Callback( | |
| 411 Seobeo_SSE_Stream *p_stream, | |
| 412 void (*cb)(Seobeo_SSE_Stream *, void *), | |
| 413 void *ctx) | |
| 414 { | |
| 415 if (!p_stream) | |
| 416 return; | |
| 417 pthread_mutex_lock(&g_sse_mutex); | |
| 418 p_stream->detach_cb = cb; | |
| 419 p_stream->detach_ctx = ctx; | |
| 420 pthread_mutex_unlock(&g_sse_mutex); | |
| 421 } | |
| 422 | |
| 410 void Seobeo_SSE_Server_Detach_Handle(Seobeo_Handle *p_handle) | 423 void Seobeo_SSE_Server_Detach_Handle(Seobeo_Handle *p_handle) |
| 411 { | 424 { |
| 412 if (!p_handle) | 425 if (!p_handle) |
| 413 return; | 426 return; |
| 414 p_handle->is_sse = FALSE; | 427 p_handle->is_sse = FALSE; |
| 428 | |
| 429 /* Save callback info before releasing the stream reference. */ | |
| 430 void (*detach_cb)(Seobeo_SSE_Stream *, void *) = NULL; | |
| 431 void *detach_ctx = NULL; | |
| 432 Seobeo_SSE_Stream *cb_stream = NULL; | |
| 433 | |
| 415 pthread_mutex_lock(&g_sse_mutex); | 434 pthread_mutex_lock(&g_sse_mutex); |
| 416 size_t count = Dowa_Array_Length(g_sse_streams); | 435 size_t count = Dowa_Array_Length(g_sse_streams); |
| 417 for (size_t i = 0; i < count; i++) | 436 for (size_t i = 0; i < count; i++) |
| 418 { | 437 { |
| 419 Seobeo_SSE_Stream *p_stream = g_sse_streams[i]; | 438 Seobeo_SSE_Stream *p_stream = g_sse_streams[i]; |
| 420 if (p_stream->p_handle != p_handle) | 439 if (p_stream->p_handle != p_handle) |
| 421 continue; | 440 continue; |
| 422 p_stream->closed = TRUE; | 441 p_stream->closed = TRUE; |
| 423 p_stream->p_handle = NULL; | 442 p_stream->p_handle = NULL; |
| 424 sse_clear_pending_unlocked(p_stream); | 443 sse_clear_pending_unlocked(p_stream); |
| 444 detach_cb = p_stream->detach_cb; | |
| 445 detach_ctx = p_stream->detach_ctx; | |
| 446 /* Keep a live reference for the callback; release afterward. */ | |
| 447 cb_stream = p_stream; | |
| 425 g_sse_streams[i] = Dowa_Array_Pop(g_sse_streams); | 448 g_sse_streams[i] = Dowa_Array_Pop(g_sse_streams); |
| 426 sse_release_unlocked(p_stream); | 449 /* Do NOT call sse_release_unlocked here; do it after mutex released |
| 450 * so the callback can safely acquire its own locks. */ | |
| 427 break; | 451 break; |
| 428 } | 452 } |
| 429 pthread_mutex_unlock(&g_sse_mutex); | 453 pthread_mutex_unlock(&g_sse_mutex); |
| 454 | |
| 455 /* Fire callback outside the mutex so callers may acquire other locks. */ | |
| 456 if (detach_cb && cb_stream) | |
| 457 detach_cb(cb_stream, detach_ctx); | |
| 458 | |
| 459 /* Drop the server's reference (the callback may hold its own reference). */ | |
| 460 if (cb_stream) | |
| 461 Seobeo_SSE_Release(cb_stream); | |
| 430 } | 462 } |
| 431 | 463 |
| 432 void Seobeo_SSE_Server_Destroy(void) | 464 void Seobeo_SSE_Server_Destroy(void) |
| 433 { | 465 { |
| 434 pthread_mutex_lock(&g_sse_mutex); | 466 pthread_mutex_lock(&g_sse_mutex); |