mirror of
https://github.com/sablierapp/sablier.git
synced 2025-12-21 13:23:03 +01:00
This features adds rfc7807 Problem detail responses when an error happens processing a request. This will greatly improve the common issues with "blank pages" and "404 pages" issues which should now properly tell the user what input was wrong (group that does not exist, container name that does not exist, etc.)
152 lines
3.9 KiB
Go
152 lines
3.9 KiB
Go
package app
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"github.com/sablierapp/sablier/app/discovery"
|
|
"github.com/sablierapp/sablier/app/http/routes"
|
|
"github.com/sablierapp/sablier/app/providers/docker"
|
|
"github.com/sablierapp/sablier/app/providers/dockerswarm"
|
|
"github.com/sablierapp/sablier/app/providers/kubernetes"
|
|
"log/slog"
|
|
"os"
|
|
|
|
"github.com/sablierapp/sablier/app/instance"
|
|
"github.com/sablierapp/sablier/app/providers"
|
|
"github.com/sablierapp/sablier/app/sessions"
|
|
"github.com/sablierapp/sablier/app/storage"
|
|
"github.com/sablierapp/sablier/app/theme"
|
|
"github.com/sablierapp/sablier/config"
|
|
"github.com/sablierapp/sablier/internal/server"
|
|
"github.com/sablierapp/sablier/pkg/tinykv"
|
|
"github.com/sablierapp/sablier/version"
|
|
log "github.com/sirupsen/logrus"
|
|
)
|
|
|
|
func Start(ctx context.Context, conf config.Config) error {
|
|
|
|
logLevel, err := log.ParseLevel(conf.Logging.Level)
|
|
|
|
if err != nil {
|
|
log.Warnf("unrecognized log level \"%s\" must be one of [panic, fatal, error, warn, info, debug, trace]", conf.Logging.Level)
|
|
logLevel = log.InfoLevel
|
|
}
|
|
|
|
logger := slog.Default()
|
|
|
|
log.SetLevel(logLevel)
|
|
|
|
log.Info(version.Info())
|
|
|
|
provider, err := NewProvider(conf.Provider)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
log.Infof("using provider \"%s\"", conf.Provider.Name)
|
|
|
|
store := tinykv.New(conf.Sessions.ExpirationInterval, onSessionExpires(provider))
|
|
|
|
storage, err := storage.NewFileStorage(conf.Storage)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
sessionsManager := sessions.NewSessionsManager(store, provider)
|
|
defer sessionsManager.Stop()
|
|
|
|
if storage.Enabled() {
|
|
defer saveSessions(storage, sessionsManager)
|
|
loadSessions(storage, sessionsManager)
|
|
}
|
|
|
|
if conf.Provider.AutoStopOnStartup {
|
|
err := discovery.StopAllUnregisteredInstances(context.Background(), provider, store.Keys())
|
|
if err != nil {
|
|
log.Warnf("Stopping unregistered instances had an error: %v", err)
|
|
}
|
|
}
|
|
|
|
var t *theme.Themes
|
|
|
|
if conf.Strategy.Dynamic.CustomThemesPath != "" {
|
|
log.Tracef("loading themes with custom theme path: %s", conf.Strategy.Dynamic.CustomThemesPath)
|
|
custom := os.DirFS(conf.Strategy.Dynamic.CustomThemesPath)
|
|
t, err = theme.NewWithCustomThemes(custom)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
} else {
|
|
log.Trace("loading themes without custom themes")
|
|
t, err = theme.New()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
strategy := &routes.ServeStrategy{
|
|
Theme: t,
|
|
SessionsManager: sessionsManager,
|
|
StrategyConfig: conf.Strategy,
|
|
SessionsConfig: conf.Sessions,
|
|
}
|
|
|
|
server.Start(ctx, logger, conf.Server, strategy)
|
|
|
|
return nil
|
|
}
|
|
|
|
func onSessionExpires(provider providers.Provider) func(key string, instance instance.State) {
|
|
return func(_key string, _instance instance.State) {
|
|
go func(key string, instance instance.State) {
|
|
log.Debugf("stopping %s...", key)
|
|
err := provider.Stop(context.Background(), key)
|
|
|
|
if err != nil {
|
|
log.Warnf("error stopping %s: %s", key, err.Error())
|
|
} else {
|
|
log.Debugf("stopped %s", key)
|
|
}
|
|
}(_key, _instance)
|
|
}
|
|
}
|
|
|
|
func loadSessions(storage storage.Storage, sessions sessions.Manager) {
|
|
reader, err := storage.Reader()
|
|
if err != nil {
|
|
log.Error("error loading sessions", err)
|
|
}
|
|
err = sessions.LoadSessions(reader)
|
|
if err != nil {
|
|
log.Error("error loading sessions", err)
|
|
}
|
|
}
|
|
|
|
func saveSessions(storage storage.Storage, sessions sessions.Manager) {
|
|
writer, err := storage.Writer()
|
|
if err != nil {
|
|
log.Error("error saving sessions", err)
|
|
return
|
|
}
|
|
err = sessions.SaveSessions(writer)
|
|
if err != nil {
|
|
log.Error("error saving sessions", err)
|
|
}
|
|
}
|
|
|
|
func NewProvider(config config.Provider) (providers.Provider, error) {
|
|
if err := config.IsValid(); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
switch config.Name {
|
|
case "swarm", "docker_swarm":
|
|
return dockerswarm.NewDockerSwarmProvider()
|
|
case "docker":
|
|
return docker.NewDockerClassicProvider()
|
|
case "kubernetes":
|
|
return kubernetes.NewKubernetesProvider(config.Kubernetes)
|
|
}
|
|
return nil, fmt.Errorf("unimplemented provider %s", config.Name)
|
|
}
|