keyctl/pkg/api/server.go

112 lines
2.3 KiB
Go

// Copyright (C) 2023 Marius Schellenberger
package api
import (
"context"
"net"
"net/http"
"os"
"time"
"git.giftfish.de/ston1th/keyctl/pkg/api/types"
serverv1 "git.giftfish.de/ston1th/keyctl/pkg/api/v1/server"
"git.giftfish.de/ston1th/keyctl/pkg/db"
"github.com/go-logr/logr"
"github.com/gorilla/mux"
)
// Server is the webapp and api server
type Server struct {
srv *http.Server
mux *mux.Router
log logr.Logger
Data *types.ContextData
listen net.Listener
socket net.Listener
}
type notFoundHandler struct {
s *Server
}
func (nf *notFoundHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
types.NewContext(w, r, nf.s.Data, nf.s.log).Err(types.ErrInvalidAPIRoute)
}
// NewHTTPServer returns a new HTTPServer
func NewServer(log logr.Logger, listen, socket string) (*Server, error) {
s := &Server{
mux: mux.NewRouter(),
log: log,
Data: &types.ContextData{Approver: types.NewApprover()},
}
l, err := net.Listen("tcp", listen)
if err != nil {
return nil, err
}
s.listen = l
sock, err := unixListener(socket)
net.Listen("unix", socket)
if err != nil {
return nil, err
}
s.socket = sock
s.mux.NotFoundHandler = &notFoundHandler{s}
for _, v := range serverv1.Routes {
s.mux.HandleFunc(v.Path, s.contextWrapper(v.Handler)).Methods(v.Methods...)
}
return s, nil
}
func unixListener(socket string) (sock net.Listener, err error) {
sock, err = net.Listen("unix", socket)
if err != nil {
return
}
err = os.Chmod(socket, 0660)
return
}
func (s *Server) Start(db *db.DB) {
s.srv = &http.Server{
Handler: s.mux,
ReadTimeout: 10 * time.Second,
WriteTimeout: 10 * time.Second,
}
s.Data.DB = db
go func() {
err := s.srv.Serve(s.listen)
if err != nil && err != http.ErrServerClosed {
s.log.Error(err, "")
}
}()
go func() {
err := s.srv.Serve(s.socket)
if err != nil && err != http.ErrServerClosed {
s.log.Error(err, "")
}
}()
return
}
func (s *Server) contextWrapper(h types.CtxHandler) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
h(types.NewContext(w, r, s.Data, s.log))
}
}
// Stop stops listening for incoming connections and closes currently open connections
func (s *Server) Shutdown(ctx context.Context) {
s.log.Info("stopping")
err := s.srv.Shutdown(ctx)
if err != nil {
s.log.Error(err, "")
}
s.log.Info("stopped")
}