mirror of
https://github.com/hanzo-fi/go-libs.git
synced 2026-10-30 20:53:44 +00:00
122 lines
3.1 KiB
Go
122 lines
3.1 KiB
Go
package httpserver
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"net"
|
|
"net/http"
|
|
"time"
|
|
|
|
logging "github.com/hanzo-fi/go-libs/v5/pkg/observe/log"
|
|
"github.com/hanzo-fi/go-libs/v5/pkg/transport/serverport"
|
|
)
|
|
|
|
// Hook represents a lifecycle hook for the HTTP server.
|
|
// OnStart starts the server, OnStop shuts it down gracefully.
|
|
type Hook struct {
|
|
OnStart func(ctx context.Context) error
|
|
OnStop func(ctx context.Context) error
|
|
}
|
|
|
|
func ContextWithServerInfo(ctx context.Context) context.Context {
|
|
return serverport.ContextWithServerInfo(ctx, serverPortDiscr)
|
|
}
|
|
|
|
const serverPortDiscr = "http"
|
|
|
|
func URL(ctx context.Context) string {
|
|
return fmt.Sprintf("http://%s", serverport.Address(ctx, serverPortDiscr))
|
|
}
|
|
|
|
func startServer(ctx context.Context, s *serverport.Server, handler http.Handler, options ...func(server *http.Server)) (func(ctx context.Context) error, error) {
|
|
|
|
if err := s.Listen(ctx); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
srv := &http.Server{
|
|
Handler: handler,
|
|
ReadHeaderTimeout: 10 * time.Second,
|
|
IdleTimeout: 120 * time.Second,
|
|
}
|
|
for _, option := range options {
|
|
option(srv)
|
|
}
|
|
|
|
go func() {
|
|
if err := srv.Serve(s.Listener); err != nil && !errors.Is(err, http.ErrServerClosed) {
|
|
logging.FromContext(ctx).Errorf("failed to serve: %v", err)
|
|
}
|
|
}()
|
|
|
|
return func(ctx context.Context) error {
|
|
return srv.Shutdown(ctx)
|
|
}, nil
|
|
}
|
|
|
|
type ServerOptions struct {
|
|
serverOptions []serverport.ServerOpts
|
|
httpServerOpts []func(server *http.Server)
|
|
}
|
|
|
|
type ServerOptionModifier func(server *ServerOptions)
|
|
|
|
func WithServerPortOptions(opts ...serverport.ServerOpts) ServerOptionModifier {
|
|
return func(serverOptions *ServerOptions) {
|
|
serverOptions.serverOptions = append(serverOptions.serverOptions, opts...)
|
|
}
|
|
}
|
|
|
|
func WithListener(listener net.Listener) ServerOptionModifier {
|
|
return WithServerPortOptions(serverport.WithListener(listener))
|
|
}
|
|
|
|
func WithAddress(addr string) ServerOptionModifier {
|
|
return WithServerPortOptions(serverport.WithAddress(addr))
|
|
}
|
|
|
|
func WithHttpServerOpts(opts ...func(server *http.Server)) ServerOptionModifier {
|
|
return func(server *ServerOptions) {
|
|
server.httpServerOpts = opts
|
|
}
|
|
}
|
|
|
|
func NewHook(handler http.Handler, serverOptionModifiers ...ServerOptionModifier) Hook {
|
|
var (
|
|
close func(ctx context.Context) error
|
|
err error
|
|
)
|
|
|
|
serverOptions := &ServerOptions{}
|
|
for _, serverOptionModifier := range serverOptionModifiers {
|
|
serverOptionModifier(serverOptions)
|
|
}
|
|
|
|
server := serverport.NewServer(serverPortDiscr)
|
|
for _, option := range serverOptions.serverOptions {
|
|
option(server)
|
|
}
|
|
|
|
return Hook{
|
|
OnStart: func(ctx context.Context) error {
|
|
logging.FromContext(ctx).Infof("Start HTTP server")
|
|
defer func() {
|
|
logging.FromContext(ctx).Infof("HTTP server started")
|
|
}()
|
|
close, err = startServer(ctx, server, handler, serverOptions.httpServerOpts...)
|
|
return err
|
|
},
|
|
OnStop: func(ctx context.Context) error {
|
|
if close == nil {
|
|
return nil
|
|
}
|
|
logging.FromContext(ctx).Infof("Stop HTTP server")
|
|
defer func() {
|
|
logging.FromContext(ctx).Infof("HTTP server stopped")
|
|
}()
|
|
return close(ctx)
|
|
},
|
|
}
|
|
}
|