package director import ( "context" "net/http" "net/url" "forge.cadoles.com/cadoles/bouncer/internal/store" "github.com/pkg/errors" "gitlab.com/wpetit/goweb/logger" ) type contextKey string const ( contextKeyProxy contextKey = "proxy" contextKeyLayers contextKey = "layers" contextKeyOriginalURL contextKey = "originalURL" contextKeyHandleError contextKey = "handleError" ) var ( errContextKeyNotFound = errors.New("context key not found") errUnexpectedContextValue = errors.New("unexpected context value") ) func withOriginalURL(ctx context.Context, url *url.URL) context.Context { return context.WithValue(ctx, contextKeyOriginalURL, url) } func OriginalURL(ctx context.Context) (*url.URL, error) { url, err := ctxValue[*url.URL](ctx, contextKeyOriginalURL) if err != nil { return nil, errors.WithStack(err) } return url, nil } func withLayers(ctx context.Context, layers []*store.Layer) context.Context { return context.WithValue(ctx, contextKeyLayers, layers) } func ctxLayers(ctx context.Context) ([]*store.Layer, error) { layers, err := ctxValue[[]*store.Layer](ctx, contextKeyLayers) if err != nil { return nil, errors.WithStack(err) } return layers, nil } func ctxValue[T any](ctx context.Context, key contextKey) (T, error) { raw := ctx.Value(key) if raw == nil { return *new(T), errors.WithStack(errContextKeyNotFound) } value, ok := raw.(T) if !ok { return *new(T), errors.WithStack(errUnexpectedContextValue) } return value, nil } type HandleErrorFunc func(w http.ResponseWriter, r *http.Request, status int, err error) func withHandleError(ctx context.Context, fn HandleErrorFunc) context.Context { return context.WithValue(ctx, contextKeyHandleError, fn) } func HandleError(ctx context.Context, w http.ResponseWriter, r *http.Request, status int, err error) { err = errors.WithStack(err) fn, ok := ctx.Value(contextKeyHandleError).(HandleErrorFunc) if !ok { logger.Error(ctx, err.Error(), logger.CapturedE(err)) http.Error(w, http.StatusText(status), status) return } fn(w, r, status, err) }