114 lines
3.0 KiB
Go
114 lines
3.0 KiB
Go
package handlers
|
|
|
|
import (
|
|
"context"
|
|
"github.com/winc-link/hummingbird/internal/pkg/container"
|
|
"github.com/winc-link/hummingbird/internal/pkg/di"
|
|
"github.com/winc-link/hummingbird/internal/pkg/startup"
|
|
"net/http"
|
|
"strconv"
|
|
"sync"
|
|
"time"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
)
|
|
|
|
// HttpServer contains references to dependencies required by the http server implementation.
|
|
type HttpServer struct {
|
|
router *gin.Engine
|
|
isRunning bool
|
|
doListenAndServe bool
|
|
}
|
|
|
|
// NewHttpServer is a factory method that returns an initialized HttpServer receiver struct.
|
|
func NewHttpServer(router *gin.Engine, doListenAndServe bool) *HttpServer {
|
|
return &HttpServer{
|
|
router: router,
|
|
isRunning: false,
|
|
doListenAndServe: doListenAndServe,
|
|
}
|
|
}
|
|
|
|
// IsRunning returns whether or not the http server is running. It is provided to support delayed shutdown of
|
|
// any resources required to successfully process http requests until after all outstanding requests have been
|
|
// processed (e.g. a database connection).
|
|
func (b *HttpServer) IsRunning() bool {
|
|
return b.isRunning
|
|
}
|
|
|
|
// BootstrapHandler fulfills the BootstrapHandler contract. It creates two go routines -- one that executes ListenAndServe()
|
|
// and another that waits on closure of a context's done channel before calling Shutdown() to cleanly shut down the
|
|
// http server.
|
|
func (b *HttpServer) BootstrapHandler(
|
|
ctx context.Context,
|
|
wg *sync.WaitGroup,
|
|
_ startup.Timer,
|
|
dic *di.Container) bool {
|
|
|
|
lc := container.LoggingClientFrom(dic.Get)
|
|
|
|
if !b.doListenAndServe {
|
|
lc.Info("Web server intentionally NOT started.")
|
|
wg.Add(1)
|
|
go func() {
|
|
defer wg.Done()
|
|
|
|
b.isRunning = true
|
|
<-ctx.Done()
|
|
b.isRunning = false
|
|
}()
|
|
return true
|
|
}
|
|
|
|
bootstrapConfig := container.ConfigurationFrom(dic.Get).GetBootstrap()
|
|
|
|
// this allows env override to explicitly set the value used
|
|
// for ListenAndServe as needed for different deployments
|
|
port := strconv.Itoa(bootstrapConfig.Service.Port)
|
|
addr := bootstrapConfig.Service.ServerBindAddr + ":" + port
|
|
// for backwards compatibility, the Host value is the default value if
|
|
// the ServerBindAddr value is not specified
|
|
if bootstrapConfig.Service.ServerBindAddr == "" {
|
|
addr = bootstrapConfig.Service.Host + ":" + port
|
|
}
|
|
|
|
timeout := time.Millisecond * time.Duration(bootstrapConfig.Service.Timeout)
|
|
server := &http.Server{
|
|
Addr: addr,
|
|
Handler: b.router,
|
|
WriteTimeout: timeout,
|
|
ReadTimeout: timeout,
|
|
}
|
|
|
|
wg.Add(1)
|
|
go func() {
|
|
defer wg.Done()
|
|
|
|
<-ctx.Done()
|
|
_ = server.Shutdown(context.Background())
|
|
lc.Info("Web server shut down")
|
|
}()
|
|
|
|
lc.Info("Web server starting (" + addr + ")")
|
|
|
|
wg.Add(1)
|
|
go func() {
|
|
defer func() {
|
|
wg.Done()
|
|
b.isRunning = false
|
|
}()
|
|
|
|
b.isRunning = true
|
|
err := server.ListenAndServe()
|
|
if err != nil {
|
|
lc.Errorf("Web server failed: %v", err)
|
|
cancel := container.CancelFuncFrom(dic.Get)
|
|
cancel() // this will caused the service to stop
|
|
} else {
|
|
lc.Info("Web server stopped")
|
|
}
|
|
}()
|
|
|
|
return true
|
|
}
|