mirror of
https://github.com/hay-kot/homebox.git
synced 2024-11-22 00:25:43 +00:00
chore: bump http kit (#817)
* use new httpkit runner * refactor out last httpkit changes * fix timeout defaults * fix wrong time input - closes #819
This commit is contained in:
parent
77b4d594af
commit
2867a05c92
10 changed files with 121 additions and 67 deletions
|
@ -1,22 +1,18 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/hay-kot/homebox/backend/internal/core/services"
|
"github.com/hay-kot/homebox/backend/internal/core/services"
|
||||||
"github.com/hay-kot/homebox/backend/internal/core/services/reporting/eventbus"
|
"github.com/hay-kot/homebox/backend/internal/core/services/reporting/eventbus"
|
||||||
"github.com/hay-kot/homebox/backend/internal/data/ent"
|
"github.com/hay-kot/homebox/backend/internal/data/ent"
|
||||||
"github.com/hay-kot/homebox/backend/internal/data/repo"
|
"github.com/hay-kot/homebox/backend/internal/data/repo"
|
||||||
"github.com/hay-kot/homebox/backend/internal/sys/config"
|
"github.com/hay-kot/homebox/backend/internal/sys/config"
|
||||||
"github.com/hay-kot/homebox/backend/pkgs/mailer"
|
"github.com/hay-kot/homebox/backend/pkgs/mailer"
|
||||||
"github.com/hay-kot/httpkit/server"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type app struct {
|
type app struct {
|
||||||
conf *config.Config
|
conf *config.Config
|
||||||
mailer mailer.Mailer
|
mailer mailer.Mailer
|
||||||
db *ent.Client
|
db *ent.Client
|
||||||
server *server.Server
|
|
||||||
repos *repo.AllRepos
|
repos *repo.AllRepos
|
||||||
services *services.AllServices
|
services *services.AllServices
|
||||||
bus *eventbus.EventBus
|
bus *eventbus.EventBus
|
||||||
|
@ -37,13 +33,3 @@ func new(conf *config.Config) *app {
|
||||||
|
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *app) startBgTask(t time.Duration, fn func()) {
|
|
||||||
timer := time.NewTimer(t)
|
|
||||||
|
|
||||||
for {
|
|
||||||
timer.Reset(t)
|
|
||||||
a.server.Background(fn)
|
|
||||||
<-timer.C
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
37
backend/app/api/bgrunner.go
Normal file
37
backend/app/api/bgrunner.go
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type BackgroundTask struct {
|
||||||
|
name string
|
||||||
|
Interval time.Duration
|
||||||
|
Fn func(context.Context)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (tsk *BackgroundTask) Name() string {
|
||||||
|
return tsk.name
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewTask(name string, interval time.Duration, fn func(context.Context)) *BackgroundTask {
|
||||||
|
return &BackgroundTask{
|
||||||
|
Interval: interval,
|
||||||
|
Fn: fn,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (tsk *BackgroundTask) Start(ctx context.Context) error {
|
||||||
|
timer := time.NewTimer(tsk.Interval)
|
||||||
|
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
return nil
|
||||||
|
case <-timer.C:
|
||||||
|
timer.Reset(tsk.Interval)
|
||||||
|
tsk.Fn(ctx)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -23,7 +23,7 @@ import (
|
||||||
"github.com/hay-kot/homebox/backend/internal/sys/config"
|
"github.com/hay-kot/homebox/backend/internal/sys/config"
|
||||||
"github.com/hay-kot/homebox/backend/internal/web/mid"
|
"github.com/hay-kot/homebox/backend/internal/web/mid"
|
||||||
"github.com/hay-kot/httpkit/errchain"
|
"github.com/hay-kot/httpkit/errchain"
|
||||||
"github.com/hay-kot/httpkit/server"
|
"github.com/hay-kot/httpkit/graceful"
|
||||||
"github.com/rs/zerolog"
|
"github.com/rs/zerolog"
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
"github.com/rs/zerolog/pkgerrors"
|
"github.com/rs/zerolog/pkgerrors"
|
||||||
|
@ -178,41 +178,54 @@ func run(cfg *config.Config) error {
|
||||||
middleware.StripSlashes,
|
middleware.StripSlashes,
|
||||||
)
|
)
|
||||||
|
|
||||||
chain := errchain.New(mid.Errors(app.server, logger))
|
chain := errchain.New(mid.Errors(logger))
|
||||||
|
|
||||||
app.mountRoutes(router, chain, app.repos)
|
app.mountRoutes(router, chain, app.repos)
|
||||||
|
|
||||||
app.server = server.NewServer(
|
runner := graceful.NewRunner()
|
||||||
server.WithHost(app.conf.Web.Host),
|
|
||||||
server.WithPort(app.conf.Web.Port),
|
runner.AddFunc("server", func(ctx context.Context) error {
|
||||||
server.WithReadTimeout(app.conf.Web.ReadTimeout),
|
httpserver := http.Server{
|
||||||
server.WithWriteTimeout(app.conf.Web.WriteTimeout),
|
Addr: fmt.Sprintf("%s:%s", cfg.Web.Host, cfg.Web.Port),
|
||||||
server.WithIdleTimeout(app.conf.Web.IdleTimeout),
|
Handler: router,
|
||||||
)
|
ReadTimeout: cfg.Web.ReadTimeout,
|
||||||
log.Info().Msgf("Starting HTTP Server on %s:%s", app.server.Host, app.server.Port)
|
WriteTimeout: cfg.Web.WriteTimeout,
|
||||||
|
IdleTimeout: cfg.Web.IdleTimeout,
|
||||||
|
}
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
<-ctx.Done()
|
||||||
|
_ = httpserver.Shutdown(context.Background())
|
||||||
|
}()
|
||||||
|
|
||||||
|
log.Info().Msgf("Server is running on %s:%s", cfg.Web.Host, cfg.Web.Port)
|
||||||
|
return httpserver.ListenAndServe()
|
||||||
|
})
|
||||||
|
|
||||||
// =========================================================================
|
// =========================================================================
|
||||||
// Start Reoccurring Tasks
|
// Start Reoccurring Tasks
|
||||||
|
|
||||||
go app.bus.Run()
|
runner.AddFunc("eventbus", app.bus.Run)
|
||||||
|
|
||||||
go app.startBgTask(time.Duration(24)*time.Hour, func() {
|
runner.AddPlugin(NewTask("purge-tokens", time.Duration(24)*time.Hour, func(ctx context.Context) {
|
||||||
_, err := app.repos.AuthTokens.PurgeExpiredTokens(context.Background())
|
_, err := app.repos.AuthTokens.PurgeExpiredTokens(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().
|
log.Error().
|
||||||
Err(err).
|
Err(err).
|
||||||
Msg("failed to purge expired tokens")
|
Msg("failed to purge expired tokens")
|
||||||
}
|
}
|
||||||
})
|
}))
|
||||||
go app.startBgTask(time.Duration(24)*time.Hour, func() {
|
|
||||||
_, err := app.repos.Groups.InvitationPurge(context.Background())
|
runner.AddPlugin(NewTask("purge-invitations", time.Duration(24)*time.Hour, func(ctx context.Context) {
|
||||||
|
_, err := app.repos.Groups.InvitationPurge(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().
|
log.Error().
|
||||||
Err(err).
|
Err(err).
|
||||||
Msg("failed to purge expired invitations")
|
Msg("failed to purge expired invitations")
|
||||||
}
|
}
|
||||||
})
|
}))
|
||||||
go app.startBgTask(time.Duration(1)*time.Hour, func() {
|
|
||||||
|
runner.AddPlugin(NewTask("send-notifications", time.Duration(1)*time.Hour, func(ctx context.Context) {
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
|
|
||||||
if now.Hour() == 8 {
|
if now.Hour() == 8 {
|
||||||
|
@ -224,7 +237,7 @@ func run(cfg *config.Config) error {
|
||||||
Msg("failed to send notifiers")
|
Msg("failed to send notifiers")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
}))
|
||||||
|
|
||||||
// TODO: Remove through external API that does setup
|
// TODO: Remove through external API that does setup
|
||||||
if cfg.Demo {
|
if cfg.Demo {
|
||||||
|
@ -233,13 +246,24 @@ func run(cfg *config.Config) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
if cfg.Debug.Enabled {
|
if cfg.Debug.Enabled {
|
||||||
debugrouter := app.debugRouter()
|
runner.AddFunc("debug", func(ctx context.Context) error {
|
||||||
go func() {
|
debugserver := http.Server{
|
||||||
if err := http.ListenAndServe(":"+cfg.Debug.Port, debugrouter); err != nil {
|
Addr: fmt.Sprintf("%s:%s", cfg.Web.Host, cfg.Debug.Port),
|
||||||
log.Fatal().Err(err).Msg("failed to start debug server")
|
Handler: app.debugRouter(),
|
||||||
|
ReadTimeout: cfg.Web.ReadTimeout,
|
||||||
|
WriteTimeout: cfg.Web.WriteTimeout,
|
||||||
|
IdleTimeout: cfg.Web.IdleTimeout,
|
||||||
}
|
}
|
||||||
}()
|
|
||||||
|
go func() {
|
||||||
|
<-ctx.Done()
|
||||||
|
_ = debugserver.Shutdown(context.Background())
|
||||||
|
}()
|
||||||
|
|
||||||
|
log.Info().Msgf("Debug server is running on %s:%s", cfg.Web.Host, cfg.Debug.Port)
|
||||||
|
return debugserver.ListenAndServe()
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
return app.server.Start(router)
|
return runner.Start(context.Background())
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,7 @@ require (
|
||||||
github.com/gocarina/gocsv v0.0.0-20231116093920-b87c2d0e983a
|
github.com/gocarina/gocsv v0.0.0-20231116093920-b87c2d0e983a
|
||||||
github.com/google/uuid v1.6.0
|
github.com/google/uuid v1.6.0
|
||||||
github.com/gorilla/schema v1.2.1
|
github.com/gorilla/schema v1.2.1
|
||||||
github.com/hay-kot/httpkit v0.0.6
|
github.com/hay-kot/httpkit v0.0.9
|
||||||
github.com/mattn/go-sqlite3 v1.14.22
|
github.com/mattn/go-sqlite3 v1.14.22
|
||||||
github.com/olahol/melody v1.1.4
|
github.com/olahol/melody v1.1.4
|
||||||
github.com/pkg/errors v0.9.1
|
github.com/pkg/errors v0.9.1
|
||||||
|
|
|
@ -86,6 +86,12 @@ github.com/hashicorp/hcl/v2 v2.19.1 h1://i05Jqznmb2EXqa39Nsvyan2o5XyMowW5fnCKW5R
|
||||||
github.com/hashicorp/hcl/v2 v2.19.1/go.mod h1:ThLC89FV4p9MPW804KVbe/cEXoQ8NZEh+JtMeeGErHE=
|
github.com/hashicorp/hcl/v2 v2.19.1/go.mod h1:ThLC89FV4p9MPW804KVbe/cEXoQ8NZEh+JtMeeGErHE=
|
||||||
github.com/hay-kot/httpkit v0.0.6 h1:BidC4UrkS7zRhoTdpKLeF8ODJPKcOZkJ2tk2t2ZIQjQ=
|
github.com/hay-kot/httpkit v0.0.6 h1:BidC4UrkS7zRhoTdpKLeF8ODJPKcOZkJ2tk2t2ZIQjQ=
|
||||||
github.com/hay-kot/httpkit v0.0.6/go.mod h1:1s/OJwWRyH6tBtTw76jTp6kwBYvjswziXaokPQH7eKQ=
|
github.com/hay-kot/httpkit v0.0.6/go.mod h1:1s/OJwWRyH6tBtTw76jTp6kwBYvjswziXaokPQH7eKQ=
|
||||||
|
github.com/hay-kot/httpkit v0.0.7 h1:KxGi+MwXFavfFUfJEMpye5cnMef9TlFu3v7UZipUB8U=
|
||||||
|
github.com/hay-kot/httpkit v0.0.7/go.mod h1:AD22YluZrvBDxmtB3Pw2SOyp3A2PZqcmBZa0+COrhoU=
|
||||||
|
github.com/hay-kot/httpkit v0.0.8 h1:n+Z5z35YZcdD9cGwbnIPRbrgDw9LY6lqakH4zYr5z+A=
|
||||||
|
github.com/hay-kot/httpkit v0.0.8/go.mod h1:AD22YluZrvBDxmtB3Pw2SOyp3A2PZqcmBZa0+COrhoU=
|
||||||
|
github.com/hay-kot/httpkit v0.0.9 h1:hu2TPY9awmIYWXxWGubaXl2U61pPvaVsm9YwboBRGu0=
|
||||||
|
github.com/hay-kot/httpkit v0.0.9/go.mod h1:AD22YluZrvBDxmtB3Pw2SOyp3A2PZqcmBZa0+COrhoU=
|
||||||
github.com/jarcoal/httpmock v1.3.0 h1:2RJ8GP0IIaWwcC9Fp2BmVi8Kog3v2Hn7VXM3fTd+nuc=
|
github.com/jarcoal/httpmock v1.3.0 h1:2RJ8GP0IIaWwcC9Fp2BmVi8Kog3v2Hn7VXM3fTd+nuc=
|
||||||
github.com/jarcoal/httpmock v1.3.0/go.mod h1:3yb8rc4BI7TCBhFY8ng0gjuLKJNquuDNiPaZjnENuYg=
|
github.com/jarcoal/httpmock v1.3.0/go.mod h1:3yb8rc4BI7TCBhFY8ng0gjuLKJNquuDNiPaZjnENuYg=
|
||||||
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
|
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
package eventbus
|
package eventbus
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
|
@ -43,24 +44,29 @@ func New() *EventBus {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *EventBus) Run() {
|
func (e *EventBus) Run(ctx context.Context) error {
|
||||||
if e.started {
|
if e.started {
|
||||||
panic("event bus already started")
|
panic("event bus already started")
|
||||||
}
|
}
|
||||||
|
|
||||||
e.started = true
|
e.started = true
|
||||||
|
|
||||||
for event := range e.ch {
|
for {
|
||||||
e.mu.RLock()
|
select {
|
||||||
arr, ok := e.subscribers[event.event]
|
case <-ctx.Done():
|
||||||
e.mu.RUnlock()
|
return nil
|
||||||
|
case event := <-e.ch:
|
||||||
|
e.mu.RLock()
|
||||||
|
arr, ok := e.subscribers[event.event]
|
||||||
|
e.mu.RUnlock()
|
||||||
|
|
||||||
if !ok {
|
if !ok {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, fn := range arr {
|
for _, fn := range arr {
|
||||||
fn(event.data)
|
fn(event.data)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,7 +45,9 @@ func TestMain(m *testing.M) {
|
||||||
log.Fatalf("failed opening connection to sqlite: %v", err)
|
log.Fatalf("failed opening connection to sqlite: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
go tbus.Run()
|
go func() {
|
||||||
|
_ = tbus.Run(context.Background())
|
||||||
|
}()
|
||||||
|
|
||||||
err = client.Schema.Create(context.Background())
|
err = client.Schema.Create(context.Background())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -6,6 +6,7 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/ardanlabs/conf/v3"
|
"github.com/ardanlabs/conf/v3"
|
||||||
)
|
)
|
||||||
|
@ -39,12 +40,12 @@ type DebugConf struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type WebConfig struct {
|
type WebConfig struct {
|
||||||
Port string `yaml:"port" conf:"default:7745"`
|
Port string `yaml:"port" conf:"default:7745"`
|
||||||
Host string `yaml:"host"`
|
Host string `yaml:"host"`
|
||||||
MaxUploadSize int64 `yaml:"max_file_upload" conf:"default:10"`
|
MaxUploadSize int64 `yaml:"max_file_upload" conf:"default:10"`
|
||||||
ReadTimeout int `yaml:"read_timeout" conf:"default:10"`
|
ReadTimeout time.Duration `yaml:"read_timeout" conf:"default:10s"`
|
||||||
WriteTimeout int `yaml:"write_timeout" conf:"default:10"`
|
WriteTimeout time.Duration `yaml:"write_timeout" conf:"default:10s"`
|
||||||
IdleTimeout int `yaml:"idle_timeout" conf:"default:30"`
|
IdleTimeout time.Duration `yaml:"idle_timeout" conf:"default:30s"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// New parses the CLI/Config file and returns a Config struct. If the file argument is an empty string, the
|
// New parses the CLI/Config file and returns a Config struct. If the file argument is an empty string, the
|
||||||
|
|
|
@ -16,7 +16,7 @@ type ErrorResponse struct {
|
||||||
Fields map[string]string `json:"fields,omitempty"`
|
Fields map[string]string `json:"fields,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func Errors(svr *server.Server, log zerolog.Logger) errchain.ErrorHandler {
|
func Errors(log zerolog.Logger) errchain.ErrorHandler {
|
||||||
return func(h errchain.Handler) http.Handler {
|
return func(h errchain.Handler) http.Handler {
|
||||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
err := h.ServeHTTP(w, r)
|
err := h.ServeHTTP(w, r)
|
||||||
|
@ -71,14 +71,6 @@ func Errors(svr *server.Server, log zerolog.Logger) errchain.ErrorHandler {
|
||||||
if err := server.JSON(w, code, resp); err != nil {
|
if err := server.JSON(w, code, resp); err != nil {
|
||||||
log.Err(err).Msg("failed to write response")
|
log.Err(err).Msg("failed to write response")
|
||||||
}
|
}
|
||||||
|
|
||||||
// If Showdown error, return error
|
|
||||||
if server.IsShutdownError(err) {
|
|
||||||
err := svr.Shutdown(err.Error())
|
|
||||||
if err != nil {
|
|
||||||
log.Err(err).Msg("failed to shutdown server")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
<label class="label">
|
<label class="label">
|
||||||
<span class="label-text"> {{ label }}</span>
|
<span class="label-text"> {{ label }}</span>
|
||||||
</label>
|
</label>
|
||||||
<input ref="input" v-model="selected" type="date" class="input input-bordered w-full" />
|
<VueDatePicker v-model="selected" :enable-time-picker="false" clearable :dark="isDark" />
|
||||||
</div>
|
</div>
|
||||||
<div v-else class="sm:grid sm:grid-cols-4 sm:items-start sm:gap-4">
|
<div v-else class="sm:grid sm:grid-cols-4 sm:items-start sm:gap-4">
|
||||||
<label class="label">
|
<label class="label">
|
||||||
|
|
Loading…
Reference in a new issue