Files
sablier/internal/api/start_dynamic.go
Alexis Couvreur fca9c79289 refactor: reorganize code structure (#556)
* refactor: rename providers to Provider

* refactor folders

* fix build cmd

* fix build cmd

* fix build cmd

* fix cmd start
2025-03-10 14:11:40 -04:00

134 lines
3.8 KiB
Go

package api
import (
"bufio"
"bytes"
"errors"
"github.com/sablierapp/sablier/pkg/sablier"
"sort"
"strconv"
"strings"
"time"
"github.com/gin-gonic/gin"
"github.com/sablierapp/sablier/pkg/theme"
)
type DynamicRequest struct {
Group string `form:"group"`
Names []string `form:"names"`
ShowDetails bool `form:"show_details"`
DisplayName string `form:"display_name"`
Theme string `form:"theme"`
SessionDuration time.Duration `form:"session_duration"`
RefreshFrequency time.Duration `form:"refresh_frequency"`
}
func StartDynamic(router *gin.RouterGroup, s *ServeStrategy) {
router.GET("/strategies/dynamic", func(c *gin.Context) {
request := DynamicRequest{
Theme: s.StrategyConfig.Dynamic.DefaultTheme,
ShowDetails: s.StrategyConfig.Dynamic.ShowDetailsByDefault,
RefreshFrequency: s.StrategyConfig.Dynamic.DefaultRefreshFrequency,
SessionDuration: s.SessionsConfig.DefaultDuration,
}
if err := c.ShouldBind(&request); err != nil {
AbortWithProblemDetail(c, ProblemValidation(err))
return
}
if len(request.Names) == 0 && request.Group == "" {
AbortWithProblemDetail(c, ProblemValidation(errors.New("'names' or 'group' query parameter must be set")))
return
}
if len(request.Names) > 0 && request.Group != "" {
AbortWithProblemDetail(c, ProblemValidation(errors.New("'names' and 'group' query parameters are both set, only one must be set")))
return
}
var sessionState *sablier.SessionState
var err error
if len(request.Names) > 0 {
sessionState, err = s.Sablier.RequestSession(c, request.Names, request.SessionDuration)
} else {
sessionState, err = s.Sablier.RequestSessionGroup(c, request.Group, request.SessionDuration)
var groupNotFoundError sablier.ErrGroupNotFound
if errors.As(err, &groupNotFoundError) {
AbortWithProblemDetail(c, ProblemGroupNotFound(groupNotFoundError))
return
}
}
if err != nil {
AbortWithProblemDetail(c, ProblemError(err))
return
}
if sessionState == nil {
AbortWithProblemDetail(c, ProblemError(errors.New("session could not be created, please check logs for more details")))
return
}
AddSablierHeader(c, sessionState)
renderOptions := theme.Options{
DisplayName: request.DisplayName,
ShowDetails: request.ShowDetails,
SessionDuration: request.SessionDuration,
RefreshFrequency: request.RefreshFrequency,
InstanceStates: sessionStateToRenderOptionsInstanceState(sessionState),
}
buf := new(bytes.Buffer)
writer := bufio.NewWriter(buf)
err = s.Theme.Render(request.Theme, renderOptions, writer)
var themeNotFound theme.ErrThemeNotFound
if errors.As(err, &themeNotFound) {
AbortWithProblemDetail(c, ProblemThemeNotFound(themeNotFound))
return
}
writer.Flush()
c.Header("Cache-Control", "no-cache")
c.Header("Content-Type", "text/html")
c.Header("Content-Length", strconv.Itoa(buf.Len()))
c.Writer.Write(buf.Bytes())
})
}
func sessionStateToRenderOptionsInstanceState(sessionState *sablier.SessionState) (instances []theme.Instance) {
if sessionState == nil {
return
}
for _, v := range sessionState.Instances {
instances = append(instances, instanceStateToRenderOptionsRequestState(v.Instance))
}
sort.SliceStable(instances, func(i, j int) bool {
return strings.Compare(instances[i].Name, instances[j].Name) == -1
})
return
}
func instanceStateToRenderOptionsRequestState(instanceState sablier.InstanceInfo) theme.Instance {
var err error
if instanceState.Message == "" {
err = nil
} else {
err = errors.New(instanceState.Message)
}
return theme.Instance{
Name: instanceState.Name,
Status: string(instanceState.Status),
CurrentReplicas: instanceState.CurrentReplicas,
DesiredReplicas: instanceState.DesiredReplicas,
Error: err,
}
}