mirror of
https://github.com/sablierapp/sablier.git
synced 2025-12-21 21:33:06 +01:00
279 lines
5.9 KiB
Go
279 lines
5.9 KiB
Go
package caddy
|
|
|
|
import (
|
|
"fmt"
|
|
"net/http"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/caddyserver/caddy/v2/caddyconfig/caddyfile"
|
|
"github.com/caddyserver/caddy/v2/caddyconfig/httpcaddyfile"
|
|
"github.com/caddyserver/caddy/v2/modules/caddyhttp"
|
|
)
|
|
|
|
func init() {
|
|
httpcaddyfile.RegisterHandlerDirective("sablier", parseCaddyfile)
|
|
|
|
}
|
|
|
|
type DynamicConfiguration struct {
|
|
DisplayName string
|
|
ShowDetails *bool
|
|
Theme string
|
|
RefreshFrequency *time.Duration
|
|
}
|
|
|
|
type BlockingConfiguration struct {
|
|
Timeout *time.Duration
|
|
}
|
|
|
|
type Config struct {
|
|
SablierURL string
|
|
Names []string
|
|
Group string
|
|
SessionDuration *time.Duration
|
|
Dynamic *DynamicConfiguration
|
|
Blocking *BlockingConfiguration
|
|
}
|
|
|
|
func CreateConfig() *Config {
|
|
return &Config{
|
|
SablierURL: "http://sablier:10000",
|
|
Names: []string{},
|
|
SessionDuration: nil,
|
|
Dynamic: nil,
|
|
Blocking: nil,
|
|
}
|
|
}
|
|
|
|
// UnmarshalCaddyfile implements caddyfile.Unmarshaler. Syntax:
|
|
//
|
|
// sablier [<sablierURL>] {
|
|
// [names container1,container2,...]
|
|
// [group mygroup]
|
|
// [session_duration 30m]
|
|
// dynamic {
|
|
// [display_name This is my display name]
|
|
// [show_details yes|true|on]
|
|
// [theme hacker-terminal]
|
|
// [refresh_frequency 2s]
|
|
// }
|
|
// blocking {
|
|
// [timeout 1m]
|
|
// }
|
|
// }
|
|
//
|
|
func (c *Config) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
|
|
for d.Next() {
|
|
if d.NextArg() {
|
|
c.SablierURL = d.Val()
|
|
} else {
|
|
c.SablierURL = "http://sablier:10000"
|
|
}
|
|
if d.NextArg() {
|
|
return d.ArgErr()
|
|
}
|
|
for nesting := d.Nesting(); d.NextBlock(nesting); {
|
|
subdirective := d.Val()
|
|
args := strings.Join(d.RemainingArgs(), " ")
|
|
switch subdirective {
|
|
case "names":
|
|
c.Names = parseNames(args)
|
|
case "group":
|
|
c.Group = args
|
|
case "session_duration":
|
|
duration, err := time.ParseDuration(args)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
c.SessionDuration = &duration
|
|
case "dynamic":
|
|
dynamic, err := parseDynamic(d)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
c.Dynamic = dynamic
|
|
case "blocking":
|
|
blocking, err := parseBlocking(d)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
c.Blocking = blocking
|
|
}
|
|
}
|
|
}
|
|
|
|
if c.Blocking == nil && c.Dynamic == nil {
|
|
return fmt.Errorf("you must specify one strategy (dynamic or blocking)")
|
|
}
|
|
|
|
if c.Blocking != nil && c.Dynamic != nil {
|
|
return fmt.Errorf("you must specify only one strategy")
|
|
}
|
|
|
|
if len(c.Names) == 0 && len(c.Group) == 0 {
|
|
return fmt.Errorf("you must specify names or group")
|
|
}
|
|
|
|
if len(c.Names) > 0 && len(c.Group) > 0 {
|
|
return fmt.Errorf("you must specify either names or group")
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func parseNames(value string) []string {
|
|
names := strings.Split(value, " ")
|
|
for i := range names {
|
|
names[i] = strings.TrimSpace(names[i])
|
|
}
|
|
|
|
if len(names) == 1 && names[0] == "" {
|
|
return make([]string, 0)
|
|
}
|
|
|
|
return names
|
|
}
|
|
|
|
func parseDynamic(d *caddyfile.Dispenser) (*DynamicConfiguration, error) {
|
|
conf := &DynamicConfiguration{}
|
|
for nesting := d.Nesting(); d.NextBlock(nesting); {
|
|
subdirective := d.Val()
|
|
args := strings.Join(d.RemainingArgs(), " ")
|
|
switch subdirective {
|
|
case "display_name":
|
|
conf.DisplayName = args
|
|
case "show_details":
|
|
shouldShow := isEnabledArg(args)
|
|
conf.ShowDetails = &shouldShow
|
|
case "theme":
|
|
conf.Theme = args
|
|
case "refresh_frequency":
|
|
duration, err := time.ParseDuration(args)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
conf.RefreshFrequency = &duration
|
|
}
|
|
}
|
|
return conf, nil
|
|
}
|
|
|
|
func parseBlocking(d *caddyfile.Dispenser) (*BlockingConfiguration, error) {
|
|
conf := &BlockingConfiguration{}
|
|
for nesting := d.Nesting(); d.NextBlock(nesting); {
|
|
subdirective := d.Val()
|
|
args := strings.Join(d.RemainingArgs(), " ")
|
|
switch subdirective {
|
|
case "timeout":
|
|
duration, err := time.ParseDuration(args)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
conf.Timeout = &duration
|
|
}
|
|
}
|
|
return conf, nil
|
|
}
|
|
|
|
func parseCaddyfile(h httpcaddyfile.Helper) (caddyhttp.MiddlewareHandler, error) {
|
|
var c Config
|
|
err := c.UnmarshalCaddyfile(h.Dispenser)
|
|
return SablierMiddleware{Config: c}, err
|
|
}
|
|
|
|
func isEnabledArg(s string) bool {
|
|
if s == "yes" || s == "true" || s == "on" {
|
|
return true
|
|
}
|
|
return false
|
|
}
|
|
|
|
func (c *Config) BuildRequest() (*http.Request, error) {
|
|
if c.Dynamic != nil {
|
|
return c.buildDynamicRequest()
|
|
} else if c.Blocking != nil {
|
|
return c.buildBlockingRequest()
|
|
}
|
|
return nil, fmt.Errorf("no strategy configured")
|
|
}
|
|
|
|
func (c *Config) buildDynamicRequest() (*http.Request, error) {
|
|
if c.Dynamic == nil {
|
|
return nil, fmt.Errorf("dynamic config is nil")
|
|
}
|
|
|
|
request, err := http.NewRequest("GET", fmt.Sprintf("%s/api/strategies/dynamic", c.SablierURL), nil)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
q := request.URL.Query()
|
|
|
|
if c.SessionDuration != nil {
|
|
q.Add("session_duration", c.SessionDuration.String())
|
|
}
|
|
|
|
for _, name := range c.Names {
|
|
q.Add("names", name)
|
|
}
|
|
|
|
if c.Group != "" {
|
|
q.Add("group", c.Group)
|
|
}
|
|
|
|
if c.Dynamic.DisplayName != "" {
|
|
q.Add("display_name", c.Dynamic.DisplayName)
|
|
}
|
|
|
|
if c.Dynamic.Theme != "" {
|
|
q.Add("theme", c.Dynamic.Theme)
|
|
}
|
|
|
|
if c.Dynamic.RefreshFrequency != nil {
|
|
q.Add("refresh_frequency", c.Dynamic.RefreshFrequency.String())
|
|
}
|
|
|
|
if c.Dynamic.ShowDetails != nil {
|
|
q.Add("show_details", strconv.FormatBool(*c.Dynamic.ShowDetails))
|
|
}
|
|
|
|
request.URL.RawQuery = q.Encode()
|
|
|
|
return request, nil
|
|
}
|
|
|
|
func (c *Config) buildBlockingRequest() (*http.Request, error) {
|
|
if c.Blocking == nil {
|
|
return nil, fmt.Errorf("blocking config is nil")
|
|
}
|
|
|
|
request, err := http.NewRequest("GET", fmt.Sprintf("%s/api/strategies/blocking", c.SablierURL), nil)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
q := request.URL.Query()
|
|
|
|
if c.SessionDuration != nil {
|
|
q.Add("session_duration", c.SessionDuration.String())
|
|
}
|
|
|
|
for _, name := range c.Names {
|
|
q.Add("names", name)
|
|
}
|
|
|
|
if c.Group != "" {
|
|
q.Add("group", c.Group)
|
|
}
|
|
|
|
if c.Blocking.Timeout != nil {
|
|
q.Add("timeout", c.Blocking.Timeout.String())
|
|
}
|
|
|
|
request.URL.RawQuery = q.Encode()
|
|
|
|
return request, nil
|
|
}
|