mirror of
https://github.com/gomods/athens
synced 2026-02-03 11:00:32 +00:00
* Athens: introduce singleflight * fix ci * small fixes * Remove unnecessary method * simplify folder structure * dcoument stasher iface * fixes * Fix olympus * Remove Version from Download Protocol * fix olympus * refactor fetcher * consolodate wrapping styles * fix olympus * Further refactoring * fix typo
195 lines
5.5 KiB
Go
195 lines
5.5 KiB
Go
package actions
|
|
|
|
import (
|
|
stdlog "log"
|
|
|
|
"github.com/gobuffalo/buffalo"
|
|
"github.com/gobuffalo/buffalo/middleware"
|
|
"github.com/gobuffalo/buffalo/middleware/csrf"
|
|
"github.com/gobuffalo/buffalo/middleware/i18n"
|
|
"github.com/gobuffalo/buffalo/middleware/ssl"
|
|
"github.com/gobuffalo/buffalo/worker"
|
|
"github.com/gobuffalo/gocraft-work-adapter"
|
|
"github.com/gobuffalo/packr"
|
|
"github.com/gocraft/work"
|
|
"github.com/gomods/athens/pkg/cdn/metadata/azurecdn"
|
|
"github.com/gomods/athens/pkg/config/env"
|
|
"github.com/gomods/athens/pkg/download"
|
|
"github.com/gomods/athens/pkg/eventlog"
|
|
"github.com/gomods/athens/pkg/log"
|
|
"github.com/gomods/athens/pkg/module"
|
|
"github.com/gomods/athens/pkg/stash"
|
|
"github.com/gomods/athens/pkg/storage"
|
|
"github.com/gomodule/redigo/redis"
|
|
"github.com/rs/cors"
|
|
"github.com/spf13/afero"
|
|
"github.com/unrolled/secure"
|
|
)
|
|
|
|
// AppConfig contains dependencies used in App
|
|
type AppConfig struct {
|
|
Storage storage.Backend
|
|
EventLog eventlog.Eventlog
|
|
CacheMissesLog eventlog.Appender
|
|
}
|
|
|
|
const (
|
|
// OlympusWorkerName is the name of the Olympus worker
|
|
OlympusWorkerName = "olympus-worker"
|
|
// DownloadHandlerName is name of the handler downloading packages from VCS
|
|
DownloadHandlerName = "download-handler"
|
|
// PushNotificationHandlerName is the name of the handler processing push notifications
|
|
PushNotificationHandlerName = "push-notification-worker"
|
|
)
|
|
|
|
var (
|
|
workerQueue = "default"
|
|
workerModuleKey = "module"
|
|
workerVersionKey = "version"
|
|
workerPushNotificationKey = "push-notification"
|
|
// ENV is used to help switch settings based on where the
|
|
// application is being run. Default is "development".
|
|
ENV = env.GoEnvironmentWithDefault("development")
|
|
// T is buffalo Translator
|
|
T *i18n.Translator
|
|
)
|
|
|
|
// App is where all routes and middleware for buffalo should be defined.
|
|
// This is the nerve center of your application.
|
|
func App(config *AppConfig) (*buffalo.App, error) {
|
|
port := env.Port(":3001")
|
|
|
|
w, err := getWorker(config.Storage, config.EventLog)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
lvl, err := env.LogLevel()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
lggr := log.New(env.CloudRuntime(), lvl)
|
|
|
|
blvl, err := env.BuffaloLogLevel()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
blggr := log.Buffalo(blvl)
|
|
|
|
app := buffalo.New(buffalo.Options{
|
|
Addr: port,
|
|
Env: ENV,
|
|
PreWares: []buffalo.PreWare{
|
|
cors.Default().Handler,
|
|
},
|
|
SessionName: "_olympus_session",
|
|
Worker: w,
|
|
WorkerOff: true, // TODO(marwan): turned off until worker is being used.
|
|
Logger: blggr,
|
|
})
|
|
|
|
// Automatically redirect to SSL
|
|
app.Use(ssl.ForceSSL(secure.Options{
|
|
SSLRedirect: ENV == "production",
|
|
SSLProxyHeaders: map[string]string{"X-Forwarded-Proto": "https"},
|
|
}))
|
|
|
|
if ENV == "development" {
|
|
app.Use(middleware.ParameterLogger)
|
|
}
|
|
initializeTracing(app)
|
|
// Protect against CSRF attacks. https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF)
|
|
// Remove to disable this.
|
|
if env.EnableCSRFProtection() {
|
|
csrfMiddleware := csrf.New
|
|
app.Use(csrfMiddleware)
|
|
}
|
|
|
|
// TODO: parameterize the GoGet getter here.
|
|
//
|
|
// Defaulting to Azure for now
|
|
app.Use(GoGet(azurecdn.Metadata{
|
|
// TODO: initialize the azurecdn.Storage struct here
|
|
}))
|
|
|
|
// Setup and use translations:
|
|
if T, err = i18n.New(packr.NewBox("../locales"), "en-US"); err != nil {
|
|
app.Stop(err)
|
|
}
|
|
app.Use(T.Middleware())
|
|
|
|
app.GET("/diff/{lastID}", diffHandler(config.Storage, config.EventLog))
|
|
app.GET("/feed/{lastID}", feedHandler(config.Storage))
|
|
app.GET("/eventlog/{sequence_id}", eventlogHandler(config.EventLog))
|
|
app.POST("/cachemiss", cachemissHandler(w))
|
|
app.POST("/push", pushNotificationHandler(w))
|
|
app.GET("/healthz", healthHandler)
|
|
|
|
// Download Protocol
|
|
goBin := env.GoBinPath()
|
|
fs := afero.NewOsFs()
|
|
mf, err := module.NewGoGetFetcher(goBin, fs)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
st := stash.New(mf, config.Storage)
|
|
dpOpts := &download.Opts{
|
|
Storage: config.Storage,
|
|
Stasher: st,
|
|
GoBinPath: goBin,
|
|
Fs: fs,
|
|
}
|
|
dp := download.New(dpOpts)
|
|
|
|
handlerOpts := &download.HandlerOpts{Protocol: dp, Logger: lggr, Engine: renderEng}
|
|
download.RegisterHandlers(app, handlerOpts)
|
|
|
|
app.ServeFiles("/", assetsBox) // serve files from the public directory
|
|
|
|
return app, nil
|
|
}
|
|
|
|
func getWorker(store storage.Backend, eLog eventlog.Eventlog) (worker.Worker, error) {
|
|
workerType := env.OlympusBackgroundWorkerType()
|
|
switch workerType {
|
|
case "redis":
|
|
return registerRedis(store, eLog)
|
|
case "memory":
|
|
return registerInMem(store, eLog)
|
|
default:
|
|
stdlog.Printf("Provided background worker type %s. Expected redis|memory. Defaulting to memory", workerType)
|
|
return registerInMem(store, eLog)
|
|
}
|
|
}
|
|
|
|
func registerInMem(store storage.Backend, eLog eventlog.Eventlog) (worker.Worker, error) {
|
|
w := worker.NewSimple()
|
|
if err := w.Register(PushNotificationHandlerName, GetProcessPushNotificationJob(store, eLog)); err != nil {
|
|
return nil, err
|
|
}
|
|
return w, nil
|
|
}
|
|
|
|
func registerRedis(store storage.Backend, eLog eventlog.Eventlog) (worker.Worker, error) {
|
|
port := env.OlympusRedisQueuePortWithDefault(":6379")
|
|
w := gwa.New(gwa.Options{
|
|
Pool: &redis.Pool{
|
|
MaxActive: 5,
|
|
MaxIdle: 5,
|
|
Wait: true,
|
|
Dial: func() (redis.Conn, error) {
|
|
return redis.Dial("tcp", port)
|
|
},
|
|
},
|
|
Name: OlympusWorkerName,
|
|
MaxConcurrency: env.AthensMaxConcurrency(),
|
|
})
|
|
|
|
opts := work.JobOptions{
|
|
SkipDead: true,
|
|
MaxFails: env.WorkerMaxFails(),
|
|
}
|
|
|
|
return w, w.RegisterWithOptions(PushNotificationHandlerName, opts, GetProcessPushNotificationJob(store, eLog))
|
|
}
|