mirror of
https://github.com/tnb-labs/panel.git
synced 2026-09-01 14:55:12 +08:00
ea22c2f0a7
Replace the samber/do runtime container with explicit constructor dependencies and generated Wire graphs for ace and cli. Keep CLI application loading isolated and verify generated files in CI.
128 lines
2.9 KiB
Go
128 lines
2.9 KiB
Go
package app
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"net/http"
|
|
"os"
|
|
"os/signal"
|
|
"syscall"
|
|
"time"
|
|
|
|
"github.com/bddjr/hlfhr"
|
|
"github.com/go-chi/chi/v5"
|
|
"github.com/go-gormigrate/gormigrate/v2"
|
|
"github.com/libtnb/cron"
|
|
|
|
"github.com/acepanel/panel/v3/pkg/config"
|
|
"github.com/acepanel/panel/v3/pkg/tlscert"
|
|
"github.com/acepanel/panel/v3/pkg/types"
|
|
)
|
|
|
|
type Ace struct {
|
|
conf *config.Config
|
|
router *chi.Mux
|
|
server *hlfhr.Server
|
|
reloader *tlscert.Reloader
|
|
migrator *gormigrate.Gormigrate
|
|
cron *cron.Cron
|
|
runner types.TaskRunner
|
|
}
|
|
|
|
func NewAce(router *chi.Mux, conf *config.Config, cron *cron.Cron, migrator *gormigrate.Gormigrate, server *hlfhr.Server, reloader *tlscert.Reloader, runner types.TaskRunner) (*Ace, error) {
|
|
return &Ace{
|
|
conf: conf,
|
|
router: router,
|
|
server: server,
|
|
reloader: reloader,
|
|
migrator: migrator,
|
|
cron: cron,
|
|
runner: runner,
|
|
}, nil
|
|
}
|
|
|
|
func (r *Ace) Run() error {
|
|
// migrate database
|
|
if err := r.migrator.Migrate(); err != nil {
|
|
return err
|
|
}
|
|
fmt.Println("[DB] database migrated")
|
|
|
|
// start cron scheduler
|
|
if err := r.cron.Start(); err != nil {
|
|
return err
|
|
}
|
|
fmt.Println("[CRON] cron scheduler started")
|
|
|
|
// create context for runner
|
|
runnerCtx, runnerCancel := context.WithCancel(context.Background())
|
|
defer runnerCancel()
|
|
|
|
// start task runner
|
|
r.runner.Run(runnerCtx)
|
|
|
|
// setup graceful shutdown
|
|
quit := make(chan os.Signal, 1)
|
|
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
|
|
|
|
// run http server in goroutine
|
|
serverErr := make(chan error, 1)
|
|
go func() {
|
|
fmt.Println("[HTTP] listening and serving on port", r.conf.HTTP.Port)
|
|
if r.conf.HTTP.IsHTTPS() {
|
|
if err := r.server.ListenAndServeTLS("", ""); !errors.Is(err, http.ErrServerClosed) {
|
|
serverErr <- err
|
|
}
|
|
} else {
|
|
if err := r.server.ListenAndServe(); !errors.Is(err, http.ErrServerClosed) {
|
|
serverErr <- err
|
|
}
|
|
}
|
|
close(serverErr)
|
|
}()
|
|
|
|
// wait for shutdown signal or server error
|
|
select {
|
|
case err := <-serverErr:
|
|
if err != nil {
|
|
return err
|
|
}
|
|
case sig := <-quit:
|
|
fmt.Println("[APP] received signal:", sig)
|
|
}
|
|
|
|
// graceful shutdown
|
|
fmt.Println("[APP] shutting down gracefully...")
|
|
|
|
// stop cron scheduler
|
|
cronCtx, cronCancel := context.WithTimeout(context.Background(), 30*time.Second)
|
|
_ = r.cron.Stop(cronCtx)
|
|
cronCancel()
|
|
fmt.Println("[CRON] cron scheduler stopped")
|
|
|
|
// stop task runner
|
|
runnerCancel()
|
|
fmt.Println("[QUEUE] task runner stopped")
|
|
|
|
// close certificate reloader
|
|
if r.reloader != nil {
|
|
if err := r.reloader.Close(); err != nil {
|
|
fmt.Println("[TLS] certificate reloader close error:", err)
|
|
}
|
|
}
|
|
|
|
// shutdown http server
|
|
shutdownCtx, shutdownCancel := context.WithTimeout(context.Background(), 30*time.Second)
|
|
defer shutdownCancel()
|
|
|
|
if err := r.server.Shutdown(shutdownCtx); err != nil {
|
|
fmt.Println("[HTTP] server shutdown error:", err)
|
|
return err
|
|
}
|
|
fmt.Println("[HTTP] server stopped")
|
|
|
|
fmt.Println("[APP] shutdown complete")
|
|
return nil
|
|
}
|