package main import ( "bytes" "context" "io" "log" "net" "os" "os/exec" guslog "tildegit.org/tjp/gus/contrib/log" "tildegit.org/tjp/gus/gemini" ) 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) } // set up the network listener listener, err := net.Listen("tcp4", ":1965") if err != nil { log.Fatal(err) } // add request logging to the request handler handler := guslog.Requests(os.Stdout, nil)(cowsayHandler) // run the server gemini.NewServer(context.Background(), tlsconf, listener, handler).Serve() } func cowsayHandler(ctx context.Context, req *gemini.Request) *gemini.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 }