# orca.web.server

> A module of morca's API.

`orca ui`'s server: one handler that looks each request up in the route table (`orca.web.routes`), checks who it's from (`orca.web.auth`) and answers it as its route's kind says.

```
ORCA_DATABASE_URL=postgresql:///orca ./build/orca ui     # 127.0.0.1:8270
```

A request goes through, in order:

1. The stylesheet, `/healthz` (200 once the database answers, without a
   login: what a deploy waits for before it retires the old UI; 503
   `draining` once a drain has started), and the
   worker API (`POST /api/worker/...`, `orca.api.worker`, its own token),
   answered before anything else.
2. The route. A `POST` that's no action, or another method than `GET`,
   `HEAD` or `POST`, is 405.
3. A `POST` whose `Origin` (or `Referer`) isn't the UI's own is refused
   (403), unless it's a script's with no `Origin` (`orca.web.auth`).
4. The database, per request; `/api/login` is answered here, before any
   token is looked at.
5. Who it's from: an API token or a session. A token that's no use is 401.
6. By the route's kind (`orca.web.router`): logging in or out as the
   handler says; a page with who's logged in (or a way to log in) in its
   header; an action, once login is on only with a session, audited as its
   user's.

The UI holds no state: its actions are rows the scheduler acts on, and it
can run beside the scheduler or anywhere else that reaches the database.
`ORCA_UI_ADDR` (`host:port`) moves it; it binds to localhost unless told
otherwise. `ORCA_WORKER_ADDR` serves the worker API on a listener of its
own as well (`orca.api.worker`). SIGTERM or SIGINT drains it: no new
connections, `/healthz` 503, the requests in flight answered, then exit 0 within
`ORCA_UI_DRAIN_SECONDS` (8; `orca.web.drain`).

## Structs

### `Ui`

```mojo
struct Ui
```

The pages, the API and the actions, over the database at `url`.

Implements: `Copyable`, `Handler`, `Movable`

Fields:

- `url: String`
- `table: List[Route]`
- `draining: AtomicFlag`: Set once a drain has started (`orca.web.drain.Drain.draining`).

#### `BodyType`

```mojo
comptime BodyType = InlineBody
```

The ``Body`` impl this handler authors its response with.

Defaults to :struct:`InlineBody` so plain handlers that return
``Response`` conform without declaring it. Override in a handler that
returns a typed ``ResponseImpl[SomeBody]``.

#### `__init__`

```mojo
def __init__(out self, url: String, draining: AtomicFlag)
```

#### `serve`

```mojo
def serve(self, req: Request) -> Response
```

## Functions

### `read_page`

```mojo
def read_page(mut db: State, url: String) -> Page
```

What `GET url` answers, for `orca` commands that print a page's JSON over the database (`orca.remote`).

### `act`

```mojo
def act(mut db: State, path: String, form: String) -> Optional[Page]
```

The action `path` with the fields of `form`, as the UI's button does it, or None if `path` names none (`orca.remote`). Not audited: the command acts as whoever can reach the database.

### `serve_ui`

```mojo
def serve_ui(url: String, addr: String, worker_addr: String = "")
```

Serves the pages on `addr` until SIGTERM or SIGINT drains them (`orca.web.drain`), and the worker API on `worker_addr` too, if one is given (`orca.api.worker`), until the process ends.

## Aliases

### `DEFAULT_ADDR`

```mojo
comptime DEFAULT_ADDR = "127.0.0.1:8270"
```

### `STYLESHEET`

```mojo
comptime STYLESHEET = "/static/orca.css"
```

### `HEALTHZ`

```mojo
comptime HEALTHZ = "/healthz"
```
