Browse Source

Presets :tada:

DarthSim 7 years ago
parent
commit
a157a818f6
4 changed files with 133 additions and 12 deletions
  1. 39 4
      config.go
  2. 5 0
      errors.go
  3. 40 0
      presets.go
  4. 49 8
      processing_options.go

+ 39 - 4
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")
 	}

+ 5 - 0
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...))
+}

+ 40 - 0
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)
+	}
+}

+ 49 - 8
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
-
-	po := defaultProcessingOptions()
+func parseURLOptions(opts []string) (urlOptions, []string) {
+	parsed := make(urlOptions)
+	urlStart := len(opts) + 1
 
-	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
 	}