update to new webserver module

This commit is contained in:
2026-01-10 14:46:49 +11:00
parent 28b7ba34f0
commit a0cd269466
14 changed files with 199 additions and 69 deletions

View File

@@ -25,7 +25,7 @@ func setupAuth(
server,
conn,
logger,
handler.NewErrorPage,
handler.ErrorPage,
)
if err != nil {
return nil, errors.Wrap(err, "hwsauth.NewAuthenticator")

View File

@@ -2,10 +2,12 @@ package main
import (
"database/sql"
"git.haelnorr.com/h/golib/hws"
"io/fs"
"net/http"
"projectreshoot/internal/config"
"projectreshoot/internal/handler"
"git.haelnorr.com/h/golib/hws"
"git.haelnorr.com/h/golib/hlog"
"git.haelnorr.com/h/golib/jwt"
@@ -26,14 +28,14 @@ func setupHttpServer(
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")
}
httpServer.ReadHeaderTimeout(config.ReadHeaderTimeout)
httpServer.WriteTimeout(config.WriteTimeout)
httpServer.IdleTimeout(config.IdleTimeout)
httpServer.GZIP = config.GZIP
ignoredPaths := []string{
"/static/css/output.css",
@@ -45,6 +47,11 @@ func setupHttpServer(
return nil, errors.Wrap(err, "setupAuth")
}
err = httpServer.AddErrorPage(handler.ErrorPage)
if err != nil {
return nil, errors.Wrap(err, "httpServer.AddErrorPage")
}
err = httpServer.AddLogger(logger)
if err != nil {
return nil, errors.Wrap(err, "httpServer.AddLogger")

View File

@@ -114,7 +114,7 @@ func addRoutes(
{
Path: "/movie/{movie_id}",
Method: hws.MethodGET,
Handler: handler.Movie(config, logger),
Handler: handler.Movie(server, config),
},
}

View File

@@ -67,7 +67,7 @@ func run(ctx context.Context, w io.Writer, args map[string]string, config *confi
// Runs the http server
logger.Debug().Msg("Starting up the HTTP server")
err = httpServer.Start()
err = httpServer.Start(ctx)
if err != nil {
return errors.Wrap(err, "httpServer.Start")
}
@@ -79,7 +79,10 @@ 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()
httpServer.Shutdown(shutdownCtx)
err := httpServer.Shutdown(shutdownCtx)
if err != nil {
logger.Error().Err(err).Msg("Graceful shutdown failed")
}
})
wg.Wait()
logger.Info().Msg("Shutting down")

8
go.mod
View File

@@ -19,8 +19,13 @@ require (
modernc.org/sqlite v1.35.0
)
replace git.haelnorr.com/h/golib/hwsauth => /home/haelnorr/projects/golib/hwsauth
replace git.haelnorr.com/h/golib/hws => /home/haelnorr/projects/golib/hws
require (
github.com/dustin/go-humanize v1.0.1 // indirect
github.com/go-logr/logr v1.4.3 // indirect
github.com/golang-jwt/jwt v3.2.2+incompatible // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/mattn/go-colorable v0.1.14 // indirect
@@ -34,6 +39,9 @@ require (
golang.org/x/exp v0.0.0-20240325151524-a685a6edb6d8 // indirect
golang.org/x/sync v0.16.0 // indirect
golang.org/x/sys v0.34.0 // indirect
k8s.io/apimachinery v0.35.0 // indirect
k8s.io/klog/v2 v2.130.1 // indirect
k8s.io/utils v0.0.0-20251002143259-bc988d571ff4 // indirect
modernc.org/libc v1.61.13 // indirect
modernc.org/mathutil v1.7.1 // indirect
modernc.org/memory v1.8.2 // indirect

16
go.sum
View File

@@ -4,10 +4,6 @@ git.haelnorr.com/h/golib/env v0.9.0 h1:Ahqr3PbHy7HdWEHUhylzIZy6Gg8mST5UdgKlU2RAh
git.haelnorr.com/h/golib/env v0.9.0/go.mod h1:glUQVdA1HMKX1avTDyTyuhcr36SSxZtlJxKDT5KTztg=
git.haelnorr.com/h/golib/hlog v0.9.0 h1:ib8n2MdmiRK2TF067p220kXmhDe9aAnlcsgpuv+QpvE=
git.haelnorr.com/h/golib/hlog v0.9.0/go.mod h1:oOlzb8UVHUYP1k7dN5PSJXVskAB2z8EYgRN85jAi0Zk=
git.haelnorr.com/h/golib/hws v0.1.0 h1:+0eNq1uGWrGfbS5AgHeGoGDjVfCWuaVu+1wBxgPqyOY=
git.haelnorr.com/h/golib/hws v0.1.0/go.mod h1:b2pbkMaebzmck9TxqGBGzTJPEcB5TWcEHwFknLE7dqM=
git.haelnorr.com/h/golib/hwsauth v0.2.0 h1:rLfTtxo0lBUMuWzEdoS1Y4i8/UiCzDZ5DS+6WC/C974=
git.haelnorr.com/h/golib/hwsauth v0.2.0/go.mod h1:d1oXUstDHqKwCXzcEMdHGC8yoT2S2gwpJkrEo8daCMs=
git.haelnorr.com/h/golib/jwt v0.9.2 h1:l1Ow7DPGACAU54CnMP/NlZjdc4nRD1wr3xZ8a7taRvU=
git.haelnorr.com/h/golib/jwt v0.9.2/go.mod h1:fbuPrfucT9lL0faV5+Q5Gk9WFJxPlwzRPpbMQKYZok4=
git.haelnorr.com/h/golib/tmdb v0.8.0 h1:OQ6M2TB8FHm8fJD7/ebfWm63Duzfp0kmFX9genEig34=
@@ -21,11 +17,13 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY=
github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
github.com/google/pprof v0.0.0-20240409012703-83162a5b38cd h1:gbpYu9NMq8jhDVbvlGkMFWCjLFlqqEZjEmObmhUy6Vo=
github.com/google/pprof v0.0.0-20240409012703-83162a5b38cd/go.mod h1:kf6iHlnVGwgKolg33glAes7Yg/8iWP8ukqeldJSO7jw=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
@@ -79,6 +77,12 @@ golang.org/x/tools v0.35.0 h1:mBffYraMEf7aa0sB+NuKnuCy8qI/9Bughn8dC2Gu5r0=
golang.org/x/tools v0.35.0/go.mod h1:NKdj5HkL/73byiZSJjqJgKn3ep7KjFkBOkR/Hps3VPw=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
k8s.io/apimachinery v0.35.0 h1:Z2L3IHvPVv/MJ7xRxHEtk6GoJElaAqDCCU0S6ncYok8=
k8s.io/apimachinery v0.35.0/go.mod h1:jQCgFZFR1F4Ik7hvr2g84RTJSZegBc8yHgFWKn//hns=
k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk=
k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
k8s.io/utils v0.0.0-20251002143259-bc988d571ff4 h1:SjGebBtkBqHFOli+05xYbK8YF1Dzkbzn+gDM4X9T4Ck=
k8s.io/utils v0.0.0-20251002143259-bc988d571ff4/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
modernc.org/cc/v4 v4.24.4 h1:TFkx1s6dCkQpd6dKurBNmpo+G8Zl4Sq/ztJ+2+DEsh0=
modernc.org/cc/v4 v4.24.4/go.mod h1:uVtb5OGqUKpoLWhqwNQo/8LwvoiEBLvZXIQ/SmO6mL0=
modernc.org/ccgo/v4 v4.23.16 h1:Z2N+kk38b7SfySC1ZkpGLN2vthNJP1+ZzGZIlH7uBxo=

View File

@@ -90,9 +90,9 @@ func GetConfig(args map[string]string) (*Config, error) {
TrustedHost: env.String("TRUSTED_HOST", "127.0.0.1"),
SSL: env.Bool("SSL_MODE", false),
GZIP: env.Bool("GZIP", false),
ReadHeaderTimeout: env.Duration("READ_HEADER_TIMEOUT", 2),
WriteTimeout: env.Duration("WRITE_TIMEOUT", 10),
IdleTimeout: env.Duration("IDLE_TIMEOUT", 120),
ReadHeaderTimeout: env.Duration("READ_HEADER_TIMEOUT", 2) * time.Second,
WriteTimeout: env.Duration("WRITE_TIMEOUT", 10) * time.Second,
IdleTimeout: env.Duration("IDLE_TIMEOUT", 120) * time.Second,
DBName: "00001",
DBLockTimeout: env.Duration("DB_LOCK_TIMEOUT", 60),
SecretKey: env.String("SECRET_KEY", ""),

View File

@@ -57,7 +57,14 @@ func ChangeUsername(
// Start the transaction
tx, err := conn.BeginTx(ctx, nil)
if err != nil {
server.ThrowWarn(w, hws.NewError(http.StatusServiceUnavailable, "Error updating username", err))
err := server.ThrowError(w, r, hws.HWSError{
StatusCode: http.StatusServiceUnavailable,
Message: "Error updating username",
Error: err,
})
if err != nil {
server.ThrowFatal(w, err)
}
return
}
r.ParseForm()
@@ -65,7 +72,14 @@ func ChangeUsername(
unique, err := models.CheckUsernameUnique(tx, newUsername)
if err != nil {
tx.Rollback()
server.ThrowWarn(w, hws.NewError(http.StatusInternalServerError, "Error updating username", err))
err := server.ThrowError(w, r, hws.HWSError{
StatusCode: http.StatusInternalServerError,
Message: "Error updating username",
Error: err,
})
if err != nil {
server.ThrowFatal(w, err)
}
return
}
if !unique {
@@ -78,7 +92,14 @@ func ChangeUsername(
err = user.ChangeUsername(tx, newUsername)
if err != nil {
tx.Rollback()
server.ThrowWarn(w, hws.NewError(http.StatusInternalServerError, "Error updating username", err))
err := server.ThrowError(w, r, hws.HWSError{
StatusCode: http.StatusInternalServerError,
Message: "Error updating username",
Error: err,
})
if err != nil {
server.ThrowFatal(w, err)
}
return
}
tx.Commit()
@@ -101,7 +122,14 @@ func ChangeBio(
// Start the transaction
tx, err := conn.BeginTx(ctx, nil)
if err != nil {
server.ThrowWarn(w, hws.NewError(http.StatusServiceUnavailable, "Error updating bio", err))
err := server.ThrowError(w, r, hws.HWSError{
StatusCode: http.StatusServiceUnavailable,
Message: "Error updating bio",
Error: err,
})
if err != nil {
server.ThrowFatal(w, err)
}
return
}
r.ParseForm()
@@ -117,7 +145,14 @@ func ChangeBio(
err = user.ChangeBio(tx, newBio)
if err != nil {
tx.Rollback()
server.ThrowWarn(w, hws.NewError(http.StatusInternalServerError, "Error updating bio", err))
err := server.ThrowError(w, r, hws.HWSError{
StatusCode: http.StatusInternalServerError,
Message: "Error updating bio",
Error: err,
})
if err != nil {
server.ThrowFatal(w, err)
}
return
}
tx.Commit()
@@ -154,7 +189,14 @@ func ChangePassword(
// Start the transaction
tx, err := conn.BeginTx(ctx, nil)
if err != nil {
server.ThrowWarn(w, hws.NewError(http.StatusServiceUnavailable, "Error updating password", err))
err := server.ThrowError(w, r, hws.HWSError{
StatusCode: http.StatusServiceUnavailable,
Message: "Error updating password",
Error: err,
})
if err != nil {
server.ThrowFatal(w, err)
}
return
}
newPass, err := validateChangePassword(r)
@@ -167,7 +209,14 @@ func ChangePassword(
err = user.SetPassword(tx, newPass)
if err != nil {
tx.Rollback()
server.ThrowWarn(w, hws.NewError(http.StatusInternalServerError, "Error updating password", err))
err := server.ThrowError(w, r, hws.HWSError{
StatusCode: http.StatusInternalServerError,
Message: "Error updating password",
Error: err,
})
if err != nil {
server.ThrowFatal(w, err)
}
return
}
tx.Commit()

View File

@@ -3,14 +3,16 @@ package handler
import (
"net/http"
"projectreshoot/internal/view/page"
"git.haelnorr.com/h/golib/hws"
"github.com/pkg/errors"
)
func ErrorPage(
errorCode int,
w http.ResponseWriter,
r *http.Request,
) {
message := map[int]string{
) (hws.ErrorPage, error) {
messages := map[int]string{
400: "The request you made was malformed or unexpected.",
401: "You need to login to view this page.",
403: "You do not have permission to view this page.",
404: "The page or resource you have requested does not exist.",
@@ -18,25 +20,9 @@ func ErrorPage(
continues to happen contact an administrator.`,
503: "The server is currently down for maintenance and should be back soon. =)",
}
w.WriteHeader(errorCode)
page.Error(errorCode, http.StatusText(errorCode), message[errorCode]).
Render(r.Context(), w)
}
func NewErrorPage(
errorCode int,
w http.ResponseWriter,
r *http.Request,
) error {
message := map[int]string{
401: "You need to login to view this page.",
403: "You do not have permission to view this page.",
404: "The page or resource you have requested does not exist.",
500: `An error occured on the server. Please try again, and if this
continues to happen contact an administrator.`,
503: "The server is currently down for maintenance and should be back soon. =)",
msg, exists := messages[errorCode]
if !exists {
return nil, errors.New("No valid message for the given code")
}
w.WriteHeader(errorCode)
return page.Error(errorCode, http.StatusText(errorCode), message[errorCode]).
Render(r.Context(), w)
return page.Error(errorCode, http.StatusText(errorCode), msg), nil
}

View File

@@ -12,7 +12,14 @@ func Root() http.Handler {
return http.HandlerFunc(
func(w http.ResponseWriter, r *http.Request) {
if r.URL.Path != "/" {
ErrorPage(http.StatusNotFound, w, r)
page, err := ErrorPage(http.StatusNotFound)
if err != nil {
// TODO: add logger for this
}
err = page.Render(r.Context(), w)
if err != nil {
// TODO: add logger for this
}
return
}
page.Index().Render(r.Context(), w)

View File

@@ -66,7 +66,14 @@ func LoginRequest(
// Start the transaction
tx, err := conn.BeginTx(ctx, nil)
if err != nil {
server.ThrowWarn(w, hws.NewError(http.StatusServiceUnavailable, "Login failed", err))
err := server.ThrowError(w, r, hws.HWSError{
StatusCode: http.StatusServiceUnavailable,
Message: "Login failed",
Error: err,
})
if err != nil {
server.ThrowFatal(w, err)
}
return
}
r.ParseForm()
@@ -74,9 +81,16 @@ func LoginRequest(
if err != nil {
tx.Rollback()
if err.Error() != "Username or password incorrect" {
server.ThrowWarn(w, hws.NewError(http.StatusInternalServerError, "Login failed", err))
err := server.ThrowError(w, r, hws.HWSError{
StatusCode: http.StatusInternalServerError,
Message: "Login failed",
Error: err,
})
if err != nil {
server.ThrowFatal(w, err)
}
} else {
form.LoginForm(err.Error()).Render(r.Context(), w)
form.LoginForm("Username or password incorrect").Render(r.Context(), w)
}
return
}
@@ -85,7 +99,14 @@ func LoginRequest(
err = auth.Login(w, r, user, rememberMe)
if err != nil {
tx.Rollback()
server.ThrowWarn(w, hws.NewError(http.StatusInternalServerError, "Login failed", err))
err := server.ThrowError(w, r, hws.HWSError{
StatusCode: http.StatusInternalServerError,
Message: "Login failed",
Error: err,
})
if err != nil {
server.ThrowFatal(w, err)
}
return
}

View File

@@ -23,14 +23,28 @@ func Logout(
tx, err := conn.BeginTx(ctx, nil)
if err != nil {
server.ThrowError(w, r, hws.NewError(http.StatusInternalServerError, "Logout failed", err))
err := server.ThrowError(w, r, hws.HWSError{
StatusCode: http.StatusInternalServerError,
Message: "Logout failed",
Error: err,
})
if err != nil {
server.ThrowFatal(w, err)
}
return
}
defer tx.Rollback()
err = auth.Logout(tx, w, r)
if err != nil {
server.ThrowError(w, r, hws.NewError(http.StatusInternalServerError, "Logout failed", err))
err := server.ThrowError(w, r, hws.HWSError{
StatusCode: http.StatusInternalServerError,
Message: "Logout failed",
Error: err,
})
if err != nil {
server.ThrowFatal(w, err)
}
return
}
tx.Commit()

View File

@@ -6,36 +6,53 @@ import (
"projectreshoot/internal/view/page"
"strconv"
"git.haelnorr.com/h/golib/hlog"
"git.haelnorr.com/h/golib/hws"
"git.haelnorr.com/h/golib/tmdb"
)
func Movie(
server *hws.Server,
config *config.Config,
logger *hlog.Logger,
) http.Handler {
return http.HandlerFunc(
func(w http.ResponseWriter, r *http.Request) {
id := r.PathValue("movie_id")
movie_id, err := strconv.ParseInt(id, 10, 32)
if err != nil {
ErrorPage(http.StatusNotFound, w, r)
logger.Error().Err(err).Str("movie_id", id).
Msg("Error occured getting the movie")
err := server.ThrowError(w, r, hws.HWSError{
StatusCode: http.StatusBadRequest,
Message: "Movie ID provided is not valid",
Error: err,
Level: hws.ErrorDEBUG,
RenderErrorPage: true,
})
if err != nil {
server.ThrowFatal(w, err)
}
return
}
movie, err := tmdb.GetMovie(int32(movie_id), config.TMDBToken)
if err != nil {
ErrorPage(http.StatusInternalServerError, w, r)
logger.Error().Err(err).Int32("movie_id", int32(movie_id)).
Msg("Error occured getting the movie")
err := server.ThrowError(w, r, hws.HWSError{
StatusCode: http.StatusInternalServerError,
Message: "An error occured when trying to retrieve the requested movie",
Error: err,
})
if err != nil {
server.ThrowFatal(w, err)
}
return
}
credits, err := tmdb.GetCredits(int32(movie_id), config.TMDBToken)
if err != nil {
ErrorPage(http.StatusInternalServerError, w, r)
logger.Error().Err(err).Int32("movie_id", int32(movie_id)).
Msg("Error occured getting the movie credits")
err := server.ThrowError(w, r, hws.HWSError{
StatusCode: http.StatusInternalServerError,
Message: "An error occured when trying to retrieve the credits for the requested movie",
Error: err,
})
if err != nil {
server.ThrowFatal(w, err)
}
return
}
page.Movie(movie, credits, &config.TMDBConfig.Image).Render(r.Context(), w)

View File

@@ -44,7 +44,14 @@ func Reauthenticate(
// Start the transaction
tx, err := conn.BeginTx(ctx, nil)
if err != nil {
server.ThrowError(w, r, hws.NewError(http.StatusInternalServerError, "Failed to start transaction", err))
err := server.ThrowError(w, r, hws.HWSError{
StatusCode: http.StatusInternalServerError,
Message: "Failed to start transcation",
Error: err,
})
if err != nil {
server.ThrowFatal(w, err)
}
return
}
defer tx.Rollback()
@@ -56,7 +63,14 @@ func Reauthenticate(
}
err = auth.RefreshAuthTokens(tx, w, r)
if err != nil {
server.ThrowError(w, r, hws.NewError(http.StatusInternalServerError, "Failed to refresh user tokens", err))
err := server.ThrowError(w, r, hws.HWSError{
StatusCode: http.StatusInternalServerError,
Message: "Failed to refresh user tokens",
Error: err,
})
if err != nil {
server.ThrowFatal(w, err)
}
return
}
tx.Commit()