func (s *Service) HandleOutbound(_ service.DIDCommMsg, _, _ string) (string, error) {
	return "", errors.New("not implemented")
}
HandleOutbound handles outbound didexchange messages.
package didexchange
import (
	"encoding/json"
	"errors"
	"fmt"
	"strings"
	"github.com/google/uuid"
	"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/protocol/decorator"
	"github.com/hyperledger/aries-framework-go/pkg/didcomm/protocol/mediator"
	"github.com/hyperledger/aries-framework-go/pkg/didcomm/transport"
	"github.com/hyperledger/aries-framework-go/pkg/doc/did"
	vdrapi "github.com/hyperledger/aries-framework-go/pkg/framework/aries/api/vdr"
	"github.com/hyperledger/aries-framework-go/pkg/internal/logutil"
	"github.com/hyperledger/aries-framework-go/pkg/kms"
	"github.com/hyperledger/aries-framework-go/pkg/store/connection"
	didstore "github.com/hyperledger/aries-framework-go/pkg/store/did"
	"github.com/hyperledger/aries-framework-go/pkg/vdr"
	"github.com/hyperledger/aries-framework-go/spi/storage"
)
var logger = log.New("aries-framework/did-exchange/service")
const (
	DIDExchange = "didexchange"
	PIURI = "https://didcomm.org/didexchange/1.0"
	InvitationMsgType = PIURI + "/invitation"
	RequestMsgType = PIURI + "/request"
	ResponseMsgType = PIURI + "/response"
	AckMsgType = PIURI + "/ack"
	CompleteMsgType = PIURI + "/complete"
	oobMsgType             = "oob-invitation"
	routerConnsMetadataKey = "routerConnections"
)
const (
	myNSPrefix = "my"
	theirNSPrefix = "their"
)
type message struct {
	Msg           service.DIDCommMsgMap
	ThreadID      string
	Options       *options
	NextStateName string
	ConnRecord    *connection.Record
	err error
}
type provider interface {
	OutboundDispatcher() dispatcher.Outbound
	StorageProvider() storage.Provider
	ProtocolStateStorageProvider() storage.Provider
	DIDConnectionStore() didstore.ConnectionStore
	Crypto() crypto.Crypto
	KMS() kms.KeyManager
	VDRegistry() vdrapi.Registry
	Service(id string) (interface{}, error)
	KeyType() kms.KeyType
	KeyAgreementType() kms.KeyType
	MediaTypeProfiles() []string
}
type stateMachineMsg struct {
	service.DIDCommMsg
	connRecord *connection.Record
	options    *options
}
type Service struct {
	service.Action
	service.Message
	ctx                *context
	callbackChannel    chan *message
	connectionRecorder *connection.Recorder
	connectionStore    didstore.ConnectionStore
}
type context struct {
	outboundDispatcher dispatcher.Outbound
	crypto             crypto.Crypto
	kms                kms.KeyManager
	connectionRecorder *connection.Recorder
	connectionStore    didstore.ConnectionStore
	vdRegistry         vdrapi.Registry
	routeSvc           mediator.ProtocolService
	doACAPyInterop     bool
	keyType            kms.KeyType
	keyAgreementType   kms.KeyType
	mediaTypeProfiles  []string
}
type opts interface {
	PublicDID() string
	Label() string
	RouterConnections() []string
}
func New(prov provider) (*Service, error) {
	connRecorder, err := connection.NewRecorder(prov)
	if err != nil {
		return nil, fmt.Errorf("failed to initialize connection recorder: %w", err)
	}
	s, err := prov.Service(mediator.Coordination)
	if err != nil {
		return nil, err
	}
	routeSvc, ok := s.(mediator.ProtocolService)
	if !ok {
		return nil, errors.New("cast service to Route Service failed")
	}
	const callbackChannelSize = 10
	keyType := prov.KeyType()
	if keyType == "" {
		keyType = kms.ED25519Type
	}
	keyAgreementType := prov.KeyAgreementType()
	if keyAgreementType == "" {
		keyAgreementType = kms.X25519ECDHKWType
	}
	mediaTypeProfiles := prov.MediaTypeProfiles()
	if len(mediaTypeProfiles) == 0 {
		mediaTypeProfiles = []string{transport.MediaTypeAIP2RFC0019Profile}
	}
	svc := &Service{
		ctx: &context{
			outboundDispatcher: prov.OutboundDispatcher(),
			crypto:             prov.Crypto(),
			kms:                prov.KMS(),
			vdRegistry:         prov.VDRegistry(),
			connectionRecorder: connRecorder,
			connectionStore:    prov.DIDConnectionStore(),
			routeSvc:           routeSvc,
			doACAPyInterop:     doACAPyInterop,
			keyType:            keyType,
			keyAgreementType:   keyAgreementType,
			mediaTypeProfiles:  mediaTypeProfiles,
		},
		callbackChannel:    make(chan *message, callbackChannelSize),
		connectionRecorder: connRecorder,
		connectionStore:    prov.DIDConnectionStore(),
	}
	go svc.startInternalListener()
	return svc, nil
}
func retrievingRouterConnections(msg service.DIDCommMsg) []string {
	raw, found := msg.Metadata()[routerConnsMetadataKey]
	if !found {
		return nil
	}
	connections, ok := raw.([]string)
	if !ok {
		return nil
	}
	return connections
}
func (s *Service) HandleInbound(msg service.DIDCommMsg, ctx service.DIDCommContext) (string, error) {
	logger.Debugf("receive inbound message : %s", msg)
	thID, err := msg.ThreadID()
	if err != nil {
		return "", err
	}
	next, err := s.nextState(msg.Type(), thID)
	if err != nil {
		return "", fmt.Errorf("handle inbound - next state : %w", err)
	}
	connRecord, err := s.connectionRecord(msg)
	if err != nil {
		return "", fmt.Errorf("failed to fetch connection record : %w", err)
	}
	logger.Debugf("connection record: %+v", connRecord)
	internalMsg := &message{
		Options:       &options{routerConnections: retrievingRouterConnections(msg)},
		Msg:           msg.Clone(),
		ThreadID:      thID,
		NextStateName: next.Name(),
		ConnRecord:    connRecord,
	}
	go func(msg *message, aEvent chan<- service.DIDCommAction) {
		if err = s.handle(msg, aEvent); err != nil {
			logutil.LogError(logger, DIDExchange, "processMessage", err.Error(),
				logutil.CreateKeyValueString("msgType", msg.Msg.Type()),
				logutil.CreateKeyValueString("msgID", msg.Msg.ID()),
				logutil.CreateKeyValueString("connectionID", msg.ConnRecord.ConnectionID))
		}
		logutil.LogDebug(logger, DIDExchange, "processMessage", "success",
			logutil.CreateKeyValueString("msgType", msg.Msg.Type()),
			logutil.CreateKeyValueString("msgID", msg.Msg.ID()),
			logutil.CreateKeyValueString("connectionID", msg.ConnRecord.ConnectionID))
	}(internalMsg, s.ActionEvent())
	logutil.LogDebug(logger, DIDExchange, "handleInbound", "success",
		logutil.CreateKeyValueString("msgType", msg.Type()),
		logutil.CreateKeyValueString("msgID", msg.ID()),
		logutil.CreateKeyValueString("connectionID", internalMsg.ConnRecord.ConnectionID))
	return connRecord.ConnectionID, nil
}
func (s *Service) Name() string {
	return DIDExchange
}
func findNamespace(msgType string) string {
	namespace := theirNSPrefix
	if msgType == InvitationMsgType || msgType == ResponseMsgType || msgType == oobMsgType {
		namespace = myNSPrefix
	}
	return namespace
}
func (s *Service) Accept(msgType string) bool {
	return msgType == InvitationMsgType ||
		msgType == RequestMsgType ||
		msgType == ResponseMsgType ||
		msgType == AckMsgType ||
		msgType == CompleteMsgType
}