111 lines
2.5 KiB
Go
111 lines
2.5 KiB
Go
package listeners
|
|
|
|
import (
|
|
"context"
|
|
"log/slog"
|
|
"net/http"
|
|
"sync"
|
|
"sync/atomic"
|
|
"time"
|
|
|
|
"git.savin.nyc/alex/go-receipt-tracker/listeners/handlers"
|
|
"github.com/gin-contrib/cors"
|
|
"github.com/gin-gonic/gin"
|
|
"github.com/uptrace/bun"
|
|
)
|
|
|
|
const TypeApi = "api"
|
|
|
|
// HTTPHealthCheck is a listener for providing an HTTP healthcheck endpoint.
|
|
type HttpApi struct {
|
|
sync.RWMutex
|
|
id string // the internal id of the listener
|
|
address string // the network address to bind to
|
|
config Config // configuration values for the listener
|
|
listen *http.Server // the http server
|
|
end uint32 // ensure the close methods are only called once
|
|
db *bun.DB //
|
|
}
|
|
|
|
// NewHTTPHealthCheck initializes and returns a new HTTP listener, listening on an address.
|
|
func NewHttpApi(config Config, db *bun.DB) *HttpApi {
|
|
return &HttpApi{
|
|
id: config.ID,
|
|
address: config.Address,
|
|
config: config,
|
|
db: db,
|
|
}
|
|
}
|
|
|
|
// ID returns the id of the listener.
|
|
func (l *HttpApi) ID() string {
|
|
return l.id
|
|
}
|
|
|
|
// Address returns the address of the listener.
|
|
func (l *HttpApi) Address() string {
|
|
return l.address
|
|
}
|
|
|
|
// Protocol returns the address of the listener.
|
|
func (l *HttpApi) Protocol() string {
|
|
if l.listen != nil && l.listen.TLSConfig != nil {
|
|
return "https"
|
|
}
|
|
|
|
return "http"
|
|
}
|
|
|
|
// Init initializes the listener.
|
|
func (l *HttpApi) Init(_ *slog.Logger) error {
|
|
|
|
handlers.DB = l.db
|
|
router := gin.Default()
|
|
router.Use(cors.Default())
|
|
|
|
v1 := router.Group("/api/v1")
|
|
{
|
|
v1.GET("/", handlers.HomePage)
|
|
v1.GET("/receipts", handlers.GetReceipts)
|
|
v1.GET("/receipts/:id", handlers.GetReceipt)
|
|
v1.DELETE("/receipts/:id", handlers.RemoveReceipt)
|
|
v1.POST("/receipts", handlers.AddReceipt)
|
|
v1.PUT("/receipts/:id", handlers.UpdateReceipt)
|
|
v1.GET("/receipts/:id/items", handlers.GetItems)
|
|
}
|
|
|
|
l.listen = &http.Server{
|
|
ReadTimeout: 5 * time.Second,
|
|
WriteTimeout: 5 * time.Second,
|
|
Addr: l.address,
|
|
Handler: router.Handler(),
|
|
}
|
|
|
|
if l.config.TLSConfig != nil {
|
|
l.listen.TLSConfig = l.config.TLSConfig
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// Serve starts listening for new connections and serving responses.
|
|
func (l *HttpApi) Serve() {
|
|
if l.listen.TLSConfig != nil {
|
|
_ = l.listen.ListenAndServeTLS("", "")
|
|
} else {
|
|
_ = l.listen.ListenAndServe()
|
|
}
|
|
}
|
|
|
|
// Close closes the listener and any client connections.
|
|
func (l *HttpApi) Close() {
|
|
l.Lock()
|
|
defer l.Unlock()
|
|
|
|
if atomic.CompareAndSwapUint32(&l.end, 0, 1) {
|
|
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
|
defer cancel()
|
|
_ = l.listen.Shutdown(ctx)
|
|
}
|
|
}
|