func WithProtocolServices(services ...dispatcher.ProtocolService) ProviderOption {
	return func(opts *Provider) error {
		opts.services = services
		return nil
	}
}
WithProtocolServices injects a protocol services into the context.
package context
import (
	"encoding/json"
	"errors"
	"fmt"
	"strings"
	"time"
	"github.com/btcsuite/btcutil/base58"
	"github.com/cenkalti/backoff/v4"
	jsonld "github.com/piprate/json-gold/ld"
	"github.com/hyperledger/aries-framework-go/pkg/common/log"
	"github.com/hyperledger/aries-framework-go/pkg/crypto"
	"github.com/hyperledger/aries-framework-go/pkg/didcomm/common/service"
	"github.com/hyperledger/aries-framework-go/pkg/didcomm/dispatcher"
	"github.com/hyperledger/aries-framework-go/pkg/didcomm/packer"
	"github.com/hyperledger/aries-framework-go/pkg/didcomm/protocol/didexchange"
	"github.com/hyperledger/aries-framework-go/pkg/didcomm/transport"
	"github.com/hyperledger/aries-framework-go/pkg/framework/aries/api"
	vdrapi "github.com/hyperledger/aries-framework-go/pkg/framework/aries/api/vdr"
	"github.com/hyperledger/aries-framework-go/pkg/kms"
	"github.com/hyperledger/aries-framework-go/pkg/secretlock"
	"github.com/hyperledger/aries-framework-go/pkg/store/did"
	"github.com/hyperledger/aries-framework-go/pkg/store/ld"
	"github.com/hyperledger/aries-framework-go/pkg/store/verifiable"
	"github.com/hyperledger/aries-framework-go/pkg/vdr/fingerprint"
	"github.com/hyperledger/aries-framework-go/spi/storage"
)
const (
	defaultGetDIDsMaxRetries = 3
	kaIdentifier             = "#"
)
var logger = log.New("aries-framework/pkg/framework/context")
type Provider struct {
	services                   []dispatcher.ProtocolService
	msgSvcProvider             api.MessageServiceProvider
	storeProvider              storage.Provider
	protocolStateStoreProvider storage.Provider
	kms                        kms.KeyManager
	secretLock                 secretlock.Service
	crypto                     crypto.Crypto
	packager                   transport.Packager
	primaryPacker              packer.Packer
	packers                    []packer.Packer
	serviceEndpoint            string
	routerEndpoint             string
	outboundDispatcher         dispatcher.Outbound
	messenger                  service.MessengerHandler
	outboundTransports         []transport.OutboundTransport
	vdr                        vdrapi.Registry
	verifiableStore            verifiable.Store
	didConnectionStore         did.ConnectionStore
	contextStore               ld.ContextStore
	remoteProviderStore        ld.RemoteProviderStore
	documentLoader             jsonld.DocumentLoader
	transportReturnRoute       string
	frameworkID                string
	keyType                    kms.KeyType
	keyAgreementType           kms.KeyType
	mediaTypeProfiles          []string
	getDIDsMaxRetries          uint64
	getDIDsBackOffDuration     time.Duration
}
type inboundHandler struct {
	handlers []dispatcher.ProtocolService
}
func (in *inboundHandler) HandleInbound(msg service.DIDCommMsg, ctx service.DIDCommContext) (string, error) {
	for i := range in.handlers {
		if in.handlers[i].Accept(msg.Type()) {
			return in.handlers[i].HandleInbound(msg, ctx)
		}
	}
	return "", fmt.Errorf("no inbound handlers for msg type: %s", msg.Type())
}
func New(opts ...ProviderOption) (*Provider, error) {
	ctxProvider := Provider{
		getDIDsMaxRetries:      defaultGetDIDsMaxRetries,
		getDIDsBackOffDuration: time.Second,
	}
	for _, opt := range opts {
		err := opt(&ctxProvider)
		if err != nil {
			return nil, fmt.Errorf("option failed: %w", err)
		}
	}
	return &ctxProvider, nil
}
func (p *Provider) OutboundDispatcher() dispatcher.Outbound {
	return p.outboundDispatcher
}
func (p *Provider) OutboundTransports() []transport.OutboundTransport {
	return p.outboundTransports
}
func (p *Provider) Service(id string) (interface{}, error) {
	for _, v := range p.services {
		if v.Name() == id {
			return v, nil
		}
	}
	return nil, api.ErrSvcNotFound
}
func (p *Provider) KMS() kms.KeyManager {
	return p.kms
}
func (p *Provider) SecretLock() secretlock.Service {
	return p.secretLock
}
func (p *Provider) Crypto() crypto.Crypto {
	return p.crypto
}
func (p *Provider) Packager() transport.Packager {
	return p.packager
}
func (p *Provider) Messenger() service.Messenger {
	return p.messenger
}
func (p *Provider) Packers() []packer.Packer {
	return p.packers
}
func (p *Provider) PrimaryPacker() packer.Packer {
	return p.primaryPacker
}
func (p *Provider) ServiceEndpoint() string {
	return p.serviceEndpoint
}
func (p *Provider) RouterEndpoint() string {
	return p.routerEndpoint
}
func (p *Provider) tryToHandle(
	svc service.InboundHandler, msg service.DIDCommMsgMap, ctx service.DIDCommContext) error {
	if err := p.messenger.HandleInbound(msg, ctx); err != nil {
		return fmt.Errorf("messenger HandleInbound: %w", err)
	}
	_, err := svc.HandleInbound(msg, ctx)
	return err
}
func (p *Provider) InboundMessageHandler() transport.InboundMessageHandler {
	return func(envelope *transport.Envelope) error {
		msg, err := service.ParseDIDCommMsgMap(envelope.Message)
		if err != nil {
			return err
		}
		for _, svc := range p.services {
			if svc.Accept(msg.Type()) {
				var myDID, theirDID string
				switch svc.Name() {
				case didexchange.DIDExchange:
				default:
					myDID, theirDID, err = p.getDIDs(envelope)
					if err != nil {
						return fmt.Errorf("inbound message handler: %w", err)
					}
				}
				_, err = svc.HandleInbound(msg, service.NewDIDCommContext(myDID, theirDID, nil))
				return err
			}
		}
		for _, svc := range p.msgSvcProvider.Services() {
			h := struct {
				Purpose []string `json:"~purpose"`
			}{}
			err = msg.Decode(&h)
			if err != nil {
				return err
			}
			if svc.Accept(msg.Type(), h.Purpose) {
				myDID, theirDID, err := p.getDIDs(envelope)
				if err != nil {
					return fmt.Errorf("inbound message handler: %w", err)
				}
				return p.tryToHandle(svc, msg, service.NewDIDCommContext(myDID, theirDID, nil))
			}
		}
		return fmt.Errorf("no message handlers found for the message type: %s", msg.Type())
	}
}
func (p *Provider) getDIDs(envelope *transport.Envelope) (string, string, error) {
	var (
		myDID    string
		theirDID string
		err      error
	)
	return myDID, theirDID, backoff.Retry(func() error {
		var notFound bool
		if id := strings.Index(string(envelope.ToKey), kaIdentifier); id > 0 &&
			strings.Index(string(envelope.ToKey), "\"kid\":\"did:") > 0 {
			myDID, err = pubKeyToDID(envelope.ToKey)
			if err != nil {
				return fmt.Errorf("getMyDID: envelope.ToKey as myDID: %w", err)
			}
			logger.Debugf("envelope.ToKey as myDID: %v", myDID)
		} else {
			myDID, err = p.didConnectionStore.GetDID(base58.Encode(envelope.ToKey))
			if errors.Is(err, did.ErrNotFound) {
				notFound = true
				didKey, _ := fingerprint.CreateDIDKey(envelope.ToKey)
				myDID, err = p.didConnectionStore.GetDID(didKey)
				if err != nil && !errors.Is(err, did.ErrNotFound) {
					return fmt.Errorf("failed to get my did from didKey: %w", err)
				}
			} else if err != nil {
				return fmt.Errorf("failed to get my did: %w", err)
			}
		}
		if id := strings.Index(string(envelope.FromKey), kaIdentifier); id > 0 &&
			strings.Index(string(envelope.FromKey), "\"kid\":\"did:") > 0 {
			theirDID, err = pubKeyToDID(envelope.FromKey)
			if err != nil {
				return fmt.Errorf("getDIDs: envelope.FromKey as theirDID: %w", err)
			}
			logger.Debugf("envelope.FromKey as theirDID: %v", theirDID)
		} else {
			if envelope.FromKey != nil {
				theirDID, err = p.didConnectionStore.GetDID(base58.Encode(envelope.FromKey))
				if notFound && errors.Is(err, did.ErrNotFound) {
					didKey, _ := fingerprint.CreateDIDKey(envelope.FromKey)
					theirDID, err = p.didConnectionStore.GetDID(didKey)
					if err != nil && !errors.Is(err, did.ErrNotFound) {
						return fmt.Errorf("failed to get their did from didKey: %w", err)
					}
				} else if err != nil {
					return fmt.Errorf("failed to get their did: %w", err)
				}
			}
		}
		return nil
	}, backoff.WithMaxRetries(backoff.NewConstantBackOff(p.getDIDsBackOffDuration), p.getDIDsMaxRetries))
}
func pubKeyToDID(key []byte) (string, error) {
	toKey := &crypto.PublicKey{}
	err := json.Unmarshal(key, toKey)
	if err != nil {
		return "", fmt.Errorf("pubKeyToDID: unmarshal key: %w", err)
	}
	return toKey.KID[:strings.Index(toKey.KID, kaIdentifier)], nil
}
func (p *Provider) InboundDIDCommMessageHandler() func() service.InboundHandler {
	return func() service.InboundHandler {
		tmp := make([]dispatcher.ProtocolService, len(p.services))
		copy(tmp, p.services)
		return &inboundHandler{handlers: tmp}
	}
}
func (p *Provider) StorageProvider() storage.Provider {
	return p.storeProvider
}
func (p *Provider) ProtocolStateStorageProvider() storage.Provider {
	return p.protocolStateStoreProvider
}
func (p *Provider) VDRegistry() vdrapi.Registry {
	return p.vdr
}
func (p *Provider) TransportReturnRoute() string {
	return p.transportReturnRoute
}
func (p *Provider) AriesFrameworkID() string {
	return p.frameworkID
}
func (p *Provider) VerifiableStore() verifiable.Store {
	return p.verifiableStore
}
func (p *Provider) DIDConnectionStore() did.ConnectionStore {
	return p.didConnectionStore
}
func (p *Provider) JSONLDContextStore() ld.ContextStore {
	return p.contextStore
}
func (p *Provider) JSONLDRemoteProviderStore() ld.RemoteProviderStore {
	return p.remoteProviderStore
}
func (p *Provider) JSONLDDocumentLoader() jsonld.DocumentLoader {
	return p.documentLoader
}
func (p *Provider) KeyType() kms.KeyType {
	return p.keyType
}
func (p *Provider) KeyAgreementType() kms.KeyType {
	return p.keyAgreementType
}
func (p *Provider) MediaTypeProfiles() []string {
	return p.mediaTypeProfiles
}
type ProviderOption func(opts *Provider) error
func WithOutboundTransports(transports ...transport.OutboundTransport) ProviderOption {
	return func(opts *Provider) error {
		opts.outboundTransports = transports
		return nil
	}
}
func WithGetDIDsMaxRetries(retries uint64) ProviderOption {
	return func(opts *Provider) error {
		opts.getDIDsMaxRetries = retries
		return nil
	}
}
func WithGetDIDsBackOffDuration(duration time.Duration) ProviderOption {
	return func(opts *Provider) error {
		opts.getDIDsBackOffDuration = duration
		return nil
	}
}
func WithOutboundDispatcher(outboundDispatcher dispatcher.Outbound) ProviderOption {
	return func(opts *Provider) error {
		opts.outboundDispatcher = outboundDispatcher
		return nil
	}
}
func WithMessengerHandler(mh service.MessengerHandler) ProviderOption {
	return func(opts *Provider) error {
		opts.messenger = mh
		return nil
	}
}
func WithTransportReturnRoute(transportReturnRoute string) ProviderOption {
	return func(opts *Provider) error {
		opts.transportReturnRoute = transportReturnRoute
		return nil
	}
}