package main import ( "context" "errors" "log" "net/http" "os" "os/signal" "syscall" "time" "hakurei.app/cmd/pkgserver/internal/ui" "hakurei.app/command" "hakurei.app/internal/rosa" ) const shutdownTimeout = 15 * time.Second func main() { log.SetFlags(0) log.SetPrefix("pkgserver: ") var ( flagAddr string ) ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM, syscall.SIGHUP) defer stop() c := command.New(os.Stderr, log.Printf, "pkgserver", func(args []string) error { var ( report *rosa.Report ) switch len(args) { case 0: break case 1: var err error rosa.DropCaches(rosa.OptLLVMNoLTO) report, err = rosa.OpenReport(args[0]) if err != nil { return err } default: return errors.New("pkgserver requires 1 argument") } var index packageIndex index.search = make(searchCache) if err := index.populate(report); err != nil { return err } ticker := time.NewTicker(1 * time.Minute) go func() { for { select { case <-ctx.Done(): ticker.Stop() return case <-ticker.C: index.search.clean() } } }() var mux http.ServeMux ui.Register(&mux) index.registerAPI(&mux) server := http.Server{ Addr: flagAddr, Handler: &mux, } go func() { <-ctx.Done() c, cancel := context.WithTimeout(context.Background(), shutdownTimeout) defer cancel() if err := server.Shutdown(c); err != nil { log.Fatal(err) } }() return server.ListenAndServe() }).Flag( &flagAddr, "addr", command.StringFlag(":8067"), "TCP network address to listen on", ) c.MustParse(os.Args[1:], func(err error) { if errors.Is(err, http.ErrServerClosed) { os.Exit(0) } log.Fatal(err) }) }