package main import ( "bytes" "context" "io" "log" "os" "os/exec" "tildegit.org/tjp/gus" "tildegit.org/tjp/gus/gemini" "tildegit.org/tjp/gus/logging" ) func main() { // Get TLS files from the environment certfile, keyfile := envConfig() // build a TLS configuration suitable for gemini tlsconf, err := gemini.FileTLS(certfile, keyfile) if err != nil { log.Fatal(err) } _, infoLog, _, errLog := logging.DefaultLoggers() // add request logging to the request handler handler := logging.LogRequests(infoLog)(cowsayHandler) // run the server server, err := gemini.NewServer(context.Background(), "localhost", "tcp4", ":1965", handler, errLog, tlsconf) if err != nil { log.Fatal(err) } server.Serve() } func cowsayHandler(ctx context.Context, req *gus.Request) *gus.Response { // prompt for a query if there is none already if req.RawQuery == "" { return gemini.Input("enter a phrase") } // find the "cowsay" executable binpath, err := exec.LookPath("cowsay") if err != nil { return gemini.Failure(err) } // build the command and set the query to be passed to its stdin cmd := exec.CommandContext(ctx, binpath) cmd.Stdin = bytes.NewBufferString(req.UnescapedQuery()) // set up a pipe so we can read the command's stdout rd, err := cmd.StdoutPipe() if err != nil { return gemini.Failure(err) } // start the command if err := cmd.Start(); err != nil { return gemini.Failure(err) } // read the complete stdout contents, clean up the process on error buf, err := io.ReadAll(rd) if err != nil { cmd.Process.Kill() cmd.Wait() return gemini.Failure(err) } // wait for the process to close cmd.Wait() // pass the buffer to the response wrapped in ``` toggles, // and include a link to start over out := io.MultiReader( bytes.NewBufferString("```\n"), bytes.NewBuffer(buf), bytes.NewBufferString("\n```\n=> . again"), ) return gemini.Success("text/gemini", out) } func envConfig() (string, string) { certfile, ok := os.LookupEnv("SERVER_CERTIFICATE") if !ok { log.Fatal("missing SERVER_CERTIFICATE environment variable") } keyfile, ok := os.LookupEnv("SERVER_PRIVATEKEY") if !ok { log.Fatal("missing SERVER_PRIVATEKEY environment variable") } return certfile, keyfile }