view seobeo/os/s_macos_edge.c @ 279:b3b547563ec7

Add Google connector service and agent wiki Implement the C/Seobeo Google Drive and Gmail connector with encrypted OAuth storage, Zenbu authentication, browser testing, AI tool discovery, chunked HTTP decoding, and Bazel coverage. Consolidate repository guidance into progressive wiki documentation and enforce arena-first allocation for new first-party C code. Co-authored-by: Copilot <[email protected]> Copilot-Session: 84c338fd-0939-4bb3-b7f3-1062eb213e5d
author MrJuneJune <me@mrjunejune.com>
date Mon, 17 Aug 2026 22:22:36 -0700
parents 1f9877b637e9
children
line wrap: on
line source

#include <sys/event.h>
#include "seobeo/seobeo.h"


void *Seobeo_Web_Edge_Worker(void *vargs)
{
  WorkerArgs *args = vargs;
  struct kevent evlist[64];

  // Each thread creates its own kqueue to avoid race conditions
  int kq = kqueue();
  if (kq < 0) {
    perror("kqueue");
    return NULL;
  }

  // Add server socket to this thread's kqueue
  struct kevent kev = {
    .ident  = args->srv->socket,
    .filter = EVFILT_READ,
    .flags  = EV_ADD,
    .udata  = args->srv
  };
  kevent(kq, &kev, 1, NULL, 0, NULL);

  while (!Seobeo_Web_Server_Is_Stopping())
  {
    struct timespec timeout = {
      .tv_nsec = 250 * 1000 * 1000,
    };
    int ne = kevent(kq, NULL, 0, evlist, 64, &timeout);
    if (ne < 0) {
      if (errno == EINTR) continue;
      perror("kevent");
      continue;
    }

    for (int i = 0; i < ne; i++)
    {
      Seobeo_Handle *h = evlist[i].udata;
      if (h == args->srv)
      {
        // Accept new connections in a loop (for edge-triggered behavior)
        while (1) {
          Seobeo_Handle *cli = Seobeo_Stream_Handle_Server_Accept(args->srv);
          if (!cli) break;

          struct kevent client_kev = {
            .ident  = cli->socket,
            .filter = EVFILT_READ,
            .flags  = EV_ADD | EV_ONESHOT,
            .udata  = cli
          };
          kevent(kq, &client_kev, 1, NULL, 0, NULL);
        }
      } else {
        if (h->is_sse)
        {
          if (evlist[i].flags & EV_EOF)
          {
            Seobeo_Handle_Destroy(h);
            continue;
          }
          int32 read_result = Seobeo_Handle_Read(h);
          if (read_result < 0)
          {
            Seobeo_Handle_Destroy(h);
            continue;
          }
          if (h->read_buffer_len)
            Seobeo_Handle_Consume(h, h->read_buffer_len);
          struct kevent sse_kev = {
            .ident  = h->socket,
            .filter = EVFILT_READ,
            .flags  = EV_ADD | EV_ONESHOT,
            .udata  = h
          };
          kevent(kq, &sse_kev, 1, NULL, 0, NULL);
          continue;
        }

        // Remove from kqueue first
        struct kevent del_kev = {
          .ident  = h->socket,
          .filter = EVFILT_READ,
          .flags  = EV_DELETE,
        };
        kevent(kq, &del_kev, 1, NULL, 0, NULL);

        // macOS handles ordinary requests once, while SSE takes ownership.
        Seobeo_Web_ClientHandle_Request(h, args->cache, FALSE);
        if (h->is_sse)
        {
          struct kevent sse_kev = {
            .ident  = h->socket,
            .filter = EVFILT_READ,
            .flags  = EV_ADD | EV_ONESHOT,
            .udata  = h
          };
          kevent(kq, &sse_kev, 1, NULL, 0, NULL);
        }
        else
        {
          Seobeo_Handle_Destroy(h);
        }
      }
    }
  }

  close(kq);
  return NULL;
}

void  Seobeo_Web_Edge(
    Seobeo_Handle *p_server_handle,
    int            thread_count,
    Seobeo_Cache_Entry *p_html_cache)
{
  pthread_attr_t attr;
  pthread_attr_init(&attr);
  pthread_attr_setstacksize(&attr, 5 * 1024 * 1024); // 5 MB

  pthread_t  threads[thread_count];
  for (int i = 0; i < thread_count; i++)
  {
    WorkerArgs *args = malloc(sizeof(WorkerArgs));
    *args = (WorkerArgs){ p_server_handle, p_html_cache };

    pthread_create(&threads[i], &attr, Seobeo_Web_Edge_Worker, args);
  }
  for (int i = 0; i < thread_count; i++)
  {
    pthread_join(threads[i], NULL);
  }

  pthread_attr_destroy(&attr);
  return;
}