func (m *Messenger) saveRecord(msgID string, rec record) error {
	src, err := json.Marshal(rec)
	if err != nil {
		return fmt.Errorf("marshal record: %w", err)
	}
	return m.store.Put(msgID, src)
}
saveRecord saves incoming message payload.
package messenger
import (
	"encoding/json"
	"errors"
	"fmt"
	"github.com/google/uuid"
	"github.com/hyperledger/aries-framework-go/pkg/common/log"
	"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/spi/storage"
)
const MessengerStore = "messenger_store"
type record struct {
	MyDID          string `json:"my_did,omitempty"`
	TheirDID       string `json:"their_did,omitempty"`
	ThreadID       string `json:"thread_id,omitempty"`
	ParentThreadID string `json:"parent_thread_id,omitempty"`
}
type Provider interface {
	OutboundDispatcher() dispatcher.Outbound
	StorageProvider() storage.Provider
}
type Messenger struct {
	store      storage.Store
	dispatcher dispatcher.Outbound
}
var logger = log.New("aries-framework/pkg/didcomm/messenger")
func NewMessenger(ctx Provider) (*Messenger, error) {
	store, err := ctx.StorageProvider().OpenStore(MessengerStore)
	if err != nil {
		return nil, fmt.Errorf("open store: %w", err)
	}
	return &Messenger{
		store:      store,
		dispatcher: ctx.OutboundDispatcher(),
	}, nil
}
func (m *Messenger) HandleInbound(msg service.DIDCommMsgMap, ctx service.DIDCommContext) error {
	if msg.ID() == "" {
		return errors.New("message-id is absent and can't be processed")
	}
	thID, err := msg.ThreadID()
	if err != nil {
		return fmt.Errorf("threadID: %w", err)
	}
	return m.saveRecord(msg.ID(), record{
		ParentThreadID: msg.ParentThreadID(),
		MyDID:          ctx.MyDID(),
		TheirDID:       ctx.TheirDID(),
		ThreadID:       thID,
	})
}
func (m *Messenger) Send(msg service.DIDCommMsgMap, myDID, theirDID string, opts ...service.Opt) error {
	fillIfMissing(msg, opts...)
	msg.UnsetThread()
	msg.SetThread(msg.ID(), "", opts...)
	return m.dispatcher.SendToDID(msg, myDID, theirDID)
}
func (m *Messenger) SendToDestination(msg service.DIDCommMsgMap, sender string,
	destination *service.Destination, opts ...service.Opt) error {
	fillIfMissing(msg, opts...)
	msg.UnsetThread()
	return m.dispatcher.Send(msg, sender, destination)
}
func (m *Messenger) ReplyTo(msgID string, msg service.DIDCommMsgMap, opts ...service.Opt) error {
	fillIfMissing(msg, opts...)
	rec, err := m.getRecord(msgID)
	if err != nil {
		return fmt.Errorf("get record: %w", err)
	}
	msg.UnsetThread()
	msg.SetThread(rec.ThreadID, rec.ParentThreadID, opts...)
	return m.dispatcher.SendToDID(msg, rec.MyDID, rec.TheirDID)
}
func (m *Messenger) ReplyToMsg(in, out service.DIDCommMsgMap, myDID, theirDID string, opts ...service.Opt) error {
	fillIfMissing(out, opts...)
	thID, err := in.ThreadID()
	if err != nil {
		return fmt.Errorf("get threadID: %w", err)
	}
	out.UnsetThread()
	out.SetThread(thID, in.ParentThreadID(), opts...)
	return m.dispatcher.SendToDID(out, myDID, theirDID)
}
func (m *Messenger) ReplyToNested(msg service.DIDCommMsgMap, opts *service.NestedReplyOpts) error {
	fillIfMissing(msg, service.WithVersion(opts.V))
	if err := m.fillNestedReplyOption(opts); err != nil {
		return fmt.Errorf("failed to prepare nested reply options: %w", err)
	}
	msg.UnsetThread()
	msg.SetThread("", opts.ThreadID, service.WithVersion(opts.V))
	return m.dispatcher.SendToDID(msg, opts.MyDID, opts.TheirDID)
}
func fillIfMissing(msg service.DIDCommMsgMap, opts ...service.Opt) {
	if msg.ID() == "" {
		msg.SetID(uuid.New().String(), opts...)
	}
}
func (m *Messenger) getRecord(msgID string) (*record, error) {
	src, err := m.store.Get(msgID)
	if err != nil {
		return nil, fmt.Errorf("store get: %w", err)
	}
	var r *record
	if err = json.Unmarshal(src, &r); err != nil {
		return nil, fmt.Errorf("unmarshal record: %w", err)
	}
	return r, nil
}