diff options
| author | eunhhu <[email protected]> | 2026-09-27 19:30:25 +0100 |
|---|---|---|
| committer | eunhhu <[email protected]> | 2026-09-27 19:30:25 +0100 |
| commit | d72f57af85bb57042332da8bc002a2a0640639a0 (patch) | |
| tree | b1a0ad2b798da32532f47ee431ca5ee24ec9f1ca /serve/surface.h | |
| parent | 6d276be51ba89b04a60bb16b5179c015ad202c7c (diff) | |
| download | pure-d72f57af85bb57042332da8bc002a2a0640639a0.tar.gz pure-d72f57af85bb57042332da8bc002a2a0640639a0.zip | |
Run a surface for people inside the node (design 010)
pure-serve --surface LIBRARY [-- ARGUMENTS] maps a library and runs its
pure_surface_run in a thread of its own (serve/surface.h). The surface
reads the app as of the last save where it is, a published snapshot in a
reader app, as a connection thread reads views; an eventfd tells it of
each new snapshot; and its events (a key pressed, text typed) are
requests without a host in the owner's queue, applied and saved with the
round, their results handed back to the surface's waiter. So one node
serves programs over HTTP and people on its display with one owner of
its states, and nothing between the states and the screen. pure-serve
exports its pure_* functions for the surface to call, one copy of the
app model in the process; the table carries sizeof(PureApp) and
sizeof(PureModule) so a surface built for another layout refuses.
The check builds a probe surface that types, presses and reads: its
events show in HTTP views, an HTTP input shows in it, wrong inputs are
refused, it stops with the server, and a module without states cannot
have one. Without a surface the request path measured the same (small
GETs 140.9k vs 139.9k, app totals 126.3k vs 126.3k over eight rounds);
the exported symbols cost 11 KB of the file and 24 KiB idle.
Diffstat (limited to 'serve/surface.h')
| -rw-r--r-- | serve/surface.h | 48 |
1 files changed, 48 insertions, 0 deletions
diff --git a/serve/surface.h b/serve/surface.h new file mode 100644 index 0000000..a79bf05 --- /dev/null +++ b/serve/surface.h @@ -0,0 +1,48 @@ +#ifndef PURE_SURFACE_H +#define PURE_SURFACE_H +#include "module.h" + +/* A surface shows an app to people (Vega's display, say): a library that + * pure-serve maps and runs in a thread of its own beside its connection + * threads (--surface LIBRARY [-- ARGUMENTS]). It reads the app as of the + * last save, as a connection thread reads views, and gives it events that + * the owner applies with the requests, one save a round. So a node is one + * process with one owner of its states, whether people or programs use it, + * and a surface reads states where they are, with no HTTP or JSON between. + * + * The library exports + * + * int pure_surface_run(const PureSurface *, int argc, char **argv); + * + * and calls the app model (core/module.h) as pure-serve exports it: one + * copy of that code in the process, the host's. argv[0] is the library. + * pure_surface_run returns when stopping says so (the changes descriptor + * becomes readable then too), or when it is done; the server serves on. */ +enum { PURE_SURFACE_VERSION = 1 }; + +typedef struct PureSurfaceHost PureSurfaceHost; +typedef struct { + unsigned version; + size_t app_size, module_size; /* sizeof(PureApp), sizeof(PureModule): a surface built for another layout refuses */ + const PureModule *module; + PureSurfaceHost *host; + /* An eventfd, readable after each save that changed what views show and + * when the server stops: poll it with the surface's own descriptors, and + * read its 8 bytes to clear it. */ + int changes; + /* The app as of the last save, shown in reader (a zeroed app the first + * time, the same one after): its views, rows and texts read as + * core/module.h says while the snapshot is held. Give it back with + * release. NULL before the first save. */ + PureSnapshot *(*read)(PureSurfaceHost *, PureApp *reader); + void (*release)(PureSurfaceHost *, PureSnapshot *); + /* An event, applied by the owner with the next save: a key input pressed + * and released, or text typed into a text input. Returns once it was + * applied and saved (PURE_OK), or why it was not. */ + PureResult (*press)(PureSurfaceHost *, uint32_t input); + PureResult (*type)(PureSurfaceHost *, uint32_t input, PureSpan text); + bool (*stopping)(PureSurfaceHost *); +} PureSurface; + +typedef int (*PureSurfaceRun)(const PureSurface *, int argc, char **argv); +#endif |
