// Copyright (c) 2026 Charles KWON OhJun (charleskwonohjun@gmail.com) // All rights reserved. package pgserver import ( "context" "fmt" "os" "strconv" "five/hbrt" ) // init wires the PG-server entry points into the runtime as // HB_FUNCs. Importing this package (e.g. via _ "five/hbrtl/pgserver" // from hbrtl's bootstrap) is enough; PRG code then sees: // // pg_server_start( nPort | cAddr [, cAuthMode ] ) // → starts server, blocks // (call inside SPAWN to keep // the calling thread free) // pg_server_stop() → closes the active server // // Embedded callers compose this with their own DBF setup: // // #include "FiveSqlDef.ch" // PROCEDURE Main() // USE customers SHARED // USE orders SHARED NEW // pg_server_start( 5432 ) /* blocks; psql can now connect */ // RETURN func init() { hbrt.HB_FUNC("PG_SERVER_START", pgServerStart) hbrt.HB_FUNC("PG_SERVER_STOP", pgServerStop) } func pgServerStart(ctx *hbrt.HBContext) { listen := ":5432" if ctx.PCount() >= 1 { if ctx.IsNumeric(1) { listen = ":" + strconv.Itoa(ctx.ParNI(1)) } else if ctx.IsChar(1) { listen = ctx.ParC(1) } } cfg := Config{Listen: listen} if ctx.PCount() >= 2 && ctx.IsChar(2) { cfg.AuthMode = ctx.ParC(2) } srv := NewServer(ctx.T.VM(), cfg) setActiveServer(srv) fmt.Fprintf(os.Stderr, "pgserver: listening on %s (auth=%s)\n", cfg.listenAddr(), defaultStr(cfg.AuthMode, "trust")) if err := srv.Serve(context.Background()); err != nil { fmt.Fprintf(os.Stderr, "pgserver: %v\n", err) } ctx.RetNil() } func pgServerStop(ctx *hbrt.HBContext) { if srv := takeActiveServer(); srv != nil { _ = srv.Close() } ctx.RetNil() } func defaultStr(s, fallback string) string { if s == "" { return fallback } return s } // activeServer tracks the most recently started server so // pg_server_stop() can find it without the PRG layer needing to // hold a handle. v1.0 is single-server-per-process; a future // upgrade can swap this for a slice. var activeServerSlot *Server func setActiveServer(s *Server) { activeServerSlot = s } func takeActiveServer() *Server { s := activeServerSlot activeServerSlot = nil return s }