func New() (pr *MultiProcessor, err error) { mg, err := magickadapter.New() if err != nil { return } bm, err := bimgadapter.New() if err != nil { return } pr = &MultiProcessor{ magick: mg, bimg: bm, } return }
func main() { maxProcs := runtime.NumCPU() runtime.GOMAXPROCS(maxProcs) var ( listen_host string fs_basepath string fs_cachepath string http_origin string error_imgpath string secret string rate_limit_by_path int rate_limit_bursts int concurrency int newrelic_key string ) flag.StringVar(&listen_host, "listen", "localhost:3000", "HTTP host:port to listen for incoming requests") flag.StringVar(&fs_basepath, "basepath", "", "File system base path to lookup images") flag.StringVar(&fs_cachepath, "cachepath", "", "File system base path to cache images") flag.StringVar(&http_origin, "httporigin", "", "HTTP endpoint to lookup origin images") flag.StringVar(&error_imgpath, "errorimgpath", "./fixtures/error.png", "Error image path in local filesystem") flag.StringVar(&secret, "secret", "", "Secret used to check image signature") flag.StringVar(&newrelic_key, "newrelic", "", "NewRelic application key") flag.IntVar(&rate_limit_by_path, "ratelimit", 0, "Rate limit. Concurrent images per request path") flag.IntVar(&rate_limit_bursts, "bursts", 5, "Rate limits bursts") flag.IntVar(&concurrency, "concurrency", 0, "Max concurrent requests") flag.Parse() var store btcdn.Store var storeErr error var newrelic *gorelic.Agent if fs_basepath != "" { store, storeErr = btcdn.NewFsStore(fs_basepath) } else { store, storeErr = btcdn.NewHttpStore(http_origin) } if storeErr != nil { log.Fatal(storeErr) } pr, err := processor.New() if err != nil { log.Fatal(err) } imgSrv, err := btcdn.NewImageServer(store, pr, error_imgpath) if err != nil { log.Fatal(err) } router := mux.NewRouter() var srv http.Handler srv = router if secret == "" { // no security log.Println("No secret. Using ImageServer with no DoS protection") router.HandleFunc("/", imgSrv.ServeHTTP) } else { // secure server log.Println("Secret provided. Using ImageServer with DoS protection") srv = btcdn.NewSecureServer(imgSrv, secret, router) } // Only cache named sizes // to the filesystem for now if fs_cachepath != "" { log.Println("Caching named sizes to", fs_cachepath) cachedEndpoint := btcdn.NewCachedEndpoint(imgSrv, fs_cachepath) srv = btcdn.NewNamedSizesServer(cachedEndpoint, router) } else { srv = btcdn.NewNamedSizesServer(imgSrv, router) } // Setup rate-limited server if rate_limit_by_path > 0 { store, err := tstore.New(65536) if err != nil { log.Fatal(err) } quota := throttled.RateQuota{throttled.PerSec(rate_limit_by_path), rate_limit_bursts} rateLimiter, err := throttled.NewGCRARateLimiter(store, quota) if err != nil { log.Fatal(err) } httpRateLimiter := throttled.HTTPRateLimiter{ RateLimiter: rateLimiter, VaryBy: &throttled.VaryBy{Path: true}, } log.Println("Rate limiting by path with ", rate_limit_by_path, "reqs. per second with bursts of ", rate_limit_bursts) srv = httpRateLimiter.RateLimit(srv) } // http.HandleFunc("/favicon.ico", FaviconHandler) var concurrencyPrompt string if concurrency > 0 { srv = httpool.Wrap(srv, concurrency) concurrencyPrompt = fmt.Sprintf("concurrency: %d", concurrency) } if newrelic_key != "" { newrelic = gorelic.NewAgent() newrelic.NewrelicLicense = newrelic_key newrelic.NewrelicName = "Btcdn (Go image resizer" newrelic.CollectHTTPStat = true newrelic.Run() srv = newrelic.WrapHTTPHandler(srv) log.Println("Newrelic support enabled") } log.Println("Serving on", listen_host, "cores:", maxProcs, "store:", concurrencyPrompt, store.String(), "error img:", error_imgpath) log.Fatal(http.ListenAndServe(listen_host, srv)) }