Error
+{ fmt.Sprintf("%#v", err) }
+ for k, v := range err.Info { +{ k } { fmt.Sprint(v) }
+ } + if err.Endpoint != "" { + Retry + } +diff --git a/.gitignore b/.gitignore index 0eaee3f..393af3b 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,4 @@ node_modules/ .dist/ *_templ.go *.env -./assets/css/uno.css +uno.css diff --git a/app/app.go b/app/app.go new file mode 100644 index 0000000..7cd0d4f --- /dev/null +++ b/app/app.go @@ -0,0 +1,123 @@ +package app + +import ( + "context" + "errors" + "fmt" + "log/slog" + "net/http" + + "forge.capytal.company/capytalcode/project-comicverse/lib/middleware" + "forge.capytal.company/capytalcode/project-comicverse/lib/router" + "forge.capytal.company/capytalcode/project-comicverse/lib/router/rerrors" + "github.com/minio/minio-go/v7" + "keikos.work/configs" + "keikos.work/handlers/pages" +) + +type App interface { + Start() error + Stop() error +} + +type Options struct { + Port uint + Development bool + Log *slog.Logger + + S3 *minio.Client + + Assets http.Handler +} + +type app struct { + log *slog.Logger + + s3 *minio.Client + assets http.Handler + + server *http.Server +} + +func (a *app) Start() error { + if err := a.server.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) { + return err + } + return nil +} + +func (a *app) Stop() error { + if err := a.server.Shutdown(context.Background()); err != nil { + return err + } + return nil +} + +func NewWeb(opts Options) App { + r := router.NewRouter() + + r.Use(middleware.NewLoggerMiddleware(opts.Log)) + + if opts.Development { + configs.DEVELOPMENT = true + r.Use(middleware.DevMiddleware) + } else { + r.Use(middleware.CacheMiddleware) + } + + r.Use(rerrors.NewErrorMiddleware(pages.ErrorPage{}.Component, opts.Log)) + + r.Handle("/", &pages.Home{}) + + imgs := &pages.Images{S3: opts.S3} + r.HandleFunc("GET /images", imgs.List) + r.HandleFunc("GET /images/{name}", imgs.Get) + + srv := http.Server{ + Addr: fmt.Sprintf(":%d", opts.Port), + Handler: r, + } + + return &app{ + log: opts.Log, + s3: opts.S3, + assets: opts.Assets, + server: &srv, + } +} + +func NewAdmin(opts Options) App { + r := router.NewRouter() + + r.Use(middleware.NewLoggerMiddleware(opts.Log)) + + if opts.Development { + configs.DEVELOPMENT = true + r.Use(middleware.DevMiddleware) + } else { + r.Use(middleware.CacheMiddleware) + } + + r.Use(rerrors.NewErrorMiddleware(pages.ErrorPage{}.Component, opts.Log)) + + r.Handle("/", &pages.Dashboard{}) + + imgs := &pages.Images{S3: opts.S3} + r.HandleFunc("GET /images", imgs.List) + r.HandleFunc("GET /images/{name}", imgs.Get) + r.HandleFunc("POST /images", imgs.Create) + r.HandleFunc("PUT /images/{name}", imgs.Update) + r.HandleFunc("DELETE /images/{name}", imgs.Delete) + + srv := http.Server{ + Addr: fmt.Sprintf(":%d", opts.Port), + Handler: r, + } + + return &app{ + log: opts.Log, + s3: opts.S3, + assets: opts.Assets, + server: &srv, + } +} diff --git a/cmd/main.go b/cmd/main.go deleted file mode 100644 index 17c7dc9..0000000 --- a/cmd/main.go +++ /dev/null @@ -1,78 +0,0 @@ -package main - -import ( - "context" - "errors" - "flag" - "fmt" - "log/slog" - "net/http" - "os" - "os/signal" - "syscall" - - "forge.capytal.company/capytalcode/project-comicverse/lib/middleware" - "forge.capytal.company/capytalcode/project-comicverse/lib/router" - "keikos.work/assets" - "keikos.work/configs" - "keikos.work/handlers/pages" -) - -var ( - port int64 = 8080 - dev bool = false -) - -func init() { - flag.Int64Var(&port, "port", port, "The website port") - flag.BoolVar(&dev, "dev", dev, "Run the website in development mode") -} - -func main() { - flag.Parse() - - l := slog.New(slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{ - Level: slog.LevelDebug, - })) - - if dev { - l.Info("RUNNING IN DEVELOPMENT MODE") - configs.DEVELOPMENT = true - } - - r := router.NewRouter() - - r.Use(middleware.NewLoggerMiddleware(l).Wrap) - - if configs.DEVELOPMENT { - r.Use(middleware.DevMiddleware) - r.Handle("/assets/", http.StripPrefix("/assets/", http.FileServer(http.Dir("./assets")))) - } else { - r.Use(middleware.CacheMiddleware) - r.Handle("/assets/", http.StripPrefix("/assets/", http.FileServerFS(assets.ASSETS))) - } - - r.Handle("/", pages.Routes()) - - srv := http.Server{ - Addr: fmt.Sprintf(":%d", port), - Handler: r, - } - - ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM) - defer stop() - - go func() { - if err := srv.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) { - l.Error("Listen and serve returned error", slog.String("error", err.Error())) - } - }() - - <-ctx.Done() - l.Info("Shutting down server...") - if err := srv.Shutdown(context.Background()); err != nil { - l.Error("Server shutdown returned error", slog.String("error", err.Error())) - } - - l.Info("FINAL") -} diff --git a/go.mod b/go.mod index 8b83bfd..cf306b9 100644 --- a/go.mod +++ b/go.mod @@ -2,6 +2,26 @@ module keikos.work go 1.23.3 -require forge.capytal.company/capytalcode/project-comicverse v0.0.0-20241030133525-b14b0be66b7a +require ( + forge.capytal.company/capytalcode/project-comicverse v0.0.0-20241213195940-67230ba75d8a + github.com/a-h/templ v0.2.793 + github.com/minio/minio-go/v7 v7.0.81 +) -require github.com/a-h/templ v0.2.793 // indirect +require ( + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/dustin/go-humanize v1.0.1 // indirect + github.com/go-ini/ini v1.67.0 // indirect + github.com/goccy/go-json v0.10.4 // indirect + github.com/google/uuid v1.6.0 // indirect + github.com/klauspost/compress v1.17.11 // indirect + github.com/klauspost/cpuid/v2 v2.2.9 // indirect + github.com/minio/md5-simd v1.1.2 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/rs/xid v1.6.0 // indirect + golang.org/x/crypto v0.31.0 // indirect + golang.org/x/net v0.32.0 // indirect + golang.org/x/sys v0.28.0 // indirect + golang.org/x/text v0.21.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) diff --git a/go.sum b/go.sum index 42eeb4c..f515da3 100644 --- a/go.sum +++ b/go.sum @@ -1,4 +1,44 @@ -forge.capytal.company/capytalcode/project-comicverse v0.0.0-20241030133525-b14b0be66b7a h1:lDGMhHL+B5zmrxiSEVPLNXglPApksQ7HPEAEGOuW7sI= -forge.capytal.company/capytalcode/project-comicverse v0.0.0-20241030133525-b14b0be66b7a/go.mod h1:COqB9i9nyQrQUz/ZqMvN98V7rh0t7vdXmBV36G8Q+7Q= +forge.capytal.company/capytalcode/project-comicverse v0.0.0-20241213192147-c2bbd80dcef8 h1:Jp0qWzdYZesWkcsH19sdsiiODKxsICY26oTwy2e+rmg= +forge.capytal.company/capytalcode/project-comicverse v0.0.0-20241213192147-c2bbd80dcef8/go.mod h1:COqB9i9nyQrQUz/ZqMvN98V7rh0t7vdXmBV36G8Q+7Q= +forge.capytal.company/capytalcode/project-comicverse v0.0.0-20241213195940-67230ba75d8a h1:PDmA2uCzFdn+CdS3C+Pg1YGhJERgMjwgCjUEUaIDZTM= +forge.capytal.company/capytalcode/project-comicverse v0.0.0-20241213195940-67230ba75d8a/go.mod h1:COqB9i9nyQrQUz/ZqMvN98V7rh0t7vdXmBV36G8Q+7Q= github.com/a-h/templ v0.2.793 h1:Io+/ocnfGWYO4VHdR0zBbf39PQlnzVCVVD+wEEs6/qY= github.com/a-h/templ v0.2.793/go.mod h1:lq48JXoUvuQrU0VThrK31yFwdRjTCnIE5bcPCM9IP1w= +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-ini/ini v1.67.0 h1:z6ZrTEZqSWOTyH2FlglNbNgARyHG8oLW9gMELqKr06A= +github.com/go-ini/ini v1.67.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8= +github.com/goccy/go-json v0.10.4 h1:JSwxQzIqKfmFX1swYPpUThQZp/Ka4wzJdK0LWVytLPM= +github.com/goccy/go-json v0.10.4/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= +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/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc= +github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0= +github.com/klauspost/cpuid/v2 v2.0.1/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= +github.com/klauspost/cpuid/v2 v2.2.9 h1:66ze0taIn2H33fBvCkXuv9BmCwDfafmiIVpKV9kKGuY= +github.com/klauspost/cpuid/v2 v2.2.9/go.mod h1:rqkxqrZ1EhYM9G+hXH7YdowN5R5RGN6NK4QwQ3WMXF8= +github.com/minio/md5-simd v1.1.2 h1:Gdi1DZK69+ZVMoNHRXJyNcxrMA4dSxoYHZSQbirFg34= +github.com/minio/md5-simd v1.1.2/go.mod h1:MzdKDxYpY2BT9XQFocsiZf/NKVtR7nkE4RoEpN+20RM= +github.com/minio/minio-go/v7 v7.0.81 h1:SzhMN0TQ6T/xSBu6Nvw3M5M8voM+Ht8RH3hE8S7zxaA= +github.com/minio/minio-go/v7 v7.0.81/go.mod h1:84gmIilaX4zcvAWWzJ5Z1WI5axN+hAbM5w25xf8xvC0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/rs/xid v1.6.0 h1:fV591PaemRlL6JfRxGDEPl69wICngIQ3shQtzfy2gxU= +github.com/rs/xid v1.6.0/go.mod h1:7XoLgs4eV+QndskICGsho+ADou8ySMSjJKDIan90Nz0= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U= +golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= +golang.org/x/net v0.32.0 h1:ZqPmj8Kzc+Y6e0+skZsuACbx+wzMgo5MQsJh9Qd6aYI= +golang.org/x/net v0.32.0/go.mod h1:CwU0IoeOlnQQWJ6ioyFrfRuomB8GKF6KbYXZVyeXNfs= +golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= +golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= +golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/handlers/pages/dashboard.templ b/handlers/pages/dashboard.templ new file mode 100644 index 0000000..089a099 --- /dev/null +++ b/handlers/pages/dashboard.templ @@ -0,0 +1,25 @@ +package pages + +import ( + "net/http" + + "forge.capytal.company/capytalcode/project-comicverse/lib/router/rerrors" + + "keikos.work/templates/layouts" +) + +type Dashboard struct{} + +templ (p *Dashboard) Component() { + @layouts.Page() { +
{ fmt.Sprintf("%#v", err) }
+ for k, v := range err.Info { +{ k } { fmt.Sprint(v) }
+ } + if err.Endpoint != "" { + Retry + } +
+
+}
+
+templ (p *Images) Component() {
+ @layouts.Page(layouts.PageInfo{
+ Heading: p.heading(),
+ }) {
+