From a157a818f6789206ec4903eeec17dfb39933f087 Mon Sep 17 00:00:00 2001 From: DarthSim Date: Fri, 7 Sep 2018 23:41:06 +0600 Subject: [PATCH] Presets :tada: --- config.go | 43 +++++++++++++++++++++++++++++--- errors.go | 5 ++++ presets.go | 40 ++++++++++++++++++++++++++++++ processing_options.go | 57 +++++++++++++++++++++++++++++++++++++------ 4 files changed, 133 insertions(+), 12 deletions(-) create mode 100644 presets.go diff --git a/config.go b/config.go index 84d0628a..61936845 100644 --- a/config.go +++ b/config.go @@ -1,6 +1,7 @@ package main import ( + "bufio" "bytes" "encoding/hex" "flag" @@ -10,6 +11,7 @@ import ( "os" "runtime" "strconv" + "strings" ) func intEnvConfig(i *int, name string) { @@ -73,6 +75,32 @@ func hexFileConfig(b *[]byte, filepath string) { *b = dst[:n] } +func presetEnvConfig(p *presets, name string) { + if env := os.Getenv(name); len(env) > 0 { + presetStrings := strings.Split(env, ",") + + for _, presetStr := range presetStrings { + parsePreset(p, presetStr) + } + } +} + +func presetFileConfig(p *presets, filepath string) { + if len(filepath) == 0 { + return + } + + f, err := os.Open(filepath) + if err != nil { + log.Fatalf("Can't open file %s\n", filepath) + } + + scanner := bufio.NewScanner(f) + for scanner.Scan() { + parsePreset(p, scanner.Text()) + } +} + type config struct { Bind string ReadTimeout int @@ -105,6 +133,8 @@ type config struct { ETagEnabled bool BaseURL string + + Presets presets } var conf = config{ @@ -123,8 +153,9 @@ var conf = config{ } func init() { - keypath := flag.String("keypath", "", "path of the file with hex-encoded key") - saltpath := flag.String("saltpath", "", "path of the file with hex-encoded salt") + keyPath := flag.String("keypath", "", "path of the file with hex-encoded key") + saltPath := flag.String("saltpath", "", "path of the file with hex-encoded salt") + presetsPath := flag.String("presets", "", "path of the file with presets") showVersion := flag.Bool("v", false, "show version") flag.Parse() @@ -157,8 +188,8 @@ func init() { hexEnvConfig(&conf.Key, "IMGPROXY_KEY") hexEnvConfig(&conf.Salt, "IMGPROXY_SALT") - hexFileConfig(&conf.Key, *keypath) - hexFileConfig(&conf.Salt, *saltpath) + hexFileConfig(&conf.Key, *keyPath) + hexFileConfig(&conf.Salt, *saltPath) strEnvConfig(&conf.Secret, "IMGPROXY_SECRET") @@ -172,6 +203,10 @@ func init() { strEnvConfig(&conf.BaseURL, "IMGPROXY_BASE_URL") + conf.Presets = make(presets) + presetEnvConfig(&conf.Presets, "IMGPROXY_PRESETS") + presetFileConfig(&conf.Presets, *presetsPath) + if len(conf.Key) == 0 { log.Fatalln("Key is not defined") } diff --git a/errors.go b/errors.go index af319428..1bfe4013 100644 --- a/errors.go +++ b/errors.go @@ -2,6 +2,7 @@ package main import ( "fmt" + "log" "runtime" "strings" ) @@ -43,3 +44,7 @@ func stacktrace(skip int) string { return strings.Join(lines, "\n") } + +func warning(f string, args ...interface{}) { + log.Printf("[WARNING] %s", fmt.Sprintf(f, args...)) +} diff --git a/presets.go b/presets.go new file mode 100644 index 00000000..d71665f4 --- /dev/null +++ b/presets.go @@ -0,0 +1,40 @@ +package main + +import "strings" + +type presets map[string]urlOptions + +func parsePreset(p *presets, presetStr string) { + presetStr = strings.Trim(presetStr, " ") + + if len(presetStr) == 0 || strings.HasPrefix(presetStr, "#") { + return + } + + parts := strings.Split(presetStr, "=") + + if len(parts) != 2 { + warning("Invalid preset string, omitted: %s", presetStr) + return + } + + name := strings.Trim(parts[0], " ") + if len(name) == 0 { + warning("Empty preset name, omitted: %s", presetStr) + return + } + + value := strings.Trim(parts[1], " ") + if len(value) == 0 { + warning("Empty preset value, omitted: %s", presetStr) + return + } + + optsStr := strings.Split(value, "/") + + if opts, rest := parseURLOptions(optsStr); len(rest) == 0 { + (*p)[name] = opts + } else { + warning("Invalid preset value, omitted: %s", presetStr) + } +} diff --git a/processing_options.go b/processing_options.go index c92cf863..80d87b2e 100644 --- a/processing_options.go +++ b/processing_options.go @@ -15,6 +15,8 @@ import ( "strings" ) +type urlOptions map[string][]string + type imageType int const ( @@ -242,6 +244,22 @@ func applySharpenOption(po *processingOptions, args []string) error { return nil } +func applyPresetOption(po *processingOptions, args []string) error { + for _, preset := range args { + if p, ok := conf.Presets[preset]; ok { + for name, pargs := range p { + if err := applyProcessingOption(po, name, pargs); err != nil { + return err + } + } + } else { + return fmt.Errorf("Unknown asset: %s", preset) + } + } + + return nil +} + func applyFormatOption(po *processingOptions, imgType imageType) error { if !vipsTypeSupportSave[imgType] { return errors.New("Resulting image type not supported") @@ -286,30 +304,53 @@ func applyProcessingOption(po *processingOptions, name string, args []string) er if err := applySharpenOption(po, args); err != nil { return err } + case "preset": + if err := applyPresetOption(po, args); err != nil { + return err + } } return nil } -func parsePathAdvanced(parts []string) (string, processingOptions, error) { - var urlStart int +func parseURLOptions(opts []string) (urlOptions, []string) { + parsed := make(urlOptions) + urlStart := len(opts) + 1 - po := defaultProcessingOptions() - - for i, part := range parts { - args := strings.Split(part, ":") + for i, opt := range opts { + args := strings.Split(opt, ":") if len(args) == 1 { urlStart = i break } - if err := applyProcessingOption(&po, args[0], args[1:]); err != nil { + parsed[args[0]] = args[1:] + } + + var rest []string + + if urlStart < len(opts) { + rest = opts[urlStart:] + } else { + rest = []string{} + } + + return parsed, rest +} + +func parsePathAdvanced(parts []string) (string, processingOptions, error) { + po := defaultProcessingOptions() + + options, urlParts := parseURLOptions(parts) + + for name, args := range options { + if err := applyProcessingOption(&po, name, args); err != nil { return "", po, err } } - url, imgType, err := decodeURL(parts[urlStart:]) + url, imgType, err := decodeURL(urlParts) if err != nil { return "", po, err }