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