mirror of
https://github.com/imgproxy/imgproxy.git
synced 2025-02-02 11:34:20 +02:00
Get rid of os.Exit
This commit is contained in:
parent
5d3b8f19fc
commit
8e3cf54d85
@ -1,6 +1,9 @@
|
||||
# Changelog
|
||||
|
||||
## [Unreleased]
|
||||
### Changed
|
||||
- `imgproxy -v` is replaced with `imgproxy version`.
|
||||
|
||||
### Fixed
|
||||
- Fix loadind BMP stored in ICO.
|
||||
- Fix ambiguous HEIC magic bytes (MP4 videos has been detected as HEIC).
|
||||
|
130
config.go
130
config.go
@ -58,7 +58,7 @@ func boolEnvConfig(b *bool, name string) {
|
||||
}
|
||||
}
|
||||
|
||||
func hexEnvConfig(b *[]securityKey, name string) {
|
||||
func hexEnvConfig(b *[]securityKey, name string) error {
|
||||
var err error
|
||||
|
||||
if env := os.Getenv(name); len(env) > 0 {
|
||||
@ -68,22 +68,24 @@ func hexEnvConfig(b *[]securityKey, name string) {
|
||||
|
||||
for i, part := range parts {
|
||||
if keys[i], err = hex.DecodeString(part); err != nil {
|
||||
logFatal("%s expected to be hex-encoded strings. Invalid: %s\n", name, part)
|
||||
return fmt.Errorf("%s expected to be hex-encoded strings. Invalid: %s\n", name, part)
|
||||
}
|
||||
}
|
||||
|
||||
*b = keys
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func hexFileConfig(b *[]securityKey, filepath string) {
|
||||
func hexFileConfig(b *[]securityKey, filepath string) error {
|
||||
if len(filepath) == 0 {
|
||||
return
|
||||
return nil
|
||||
}
|
||||
|
||||
f, err := os.Open(filepath)
|
||||
if err != nil {
|
||||
logFatal("Can't open file %s\n", filepath)
|
||||
return fmt.Errorf("Can't open file %s\n", filepath)
|
||||
}
|
||||
|
||||
keys := []securityKey{}
|
||||
@ -99,49 +101,55 @@ func hexFileConfig(b *[]securityKey, filepath string) {
|
||||
if key, err := hex.DecodeString(part); err == nil {
|
||||
keys = append(keys, key)
|
||||
} else {
|
||||
logFatal("%s expected to contain hex-encoded strings. Invalid: %s\n", filepath, part)
|
||||
return fmt.Errorf("%s expected to contain hex-encoded strings. Invalid: %s\n", filepath, part)
|
||||
}
|
||||
}
|
||||
|
||||
if err := scanner.Err(); err != nil {
|
||||
logFatal("Failed to read file %s: %s", filepath, err)
|
||||
return fmt.Errorf("Failed to read file %s: %s", filepath, err)
|
||||
}
|
||||
|
||||
*b = keys
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func presetEnvConfig(p presets, name string) {
|
||||
func presetEnvConfig(p presets, name string) error {
|
||||
if env := os.Getenv(name); len(env) > 0 {
|
||||
presetStrings := strings.Split(env, ",")
|
||||
|
||||
for _, presetStr := range presetStrings {
|
||||
if err := parsePreset(p, presetStr); err != nil {
|
||||
logFatal(err.Error())
|
||||
return fmt.Errorf(err.Error())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func presetFileConfig(p presets, filepath string) {
|
||||
func presetFileConfig(p presets, filepath string) error {
|
||||
if len(filepath) == 0 {
|
||||
return
|
||||
return nil
|
||||
}
|
||||
|
||||
f, err := os.Open(filepath)
|
||||
if err != nil {
|
||||
logFatal("Can't open file %s\n", filepath)
|
||||
return fmt.Errorf("Can't open file %s\n", filepath)
|
||||
}
|
||||
|
||||
scanner := bufio.NewScanner(f)
|
||||
for scanner.Scan() {
|
||||
if err := parsePreset(p, scanner.Text()); err != nil {
|
||||
logFatal(err.Error())
|
||||
return fmt.Errorf(err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
if err := scanner.Err(); err != nil {
|
||||
logFatal("Failed to read presets file: %s", err)
|
||||
return fmt.Errorf("Failed to read presets file: %s", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type config struct {
|
||||
@ -263,18 +271,12 @@ var conf = config{
|
||||
BufferPoolCalibrationThreshold: 1024,
|
||||
}
|
||||
|
||||
func configure() {
|
||||
func configure() error {
|
||||
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()
|
||||
|
||||
if *showVersion {
|
||||
fmt.Println(version)
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
if port := os.Getenv("PORT"); len(port) > 0 {
|
||||
conf.Bind = fmt.Sprintf(":%s", port)
|
||||
}
|
||||
@ -321,12 +323,20 @@ func configure() {
|
||||
boolEnvConfig(&conf.UseLinearColorspace, "IMGPROXY_USE_LINEAR_COLORSPACE")
|
||||
boolEnvConfig(&conf.DisableShrinkOnLoad, "IMGPROXY_DISABLE_SHRINK_ON_LOAD")
|
||||
|
||||
hexEnvConfig(&conf.Keys, "IMGPROXY_KEY")
|
||||
hexEnvConfig(&conf.Salts, "IMGPROXY_SALT")
|
||||
if err := hexEnvConfig(&conf.Keys, "IMGPROXY_KEY"); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := hexEnvConfig(&conf.Salts, "IMGPROXY_SALT"); err != nil {
|
||||
return err
|
||||
}
|
||||
intEnvConfig(&conf.SignatureSize, "IMGPROXY_SIGNATURE_SIZE")
|
||||
|
||||
hexFileConfig(&conf.Keys, *keyPath)
|
||||
hexFileConfig(&conf.Salts, *saltPath)
|
||||
if err := hexFileConfig(&conf.Keys, *keyPath); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := hexFileConfig(&conf.Salts, *saltPath); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
strEnvConfig(&conf.Secret, "IMGPROXY_SECRET")
|
||||
|
||||
@ -350,8 +360,12 @@ func configure() {
|
||||
|
||||
strEnvConfig(&conf.BaseURL, "IMGPROXY_BASE_URL")
|
||||
|
||||
presetEnvConfig(conf.Presets, "IMGPROXY_PRESETS")
|
||||
presetFileConfig(conf.Presets, *presetsPath)
|
||||
if err := presetEnvConfig(conf.Presets, "IMGPROXY_PRESETS"); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := presetFileConfig(conf.Presets, *presetsPath); err != nil {
|
||||
return err
|
||||
}
|
||||
boolEnvConfig(&conf.OnlyPresets, "IMGPROXY_ONLY_PRESETS")
|
||||
|
||||
strEnvConfig(&conf.WatermarkData, "IMGPROXY_WATERMARK_DATA")
|
||||
@ -379,7 +393,7 @@ func configure() {
|
||||
intEnvConfig(&conf.BufferPoolCalibrationThreshold, "IMGPROXY_BUFFER_POOL_CALIBRATION_THRESHOLD")
|
||||
|
||||
if len(conf.Keys) != len(conf.Salts) {
|
||||
logFatal("Number of keys and number of salts should be equal. Keys: %d, salts: %d", len(conf.Keys), len(conf.Salts))
|
||||
return fmt.Errorf("Number of keys and number of salts should be equal. Keys: %d, salts: %d", len(conf.Keys), len(conf.Salts))
|
||||
}
|
||||
if len(conf.Keys) == 0 {
|
||||
logWarning("No keys defined, so signature checking is disabled")
|
||||
@ -391,30 +405,30 @@ func configure() {
|
||||
}
|
||||
|
||||
if conf.SignatureSize < 1 || conf.SignatureSize > 32 {
|
||||
logFatal("Signature size should be within 1 and 32, now - %d\n", conf.SignatureSize)
|
||||
return fmt.Errorf("Signature size should be within 1 and 32, now - %d\n", conf.SignatureSize)
|
||||
}
|
||||
|
||||
if len(conf.Bind) == 0 {
|
||||
logFatal("Bind address is not defined")
|
||||
return fmt.Errorf("Bind address is not defined")
|
||||
}
|
||||
|
||||
if conf.ReadTimeout <= 0 {
|
||||
logFatal("Read timeout should be greater than 0, now - %d\n", conf.ReadTimeout)
|
||||
return fmt.Errorf("Read timeout should be greater than 0, now - %d\n", conf.ReadTimeout)
|
||||
}
|
||||
|
||||
if conf.WriteTimeout <= 0 {
|
||||
logFatal("Write timeout should be greater than 0, now - %d\n", conf.WriteTimeout)
|
||||
return fmt.Errorf("Write timeout should be greater than 0, now - %d\n", conf.WriteTimeout)
|
||||
}
|
||||
if conf.KeepAliveTimeout < 0 {
|
||||
logFatal("KeepAlive timeout should be greater than or equal to 0, now - %d\n", conf.KeepAliveTimeout)
|
||||
return fmt.Errorf("KeepAlive timeout should be greater than or equal to 0, now - %d\n", conf.KeepAliveTimeout)
|
||||
}
|
||||
|
||||
if conf.DownloadTimeout <= 0 {
|
||||
logFatal("Download timeout should be greater than 0, now - %d\n", conf.DownloadTimeout)
|
||||
return fmt.Errorf("Download timeout should be greater than 0, now - %d\n", conf.DownloadTimeout)
|
||||
}
|
||||
|
||||
if conf.Concurrency <= 0 {
|
||||
logFatal("Concurrency should be greater than 0, now - %d\n", conf.Concurrency)
|
||||
return fmt.Errorf("Concurrency should be greater than 0, now - %d\n", conf.Concurrency)
|
||||
}
|
||||
|
||||
if conf.MaxClients <= 0 {
|
||||
@ -422,43 +436,43 @@ func configure() {
|
||||
}
|
||||
|
||||
if conf.TTL <= 0 {
|
||||
logFatal("TTL should be greater than 0, now - %d\n", conf.TTL)
|
||||
return fmt.Errorf("TTL should be greater than 0, now - %d\n", conf.TTL)
|
||||
}
|
||||
|
||||
if conf.MaxSrcDimension < 0 {
|
||||
logFatal("Max src dimension should be greater than or equal to 0, now - %d\n", conf.MaxSrcDimension)
|
||||
return fmt.Errorf("Max src dimension should be greater than or equal to 0, now - %d\n", conf.MaxSrcDimension)
|
||||
} else if conf.MaxSrcDimension > 0 {
|
||||
logWarning("IMGPROXY_MAX_SRC_DIMENSION is deprecated and can be removed in future versions. Use IMGPROXY_MAX_SRC_RESOLUTION")
|
||||
}
|
||||
|
||||
if conf.MaxSrcResolution <= 0 {
|
||||
logFatal("Max src resolution should be greater than 0, now - %d\n", conf.MaxSrcResolution)
|
||||
return fmt.Errorf("Max src resolution should be greater than 0, now - %d\n", conf.MaxSrcResolution)
|
||||
}
|
||||
|
||||
if conf.MaxSrcFileSize < 0 {
|
||||
logFatal("Max src file size should be greater than or equal to 0, now - %d\n", conf.MaxSrcFileSize)
|
||||
return fmt.Errorf("Max src file size should be greater than or equal to 0, now - %d\n", conf.MaxSrcFileSize)
|
||||
}
|
||||
|
||||
if conf.MaxAnimationFrames <= 0 {
|
||||
logFatal("Max animation frames should be greater than 0, now - %d\n", conf.MaxAnimationFrames)
|
||||
return fmt.Errorf("Max animation frames should be greater than 0, now - %d\n", conf.MaxAnimationFrames)
|
||||
}
|
||||
|
||||
if conf.PngQuantizationColors < 2 {
|
||||
logFatal("Png quantization colors should be greater than 1, now - %d\n", conf.PngQuantizationColors)
|
||||
return fmt.Errorf("Png quantization colors should be greater than 1, now - %d\n", conf.PngQuantizationColors)
|
||||
} else if conf.PngQuantizationColors > 256 {
|
||||
logFatal("Png quantization colors can't be greater than 256, now - %d\n", conf.PngQuantizationColors)
|
||||
return fmt.Errorf("Png quantization colors can't be greater than 256, now - %d\n", conf.PngQuantizationColors)
|
||||
}
|
||||
|
||||
if conf.Quality <= 0 {
|
||||
logFatal("Quality should be greater than 0, now - %d\n", conf.Quality)
|
||||
return fmt.Errorf("Quality should be greater than 0, now - %d\n", conf.Quality)
|
||||
} else if conf.Quality > 100 {
|
||||
logFatal("Quality can't be greater than 100, now - %d\n", conf.Quality)
|
||||
return fmt.Errorf("Quality can't be greater than 100, now - %d\n", conf.Quality)
|
||||
}
|
||||
|
||||
if conf.GZipCompression < 0 {
|
||||
logFatal("GZip compression should be greater than or equal to 0, now - %d\n", conf.GZipCompression)
|
||||
return fmt.Errorf("GZip compression should be greater than or equal to 0, now - %d\n", conf.GZipCompression)
|
||||
} else if conf.GZipCompression > 9 {
|
||||
logFatal("GZip compression can't be greater than 9, now - %d\n", conf.GZipCompression)
|
||||
return fmt.Errorf("GZip compression can't be greater than 9, now - %d\n", conf.GZipCompression)
|
||||
}
|
||||
|
||||
if conf.GZipCompression > 0 {
|
||||
@ -473,11 +487,11 @@ func configure() {
|
||||
stat, err := os.Stat(conf.LocalFileSystemRoot)
|
||||
|
||||
if err != nil {
|
||||
logFatal("Cannot use local directory: %s", err)
|
||||
return fmt.Errorf("Cannot use local directory: %s", err)
|
||||
}
|
||||
|
||||
if !stat.IsDir() {
|
||||
logFatal("Cannot use local directory: not a directory")
|
||||
return fmt.Errorf("Cannot use local directory: not a directory")
|
||||
}
|
||||
|
||||
if conf.LocalFileSystemRoot == "/" {
|
||||
@ -491,32 +505,34 @@ func configure() {
|
||||
}
|
||||
|
||||
if conf.WatermarkOpacity <= 0 {
|
||||
logFatal("Watermark opacity should be greater than 0")
|
||||
return fmt.Errorf("Watermark opacity should be greater than 0")
|
||||
} else if conf.WatermarkOpacity > 1 {
|
||||
logFatal("Watermark opacity should be less than or equal to 1")
|
||||
return fmt.Errorf("Watermark opacity should be less than or equal to 1")
|
||||
}
|
||||
|
||||
if len(conf.PrometheusBind) > 0 && conf.PrometheusBind == conf.Bind {
|
||||
logFatal("Can't use the same binding for the main server and Prometheus")
|
||||
return fmt.Errorf("Can't use the same binding for the main server and Prometheus")
|
||||
}
|
||||
|
||||
if conf.FreeMemoryInterval <= 0 {
|
||||
logFatal("Free memory interval should be greater than zero")
|
||||
return fmt.Errorf("Free memory interval should be greater than zero")
|
||||
}
|
||||
|
||||
if conf.DownloadBufferSize < 0 {
|
||||
logFatal("Download buffer size should be greater than or equal to 0")
|
||||
return fmt.Errorf("Download buffer size should be greater than or equal to 0")
|
||||
} else if conf.DownloadBufferSize > math.MaxInt32 {
|
||||
logFatal("Download buffer size can't be greater than %d", math.MaxInt32)
|
||||
return fmt.Errorf("Download buffer size can't be greater than %d", math.MaxInt32)
|
||||
}
|
||||
|
||||
if conf.GZipBufferSize < 0 {
|
||||
logFatal("GZip buffer size should be greater than or equal to 0")
|
||||
return fmt.Errorf("GZip buffer size should be greater than or equal to 0")
|
||||
} else if conf.GZipBufferSize > math.MaxInt32 {
|
||||
logFatal("GZip buffer size can't be greater than %d", math.MaxInt32)
|
||||
return fmt.Errorf("GZip buffer size can't be greater than %d", math.MaxInt32)
|
||||
}
|
||||
|
||||
if conf.BufferPoolCalibrationThreshold < 64 {
|
||||
logFatal("Buffer pool calibration threshold should be greater than or equal to 64")
|
||||
return fmt.Errorf("Buffer pool calibration threshold should be greater than or equal to 64")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
16
download.go
16
download.go
@ -59,7 +59,7 @@ func (lr *limitReader) Read(p []byte) (n int, err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func initDownloading() {
|
||||
func initDownloading() error {
|
||||
transport := &http.Transport{
|
||||
Proxy: http.ProxyFromEnvironment,
|
||||
MaxIdleConns: conf.Concurrency,
|
||||
@ -77,11 +77,19 @@ func initDownloading() {
|
||||
}
|
||||
|
||||
if conf.S3Enabled {
|
||||
transport.RegisterProtocol("s3", newS3Transport())
|
||||
if t, err := newS3Transport(); err != nil {
|
||||
return err
|
||||
} else {
|
||||
transport.RegisterProtocol("s3", t)
|
||||
}
|
||||
}
|
||||
|
||||
if conf.GCSEnabled {
|
||||
transport.RegisterProtocol("gs", newGCSTransport())
|
||||
if t, err := newGCSTransport(); err != nil {
|
||||
return err
|
||||
} else {
|
||||
transport.RegisterProtocol("gs", t)
|
||||
}
|
||||
}
|
||||
|
||||
downloadClient = &http.Client{
|
||||
@ -92,6 +100,8 @@ func initDownloading() {
|
||||
downloadBufPool = newBufPool("download", conf.Concurrency, conf.DownloadBufferSize)
|
||||
|
||||
imagemeta.SetMaxSvgCheckRead(conf.MaxSvgCheckBytes)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func checkDimensions(width, height int) error {
|
||||
|
@ -2,6 +2,7 @@ package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
@ -14,7 +15,7 @@ type gcsTransport struct {
|
||||
client *storage.Client
|
||||
}
|
||||
|
||||
func newGCSTransport() http.RoundTripper {
|
||||
func newGCSTransport() (http.RoundTripper, error) {
|
||||
var (
|
||||
client *storage.Client
|
||||
err error
|
||||
@ -27,10 +28,10 @@ func newGCSTransport() http.RoundTripper {
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
logFatal("Can't create GCS client: %s", err)
|
||||
return nil, fmt.Errorf("Can't create GCS client: %s", err)
|
||||
}
|
||||
|
||||
return gcsTransport{client}
|
||||
return gcsTransport{client}, nil
|
||||
}
|
||||
|
||||
func (t gcsTransport) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||
|
15
gzippool.go
15
gzippool.go
@ -2,6 +2,7 @@ package main
|
||||
|
||||
import (
|
||||
"compress/gzip"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"sync"
|
||||
@ -17,26 +18,30 @@ type gzipPoolEntry struct {
|
||||
next *gzipPoolEntry
|
||||
}
|
||||
|
||||
func newGzipPool(n int) *gzipPool {
|
||||
func newGzipPool(n int) (*gzipPool, error) {
|
||||
pool := new(gzipPool)
|
||||
|
||||
for i := 0; i < n; i++ {
|
||||
pool.grow()
|
||||
if err := pool.grow(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return pool
|
||||
return pool, nil
|
||||
}
|
||||
|
||||
func (p *gzipPool) grow() {
|
||||
func (p *gzipPool) grow() error {
|
||||
gz, err := gzip.NewWriterLevel(ioutil.Discard, conf.GZipCompression)
|
||||
if err != nil {
|
||||
logFatal("Can't init GZip compression: %s", err)
|
||||
return fmt.Errorf("Can't init GZip compression: %s", err)
|
||||
}
|
||||
|
||||
p.top = &gzipPoolEntry{
|
||||
gz: gz,
|
||||
next: p.top,
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *gzipPool) Get(w io.Writer) *gzip.Writer {
|
||||
|
@ -9,7 +9,7 @@ import (
|
||||
"os"
|
||||
)
|
||||
|
||||
func healthcheck() {
|
||||
func healthcheck() int {
|
||||
network := conf.Network
|
||||
bind := conf.Bind
|
||||
|
||||
@ -27,7 +27,7 @@ func healthcheck() {
|
||||
res, err := httpc.Get("http://imgproxy/health")
|
||||
if err != nil {
|
||||
fmt.Fprintln(os.Stderr, err.Error())
|
||||
os.Exit(1)
|
||||
return 1
|
||||
}
|
||||
defer res.Body.Close()
|
||||
|
||||
@ -35,8 +35,8 @@ func healthcheck() {
|
||||
fmt.Fprintln(os.Stderr, string(msg))
|
||||
|
||||
if res.StatusCode != 200 {
|
||||
os.Exit(1)
|
||||
return 1
|
||||
}
|
||||
|
||||
os.Exit(0)
|
||||
return 0
|
||||
}
|
||||
|
11
log.go
11
log.go
@ -1,12 +1,13 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
logrus "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
func initLog() {
|
||||
func initLog() error {
|
||||
logFormat := "pretty"
|
||||
strEnvConfig(&logFormat, "IMGPROXY_LOG_FORMAT")
|
||||
|
||||
@ -32,11 +33,13 @@ func initLog() {
|
||||
if isSyslogEnabled() {
|
||||
slHook, err := newSyslogHook()
|
||||
if err != nil {
|
||||
logFatal("Unable to connect to local syslog daemon")
|
||||
return fmt.Errorf("Unable to connect to syslog daemon: %s", err)
|
||||
}
|
||||
|
||||
logrus.AddHook(slHook)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func logRequest(reqID string, r *http.Request) {
|
||||
@ -96,6 +99,10 @@ func logWarning(f string, args ...interface{}) {
|
||||
logrus.Warnf(f, args...)
|
||||
}
|
||||
|
||||
func logError(f string, args ...interface{}) {
|
||||
logrus.Errorf(f, args...)
|
||||
}
|
||||
|
||||
func logFatal(f string, args ...interface{}) {
|
||||
logrus.Fatalf(f, args...)
|
||||
}
|
||||
|
77
main.go
77
main.go
@ -1,6 +1,8 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"os/signal"
|
||||
@ -13,29 +15,46 @@ const version = "2.10.0"
|
||||
|
||||
type ctxKey string
|
||||
|
||||
func initialize() {
|
||||
func initialize() error {
|
||||
log.SetOutput(os.Stdout)
|
||||
|
||||
initLog()
|
||||
configure()
|
||||
initNewrelic()
|
||||
if err := initLog(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := configure(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := initNewrelic(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
initPrometheus()
|
||||
initDownloading()
|
||||
|
||||
if err := initDownloading(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
initErrorsReporting()
|
||||
initVips()
|
||||
|
||||
if err := initVips(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := checkPresets(conf.Presets); err != nil {
|
||||
shutdownVips()
|
||||
logFatal(err.Error())
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func main() {
|
||||
if len(os.Args) > 1 && os.Args[1] == "health" {
|
||||
healthcheck()
|
||||
func run() error {
|
||||
if err := initialize(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
initialize()
|
||||
defer shutdownVips()
|
||||
|
||||
go func() {
|
||||
@ -52,11 +71,43 @@ func main() {
|
||||
}
|
||||
}()
|
||||
|
||||
s := startServer()
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
|
||||
if prometheusEnabled {
|
||||
if err := startPrometheusServer(cancel); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
s, err := startServer(cancel)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer shutdownServer(s)
|
||||
|
||||
stop := make(chan os.Signal, 1)
|
||||
signal.Notify(stop, syscall.SIGINT, syscall.SIGTERM)
|
||||
|
||||
<-stop
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
case <-stop:
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func main() {
|
||||
if len(os.Args) > 1 {
|
||||
switch os.Args[1] {
|
||||
case "health":
|
||||
os.Exit(healthcheck())
|
||||
case "version":
|
||||
fmt.Println(version)
|
||||
os.Exit(0)
|
||||
}
|
||||
}
|
||||
|
||||
if err := run(); err != nil {
|
||||
logFatal(err.Error())
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
@ -16,9 +17,9 @@ var (
|
||||
newRelicTransactionCtxKey = ctxKey("newRelicTransaction")
|
||||
)
|
||||
|
||||
func initNewrelic() {
|
||||
func initNewrelic() error {
|
||||
if len(conf.NewRelicKey) == 0 {
|
||||
return
|
||||
return nil
|
||||
}
|
||||
|
||||
name := conf.NewRelicAppName
|
||||
@ -32,10 +33,12 @@ func initNewrelic() {
|
||||
newRelicApp, err = newrelic.NewApplication(config)
|
||||
|
||||
if err != nil {
|
||||
logFatal("Can't init New Relic agent: %s", err)
|
||||
return fmt.Errorf("Can't init New Relic agent: %s", err)
|
||||
}
|
||||
|
||||
newRelicEnabled = true
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func startNewRelicTransaction(ctx context.Context, rw http.ResponseWriter, r *http.Request) (context.Context, context.CancelFunc) {
|
||||
|
@ -18,12 +18,15 @@ var (
|
||||
headerVaryValue string
|
||||
)
|
||||
|
||||
func initProcessingHandler() {
|
||||
func initProcessingHandler() error {
|
||||
processingSem = make(chan struct{}, conf.Concurrency)
|
||||
|
||||
if conf.GZipCompression > 0 {
|
||||
var err error
|
||||
responseGzipBufPool = newBufPool("gzip", conf.Concurrency, conf.GZipBufferSize)
|
||||
responseGzipPool = newGzipPool(conf.Concurrency)
|
||||
if responseGzipPool, err = newGzipPool(conf.Concurrency); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
vary := make([]string, 0)
|
||||
@ -41,6 +44,8 @@ func initProcessingHandler() {
|
||||
}
|
||||
|
||||
headerVaryValue = strings.Join(vary, ", ")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func respondWithImage(ctx context.Context, reqID string, r *http.Request, rw http.ResponseWriter, data []byte) {
|
||||
|
@ -1,6 +1,8 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
@ -99,20 +101,25 @@ func initPrometheus() {
|
||||
)
|
||||
|
||||
prometheusEnabled = true
|
||||
}
|
||||
|
||||
func startPrometheusServer(cancel context.CancelFunc) error {
|
||||
s := http.Server{Handler: promhttp.Handler()}
|
||||
|
||||
go func() {
|
||||
l, err := listenReuseport("tcp", conf.PrometheusBind)
|
||||
if err != nil {
|
||||
logFatal(err.Error())
|
||||
}
|
||||
l, err := listenReuseport("tcp", conf.PrometheusBind)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Can't start Prometheus metrics server: %s", err)
|
||||
}
|
||||
|
||||
go func() {
|
||||
logNotice("Starting Prometheus server at %s", conf.PrometheusBind)
|
||||
if err := s.Serve(l); err != nil && err != http.ErrServerClosed {
|
||||
logFatal(err.Error())
|
||||
logError(err.Error())
|
||||
}
|
||||
cancel()
|
||||
}()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func startPrometheusDuration(m prometheus.Histogram) func() {
|
||||
|
@ -1,6 +1,7 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
http "net/http"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
@ -13,7 +14,7 @@ type s3Transport struct {
|
||||
svc *s3.S3
|
||||
}
|
||||
|
||||
func newS3Transport() http.RoundTripper {
|
||||
func newS3Transport() (http.RoundTripper, error) {
|
||||
s3Conf := aws.NewConfig()
|
||||
|
||||
if len(conf.S3Region) != 0 {
|
||||
@ -27,14 +28,14 @@ func newS3Transport() http.RoundTripper {
|
||||
|
||||
sess, err := session.NewSession()
|
||||
if err != nil {
|
||||
logFatal("Can't create S3 session: %s", err)
|
||||
return nil, fmt.Errorf("Can't create S3 session: %s", err)
|
||||
}
|
||||
|
||||
if sess.Config.Region == nil || len(*sess.Config.Region) == 0 {
|
||||
sess.Config.Region = aws.String("us-west-1")
|
||||
}
|
||||
|
||||
return s3Transport{s3.New(sess, s3Conf)}
|
||||
return s3Transport{s3.New(sess, s3Conf)}, nil
|
||||
}
|
||||
|
||||
func (t s3Transport) RoundTrip(req *http.Request) (resp *http.Response, err error) {
|
||||
|
13
server.go
13
server.go
@ -31,10 +31,10 @@ func buildRouter() *router {
|
||||
return r
|
||||
}
|
||||
|
||||
func startServer() *http.Server {
|
||||
func startServer(cancel context.CancelFunc) (*http.Server, error) {
|
||||
l, err := listenReuseport(conf.Network, conf.Bind)
|
||||
if err != nil {
|
||||
logFatal(err.Error())
|
||||
return nil, fmt.Errorf("Can't start server: %s", err)
|
||||
}
|
||||
l = netutil.LimitListener(l, conf.MaxClients)
|
||||
|
||||
@ -50,16 +50,19 @@ func startServer() *http.Server {
|
||||
s.SetKeepAlivesEnabled(false)
|
||||
}
|
||||
|
||||
initProcessingHandler()
|
||||
if err := initProcessingHandler(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
go func() {
|
||||
logNotice("Starting server at %s", conf.Bind)
|
||||
if err := s.Serve(l); err != nil && err != http.ErrServerClosed {
|
||||
logFatal(err.Error())
|
||||
logError(err.Error())
|
||||
}
|
||||
cancel()
|
||||
}()
|
||||
|
||||
return s
|
||||
return s, nil
|
||||
}
|
||||
|
||||
func shutdownServer(s *http.Server) {
|
||||
|
10
vips.go
10
vips.go
@ -9,6 +9,7 @@ package main
|
||||
import "C"
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"math"
|
||||
"os"
|
||||
"runtime"
|
||||
@ -43,13 +44,13 @@ const (
|
||||
vipsAngleD270 = C.VIPS_ANGLE_D270
|
||||
)
|
||||
|
||||
func initVips() {
|
||||
func initVips() error {
|
||||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
|
||||
if err := C.vips_initialize(); err != 0 {
|
||||
C.vips_shutdown()
|
||||
logFatal("unable to start vips!")
|
||||
return fmt.Errorf("unable to start vips!")
|
||||
}
|
||||
|
||||
// Disable libvips cache. Since processing pipeline is fine tuned, we won't get much profit from it.
|
||||
@ -95,10 +96,13 @@ func initVips() {
|
||||
vipsConf.WatermarkOpacity = C.double(conf.WatermarkOpacity)
|
||||
|
||||
if err := vipsLoadWatermark(); err != nil {
|
||||
logFatal(err.Error())
|
||||
C.vips_shutdown()
|
||||
return fmt.Errorf("Can't load watermark: %s", err)
|
||||
}
|
||||
|
||||
vipsCollectMetrics()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func shutdownVips() {
|
||||
|
Loading…
x
Reference in New Issue
Block a user