Eve Web Portal
The Eve Web Portal, evewp, is the production web layer of Eve, and it is written in Eve. It is not a tool for developers: it is where finished Eve applications are hosted, seen and watched. It also carries the Eve Web framework, which compiles Eve to WebAssembly so that the client side of a web application is written in Eve too, with no JavaScript written by the developer.
Planned: evewp belongs to level 7, the last level, and to version 0.6 of Eve. It needs the machine and the web modules of level 6 (see Server) and the safe HTML of level 7. Nothing is built yet. The design is in evewp/README.md of the Eve repository; the open questions are at its end. The graphical tool for developers is eveux, a native program, described in eveux/README.md.
What evewp does
| Part | Does |
|---|---|
| Edge | receives the public HTTP traffic of many domains and subdomains, routes each request by its Host header to the application that owns it, serves static files, and proxies dynamic requests to the Eve machine of the application |
| Host | keeps each application in its own folder, with versions; starts, watches, restarts and stops the Eve machine of each application; receives deploys and does rollbacks |
| Monitor | a graphic health server: connections, requests, domains, users, state, memory and logs of every application, and alerts |
| Web framework | Eve compiled to WebAssembly modules that run in the browser, sharing code with the server |
The Final Test of Eve
evewp is written in Eve on purpose: a production web server, used every day by real traffic, is the hardest test a language can get. It needs the network, text, concurrency, data, security, time and the compiler targets all at once, so it is the acceptance test of level 7 and a stress test of the virtual machine. Where speed decides, the copying of bytes between sockets, the sending of files and the compression are native modules of the system library, written in Zig; the decisions, the tables, the pages and the supervision are Eve. A failure of evewp is first a question about Eve: a missing feature, a slow path or a leak of the machine. It is fixed in the language or in the machine, not worked around.
Architecture
Internet
browsers --HTTPS--> reverse proxy (TLS, certificates)
| HTTP on loopback
v
evewp (an Eve program, eve -s)
Edge: host table, static files, proxy, limits
Host: apps/, versions, supervisor, deploy
Monitor: metrics, dashboard, alerts, /healthz
| IPC
+---------------+---------------+
v v v
app1.example app2.example admin.example
eve -s eve -s (the dashboard)
+ evedb + evedb
- Process isolation. The edge and the monitor never run application code. Each application is an Eve machine in its own process, so a crash or a runaway loop cannot stop the edge, the dashboard or the other applications.
- TLS. The Eve machine has no TLS server. HTTPS comes from a reverse proxy in front of evewp (Caddy, Nginx or a tunnel).
- One folder for each application.
apps/shop/holdsapp.cfg, the deployedversions/, the number of the active version, the data that survives deploys, the log and the IPC socket.
Monitoring
The edge counts what it sees; the applications are asked with vm.stat through their IPC door; the operating system gives memory and CPU. The pages show the health of everything on one screen, the domains and the application behind each, one application with its versions and logs, searchable logs and the alerts. Charts are SVG written by Eve code, so the first versions need no JavaScript at all: the pages refresh by themselves. An alert (an application down, too many 5xx answers, slow answers, repeated restarts) is sent to a webhook with the http client.
The Eve Web Framework
The client side of an application is written in Eve and compiled to WebAssembly. Pages are made on the server, from templates that escape every value by context; the interactive parts are Eve modules compiled for the browser and attached to an element of the page. The server and the browser can share modules: the same function that validates an amount runs on both sides.
No JavaScript, honestly
A WebAssembly module cannot reach the page or the network by itself: the browser offers the DOM, fetch, timers and events only as JavaScript functions, and a module is started by a few lines of JavaScript. So the developer writes no JavaScript, but the toolchain adds one small, fixed, generated loader shim (a few kilobytes, the same for every application) that starts the module and gives it the host functions. It holds no application logic. The page needs the policy script-src 'self' 'wasm-unsafe-eval'.
The browser profile
The language is the same; the libraries and the permissions differ. The compiler checks a module for the browser against a profile:
| Not allowed in the browser | Added in the browser |
|---|---|
fs, os, sockets, database, secret, the shell, threads | dom, http over the browser's fetch, storage, timers, rpc, forms, the console |
Two stages
- W1, the machine in WebAssembly. The Eve virtual machine is compiled to
wasm32and runs the program as source or as portable bytecode. It is the whole language of the profile, early, and it is what the tutorial playground uses. - W2, Eve to WebAssembly. A typed subset of Eve is compiled to a Wasm module: faster, smaller downloads for the hot code. A page can mix both.
A sketch of a module shared by the server and the browser, with the syntax that exists today:
module money is
export (format, valid_amount);
function valid_amount(text: String) => (@result: Logic) is
let result := text =~ "/^[0-9]+(\.[0-9]{1,2})?$/";
return;
function format(value: Decimal) => (@result: String) is
let result := "{value} EUR";
return;
end money;
Open points are the syntax of event handlers and reactive state in templates, and how a handler can wait for the network: a browser module has one thread, so a program is a set of handlers that run to completion, and await needs the machine to suspend a handler.
Security
- Limits on header size, body size, connections and request rate for each address and domain; an unknown
Hostnever reaches an application. - Every value in a page is escaped by context; no inline script; cookies are
HttpOnlyandSameSite=Strict. - Modules for the browser are signed and carry the list of what they may call; the loader refuses a module that asks for more than the page allows.
- The dashboard needs a login and roles; every start, stop, deploy and rollback is recorded.
Versions
| evewp | Content |
|---|---|
| 0.1 | the edge: host table, static files, proxy to an application, request log, limits, health |
| 0.2 | the monitor: metrics, dashboard pages with SVG charts, alerts |
| 0.3 | the host: application folders, versions, supervisor, deploy and rollback |
| 0.4 | pages: HTML templates, forms, sessions, login of the dashboard |
| 0.5 | the framework, stage W1: the machine in WebAssembly, the loader shim, dom, the playground |
| 0.6 | the framework, stage W2: a typed subset compiled to WebAssembly |
| 1.0 | every test of level 7 passes and the stress goals are met |
Related
The development tool is eveux, a native graphical program written in Zig, and its terminal sibling evetx; both are clients of the Eve machine, which is the server. See Server for the machine and its doors, EVE VM for the parts of eve, and Eve Database for the backend.
Read next: Compiler