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
}