modularised webserver and auth systems

This commit is contained in:
2026-01-04 01:14:06 +11:00
parent 4a21ba3821
commit 28b7ba34f0
36 changed files with 451 additions and 774 deletions

View File

@@ -0,0 +1,52 @@
package main
import (
"database/sql"
"projectreshoot/internal/config"
"projectreshoot/internal/handler"
"projectreshoot/internal/models"
"projectreshoot/pkg/contexts"
"git.haelnorr.com/h/golib/hlog"
"git.haelnorr.com/h/golib/hws"
"git.haelnorr.com/h/golib/hwsauth"
"github.com/pkg/errors"
)
func setupAuth(
config *config.Config,
logger *hlog.Logger,
conn *sql.DB,
server *hws.Server,
ignoredPaths []string,
) (*hwsauth.Authenticator[*models.User], error) {
auth, err := hwsauth.NewAuthenticator(
models.GetUserFromID,
server,
conn,
logger,
handler.NewErrorPage,
)
if err != nil {
return nil, errors.Wrap(err, "hwsauth.NewAuthenticator")
}
auth.SSL = config.SSL
auth.AccessTokenExpiry = config.AccessTokenExpiry
auth.RefreshTokenExpiry = config.RefreshTokenExpiry
auth.TokenFreshTime = config.TokenFreshTime
auth.TrustedHost = config.TrustedHost
auth.SecretKey = config.SecretKey
auth.LandingPage = "/profile"
auth.IgnorePaths(ignoredPaths...)
err = auth.Initialise()
if err != nil {
return nil, errors.Wrap(err, "auth.Initialise")
}
contexts.CurrentUser = auth.CurrentModel
return auth, nil
}

View File

@@ -0,0 +1,69 @@
package main
import (
"database/sql"
"git.haelnorr.com/h/golib/hws"
"io/fs"
"net/http"
"projectreshoot/internal/config"
"git.haelnorr.com/h/golib/hlog"
"git.haelnorr.com/h/golib/jwt"
"github.com/pkg/errors"
)
func setupHttpServer(
staticFS *fs.FS,
config *config.Config,
logger *hlog.Logger,
conn *sql.DB,
tokenGen *jwt.TokenGenerator,
) (server *hws.Server, err error) {
if staticFS == nil {
return nil, errors.New("No filesystem provided")
}
fs := http.FS(*staticFS)
httpServer, err := hws.NewServer(
config.Host,
config.Port,
config.ReadHeaderTimeout,
config.WriteTimeout,
config.IdleTimeout,
config.GZIP,
)
if err != nil {
return nil, errors.Wrap(err, "hws.NewServer")
}
ignoredPaths := []string{
"/static/css/output.css",
"/static/favicon.ico",
}
auth, err := setupAuth(config, logger, conn, httpServer, ignoredPaths)
if err != nil {
return nil, errors.Wrap(err, "setupAuth")
}
err = httpServer.AddLogger(logger)
if err != nil {
return nil, errors.Wrap(err, "httpServer.AddLogger")
}
err = httpServer.LoggerIgnorePaths(ignoredPaths...)
if err != nil {
return nil, errors.Wrap(err, "httpServer.LoggerIgnorePaths")
}
err = addRoutes(httpServer, &fs, config, logger, conn, tokenGen, auth)
if err != nil {
return nil, errors.Wrap(err, "addRoutes")
}
err = addMiddleware(httpServer, auth)
if err != nil {
return nil, errors.Wrap(err, "httpServer.AddMiddleware")
}
return httpServer, nil
}

View File

@@ -0,0 +1,23 @@
package main
import (
"git.haelnorr.com/h/golib/hws"
"git.haelnorr.com/h/golib/hwsauth"
"projectreshoot/internal/models"
"github.com/pkg/errors"
)
func addMiddleware(
server *hws.Server,
auth *hwsauth.Authenticator[*models.User],
) error {
err := server.AddMiddleware(
auth.Authenticate(),
)
if err != nil {
return errors.Wrap(err, "server.AddMiddleware")
}
return nil
}

View File

@@ -0,0 +1,127 @@
package main
import (
"database/sql"
"git.haelnorr.com/h/golib/hws"
"git.haelnorr.com/h/golib/hwsauth"
"net/http"
"projectreshoot/internal/config"
"projectreshoot/internal/handler"
"projectreshoot/internal/models"
"projectreshoot/internal/view/page"
"git.haelnorr.com/h/golib/hlog"
"git.haelnorr.com/h/golib/jwt"
"github.com/pkg/errors"
)
func addRoutes(
server *hws.Server,
staticFS *http.FileSystem,
config *config.Config,
logger *hlog.Logger,
conn *sql.DB,
tokenGen *jwt.TokenGenerator,
auth *hwsauth.Authenticator[*models.User],
) error {
// Create the routes
routes := []hws.Route{
{
Path: "/static/",
Method: hws.MethodGET,
Handler: http.StripPrefix("/static/", handler.StaticFS(staticFS, logger)),
},
{
Path: "/",
Method: hws.MethodGET,
Handler: handler.Root(),
},
{
Path: "/about",
Method: hws.MethodGET,
Handler: handler.HandlePage(page.About()),
},
{
Path: "/login",
Method: hws.MethodGET,
Handler: auth.LogoutReq(handler.LoginPage(config.TrustedHost)),
},
{
Path: "/login",
Method: hws.MethodPOST,
Handler: auth.LogoutReq(handler.LoginRequest(server, auth, conn)),
},
{
Path: "/register",
Method: hws.MethodGET,
Handler: auth.LogoutReq(handler.RegisterPage(config.TrustedHost)),
},
{
Path: "/register",
Method: hws.MethodPOST,
Handler: auth.LogoutReq(handler.RegisterRequest(config, logger, conn, tokenGen)),
},
{
Path: "/logout",
Method: hws.MethodPOST,
Handler: handler.Logout(server, auth, conn),
},
{
Path: "/reauthenticate",
Method: hws.MethodPOST,
Handler: auth.LoginReq(handler.Reauthenticate(server, auth, conn)),
},
{
Path: "/profile",
Method: hws.MethodGET,
Handler: auth.LoginReq(handler.ProfilePage()),
},
{
Path: "/account",
Method: hws.MethodGET,
Handler: auth.LoginReq(handler.AccountPage()),
},
{
Path: "/account-select-page",
Method: hws.MethodPOST,
Handler: auth.LoginReq(handler.AccountSubpage()),
},
{
Path: "/change-username",
Method: hws.MethodPOST,
Handler: auth.LoginReq(auth.FreshReq(handler.ChangeUsername(server, auth, conn))),
},
{
Path: "/change-password",
Method: hws.MethodPOST,
Handler: auth.LoginReq(auth.FreshReq(handler.ChangePassword(server, auth, conn))),
},
{
Path: "/change-bio",
Method: hws.MethodPOST,
Handler: auth.LoginReq(handler.ChangeBio(server, auth, conn)),
},
{
Path: "/movies",
Method: hws.MethodGET,
Handler: handler.MoviesPage(),
},
{
Path: "/search-movies",
Method: hws.MethodPOST,
Handler: handler.SearchMovies(config, logger),
},
{
Path: "/movie/{movie_id}",
Method: hws.MethodGET,
Handler: handler.Movie(config, logger),
},
}
// Register the routes with the server
err := server.AddRoutes(routes...)
if err != nil {
return errors.Wrap(err, "server.AddRoutes")
}
return nil
}

View File

@@ -4,11 +4,9 @@ import (
"context"
"fmt"
"io"
"net/http"
"os"
"os/signal"
"projectreshoot/internal/config"
"projectreshoot/internal/httpserver"
"projectreshoot/pkg/embedfs"
"sync"
"time"
@@ -62,16 +60,17 @@ func run(ctx context.Context, w io.Writer, args map[string]string, config *confi
)
logger.Debug().Msg("Setting up HTTP server")
httpServer := httpserver.NewServer(config, logger, conn, tokenGen, &staticFS)
httpServer, err := setupHttpServer(&staticFS, config, logger, conn, tokenGen)
if err != nil {
return errors.Wrap(err, "setupHttpServer")
}
// Runs the http server
logger.Debug().Msg("Starting up the HTTP server")
go func() {
logger.Info().Str("address", httpServer.Addr).Msg("Listening for requests")
if err := httpServer.ListenAndServe(); err != nil && err != http.ErrServerClosed {
logger.Error().Err(err).Msg("Error listening and serving")
}
}()
err = httpServer.Start()
if err != nil {
return errors.Wrap(err, "httpServer.Start")
}
// Handles graceful shutdown
var wg sync.WaitGroup
@@ -80,9 +79,7 @@ func run(ctx context.Context, w io.Writer, args map[string]string, config *confi
shutdownCtx := context.Background()
shutdownCtx, cancel := context.WithTimeout(shutdownCtx, 10*time.Second)
defer cancel()
if err := httpServer.Shutdown(shutdownCtx); err != nil {
logger.Error().Err(err).Msg("Error shutting down server")
}
httpServer.Shutdown(shutdownCtx)
})
wg.Wait()
logger.Info().Msg("Shutting down")