mailsrv/services/server.go

100 lines
1.9 KiB
Go

package services
import (
"context"
"encoding/json"
"fmt"
"io"
"mailsrv/mail"
"mailsrv/runtime"
"net/http"
"time"
"github.com/rs/zerolog/log"
)
type HTTPServer interface {
Serve()
Done() <-chan struct{}
}
type Server struct {
ctx context.Context
fnCancel context.CancelFunc
port string
queue *runtime.Queue
chDone chan struct{}
}
func NewServer(ctx context.Context, port string, queue *runtime.Queue) Server {
ctxChild, fnCancel := context.WithCancel(ctx)
return Server{
ctx: ctxChild,
fnCancel: fnCancel,
port: port,
queue: queue,
chDone: make(chan struct{}),
}
}
func (s Server) Done() <-chan struct{} {
return s.chDone
}
func (s *Server) Serve() {
mux := http.NewServeMux()
mux.HandleFunc("/mail", s.handler)
log.Info().Str("port", s.port).Msg("http server is listening...")
server := &http.Server{
Addr: fmt.Sprintf(":%s", s.port),
Handler: mux,
ReadTimeout: 10 * time.Second,
WriteTimeout: 10 * time.Second,
}
go func() {
<-s.ctx.Done()
if err := server.Shutdown(s.ctx); err != nil {
log.Err(err).Msg("bad server shutdown")
}
s.chDone <- struct{}{}
}()
go func() {
if err := server.ListenAndServe(); err != nil {
log.Err(err).Msg("http server stops listening")
s.fnCancel()
}
}()
}
func (s *Server) handler(w http.ResponseWriter, r *http.Request) {
content, err := io.ReadAll(r.Body)
if err != nil {
log.Err(err).Msg("unable to read request body")
w.WriteHeader(http.StatusInternalServerError)
return
}
var email mail.Email
if err := json.Unmarshal(content, &email); err != nil {
log.Err(err).Msg("unable to deserialized request body into mail")
w.WriteHeader(http.StatusInternalServerError)
return
}
if err := email.Validate(); err != nil {
log.Err(err).Msg("email validation failed")
w.WriteHeader(http.StatusBadRequest)
return
}
s.queue.Add(email)
w.WriteHeader(http.StatusOK)
}