mirror of
https://github.com/elyby/chrly.git
synced 2024-12-24 14:09:56 +05:30
159 lines
4.3 KiB
Go
159 lines
4.3 KiB
Go
package di
|
|
|
|
import (
|
|
"net/http"
|
|
"slices"
|
|
"strings"
|
|
|
|
"github.com/defval/di"
|
|
"github.com/etherlabsio/healthcheck/v2"
|
|
"github.com/gorilla/mux"
|
|
"github.com/spf13/viper"
|
|
"go.opentelemetry.io/contrib/instrumentation/github.com/gorilla/mux/otelmux"
|
|
|
|
. "ely.by/chrly/internal/http"
|
|
"ely.by/chrly/internal/security"
|
|
)
|
|
|
|
const ModuleSkinsystem = "skinsystem"
|
|
const ModuleProfiles = "profiles"
|
|
const ModuleSigner = "signer"
|
|
|
|
var handlersDiOptions = di.Options(
|
|
di.Provide(newHandlerFactory, di.As(new(http.Handler))),
|
|
di.Provide(newSkinsystemHandler, di.WithName(ModuleSkinsystem)),
|
|
di.Provide(newProfilesApiHandler, di.WithName(ModuleProfiles)),
|
|
di.Provide(newSignerApiHandler, di.WithName(ModuleSigner)),
|
|
)
|
|
|
|
func newHandlerFactory(
|
|
container *di.Container,
|
|
config *viper.Viper,
|
|
) (*mux.Router, error) {
|
|
enabledModules := config.GetStringSlice("modules")
|
|
|
|
// gorilla.mux has no native way to combine multiple routers.
|
|
// The hack used later in the code works for prefixes in addresses, but leads to misbehavior
|
|
// if you set an empty prefix. Since the main application should be mounted at the root prefix,
|
|
// we use it as the base router
|
|
var router *mux.Router
|
|
if slices.Contains(enabledModules, ModuleSkinsystem) {
|
|
if err := container.Resolve(&router, di.Name(ModuleSkinsystem)); err != nil {
|
|
return nil, err
|
|
}
|
|
} else {
|
|
router = mux.NewRouter()
|
|
}
|
|
|
|
router.StrictSlash(true)
|
|
router.Use(otelmux.Middleware("chrly"))
|
|
router.NotFoundHandler = http.HandlerFunc(NotFoundHandler)
|
|
|
|
if slices.Contains(enabledModules, ModuleProfiles) {
|
|
var profilesApiRouter *mux.Router
|
|
if err := container.Resolve(&profilesApiRouter, di.Name(ModuleProfiles)); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
var authenticator Authenticator
|
|
if err := container.Resolve(&authenticator); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
profilesApiRouter.Use(NewAuthenticationMiddleware(authenticator, security.ProfilesScope))
|
|
|
|
mount(router, "/api/profiles", profilesApiRouter)
|
|
}
|
|
|
|
if slices.Contains(enabledModules, ModuleSigner) {
|
|
var signerApiRouter *mux.Router
|
|
if err := container.Resolve(&signerApiRouter, di.Name(ModuleSigner)); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
var authenticator Authenticator
|
|
if err := container.Resolve(&authenticator); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
authMiddleware := NewAuthenticationMiddleware(authenticator, security.SignScope)
|
|
conditionalAuth := NewConditionalMiddleware(func(req *http.Request) bool {
|
|
return req.Method != "GET"
|
|
}, authMiddleware)
|
|
signerApiRouter.Use(conditionalAuth)
|
|
|
|
mount(router, "/api/signer", signerApiRouter)
|
|
}
|
|
|
|
// Resolve health checkers last, because all the services required by the application
|
|
// must first be initialized and each of them can publish its own checkers
|
|
var healthCheckers []*namedHealthChecker
|
|
if has, _ := container.Has(&healthCheckers); has {
|
|
if err := container.Resolve(&healthCheckers); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
checkersOptions := make([]healthcheck.Option, len(healthCheckers))
|
|
for i, checker := range healthCheckers {
|
|
checkersOptions[i] = healthcheck.WithChecker(checker.Name, checker.Checker)
|
|
}
|
|
|
|
router.Handle("/healthcheck", healthcheck.Handler(checkersOptions...)).Methods("GET")
|
|
}
|
|
|
|
return router, nil
|
|
}
|
|
|
|
func newSkinsystemHandler(
|
|
config *viper.Viper,
|
|
profilesProvider ProfilesProvider,
|
|
texturesSigner SignerService,
|
|
) (*mux.Router, error) {
|
|
config.SetDefault("textures.extra_param_name", "chrly")
|
|
config.SetDefault("textures.extra_param_value", "how do you tame a horse in Minecraft?")
|
|
|
|
skinsystem, err := NewSkinsystemApi(
|
|
profilesProvider,
|
|
texturesSigner,
|
|
config.GetString("textures.extra_param_name"),
|
|
config.GetString("textures.extra_param_value"),
|
|
)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return skinsystem.Handler(), nil
|
|
}
|
|
|
|
func newProfilesApiHandler(profilesManager ProfilesManager) (*mux.Router, error) {
|
|
profilesApi, err := NewProfilesApi(profilesManager)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return profilesApi.Handler(), nil
|
|
}
|
|
|
|
func newSignerApiHandler(signer Signer) (*mux.Router, error) {
|
|
signerApi, err := NewSignerApi(signer)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return signerApi.Handler(), nil
|
|
}
|
|
|
|
func mount(router *mux.Router, path string, handler http.Handler) {
|
|
router.PathPrefix(path).Handler(
|
|
http.StripPrefix(
|
|
strings.TrimSuffix(path, "/"),
|
|
handler,
|
|
),
|
|
)
|
|
}
|
|
|
|
type namedHealthChecker struct {
|
|
Name string
|
|
Checker healthcheck.Checker
|
|
}
|