package main import ( "context" "flag" "fmt" "log" "net/http" "os" "os/signal" "sync" "syscall" ) var Config struct { Port int SessionD string } func main() { ctx, can := signal.NotifyContext(context.Background(), syscall.SIGINT) defer can() ctx, cleanup := contextWithCleanup(ctx) defer cleanup() config(ctx) log.Printf("%+v", Config) listenAndServe(ctx) log.Println("done") } func contextWithCleanup(ctx context.Context) (context.Context, func()) { m := map[int]func(){} ctx = context.WithValue(ctx, "__cleanup__", m) return ctx, func() { defer func() { recover() }() for _, v := range m { v() } } } func contextWithCleanupFunc(ctx context.Context, foo func()) { v := ctx.Value("__cleanup__") if v == nil { panic("cannot get context with cleanup func that doesnt have cleanup init") } m := v.(map[int]func()) m[len(m)] = foo } func config(ctx context.Context) { d, err := os.MkdirTemp(os.TempDir(), "ai.*") if err != nil { panic(err) } contextWithCleanupFunc(ctx, func() { os.RemoveAll(d) }) flag.IntVar(&Config.Port, "p", 37070, "port to listen on") flag.StringVar(&Config.SessionD, "d", d, "dir to store sessions") flag.Parse() } func listenAndServe(ctx context.Context) { wg := &sync.WaitGroup{} s := &http.Server{ Addr: fmt.Sprintf(":%d", Config.Port), Handler: http.HandlerFunc(handle), } wg.Add(1) go func() { defer wg.Done() if err := s.ListenAndServe(); err != nil && ctx.Err() == nil { panic(err) } }() <-ctx.Done() s.Close() wg.Wait() } func handle(w http.ResponseWriter, r *http.Request) { }