// Command stepd provides an HTTP server that automatically executes STEP files. package main import "os" import "log" import "time" import "errors" import "context" import "net/http" import "git.tebibyte.media/sashakoshka/step" import "git.tebibyte.media/sashakoshka/go-cli" import "git.tebibyte.media/sashakoshka/step/providers" import "git.tebibyte.media/sashakoshka/goutil/container" import "git.tebibyte.media/sashakoshka/go-service/daemon" import stephttp"git.tebibyte.media/sashakoshka/step/http" import "git.tebibyte.media/sashakoshka/go-service/routines" func main () { // parse command line arguments flagAddress := cli.NewInputFlag ( 'a', "address", "The address to host the server on", ":8080", cli.ValString) flagErrorDocument := cli.NewInputFlag ( 0, "error-document", "The document to use for displaying errors", "", cli.ValString) flagDirectories := cli.NewFlag ( 'd', "directories", "Serve the contents of directories") cmd := cli.New ( "Run an HTTP server that automaticaly executes STEP files", flagAddress, flagDirectories, cli.NewHelp()) cmd.ParseOrExit(os.Args) if len(cmd.Args) > 0 { cmd.Usage() os.Exit(1) } log.Println(`==========| STEP |===========`) log.Println(`Scriptable Template Processor`) log.Println(`... initializing`) // set up the environment environment := step.Environment { } environment.FuncProviders = providers.All() err := environment.Init(context.Background()) if err != nil { log.Fatal(err) } // set up the HTTP handler handler := stephttp.Handler { Environment: &environment, Directories: flagDirectories.Value == "true", StepExt: ucontainer.NewSet(".step"), Index: []string { "index.step", "index.html", "index" }, ErrorDocument: flagErrorDocument.Value, } // set up the HTTP server httpServer := http.Server { Addr: flagAddress.Value, Handler: &handler, } // set up the routine manager httpServerRoutine := httpServerRoutine(httpServer) manager := routines.Manager { Routines: []routines.Routine { &httpServerRoutine, }, } log.Println(`.// initialized.`) ctx, done := context.WithCancel(context.Background()) daemon.OnSigint(done) log.Printf("(i) listening on %s\n", httpServer.Addr) if err := manager.Run(ctx); err != nil && !errors.Is(err, context.Canceled) { log.Fatalln(err) } } type httpServerRoutine http.Server func (this *httpServerRoutine) Run (ctx context.Context) error { ctx, done := context.WithCancel(ctx) defer done() server := http.Server(*this) go func () { <- ctx.Done() shutdownCtx, _ := context.WithTimeout ( context.Background(), 16 * time.Second) server.Shutdown(shutdownCtx) } () err := server.ListenAndServe() if ctx.Err() != nil { return ctx.Err() } return err }