7 · Publicar una app full-stack

Hora de juntarlo todo: una app de notas con login, páginas renderizadas en el servidor, y notas que persisten en nyx-kv en vez de un Map global. Las mismas formas de handler que ya escribiste — lo único nuevo son unas líneas de RESP para hablar con la base de datos.

Hablar con nyx-kv

nyx-kv habla RESP, el protocolo de Redis. Para GET/SET alcanza un helper chico sobre un socket TCP plano; para TLS, pipelines y el set completo de comandos usa std/kvclient.

fn kv_get(key: String) -> String {
    let fd: int = tcp_connect("127.0.0.1", 6380)
    if fd < 0 { return "" }
    tcp_write(fd, "*2\r\n$3\r\nGET\r\n$" +
        int_to_string(key.length()) + "\r\n" + key + "\r\n")
    let header: String = tcp_read_line(fd)
    let n: int = string_to_int(header.substring(1, header.length()))
    var value: String = ""
    if n > 0 { value = tcp_read(fd, n) }
    tcp_close(fd)
    return value
}

Las notas de un usuario se guardan como un único string unido por barras bajo notes:<user> — chico y suficiente para el tutorial. Cargar hace split por |; guardar concatena y reescribe.

Los handlers

page_home muestra un form de login cuando no hay sesión, y las notas del usuario cuando la hay. do_login arranca una sesión y redirige al home; do_create guarda una nota y redirige al home. Cada página es una plantilla, con escape seguro por defecto.

fn page_home(req: Request) -> Response {
    let user: String = session_get(req, "user")
    if user.length() == 0 {
        return response_html(200, tpl_render("{{> login_form}}", map_new()))
    }
    let titles: Array = load_notes(user)
    var items: Array = []
    var i: int = 0
    while i < titles.length() {
        let t: String = titles[i]
        var m: Map = map_new()
        m.insert("title", t)
        items.push(m)
        i = i + 1
    }
    var ctx: Map = map_new()
    ctx.insert("user", user)
    ctx.insert("items", items)
    let tmpl: String = "<h1>{{user}}'s notes</h1>
        <ul>{{#each items}}<li>{{title}}</li>{{/each}}</ul>{{> note_form}}"
    return response_html(200, tpl_render(tmpl, ctx))
}

El código completo — helpers, los dos forms como parciales, y el cableado en main() — está en el directorio de ejemplos.

Publicalo

nyx build produce un binario. Copialo a tu servidor y ejecútalo bajo systemd — sin runtime que instalar al lado.

# /etc/systemd/system/notes-app.service
[Unit]
Description=notes-app
After=network-online.target

[Service]
ExecStart=/srv/notes-app/notes-app
Environment=PORT=3000
WorkingDirectory=/srv/notes-app
Restart=always

[Install]
WantedBy=multi-user.target
$ sudo systemctl enable --now notes-app

Pon nyx-proxy adelante para terminación TLS y tienes la forma exacta que sirve este mismo sitio.

Las protecciones ya están puestas. Los bodies de request gigantes reciben un 413 automático sin ser leídos; las respuestas estáticas llevan ETags para requests condicionales; el servidor es multi-hilo por defecto. No configuraste nada de eso.

Eso es todo el framework — desde curl … | sh hasta una app full-stack desplegada. La referencia de la API tiene cada función con su firma exacta cuando necesites los detalles.