2022-03-22 09:21:55 +01:00
|
|
|
package server
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"fmt"
|
|
|
|
"log"
|
|
|
|
"net"
|
|
|
|
"net/http"
|
|
|
|
|
|
|
|
"forge.cadoles.com/wpetit/formidable/internal/server/route"
|
|
|
|
"forge.cadoles.com/wpetit/formidable/internal/server/template"
|
|
|
|
"github.com/pkg/errors"
|
|
|
|
"github.com/santhosh-tekuri/jsonschema/v5"
|
|
|
|
)
|
|
|
|
|
|
|
|
type Server struct {
|
|
|
|
host string
|
|
|
|
port uint
|
|
|
|
schema *jsonschema.Schema
|
|
|
|
defaults interface{}
|
|
|
|
values interface{}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *Server) Start(ctx context.Context) (<-chan net.Addr, <-chan error) {
|
|
|
|
errs := make(chan error)
|
|
|
|
addrs := make(chan net.Addr)
|
|
|
|
|
|
|
|
go s.run(ctx, addrs, errs)
|
|
|
|
|
|
|
|
return addrs, errs
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *Server) run(parentCtx context.Context, addrs chan net.Addr, errs chan error) {
|
|
|
|
ctx, cancel := context.WithCancel(parentCtx)
|
|
|
|
defer cancel()
|
|
|
|
|
|
|
|
listener, err := net.Listen("tcp", fmt.Sprintf("%s:%d", s.host, s.port))
|
|
|
|
if err != nil {
|
|
|
|
errs <- errors.WithStack(err)
|
|
|
|
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
addrs <- listener.Addr()
|
|
|
|
|
|
|
|
defer func() {
|
|
|
|
if err := listener.Close(); err != nil && !errors.Is(err, net.ErrClosed) {
|
|
|
|
errs <- errors.WithStack(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
close(errs)
|
|
|
|
close(addrs)
|
|
|
|
}()
|
|
|
|
|
|
|
|
go func() {
|
|
|
|
<-ctx.Done()
|
|
|
|
|
|
|
|
if err := listener.Close(); err != nil && !errors.Is(err, net.ErrClosed) {
|
|
|
|
log.Printf("%+v", errors.WithStack(err))
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
|
2022-05-04 12:23:53 +02:00
|
|
|
templates := getEmbeddedTemplates()
|
|
|
|
|
|
|
|
if err := template.Load(templates, "template"); err != nil {
|
2022-03-22 09:21:55 +01:00
|
|
|
errs <- errors.WithStack(err)
|
|
|
|
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2022-05-04 12:23:53 +02:00
|
|
|
assets := getEmbeddedAssets()
|
|
|
|
assetsHandler := http.FileServer(http.FS(assets))
|
|
|
|
|
|
|
|
handler, err := route.NewHandler(s.schema, s.defaults, s.values, assetsHandler)
|
2022-03-22 09:21:55 +01:00
|
|
|
if err != nil {
|
|
|
|
errs <- errors.WithStack(err)
|
|
|
|
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
log.Println("http server listening")
|
|
|
|
|
|
|
|
if err := http.Serve(listener, handler); err != nil && !errors.Is(err, net.ErrClosed) {
|
|
|
|
errs <- errors.WithStack(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
log.Println("http server exiting")
|
|
|
|
}
|
|
|
|
|
|
|
|
func New(funcs ...OptionFunc) *Server {
|
|
|
|
opt := defaultOption()
|
|
|
|
for _, fn := range funcs {
|
|
|
|
fn(opt)
|
|
|
|
}
|
|
|
|
|
|
|
|
return &Server{
|
|
|
|
host: opt.Host,
|
|
|
|
port: opt.Port,
|
|
|
|
schema: opt.Schema,
|
|
|
|
defaults: opt.Defaults,
|
|
|
|
values: opt.Values,
|
|
|
|
}
|
|
|
|
}
|