func CacheSize(size int) Option {
	return func(cfg *Config) {
		cfg.cacheSize = size
	}
}
CacheSize sets the maximum size of the query cache.
If size is less than or equal to 0, the cache is disabled.
package handler
import (
	"context"
	"crypto/sha256"
	"encoding/hex"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"mime"
	"net/http"
	"os"
	"strconv"
	"strings"
	"time"
	"github.com/99designs/gqlgen/complexity"
	"github.com/99designs/gqlgen/graphql"
	"github.com/gorilla/websocket"
	lru "github.com/hashicorp/golang-lru"
	"github.com/vektah/gqlparser/ast"
	"github.com/vektah/gqlparser/gqlerror"
	"github.com/vektah/gqlparser/parser"
	"github.com/vektah/gqlparser/validator"
)
type params struct {
	Query         string                 `json:"query"`
	OperationName string                 `json:"operationName"`
	Variables     map[string]interface{} `json:"variables"`
	Extensions    *extensions            `json:"extensions"`
}
type extensions struct {
	PersistedQuery *persistedQuery `json:"persistedQuery"`
}
type persistedQuery struct {
	Sha256  string `json:"sha256Hash"`
	Version int64  `json:"version"`
}
const (
	errPersistedQueryNotSupported = "PersistedQueryNotSupported"
	errPersistedQueryNotFound     = "PersistedQueryNotFound"
)
type PersistedQueryCache interface {
	Add(ctx context.Context, hash string, query string)
	Get(ctx context.Context, hash string) (string, bool)
}
type websocketInitFunc func(ctx context.Context, initPayload InitPayload) (context.Context, error)
type Config struct {
	cacheSize                       int
	upgrader                        websocket.Upgrader
	recover                         graphql.RecoverFunc
	errorPresenter                  graphql.ErrorPresenterFunc
	resolverHook                    graphql.FieldMiddleware
	requestHook                     graphql.RequestMiddleware
	tracer                          graphql.Tracer
	complexityLimit                 int
	complexityLimitFunc             graphql.ComplexityLimitFunc
	websocketInitFunc               websocketInitFunc
	disableIntrospection            bool
	connectionKeepAlivePingInterval time.Duration
	uploadMaxMemory                 int64
	uploadMaxSize                   int64
	apqCache                        PersistedQueryCache
}
func (c *Config) newRequestContext(ctx context.Context, es graphql.ExecutableSchema, doc *ast.QueryDocument, op *ast.OperationDefinition, operationName, query string, variables map[string]interface{}) (*graphql.RequestContext, error) {
	reqCtx := &graphql.RequestContext{
		Doc:                  doc,
		RawQuery:             query,
		Variables:            variables,
		OperationName:        operationName,
		DisableIntrospection: c.disableIntrospection,
		Recover:              c.recover,
		ErrorPresenter:       c.errorPresenter,
		ResolverMiddleware:   c.resolverHook,
		RequestMiddleware:    c.requestHook,
		Tracer:               c.tracer,
		ComplexityLimit:      c.complexityLimit,
	}
	if reqCtx.ComplexityLimit > 0 || c.complexityLimitFunc != nil {
		reqCtx.OperationComplexity = complexity.Calculate(es, op, variables)
	}
	err := reqCtx.Validate(ctx)
	if err != nil {
		return nil, err
	}
	return reqCtx, nil
}
type Option func(cfg *Config)
func WebsocketUpgrader(upgrader websocket.Upgrader) Option {
	return func(cfg *Config) {
		cfg.upgrader = upgrader
	}
}
func RecoverFunc(recover graphql.RecoverFunc) Option {
	return func(cfg *Config) {
		cfg.recover = recover
	}
}
func ErrorPresenter(f graphql.ErrorPresenterFunc) Option {
	return func(cfg *Config) {
		cfg.errorPresenter = f
	}
}
func IntrospectionEnabled(enabled bool) Option {
	return func(cfg *Config) {
		cfg.disableIntrospection = !enabled
	}
}
func ComplexityLimit(limit int) Option {
	return func(cfg *Config) {
		cfg.complexityLimit = limit
	}
}
func ComplexityLimitFunc(complexityLimitFunc graphql.ComplexityLimitFunc) Option {
	return func(cfg *Config) {
		cfg.complexityLimitFunc = complexityLimitFunc
	}
}
func ResolverMiddleware(middleware graphql.FieldMiddleware) Option {
	return func(cfg *Config) {
		if cfg.resolverHook == nil {
			cfg.resolverHook = middleware
			return
		}
		lastResolve := cfg.resolverHook
		cfg.resolverHook = func(ctx context.Context, next graphql.Resolver) (res interface{}, err error) {
			return lastResolve(ctx, func(ctx context.Context) (res interface{}, err error) {
				return middleware(ctx, next)
			})
		}
	}
}
func RequestMiddleware(middleware graphql.RequestMiddleware) Option {
	return func(cfg *Config) {
		if cfg.requestHook == nil {
			cfg.requestHook = middleware
			return
		}
		lastResolve := cfg.requestHook
		cfg.requestHook = func(ctx context.Context, next func(ctx context.Context) []byte) []byte {
			return lastResolve(ctx, func(ctx context.Context) []byte {
				return middleware(ctx, next)
			})
		}
	}
}
func Tracer(tracer graphql.Tracer) Option {
	return func(cfg *Config) {
		if cfg.tracer == nil {
			cfg.tracer = tracer
		} else {
			lastResolve := cfg.tracer
			cfg.tracer = &tracerWrapper{
				tracer1: lastResolve,
				tracer2: tracer,
			}
		}
		opt := RequestMiddleware(func(ctx context.Context, next func(ctx context.Context) []byte) []byte {
			ctx = tracer.StartOperationExecution(ctx)
			resp := next(ctx)
			tracer.EndOperationExecution(ctx)
			return resp
		})
		opt(cfg)
	}
}
type tracerWrapper struct {
	tracer1 graphql.Tracer
	tracer2 graphql.Tracer
}
func (tw *tracerWrapper) StartOperationParsing(ctx context.Context) context.Context {
	ctx = tw.tracer1.StartOperationParsing(ctx)
	ctx = tw.tracer2.StartOperationParsing(ctx)
	return ctx
}
func (tw *tracerWrapper) EndOperationParsing(ctx context.Context) {
	tw.tracer2.EndOperationParsing(ctx)
	tw.tracer1.EndOperationParsing(ctx)
}
func (tw *tracerWrapper) StartOperationValidation(ctx context.Context) context.Context {
	ctx = tw.tracer1.StartOperationValidation(ctx)
	ctx = tw.tracer2.StartOperationValidation(ctx)
	return ctx
}
func (tw *tracerWrapper) EndOperationValidation(ctx context.Context) {
	tw.tracer2.EndOperationValidation(ctx)
	tw.tracer1.EndOperationValidation(ctx)
}
func (tw *tracerWrapper) StartOperationExecution(ctx context.Context) context.Context {
	ctx = tw.tracer1.StartOperationExecution(ctx)
	ctx = tw.tracer2.StartOperationExecution(ctx)
	return ctx
}
func (tw *tracerWrapper) StartFieldExecution(ctx context.Context, field graphql.CollectedField) context.Context {
	ctx = tw.tracer1.StartFieldExecution(ctx, field)
	ctx = tw.tracer2.StartFieldExecution(ctx, field)
	return ctx
}
func (tw *tracerWrapper) StartFieldResolverExecution(ctx context.Context, rc *graphql.ResolverContext) context.Context {
	ctx = tw.tracer1.StartFieldResolverExecution(ctx, rc)
	ctx = tw.tracer2.StartFieldResolverExecution(ctx, rc)
	return ctx
}
func (tw *tracerWrapper) StartFieldChildExecution(ctx context.Context) context.Context {
	ctx = tw.tracer1.StartFieldChildExecution(ctx)
	ctx = tw.tracer2.StartFieldChildExecution(ctx)
	return ctx
}
func (tw *tracerWrapper) EndFieldExecution(ctx context.Context) {
	tw.tracer2.EndFieldExecution(ctx)
	tw.tracer1.EndFieldExecution(ctx)
}
func (tw *tracerWrapper) EndOperationExecution(ctx context.Context) {
	tw.tracer2.EndOperationExecution(ctx)
	tw.tracer1.EndOperationExecution(ctx)
}
func WebsocketInitFunc(websocketInitFunc websocketInitFunc) Option {
	return func(cfg *Config) {
		cfg.websocketInitFunc = websocketInitFunc
	}
}