package eghttp import ( "context" "net" "net/http" "strconv" "sync/atomic" "time" ) const ( DefaultAddr = ":8080" DefaultReadHeaderTimeout = time.Second ) type Option interface { apply(server *http.Server) } func WithPort(port int) Option { return optionFunc(func(server *http.Server) { server.Addr = net.JoinHostPort("", strconv.Itoa(port)) }) } func WithHandler(handler http.Handler) Option { return optionFunc(func(server *http.Server) { server.Handler = handler }) } // WithServerOption 使用 fn 配置 [http.Server]; func WithServerOption(fn func(server *http.Server)) Option { return optionFunc(fn) } type optionFunc func(server *http.Server) func (fn optionFunc) apply(server *http.Server) { fn(server) } // HTTPListenAndServe 创建 [http.Server] 并提供启动和停止函数; // opts 按照顺序应用到 [http.Server] 上. func HTTPListenAndServe(opts ...Option) (func(ctx context.Context) error, func(ctx context.Context)) { server := &http.Server{ Addr: DefaultAddr, ReadHeaderTimeout: DefaultReadHeaderTimeout, } for _, opt := range opts { opt.apply(server) } return HTTPServer(server) } // HTTPServer 提供 [http.Server] 的启动和停止函数; func HTTPServer(server *http.Server) (func(ctx context.Context) error, func(ctx context.Context)) { inShutdown := &atomic.Bool{} c := make(chan error, 1) goFunc := func(_ context.Context) error { err := server.ListenAndServe() if inShutdown.Load() { err = <-c } return err } stopFunc := func(ctx context.Context) { inShutdown.Store(true) c <- server.Shutdown(ctx) } return goFunc, stopFunc }