ajhahn.de
← Flash
Flash 89 lines
// flashd — the Flash language server: the stdio driver.
//
// stdin and stdout ARE the protocol channel — nothing else may ever be
// written to stdout, or the client's framing is destroyed; anything
// human-readable goes to stderr. The loop is: block on one byte, drain
// whatever else the reader already buffered, then hand every complete
// frame to the server core. Each message is handled inside its own
// arena, so a session that runs for hours holds onto nothing but the
// document store (and the decoder's one-frame buffer), both backed by
// the general-purpose allocator.
//
// A framing error is fatal by design: without a parseable Content-Length
// the byte stream can never resynchronize, so the only honest move is to
// report on stderr and exit non-zero. EOF on stdin — the client went
// away without the shutdown/exit handshake — also exits non-zero, per
// the protocol's guidance for orphaned servers.

use std
use core
use build_options
use "transport"
use "server"

pub fn main(init std.process.Init) !void {
    io := init.io
    gpa := init.gpa

    var stdout_buf [4096]u8 = undefined
    var stdout_obj = std.Io.File.stdout().writer(io, &stdout_buf)
    out := &stdout_obj.interface

    var stderr_buf [256]u8 = undefined
    var stderr_obj = std.Io.File.stderr().writer(io, &stderr_buf)
    err_out := &stderr_obj.interface

    var stdin_buf [65536]u8 = undefined
    var stdin_obj = std.Io.File.stdin().reader(io, &stdin_buf)
    rdr := &stdin_obj.interface

    var srv = server.Server.init(gpa, build_options.version)
    defer srv.deinit()
    var dec transport.Decoder = .empty
    defer dec.deinit(gpa)

    while true {
        // Block for at least one byte, then drain the reader's buffer in
        // one feed — per-byte only for the first byte of a chunk.
        b := rdr.takeByte() catch break
        first := [1]u8{b}
        try dec.feed(gpa, first[0..])
        rest := rdr.buffered()
        if rest.len > 0 {
            try dec.feed(gpa, rest)
            rdr.toss(rest.len)
        }

        while true {
            body_or_null := dec.next() catch {
                err_out.writeAll("flashd: unrecoverable framing error on stdin\n") catch {}
                err_out.flush() catch {}
                std.process.exit(1)
            }
            body := body_or_null orelse break

            var msg_arena = core.arena.ArenaAllocator.init(gpa)
            defer msg_arena.deinit()
            outcome := try srv.handle(msg_arena.allocator(), body)
            if outcome.response |resp| {
                framed := try transport.frame(msg_arena.allocator(), resp)
                try out.writeAll(framed)
                try out.flush()
            }
            if outcome.exit |code| {
                out.flush() catch {}
                std.process.exit(code)
            }
        }
    }

    // EOF without the exit notification: the client vanished.
    err_out.writeAll("flashd: stdin closed without an exit notification\n") catch {}
    err_out.flush() catch {}
    std.process.exit(1)
}

test "the driver surface is reachable" {
    _ = &main
}