this repo has no description
1package main
2
3import (
4 "context"
5 "log/slog"
6 "net"
7 "net/http"
8 "time"
9
10 "tangled.org/bnewbold.net/scrumble/store"
11
12 "github.com/bluesky-social/indigo/atproto/identity"
13 "github.com/bluesky-social/indigo/util/svcutil"
14 "github.com/labstack/echo/v4"
15 "github.com/labstack/echo/v4/middleware"
16 "github.com/prometheus/client_golang/prometheus/promhttp"
17 "gorm.io/gorm"
18)
19
20type Server struct {
21 logger *slog.Logger
22 dir identity.Directory
23 store *store.Store
24}
25
26func NewServer(db *gorm.DB) (*Server, error) {
27
28 st, err := store.NewStore(db)
29 if err != nil {
30 return nil, err
31 }
32
33 return &Server{
34 logger: slog.Default(),
35 dir: identity.DefaultDirectory(),
36 store: st,
37 }, nil
38}
39
40func (srv *Server) StartMetrics(listen string) error {
41 http.Handle("/metrics", promhttp.Handler())
42 return http.ListenAndServe(listen, nil)
43}
44
45func (srv *Server) StartHTTP(bind string) error {
46 var lc net.ListenConfig
47 ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
48 defer cancel()
49
50 li, err := lc.Listen(ctx, "tcp", bind)
51 if err != nil {
52 return err
53 }
54 return srv.startWithListener(li)
55}
56
57func (srv *Server) startWithListener(listen net.Listener) error {
58 e := echo.New()
59 e.HideBanner = true
60
61 e.Use(middleware.CORSWithConfig(middleware.CORSConfig{
62 AllowOrigins: []string{"*"},
63 AllowHeaders: []string{echo.HeaderOrigin, echo.HeaderContentType, echo.HeaderAccept, echo.HeaderAuthorization},
64 }))
65 e.Use(func(next echo.HandlerFunc) echo.HandlerFunc {
66 return func(c echo.Context) error {
67 c.Response().Header().Set(echo.HeaderServer, "ScrumbleServer")
68 return next(c)
69 }
70 })
71 e.Use(middleware.LoggerWithConfig(middleware.DefaultLoggerConfig))
72
73 e.File("/robots.txt", "assets/robots.txt")
74 e.Static("/assets", "assets")
75
76 e.Use(svcutil.MetricsMiddleware)
77
78 e.GET("/", srv.HandleHomeMessage)
79 e.GET("/_health", srv.HandleHealthCheck)
80
81 // In order to support booting on random ports in tests, we need to tell
82 // the Echo instance it's already got a port, and then use its StartServer
83 // method to re-use that listener.
84 e.Listener = listen
85 httpServer := &http.Server{}
86 // TODO: attach echo to Server, for shutdown?
87 return e.StartServer(httpServer)
88}
89
90func (srv *Server) Shutdown() []error {
91 var errs []error
92
93 // TODO: stop consumer
94 // TODO: stop echo
95 return errs
96}